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: &String) -> Option<&schema::Field>;
15    fn input_field_by_name(&self, name: &String) -> Option<&InputValue>;
16}
17
18impl FieldByNameExtension for TypeDefinition {
19    fn field_by_name(&self, name: &String) -> 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: &String) -> 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) => {
201                return union_typedef
202                    .types
203                    .iter()
204                    .any(|t| t == possible_type.name());
205            }
206            TypeDefinition::Interface(interface_typedef) => {
207                let implementes_interfaces = possible_type.interfaces();
208
209                implementes_interfaces.contains(&interface_typedef.name)
210            }
211            _ => false,
212        }
213    }
214
215    fn is_subtype(&self, sub_type: &Type, super_type: &Type) -> bool {
216        // Equivalent type is a valid subtype
217        if sub_type == super_type {
218            return true;
219        }
220
221        // If superType is non-null, maybeSubType must also be non-null.
222        if super_type.is_non_null() {
223            if sub_type.is_non_null() {
224                return self.is_subtype(sub_type.of_type(), super_type.of_type());
225            }
226            return false;
227        }
228
229        if sub_type.is_non_null() {
230            // If superType is nullable, maybeSubType may be non-null or nullable.
231            return self.is_subtype(sub_type.of_type(), super_type);
232        }
233
234        // If superType type is a list, maybeSubType type must also be a list.
235        if super_type.is_list_type() {
236            if sub_type.is_list_type() {
237                return self.is_subtype(sub_type.of_type(), super_type.of_type());
238            }
239
240            return false;
241        }
242
243        if sub_type.is_list_type() {
244            // If superType is nullable, maybeSubType may be non-null or nullable.
245            return false;
246        }
247
248        // If superType type is an abstract type, check if it is super type of maybeSubType.
249        // Otherwise, the child type is not a valid subtype of the parent type.
250        if let (Some(sub_type), Some(super_type)) = (
251            self.type_by_name(sub_type.inner_type()),
252            self.type_by_name(super_type.inner_type()),
253        ) {
254            return super_type.is_abstract_type()
255                && (sub_type.is_interface_type() || sub_type.is_object_type())
256                && self.is_possible_type(super_type, sub_type);
257        }
258
259        false
260    }
261}
262
263pub trait TypeExtension {
264    fn inner_type(&self) -> &str;
265    fn is_non_null(&self) -> bool;
266    fn is_list_type(&self) -> bool;
267    fn is_named_type(&self) -> bool;
268    fn of_type(&self) -> &Type;
269}
270
271impl TypeExtension for Type {
272    fn inner_type(&self) -> &str {
273        match self {
274            Type::NamedType(name) => name.as_str(),
275            Type::ListType(child) => child.inner_type(),
276            Type::NonNullType(child) => child.inner_type(),
277        }
278    }
279
280    fn of_type(&self) -> &Type {
281        match self {
282            Type::ListType(child) => child,
283            Type::NonNullType(child) => child,
284            Type::NamedType(_) => self,
285        }
286    }
287
288    fn is_non_null(&self) -> bool {
289        match self {
290            Type::NonNullType(_) => true,
291            _ => false,
292        }
293    }
294
295    fn is_list_type(&self) -> bool {
296        match self {
297            Type::ListType(_) => true,
298            _ => false,
299        }
300    }
301
302    fn is_named_type(&self) -> bool {
303        match self {
304            Type::NamedType(_) => true,
305            _ => false,
306        }
307    }
308}
309
310pub trait ValueExtension {
311    fn compare(&self, other: &Self) -> bool;
312    fn variables_in_use(&self) -> Vec<&str>;
313}
314
315impl ValueExtension for Value {
316    fn compare(&self, other: &Self) -> bool {
317        match (self, other) {
318            (Value::Null, Value::Null) => true,
319            (Value::Boolean(a), Value::Boolean(b)) => a == b,
320            (Value::Int(a), Value::Int(b)) => a == b,
321            (Value::Float(a), Value::Float(b)) => a == b,
322            (Value::String(a), Value::String(b)) => a.eq(b),
323            (Value::Enum(a), Value::Enum(b)) => a.eq(b),
324            (Value::List(a), Value::List(b)) => a.iter().zip(b.iter()).all(|(a, b)| a.compare(b)),
325            (Value::Object(a), Value::Object(b)) => {
326                a.iter().zip(b.iter()).all(|(a, b)| a.1.compare(b.1))
327            }
328            (Value::Variable(a), Value::Variable(b)) => a.eq(b),
329            _ => false,
330        }
331    }
332
333    fn variables_in_use(&self) -> Vec<&str> {
334        match self {
335            Value::Variable(v) => vec![v],
336            Value::List(list) => list.iter().flat_map(|v| v.variables_in_use()).collect(),
337            Value::Object(object) => object
338                .iter()
339                .flat_map(|(_, v)| v.variables_in_use())
340                .collect(),
341            _ => vec![],
342        }
343    }
344}
345
346pub trait InputValueHelpers {
347    fn is_required(&self) -> bool;
348}
349
350impl InputValueHelpers for InputValue {
351    fn is_required(&self) -> bool {
352        if let Type::NonNullType(_inner_type) = &self.value_type {
353            if self.default_value.is_none() {
354                return true;
355            }
356        }
357
358        false
359    }
360}
361
362pub trait AbstractTypeDefinitionExtension {
363    fn is_implemented_by(&self, other_type: &dyn ImplementingInterfaceExtension) -> bool;
364}
365
366pub trait TypeDefinitionExtension {
367    fn is_leaf_type(&self) -> bool;
368    fn is_composite_type(&self) -> bool;
369    fn is_input_type(&self) -> bool;
370    fn is_object_type(&self) -> bool;
371    fn is_union_type(&self) -> bool;
372    fn is_interface_type(&self) -> bool;
373    fn is_enum_type(&self) -> bool;
374    fn is_scalar_type(&self) -> bool;
375    fn is_abstract_type(&self) -> bool;
376    fn name(&self) -> &str;
377}
378
379pub trait ImplementingInterfaceExtension {
380    fn interfaces(&self) -> Vec<String>;
381    fn has_sub_type(&self, other_type: &TypeDefinition) -> bool;
382    fn has_concrete_sub_type(&self, concrete_type: &ObjectType) -> bool;
383}
384
385impl ImplementingInterfaceExtension for TypeDefinition {
386    fn interfaces(&self) -> Vec<String> {
387        match self {
388            schema::TypeDefinition::Object(o) => o.interfaces(),
389            schema::TypeDefinition::Interface(i) => i.interfaces(),
390            _ => vec![],
391        }
392    }
393
394    fn has_sub_type(&self, other_type: &TypeDefinition) -> bool {
395        match self {
396            TypeDefinition::Interface(interface_type) => {
397                interface_type.is_implemented_by(other_type)
398            }
399            TypeDefinition::Union(union_type) => return union_type.has_sub_type(other_type.name()),
400            _ => false,
401        }
402    }
403
404    fn has_concrete_sub_type(&self, concrete_type: &ObjectType) -> bool {
405        match self {
406            TypeDefinition::Interface(interface_type) => {
407                interface_type.is_implemented_by(concrete_type)
408            }
409            TypeDefinition::Union(union_type) => union_type.has_sub_type(&concrete_type.name),
410            _ => false,
411        }
412    }
413}
414
415pub trait PossibleTypesExtension {
416    fn possible_types<'a>(&self, schema: &'a schema::Document) -> Vec<&'a ObjectType>;
417}
418
419impl PossibleTypesExtension for TypeDefinition {
420    fn possible_types<'a>(&self, schema: &'a schema::Document) -> Vec<&'a ObjectType> {
421        match self {
422            TypeDefinition::Object(_) => vec![],
423            TypeDefinition::InputObject(_) => vec![],
424            TypeDefinition::Enum(_) => vec![],
425            TypeDefinition::Scalar(_) => vec![],
426            TypeDefinition::Interface(i) => schema
427                .type_map()
428                .iter()
429                .filter_map(|(_type_name, type_def)| {
430                    if let TypeDefinition::Object(o) = type_def {
431                        if i.is_implemented_by(*type_def) {
432                            return Some(o);
433                        }
434                    }
435
436                    None
437                })
438                .collect(),
439            TypeDefinition::Union(u) => u
440                .types
441                .iter()
442                .filter_map(|type_name| {
443                    if let Some(TypeDefinition::Object(o)) = schema.type_by_name(type_name) {
444                        return Some(o);
445                    }
446
447                    None
448                })
449                .collect(),
450        }
451    }
452}
453
454impl ImplementingInterfaceExtension for InterfaceType {
455    fn interfaces(&self) -> Vec<String> {
456        self.implements_interfaces.clone()
457    }
458
459    fn has_sub_type(&self, other_type: &TypeDefinition) -> bool {
460        self.is_implemented_by(other_type)
461    }
462
463    fn has_concrete_sub_type(&self, concrete_type: &ObjectType) -> bool {
464        self.is_implemented_by(concrete_type)
465    }
466}
467
468impl ImplementingInterfaceExtension for ObjectType {
469    fn interfaces(&self) -> Vec<String> {
470        self.implements_interfaces.clone()
471    }
472
473    fn has_sub_type(&self, _other_type: &TypeDefinition) -> bool {
474        false
475    }
476
477    fn has_concrete_sub_type(&self, _concrete_type: &ObjectType) -> bool {
478        false
479    }
480}
481
482pub trait SubTypeExtension {
483    fn has_sub_type(&self, other_type_name: &str) -> bool;
484}
485
486impl SubTypeExtension for UnionType {
487    fn has_sub_type(&self, other_type_name: &str) -> bool {
488        self.types.iter().any(|v| other_type_name.eq(v))
489    }
490}
491
492impl AbstractTypeDefinitionExtension for InterfaceType {
493    fn is_implemented_by(&self, other_type: &dyn ImplementingInterfaceExtension) -> bool {
494        other_type.interfaces().iter().any(|v| self.name.eq(v))
495    }
496}
497
498impl TypeDefinitionExtension for Option<&schema::TypeDefinition> {
499    fn is_leaf_type(&self) -> bool {
500        match self {
501            Some(t) => t.is_leaf_type(),
502            _ => false,
503        }
504    }
505
506    fn is_composite_type(&self) -> bool {
507        match self {
508            Some(t) => t.is_composite_type(),
509            _ => false,
510        }
511    }
512
513    fn is_input_type(&self) -> bool {
514        match self {
515            Some(t) => t.is_input_type(),
516            _ => false,
517        }
518    }
519
520    fn is_interface_type(&self) -> bool {
521        match self {
522            Some(t) => t.is_interface_type(),
523            _ => false,
524        }
525    }
526
527    fn is_object_type(&self) -> bool {
528        match self {
529            Some(t) => t.is_object_type(),
530            _ => false,
531        }
532    }
533
534    fn is_union_type(&self) -> bool {
535        match self {
536            Some(t) => t.is_union_type(),
537            _ => false,
538        }
539    }
540
541    fn is_enum_type(&self) -> bool {
542        match self {
543            Some(t) => t.is_enum_type(),
544            _ => false,
545        }
546    }
547
548    fn is_scalar_type(&self) -> bool {
549        match self {
550            Some(t) => t.is_scalar_type(),
551            _ => false,
552        }
553    }
554
555    fn is_abstract_type(&self) -> bool {
556        match self {
557            Some(t) => t.is_abstract_type(),
558            _ => false,
559        }
560    }
561
562    fn name(&self) -> &str {
563        match self {
564            Some(t) => t.name(),
565            _ => "",
566        }
567    }
568}
569
570impl TypeDefinitionExtension for schema::TypeDefinition {
571    fn name(&self) -> &str {
572        match self {
573            schema::TypeDefinition::Object(o) => &o.name,
574            schema::TypeDefinition::Interface(i) => &i.name,
575            schema::TypeDefinition::Union(u) => &u.name,
576            schema::TypeDefinition::Scalar(s) => &s.name,
577            schema::TypeDefinition::Enum(e) => &e.name,
578            schema::TypeDefinition::InputObject(i) => &i.name,
579        }
580    }
581
582    fn is_abstract_type(&self) -> bool {
583        match self {
584            schema::TypeDefinition::Interface(_i) => true,
585            schema::TypeDefinition::Union(_u) => true,
586            _ => false,
587        }
588    }
589
590    fn is_interface_type(&self) -> bool {
591        match self {
592            schema::TypeDefinition::Interface(_i) => true,
593            _ => false,
594        }
595    }
596
597    fn is_leaf_type(&self) -> bool {
598        match self {
599            schema::TypeDefinition::Scalar(_u) => true,
600            schema::TypeDefinition::Enum(_u) => true,
601            _ => false,
602        }
603    }
604
605    fn is_input_type(&self) -> bool {
606        match self {
607            schema::TypeDefinition::Scalar(_u) => true,
608            schema::TypeDefinition::Enum(_u) => true,
609            schema::TypeDefinition::InputObject(_u) => true,
610            _ => false,
611        }
612    }
613
614    fn is_composite_type(&self) -> bool {
615        match self {
616            schema::TypeDefinition::Object(_o) => true,
617            schema::TypeDefinition::Interface(_i) => true,
618            schema::TypeDefinition::Union(_u) => true,
619            _ => false,
620        }
621    }
622
623    fn is_object_type(&self) -> bool {
624        matches!(self, schema::TypeDefinition::Object(_o))
625    }
626
627    fn is_union_type(&self) -> bool {
628        matches!(self, schema::TypeDefinition::Union(_o))
629    }
630
631    fn is_enum_type(&self) -> bool {
632        matches!(self, schema::TypeDefinition::Enum(_o))
633    }
634
635    fn is_scalar_type(&self) -> bool {
636        matches!(self, schema::TypeDefinition::Scalar(_o))
637    }
638}
639
640pub trait AstNodeWithName {
641    fn node_name(&self) -> Option<&str>;
642}
643
644impl AstNodeWithName for query::OperationDefinition {
645    fn node_name(&self) -> Option<&str> {
646        match self {
647            query::OperationDefinition::Query(q) => q.name.as_deref(),
648            query::OperationDefinition::SelectionSet(_s) => None,
649            query::OperationDefinition::Mutation(m) => m.name.as_deref(),
650            query::OperationDefinition::Subscription(s) => s.name.as_deref(),
651        }
652    }
653}
654
655impl AstNodeWithName for query::FragmentDefinition {
656    fn node_name(&self) -> Option<&str> {
657        Some(&self.name)
658    }
659}
660
661impl AstNodeWithName for query::FragmentSpread {
662    fn node_name(&self) -> Option<&str> {
663        Some(&self.fragment_name)
664    }
665}
666
667pub trait FragmentSpreadExtraction {
668    fn get_recursive_fragment_spreads(&self) -> Vec<&FragmentSpread>;
669    fn get_fragment_spreads(&self) -> Vec<&FragmentSpread>;
670}
671
672impl FragmentSpreadExtraction for query::SelectionSet {
673    fn get_recursive_fragment_spreads(&self) -> Vec<&FragmentSpread> {
674        self.items
675            .iter()
676            .flat_map(|v| match v {
677                query::Selection::FragmentSpread(f) => vec![f],
678                query::Selection::Field(f) => f.selection_set.get_fragment_spreads(),
679                query::Selection::InlineFragment(f) => f.selection_set.get_fragment_spreads(),
680            })
681            .collect()
682    }
683
684    fn get_fragment_spreads(&self) -> Vec<&FragmentSpread> {
685        self.items
686            .iter()
687            .flat_map(|v| match v {
688                query::Selection::FragmentSpread(f) => vec![f],
689                _ => vec![],
690            })
691            .collect()
692    }
693}