graphql_tools/ast/
ext.rs

1use std::collections::HashMap;
2
3use lazy_static::lazy_static;
4
5use crate::static_graphql::query::{
6    self, Directive, FragmentSpread, OperationDefinition, SelectionSet, Type, Value,
7    VariableDefinition,
8};
9use crate::static_graphql::schema::{
10    self, DirectiveDefinition, InputValue, InterfaceType, ObjectType, TypeDefinition, UnionType,
11};
12
13pub trait FieldByNameExtension {
14    fn field_by_name(&self, name: &str) -> Option<&schema::Field>;
15    fn input_field_by_name(&self, name: &str) -> Option<&InputValue>;
16}
17
18impl FieldByNameExtension for TypeDefinition {
19    fn field_by_name(&self, name: &str) -> Option<&schema::Field> {
20        match self {
21            TypeDefinition::Object(object) => {
22                object.fields.iter().find(|field| field.name.eq(name))
23            }
24            TypeDefinition::Interface(interface) => {
25                interface.fields.iter().find(|field| field.name.eq(name))
26            }
27            _ => None,
28        }
29    }
30
31    fn input_field_by_name(&self, name: &str) -> Option<&InputValue> {
32        match self {
33            TypeDefinition::InputObject(input_object) => {
34                input_object.fields.iter().find(|field| field.name.eq(name))
35            }
36            _ => None,
37        }
38    }
39}
40
41pub trait OperationDefinitionExtension {
42    fn variable_definitions(&self) -> &[VariableDefinition];
43    fn directives(&self) -> &[Directive];
44    fn selection_set(&self) -> &SelectionSet;
45}
46
47impl OperationDefinitionExtension for OperationDefinition {
48    fn variable_definitions(&self) -> &[VariableDefinition] {
49        match self {
50            OperationDefinition::Query(query) => &query.variable_definitions,
51            OperationDefinition::SelectionSet(_) => &[],
52            OperationDefinition::Mutation(mutation) => &mutation.variable_definitions,
53            OperationDefinition::Subscription(subscription) => &subscription.variable_definitions,
54        }
55    }
56
57    fn selection_set(&self) -> &SelectionSet {
58        match self {
59            OperationDefinition::Query(query) => &query.selection_set,
60            OperationDefinition::SelectionSet(selection_set) => selection_set,
61            OperationDefinition::Mutation(mutation) => &mutation.selection_set,
62            OperationDefinition::Subscription(subscription) => &subscription.selection_set,
63        }
64    }
65
66    fn directives(&self) -> &[Directive] {
67        match self {
68            OperationDefinition::Query(query) => &query.directives,
69            OperationDefinition::SelectionSet(_) => &[],
70            OperationDefinition::Mutation(mutation) => &mutation.directives,
71            OperationDefinition::Subscription(subscription) => &subscription.directives,
72        }
73    }
74}
75
76pub trait SchemaDocumentExtension {
77    fn type_by_name(&self, name: &str) -> Option<&TypeDefinition>;
78    fn type_map(&self) -> HashMap<&str, &TypeDefinition>;
79    fn directive_by_name(&self, name: &str) -> Option<&DirectiveDefinition>;
80    fn object_type_by_name(&self, name: &str) -> Option<&ObjectType>;
81    fn schema_definition(&self) -> &schema::SchemaDefinition;
82    fn query_type(&self) -> &ObjectType;
83    fn mutation_type(&self) -> Option<&ObjectType>;
84    fn subscription_type(&self) -> Option<&ObjectType>;
85    fn is_subtype(&self, sub_type: &Type, super_type: &Type) -> bool;
86    fn is_named_subtype(&self, sub_type_name: &str, super_type_name: &str) -> bool;
87    fn is_possible_type(
88        &self,
89        abstract_type: &TypeDefinition,
90        possible_type: &TypeDefinition,
91    ) -> bool;
92}
93
94impl SchemaDocumentExtension for schema::Document {
95    fn type_by_name(&self, name: &str) -> Option<&TypeDefinition> {
96        for def in &self.definitions {
97            if let schema::Definition::TypeDefinition(type_def) = def {
98                if type_def.name().eq(name) {
99                    return Some(type_def);
100                }
101            }
102        }
103
104        None
105    }
106
107    fn directive_by_name(&self, name: &str) -> Option<&DirectiveDefinition> {
108        for def in &self.definitions {
109            if let schema::Definition::DirectiveDefinition(directive_def) = def {
110                if directive_def.name.eq(name) {
111                    return Some(directive_def);
112                }
113            }
114        }
115
116        None
117    }
118
119    fn schema_definition(&self) -> &schema::SchemaDefinition {
120        lazy_static! {
121            static ref DEFAULT_SCHEMA_DEF: schema::SchemaDefinition = {
122                schema::SchemaDefinition {
123                    query: Some("Query".to_string()),
124                    ..Default::default()
125                }
126            };
127        }
128        self.definitions
129            .iter()
130            .find_map(|definition| match definition {
131                schema::Definition::SchemaDefinition(schema_definition) => Some(schema_definition),
132                _ => None,
133            })
134            .unwrap_or(&*DEFAULT_SCHEMA_DEF)
135    }
136
137    fn query_type(&self) -> &ObjectType {
138        lazy_static! {
139            static ref QUERY: String = "Query".to_string();
140        }
141
142        let schema_definition = self.schema_definition();
143
144        self.object_type_by_name(schema_definition.query.as_ref().unwrap_or(&QUERY))
145            .unwrap()
146    }
147
148    fn mutation_type(&self) -> Option<&ObjectType> {
149        self.schema_definition()
150            .mutation
151            .as_ref()
152            .and_then(|name| self.object_type_by_name(name))
153    }
154
155    fn subscription_type(&self) -> Option<&ObjectType> {
156        self.schema_definition()
157            .subscription
158            .as_ref()
159            .and_then(|name| self.object_type_by_name(name))
160    }
161
162    fn object_type_by_name(&self, name: &str) -> Option<&ObjectType> {
163        match self.type_by_name(name) {
164            Some(TypeDefinition::Object(object_def)) => Some(object_def),
165            _ => None,
166        }
167    }
168
169    fn type_map(&self) -> HashMap<&str, &TypeDefinition> {
170        let mut type_map = HashMap::new();
171
172        for def in &self.definitions {
173            if let schema::Definition::TypeDefinition(type_def) = def {
174                type_map.insert(type_def.name(), type_def);
175            }
176        }
177
178        type_map
179    }
180
181    fn is_named_subtype(&self, sub_type_name: &str, super_type_name: &str) -> bool {
182        if sub_type_name == super_type_name {
183            true
184        } else if let (Some(sub_type), Some(super_type)) = (
185            self.type_by_name(sub_type_name),
186            self.type_by_name(super_type_name),
187        ) {
188            super_type.is_abstract_type() && self.is_possible_type(super_type, sub_type)
189        } else {
190            false
191        }
192    }
193
194    fn is_possible_type(
195        &self,
196        abstract_type: &TypeDefinition,
197        possible_type: &TypeDefinition,
198    ) -> bool {
199        match abstract_type {
200            TypeDefinition::Union(union_typedef) => union_typedef
201                .types
202                .iter()
203                .any(|t| t == possible_type.name()),
204            TypeDefinition::Interface(interface_typedef) => {
205                let implementes_interfaces = possible_type.interfaces();
206
207                implementes_interfaces.contains(&interface_typedef.name)
208            }
209            _ => false,
210        }
211    }
212
213    fn is_subtype(&self, sub_type: &Type, super_type: &Type) -> bool {
214        // Equivalent type is a valid subtype
215        if sub_type == super_type {
216            return true;
217        }
218
219        // If superType is non-null, maybeSubType must also be non-null.
220        if super_type.is_non_null() {
221            if sub_type.is_non_null() {
222                return self.is_subtype(sub_type.of_type(), super_type.of_type());
223            }
224            return false;
225        }
226
227        if sub_type.is_non_null() {
228            // If superType is nullable, maybeSubType may be non-null or nullable.
229            return self.is_subtype(sub_type.of_type(), super_type);
230        }
231
232        // If superType type is a list, maybeSubType type must also be a list.
233        if super_type.is_list_type() {
234            if sub_type.is_list_type() {
235                return self.is_subtype(sub_type.of_type(), super_type.of_type());
236            }
237
238            return false;
239        }
240
241        if sub_type.is_list_type() {
242            // If superType is nullable, maybeSubType may be non-null or nullable.
243            return false;
244        }
245
246        // If superType type is an abstract type, check if it is super type of maybeSubType.
247        // Otherwise, the child type is not a valid subtype of the parent type.
248        if let (Some(sub_type), Some(super_type)) = (
249            self.type_by_name(sub_type.inner_type()),
250            self.type_by_name(super_type.inner_type()),
251        ) {
252            return super_type.is_abstract_type()
253                && (sub_type.is_interface_type() || sub_type.is_object_type())
254                && self.is_possible_type(super_type, sub_type);
255        }
256
257        false
258    }
259}
260
261pub trait TypeExtension {
262    fn inner_type(&self) -> &str;
263    fn is_non_null(&self) -> bool;
264    fn is_list_type(&self) -> bool;
265    fn is_named_type(&self) -> bool;
266    fn of_type(&self) -> &Type;
267}
268
269impl TypeExtension for Type {
270    fn inner_type(&self) -> &str {
271        match self {
272            Type::NamedType(name) => name.as_str(),
273            Type::ListType(child) => child.inner_type(),
274            Type::NonNullType(child) => child.inner_type(),
275        }
276    }
277
278    fn of_type(&self) -> &Type {
279        match self {
280            Type::ListType(child) => child,
281            Type::NonNullType(child) => child,
282            Type::NamedType(_) => self,
283        }
284    }
285
286    fn is_non_null(&self) -> bool {
287        matches!(self, Type::NonNullType(_))
288    }
289
290    fn is_list_type(&self) -> bool {
291        matches!(self, Type::ListType(_))
292    }
293
294    fn is_named_type(&self) -> bool {
295        matches!(self, Type::NamedType(_))
296    }
297}
298
299pub trait ValueExtension {
300    fn compare(&self, other: &Self) -> bool;
301    fn variables_in_use(&self) -> Vec<&str>;
302}
303
304impl ValueExtension for Value {
305    fn compare(&self, other: &Self) -> bool {
306        match (self, other) {
307            (Value::Null, Value::Null) => true,
308            (Value::Boolean(a), Value::Boolean(b)) => a == b,
309            (Value::Int(a), Value::Int(b)) => a == b,
310            (Value::Float(a), Value::Float(b)) => a == b,
311            (Value::String(a), Value::String(b)) => a.eq(b),
312            (Value::Enum(a), Value::Enum(b)) => a.eq(b),
313            (Value::List(a), Value::List(b)) => a.iter().zip(b.iter()).all(|(a, b)| a.compare(b)),
314            (Value::Object(a), Value::Object(b)) => {
315                a.iter().zip(b.iter()).all(|(a, b)| a.1.compare(b.1))
316            }
317            (Value::Variable(a), Value::Variable(b)) => a.eq(b),
318            _ => false,
319        }
320    }
321
322    fn variables_in_use(&self) -> Vec<&str> {
323        match self {
324            Value::Variable(v) => vec![v],
325            Value::List(list) => list.iter().flat_map(|v| v.variables_in_use()).collect(),
326            Value::Object(object) => object
327                .iter()
328                .flat_map(|(_, v)| v.variables_in_use())
329                .collect(),
330            _ => vec![],
331        }
332    }
333}
334
335pub trait InputValueHelpers {
336    fn is_required(&self) -> bool;
337}
338
339impl InputValueHelpers for InputValue {
340    fn is_required(&self) -> bool {
341        if let Type::NonNullType(_inner_type) = &self.value_type {
342            if self.default_value.is_none() {
343                return true;
344            }
345        }
346
347        false
348    }
349}
350
351pub trait AbstractTypeDefinitionExtension {
352    fn is_implemented_by(&self, other_type: &dyn ImplementingInterfaceExtension) -> bool;
353}
354
355pub trait TypeDefinitionExtension {
356    fn is_leaf_type(&self) -> bool;
357    fn is_composite_type(&self) -> bool;
358    fn is_input_type(&self) -> bool;
359    fn is_object_type(&self) -> bool;
360    fn is_union_type(&self) -> bool;
361    fn is_interface_type(&self) -> bool;
362    fn is_enum_type(&self) -> bool;
363    fn is_scalar_type(&self) -> bool;
364    fn is_abstract_type(&self) -> bool;
365    fn name(&self) -> &str;
366}
367
368pub trait ImplementingInterfaceExtension {
369    fn interfaces(&self) -> Vec<String>;
370    fn has_sub_type(&self, other_type: &TypeDefinition) -> bool;
371    fn has_concrete_sub_type(&self, concrete_type: &ObjectType) -> bool;
372}
373
374impl ImplementingInterfaceExtension for TypeDefinition {
375    fn interfaces(&self) -> Vec<String> {
376        match self {
377            schema::TypeDefinition::Object(o) => o.interfaces(),
378            schema::TypeDefinition::Interface(i) => i.interfaces(),
379            _ => vec![],
380        }
381    }
382
383    fn has_sub_type(&self, other_type: &TypeDefinition) -> bool {
384        match self {
385            TypeDefinition::Interface(interface_type) => {
386                interface_type.is_implemented_by(other_type)
387            }
388            TypeDefinition::Union(union_type) => union_type.has_sub_type(other_type.name()),
389            _ => false,
390        }
391    }
392
393    fn has_concrete_sub_type(&self, concrete_type: &ObjectType) -> bool {
394        match self {
395            TypeDefinition::Interface(interface_type) => {
396                interface_type.is_implemented_by(concrete_type)
397            }
398            TypeDefinition::Union(union_type) => union_type.has_sub_type(&concrete_type.name),
399            _ => false,
400        }
401    }
402}
403
404pub trait PossibleTypesExtension {
405    fn possible_types<'a>(&self, schema: &'a schema::Document) -> Vec<&'a ObjectType>;
406}
407
408impl PossibleTypesExtension for TypeDefinition {
409    fn possible_types<'a>(&self, schema: &'a schema::Document) -> Vec<&'a ObjectType> {
410        match self {
411            TypeDefinition::Object(_) => vec![],
412            TypeDefinition::InputObject(_) => vec![],
413            TypeDefinition::Enum(_) => vec![],
414            TypeDefinition::Scalar(_) => vec![],
415            TypeDefinition::Interface(i) => schema
416                .type_map()
417                .iter()
418                .filter_map(|(_type_name, type_def)| {
419                    if let TypeDefinition::Object(o) = type_def {
420                        if i.is_implemented_by(*type_def) {
421                            return Some(o);
422                        }
423                    }
424
425                    None
426                })
427                .collect(),
428            TypeDefinition::Union(u) => u
429                .types
430                .iter()
431                .filter_map(|type_name| {
432                    if let Some(TypeDefinition::Object(o)) = schema.type_by_name(type_name) {
433                        return Some(o);
434                    }
435
436                    None
437                })
438                .collect(),
439        }
440    }
441}
442
443impl ImplementingInterfaceExtension for InterfaceType {
444    fn interfaces(&self) -> Vec<String> {
445        self.implements_interfaces.clone()
446    }
447
448    fn has_sub_type(&self, other_type: &TypeDefinition) -> bool {
449        self.is_implemented_by(other_type)
450    }
451
452    fn has_concrete_sub_type(&self, concrete_type: &ObjectType) -> bool {
453        self.is_implemented_by(concrete_type)
454    }
455}
456
457impl ImplementingInterfaceExtension for ObjectType {
458    fn interfaces(&self) -> Vec<String> {
459        self.implements_interfaces.clone()
460    }
461
462    fn has_sub_type(&self, _other_type: &TypeDefinition) -> bool {
463        false
464    }
465
466    fn has_concrete_sub_type(&self, _concrete_type: &ObjectType) -> bool {
467        false
468    }
469}
470
471pub trait SubTypeExtension {
472    fn has_sub_type(&self, other_type_name: &str) -> bool;
473}
474
475impl SubTypeExtension for UnionType {
476    fn has_sub_type(&self, other_type_name: &str) -> bool {
477        self.types.iter().any(|v| other_type_name.eq(v))
478    }
479}
480
481impl AbstractTypeDefinitionExtension for InterfaceType {
482    fn is_implemented_by(&self, other_type: &dyn ImplementingInterfaceExtension) -> bool {
483        other_type.interfaces().iter().any(|v| self.name.eq(v))
484    }
485}
486
487impl TypeDefinitionExtension for Option<&schema::TypeDefinition> {
488    fn is_leaf_type(&self) -> bool {
489        match self {
490            Some(t) => t.is_leaf_type(),
491            _ => false,
492        }
493    }
494
495    fn is_composite_type(&self) -> bool {
496        match self {
497            Some(t) => t.is_composite_type(),
498            _ => false,
499        }
500    }
501
502    fn is_input_type(&self) -> bool {
503        match self {
504            Some(t) => t.is_input_type(),
505            _ => false,
506        }
507    }
508
509    fn is_interface_type(&self) -> bool {
510        match self {
511            Some(t) => t.is_interface_type(),
512            _ => false,
513        }
514    }
515
516    fn is_object_type(&self) -> bool {
517        match self {
518            Some(t) => t.is_object_type(),
519            _ => false,
520        }
521    }
522
523    fn is_union_type(&self) -> bool {
524        match self {
525            Some(t) => t.is_union_type(),
526            _ => false,
527        }
528    }
529
530    fn is_enum_type(&self) -> bool {
531        match self {
532            Some(t) => t.is_enum_type(),
533            _ => false,
534        }
535    }
536
537    fn is_scalar_type(&self) -> bool {
538        match self {
539            Some(t) => t.is_scalar_type(),
540            _ => false,
541        }
542    }
543
544    fn is_abstract_type(&self) -> bool {
545        match self {
546            Some(t) => t.is_abstract_type(),
547            _ => false,
548        }
549    }
550
551    fn name(&self) -> &str {
552        match self {
553            Some(t) => t.name(),
554            _ => "",
555        }
556    }
557}
558
559impl TypeDefinitionExtension for schema::TypeDefinition {
560    fn name(&self) -> &str {
561        match self {
562            schema::TypeDefinition::Object(o) => &o.name,
563            schema::TypeDefinition::Interface(i) => &i.name,
564            schema::TypeDefinition::Union(u) => &u.name,
565            schema::TypeDefinition::Scalar(s) => &s.name,
566            schema::TypeDefinition::Enum(e) => &e.name,
567            schema::TypeDefinition::InputObject(i) => &i.name,
568        }
569    }
570
571    fn is_abstract_type(&self) -> bool {
572        matches!(
573            self,
574            schema::TypeDefinition::Interface(_) | schema::TypeDefinition::Union(_)
575        )
576    }
577
578    fn is_interface_type(&self) -> bool {
579        matches!(self, schema::TypeDefinition::Interface(_))
580    }
581
582    fn is_leaf_type(&self) -> bool {
583        matches!(
584            self,
585            schema::TypeDefinition::Scalar(_) | schema::TypeDefinition::Enum(_)
586        )
587    }
588
589    fn is_input_type(&self) -> bool {
590        matches!(
591            self,
592            schema::TypeDefinition::Scalar(_)
593                | schema::TypeDefinition::Enum(_)
594                | schema::TypeDefinition::InputObject(_)
595        )
596    }
597
598    fn is_composite_type(&self) -> bool {
599        matches!(
600            self,
601            schema::TypeDefinition::Object(_)
602                | schema::TypeDefinition::Interface(_)
603                | schema::TypeDefinition::Union(_)
604        )
605    }
606
607    fn is_object_type(&self) -> bool {
608        matches!(self, schema::TypeDefinition::Object(_o))
609    }
610
611    fn is_union_type(&self) -> bool {
612        matches!(self, schema::TypeDefinition::Union(_o))
613    }
614
615    fn is_enum_type(&self) -> bool {
616        matches!(self, schema::TypeDefinition::Enum(_o))
617    }
618
619    fn is_scalar_type(&self) -> bool {
620        matches!(self, schema::TypeDefinition::Scalar(_o))
621    }
622}
623
624pub trait AstNodeWithName {
625    fn node_name(&self) -> Option<&str>;
626}
627
628impl AstNodeWithName for query::OperationDefinition {
629    fn node_name(&self) -> Option<&str> {
630        match self {
631            query::OperationDefinition::Query(q) => q.name.as_deref(),
632            query::OperationDefinition::SelectionSet(_s) => None,
633            query::OperationDefinition::Mutation(m) => m.name.as_deref(),
634            query::OperationDefinition::Subscription(s) => s.name.as_deref(),
635        }
636    }
637}
638
639impl AstNodeWithName for query::FragmentDefinition {
640    fn node_name(&self) -> Option<&str> {
641        Some(&self.name)
642    }
643}
644
645impl AstNodeWithName for query::FragmentSpread {
646    fn node_name(&self) -> Option<&str> {
647        Some(&self.fragment_name)
648    }
649}
650
651pub trait FragmentSpreadExtraction {
652    fn get_recursive_fragment_spreads(&self) -> Vec<&FragmentSpread>;
653    fn get_fragment_spreads(&self) -> Vec<&FragmentSpread>;
654}
655
656impl FragmentSpreadExtraction for query::SelectionSet {
657    fn get_recursive_fragment_spreads(&self) -> Vec<&FragmentSpread> {
658        self.items
659            .iter()
660            .flat_map(|v| match v {
661                query::Selection::FragmentSpread(f) => vec![f],
662                query::Selection::Field(f) => f.selection_set.get_fragment_spreads(),
663                query::Selection::InlineFragment(f) => f.selection_set.get_fragment_spreads(),
664            })
665            .collect()
666    }
667
668    fn get_fragment_spreads(&self) -> Vec<&FragmentSpread> {
669        self.items
670            .iter()
671            .flat_map(|v| match v {
672                query::Selection::FragmentSpread(f) => vec![f],
673                _ => vec![],
674            })
675            .collect()
676    }
677}