Skip to main content

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