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}