mod debug;
mod directives;
mod entity;
mod enum_definitions;
mod enum_values;
mod ids;
mod objects;
mod root_operation_types;
mod scalar_definitions;
mod r#type;
mod view;
use crate::directives::*;
pub use self::{
directives::*,
entity::*,
enum_definitions::EnumDefinitionRecord,
enum_values::{EnumValue, EnumValueRecord},
ids::*,
r#type::{Definition, Type},
root_operation_types::RootOperationTypes,
scalar_definitions::ScalarDefinitionRecord,
view::{View, ViewNested},
};
use enum_definitions::EnumDefinition;
use scalar_definitions::ScalarDefinition;
pub use wrapping::Wrapping;
use std::ops::Range;
#[derive(Clone)]
pub struct FederatedGraph {
pub subgraphs: Vec<Subgraph>,
pub root_operation_types: RootOperationTypes,
pub objects: Vec<Object>,
pub interfaces: Vec<Interface>,
pub fields: Vec<Field>,
pub scalar_definitions: Vec<ScalarDefinitionRecord>,
pub enum_definitions: Vec<EnumDefinitionRecord>,
pub unions: Vec<Union>,
pub input_objects: Vec<InputObject>,
pub enum_values: Vec<EnumValueRecord>,
pub input_value_definitions: Vec<InputValueDefinition>,
pub strings: Vec<String>,
}
impl FederatedGraph {
#[cfg(feature = "from_sdl")]
pub fn from_sdl(sdl: &str) -> Result<Self, crate::DomainError> {
crate::from_sdl::from_sdl(sdl)
}
pub fn definition_name(&self, definition: Definition) -> &str {
let name_id = match definition {
Definition::Scalar(scalar_id) => self[scalar_id].name,
Definition::Object(object_id) => self.at(object_id).name,
Definition::Interface(interface_id) => self.at(interface_id).name,
Definition::Union(union_id) => self[union_id].name,
Definition::Enum(enum_id) => self[enum_id].name,
Definition::InputObject(input_object_id) => self[input_object_id].name,
};
&self[name_id]
}
pub fn iter_interfaces(&self) -> impl ExactSizeIterator<Item = View<InterfaceId, &Interface>> {
(0..self.interfaces.len()).map(|idx| self.view(InterfaceId::from(idx)))
}
pub fn iter_objects(&self) -> impl ExactSizeIterator<Item = View<ObjectId, &Object>> {
(0..self.objects.len()).map(|idx| self.view(ObjectId::from(idx)))
}
pub fn iter_scalar_definitions(&self) -> impl Iterator<Item = ScalarDefinition<'_>> {
self.scalar_definitions
.iter()
.enumerate()
.map(|(idx, _)| self.at(ScalarDefinitionId::from(idx)))
}
pub fn iter_enum_definitions(&self) -> impl Iterator<Item = EnumDefinition<'_>> {
self.enum_definitions
.iter()
.enumerate()
.map(|(idx, _)| self.at(EnumDefinitionId::from(idx)))
}
}
#[derive(Clone)]
pub struct Subgraph {
pub name: StringId,
pub url: StringId,
}
#[derive(Clone)]
pub struct Union {
pub name: StringId,
pub description: Option<StringId>,
pub members: Vec<ObjectId>,
pub directives: Vec<Directive>,
}
#[derive(Clone)]
pub struct InputObject {
pub name: StringId,
pub description: Option<StringId>,
pub fields: InputValueDefinitions,
pub directives: Vec<Directive>,
}
#[derive(Default, Clone, PartialEq, PartialOrd, Debug)]
#[allow(clippy::enum_variant_names)]
pub enum Value {
#[default]
Null,
String(StringId),
Int(i64),
Float(f64),
Boolean(bool),
UnboundEnumValue(StringId),
EnumValue(EnumValueId),
Object(Box<[(StringId, Value)]>),
List(Box<[Value]>),
}
#[derive(Clone)]
pub struct Object {
pub name: StringId,
pub directives: Vec<Directive>,
pub description: Option<StringId>,
pub implements_interfaces: Vec<InterfaceId>,
pub fields: Fields,
}
#[derive(Clone)]
pub struct Interface {
pub name: StringId,
pub directives: Vec<Directive>,
pub description: Option<StringId>,
pub implements_interfaces: Vec<InterfaceId>,
pub fields: Fields,
}
#[derive(Clone)]
pub struct Field {
pub parent_entity_id: EntityDefinitionId,
pub name: StringId,
pub description: Option<StringId>,
pub r#type: Type,
pub arguments: InputValueDefinitions,
pub directives: Vec<Directive>,
}
impl Value {
pub fn is_list(&self) -> bool {
matches!(self, Value::List(_))
}
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
}
#[derive(Clone, PartialEq)]
pub struct InputValueDefinition {
pub name: StringId,
pub r#type: Type,
pub directives: Vec<Directive>,
pub description: Option<StringId>,
pub default: Option<Value>,
}
#[derive(Clone)]
pub struct FieldProvides {
pub subgraph_id: SubgraphId,
pub fields: SelectionSet,
}
#[derive(Clone)]
pub struct FieldRequires {
pub subgraph_id: SubgraphId,
pub fields: SelectionSet,
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct SelectionSet(pub Vec<Selection>);
impl From<Vec<Selection>> for SelectionSet {
fn from(selections: Vec<Selection>) -> Self {
SelectionSet(selections)
}
}
impl FromIterator<Selection> for SelectionSet {
fn from_iter<I: IntoIterator<Item = Selection>>(iter: I) -> Self {
SelectionSet(iter.into_iter().collect())
}
}
impl std::ops::Deref for SelectionSet {
type Target = Vec<Selection>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for SelectionSet {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl SelectionSet {
pub fn find_field(&self, field_id: FieldId) -> Option<&FieldSelection> {
for selection in &self.0 {
match selection {
Selection::Field(field) => {
if field.field_id == field_id {
return Some(field);
}
}
Selection::InlineFragment { subselection, .. } => {
if let Some(found) = subselection.find_field(field_id) {
return Some(found);
}
}
}
}
None
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum Selection {
Field(FieldSelection),
InlineFragment { on: Definition, subselection: SelectionSet },
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct FieldSelection {
pub field_id: FieldId,
pub arguments: Vec<(InputValueDefinitionId, Value)>,
pub subselection: SelectionSet,
}
#[derive(Clone, Debug)]
pub struct Key {
pub subgraph_id: SubgraphId,
pub fields: SelectionSet,
pub is_interface_object: bool,
pub resolvable: bool,
}
impl Default for FederatedGraph {
fn default() -> Self {
FederatedGraph {
scalar_definitions: Vec::new(),
enum_definitions: Vec::new(),
subgraphs: Vec::new(),
interfaces: Vec::new(),
unions: Vec::new(),
input_objects: Vec::new(),
enum_values: Vec::new(),
input_value_definitions: Vec::new(),
root_operation_types: RootOperationTypes {
query: ObjectId::from(0),
mutation: None,
subscription: None,
},
objects: vec![Object {
name: StringId::from(0),
description: None,
directives: Vec::new(),
implements_interfaces: Vec::new(),
fields: FieldId::from(0)..FieldId::from(2),
}],
fields: vec![
Field {
name: StringId::from(1),
r#type: Type {
wrapping: Default::default(),
definition: Definition::Scalar(0usize.into()),
},
parent_entity_id: EntityDefinitionId::Object(ObjectId::from(0)),
arguments: NO_INPUT_VALUE_DEFINITION,
description: None,
directives: Vec::new(),
},
Field {
name: StringId::from(2),
r#type: Type {
wrapping: Default::default(),
definition: Definition::Scalar(0usize.into()),
},
parent_entity_id: EntityDefinitionId::Object(ObjectId::from(0)),
arguments: NO_INPUT_VALUE_DEFINITION,
description: None,
directives: Vec::new(),
},
],
strings: ["Query", "__type", "__schema"]
.into_iter()
.map(|string| string.to_owned())
.collect(),
}
}
}
impl std::ops::Index<InputValueDefinitions> for FederatedGraph {
type Output = [InputValueDefinition];
fn index(&self, index: InputValueDefinitions) -> &Self::Output {
let (start, len) = index;
&self.input_value_definitions[usize::from(start)..(usize::from(start) + len)]
}
}
impl std::ops::Index<Fields> for FederatedGraph {
type Output = [Field];
fn index(&self, index: Fields) -> &Self::Output {
&self.fields[usize::from(index.start)..usize::from(index.end)]
}
}
pub type InputValueDefinitionSet = Vec<InputValueDefinitionSetItem>;
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, PartialOrd)]
pub struct InputValueDefinitionSetItem {
pub input_value_definition: InputValueDefinitionId,
pub subselection: InputValueDefinitionSet,
}
pub type Fields = Range<FieldId>;
pub type InputValueDefinitions = (InputValueDefinitionId, usize);
pub const NO_INPUT_VALUE_DEFINITION: InputValueDefinitions = (InputValueDefinitionId::const_from_usize(0), 0);
pub const NO_FIELDS: Fields = Range {
start: FieldId::const_from_usize(0),
end: FieldId::const_from_usize(0),
};
pub type FieldSet = Vec<FieldSetItem>;
#[derive(Clone, PartialEq, PartialOrd)]
pub struct FieldSetItem {
pub field: FieldId,
pub arguments: Vec<(InputValueDefinitionId, Value)>,
pub subselection: FieldSet,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn override_label() {
assert!("".parse::<OverrideLabel>().is_err());
assert!("percent(heh)".parse::<OverrideLabel>().is_err());
assert!("percent(30".parse::<OverrideLabel>().is_err());
assert_eq!(
"percent(30)".parse::<OverrideLabel>().unwrap().as_percent().unwrap(),
30
);
}
}