1mod debug;
2mod directive_definitions;
3mod directives;
4mod entity;
5mod enum_definitions;
6mod enum_values;
7mod extensions;
8mod ids;
9mod input_value_definitions;
10mod objects;
11mod root_operation_types;
12mod scalar_definitions;
13mod r#type;
14mod view;
15
16pub use self::{
17    directive_definitions::*,
18    directives::*,
19    entity::*,
20    enum_definitions::EnumDefinitionRecord,
21    enum_values::{EnumValue, EnumValueRecord},
22    extensions::*,
23    ids::*,
24    root_operation_types::RootOperationTypes,
25    scalar_definitions::ScalarDefinitionRecord,
26    r#type::{Definition, Type},
27    view::{View, ViewNested},
28};
29pub use std::fmt;
30pub use wrapping::Wrapping;
31
32use crate::directives::*;
33use enum_definitions::EnumDefinition;
34use scalar_definitions::ScalarDefinition;
35use std::ops::Range;
36
37#[derive(Clone)]
38pub struct FederatedGraph {
39    pub subgraphs: Vec<Subgraph>,
40    pub extensions: Vec<Extension>,
41    pub root_operation_types: RootOperationTypes,
42    pub objects: Vec<Object>,
43    pub interfaces: Vec<Interface>,
44    pub fields: Vec<Field>,
45
46    pub directive_definitions: Vec<DirectiveDefinitionRecord>,
47    pub directive_definition_arguments: Vec<DirectiveDefinitionArgument>,
48    pub scalar_definitions: Vec<ScalarDefinitionRecord>,
49    pub enum_definitions: Vec<EnumDefinitionRecord>,
50    pub unions: Vec<Union>,
51    pub input_objects: Vec<InputObject>,
52    pub enum_values: Vec<EnumValueRecord>,
53
54    pub input_value_definitions: Vec<InputValueDefinition>,
56
57    pub strings: Vec<String>,
59}
60
61impl FederatedGraph {
62    #[cfg(feature = "from_sdl")]
63    pub fn from_sdl(sdl: &str) -> Result<Self, crate::DomainError> {
64        if sdl.trim().is_empty() {
65            return Ok(Default::default());
66        }
67        crate::from_sdl::from_sdl(sdl)
68    }
69
70    pub fn definition_name(&self, definition: Definition) -> &str {
71        let name_id = match definition {
72            Definition::Scalar(scalar_id) => self[scalar_id].name,
73            Definition::Object(object_id) => self.at(object_id).name,
74            Definition::Interface(interface_id) => self.at(interface_id).name,
75            Definition::Union(union_id) => self[union_id].name,
76            Definition::Enum(enum_id) => self[enum_id].name,
77            Definition::InputObject(input_object_id) => self[input_object_id].name,
78        };
79
80        &self[name_id]
81    }
82
83    pub fn iter_interfaces(&self) -> impl ExactSizeIterator<Item = View<InterfaceId, &Interface>> {
84        (0..self.interfaces.len()).map(|idx| self.view(InterfaceId::from(idx)))
85    }
86
87    pub fn iter_objects(&self) -> impl ExactSizeIterator<Item = View<ObjectId, &Object>> {
88        (0..self.objects.len()).map(|idx| self.view(ObjectId::from(idx)))
89    }
90
91    pub fn iter_scalar_definitions(&self) -> impl Iterator<Item = ScalarDefinition<'_>> {
92        self.scalar_definitions
93            .iter()
94            .enumerate()
95            .map(|(idx, _)| self.at(ScalarDefinitionId::from(idx)))
96    }
97
98    pub fn iter_enum_definitions(&self) -> impl Iterator<Item = EnumDefinition<'_>> {
99        self.enum_definitions
100            .iter()
101            .enumerate()
102            .map(|(idx, _)| self.at(EnumDefinitionId::from(idx)))
103    }
104}
105
106#[derive(Clone, Debug)]
107pub struct Subgraph {
108    pub name: StringId,
109    pub join_graph_enum_value: EnumValueId,
110    pub url: Option<StringId>,
111}
112
113#[derive(Clone, Debug)]
114pub struct Union {
115    pub name: StringId,
116    pub description: Option<StringId>,
117    pub members: Vec<ObjectId>,
118    pub directives: Vec<Directive>,
119}
120
121#[derive(Clone, Debug)]
122pub struct InputObject {
123    pub name: StringId,
124    pub description: Option<StringId>,
125    pub fields: InputValueDefinitions,
126    pub directives: Vec<Directive>,
127}
128
129#[derive(Default, Clone, PartialEq, PartialOrd, Debug)]
130#[allow(clippy::enum_variant_names)]
131pub enum Value {
132    #[default]
133    Null,
134    String(StringId),
135    Int(i64),
136    Float(f64),
137    Boolean(bool),
138    UnboundEnumValue(StringId),
144    EnumValue(EnumValueId),
145    Object(Box<[(StringId, Value)]>),
146    List(Box<[Value]>),
147}
148
149#[derive(Clone, Debug)]
150pub struct Object {
151    pub name: StringId,
152    pub directives: Vec<Directive>,
153    pub description: Option<StringId>,
154    pub implements_interfaces: Vec<InterfaceId>,
155    pub fields: Fields,
156}
157
158#[derive(Clone, Debug)]
159pub struct Interface {
160    pub name: StringId,
161    pub directives: Vec<Directive>,
162    pub description: Option<StringId>,
163    pub implements_interfaces: Vec<InterfaceId>,
164    pub fields: Fields,
165}
166
167#[derive(Clone, Debug)]
168pub struct Field {
169    pub parent_entity_id: EntityDefinitionId,
170    pub name: StringId,
171    pub description: Option<StringId>,
172    pub r#type: Type,
173    pub arguments: InputValueDefinitions,
174    pub directives: Vec<Directive>,
175}
176
177impl Value {
178    pub fn is_list(&self) -> bool {
179        matches!(self, Value::List(_))
180    }
181
182    pub fn is_null(&self) -> bool {
183        matches!(self, Value::Null)
184    }
185}
186
187#[derive(Clone, PartialEq, Debug)]
188pub struct InputValueDefinition {
189    pub name: StringId,
190    pub r#type: Type,
191    pub directives: Vec<Directive>,
192    pub description: Option<StringId>,
193    pub default: Option<Value>,
194}
195
196#[derive(Clone)]
198pub struct FieldProvides {
199    pub subgraph_id: SubgraphId,
200    pub fields: SelectionSet,
201}
202
203#[derive(Clone)]
205pub struct FieldRequires {
206    pub subgraph_id: SubgraphId,
207    pub fields: SelectionSet,
208}
209
210#[derive(Clone, Debug, PartialEq, PartialOrd)]
211pub struct SelectionSet(pub Vec<Selection>);
212
213impl From<Vec<Selection>> for SelectionSet {
214    fn from(selections: Vec<Selection>) -> Self {
215        SelectionSet(selections)
216    }
217}
218
219impl FromIterator<Selection> for SelectionSet {
220    fn from_iter<I: IntoIterator<Item = Selection>>(iter: I) -> Self {
221        SelectionSet(iter.into_iter().collect())
222    }
223}
224
225impl std::ops::Deref for SelectionSet {
226    type Target = Vec<Selection>;
227    fn deref(&self) -> &Self::Target {
228        &self.0
229    }
230}
231
232impl std::ops::DerefMut for SelectionSet {
233    fn deref_mut(&mut self) -> &mut Self::Target {
234        &mut self.0
235    }
236}
237
238impl SelectionSet {
239    pub fn find_field(&self, field_id: FieldId) -> Option<&FieldSelection> {
240        for selection in &self.0 {
241            match selection {
242                Selection::Field(field) => {
243                    if field.field_id == field_id {
244                        return Some(field);
245                    }
246                }
247                Selection::InlineFragment { subselection, .. } => {
248                    if let Some(found) = subselection.find_field(field_id) {
249                        return Some(found);
250                    }
251                }
252            }
253        }
254        None
255    }
256}
257
258#[derive(Clone, Debug, PartialEq, PartialOrd)]
259pub enum Selection {
260    Field(FieldSelection),
261    InlineFragment { on: Definition, subselection: SelectionSet },
262}
263
264#[derive(Clone, Debug, PartialEq, PartialOrd)]
265pub struct FieldSelection {
266    pub field_id: FieldId,
267    pub arguments: Vec<(InputValueDefinitionId, Value)>,
268    pub subselection: SelectionSet,
269}
270
271#[derive(Clone, Debug)]
272pub struct Key {
273    pub subgraph_id: SubgraphId,
275
276    pub fields: SelectionSet,
278
279    pub is_interface_object: bool,
281
282    pub resolvable: bool,
283}
284
285impl Default for FederatedGraph {
286    fn default() -> Self {
287        FederatedGraph {
288            directive_definitions: Vec::new(),
289            directive_definition_arguments: Vec::new(),
290            enum_definitions: Vec::new(),
291            subgraphs: Vec::new(),
292            extensions: Vec::new(),
293            interfaces: Vec::new(),
294            unions: Vec::new(),
295            input_objects: Vec::new(),
296            enum_values: Vec::new(),
297            input_value_definitions: Vec::new(),
298
299            scalar_definitions: vec![ScalarDefinitionRecord {
300                namespace: None,
301                name: StringId::from(3),
302                description: None,
303                directives: Vec::new(),
304            }],
305            root_operation_types: RootOperationTypes {
306                query: ObjectId::from(0),
307                mutation: None,
308                subscription: None,
309            },
310            objects: vec![Object {
311                name: StringId::from(0),
312                description: None,
313                directives: Vec::new(),
314                implements_interfaces: Vec::new(),
315                fields: FieldId::from(0)..FieldId::from(2),
316            }],
317            fields: vec![
318                Field {
319                    name: StringId::from(1),
320                    r#type: Type {
321                        wrapping: Default::default(),
322                        definition: Definition::Scalar(0usize.into()),
323                    },
324                    parent_entity_id: EntityDefinitionId::Object(ObjectId::from(0)),
325                    arguments: NO_INPUT_VALUE_DEFINITION,
326                    description: None,
327                    directives: Vec::new(),
328                },
329                Field {
330                    name: StringId::from(2),
331                    r#type: Type {
332                        wrapping: Default::default(),
333                        definition: Definition::Scalar(0usize.into()),
334                    },
335                    parent_entity_id: EntityDefinitionId::Object(ObjectId::from(0)),
336                    arguments: NO_INPUT_VALUE_DEFINITION,
337                    description: None,
338                    directives: Vec::new(),
339                },
340            ],
341            strings: ["Query", "__type", "__schema", "String"]
342                .into_iter()
343                .map(|string| string.to_owned())
344                .collect(),
345        }
346    }
347}
348
349impl std::ops::Index<InputValueDefinitions> for FederatedGraph {
350    type Output = [InputValueDefinition];
351
352    fn index(&self, index: InputValueDefinitions) -> &Self::Output {
353        let (start, len) = index;
354        &self.input_value_definitions[usize::from(start)..(usize::from(start) + len)]
355    }
356}
357
358impl std::ops::Index<Fields> for FederatedGraph {
359    type Output = [Field];
360
361    fn index(&self, index: Fields) -> &Self::Output {
362        &self.fields[usize::from(index.start)..usize::from(index.end)]
363    }
364}
365
366pub type InputValueDefinitionSet = Vec<InputValueDefinitionSetItem>;
367
368#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, PartialOrd)]
369pub struct InputValueDefinitionSetItem {
370    pub input_value_definition: InputValueDefinitionId,
371    pub subselection: InputValueDefinitionSet,
372}
373
374pub type Fields = Range<FieldId>;
376pub type InputValueDefinitions = (InputValueDefinitionId, usize);
378
379pub const NO_INPUT_VALUE_DEFINITION: InputValueDefinitions = (InputValueDefinitionId::const_from_usize(0), 0);
380pub const NO_FIELDS: Fields = Range {
381    start: FieldId::const_from_usize(0),
382    end: FieldId::const_from_usize(0),
383};
384
385pub type FieldSet = Vec<FieldSetItem>;
386
387#[derive(Clone, PartialEq, PartialOrd)]
388pub struct FieldSetItem {
389    pub field: FieldId,
390    pub arguments: Vec<(InputValueDefinitionId, Value)>,
391    pub subselection: FieldSet,
392}
393
394#[cfg(test)]
395mod tests {
396    use super::*;
397
398    #[test]
399    fn override_label() {
400        assert!("".parse::<OverrideLabel>().is_err());
401        assert!("percent(heh)".parse::<OverrideLabel>().is_err());
402        assert!("percent(30".parse::<OverrideLabel>().is_err());
403
404        assert_eq!(
405            "percent(30)".parse::<OverrideLabel>().unwrap().as_percent().unwrap(),
406            30
407        );
408    }
409}