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    pub fn query_type(&self) -> &ObjectType {
98        self.query_type_name()
99            .and_then(|name| self.object_type_by_name(name))
100            .expect("invariant violation: every valid schema must define a query type")
101    }
102
103    pub fn mutation_type(&self) -> Option<&ObjectType> {
104        self.mutation_type_name()
105            .and_then(|name| self.object_type_by_name(name))
106    }
107
108    pub fn subscription_type(&self) -> Option<&ObjectType> {
109        self.subscription_type_name()
110            .and_then(|name| self.object_type_by_name(name))
111    }
112
113    fn object_type_by_name(&self, name: &str) -> Option<&ObjectType> {
114        match self.type_by_name(name) {
115            Some(TypeDefinition::Object(object_def)) => Some(object_def),
116            _ => None,
117        }
118    }
119
120    pub fn type_map(&self) -> HashMap<&str, &TypeDefinition> {
121        let mut type_map = HashMap::new();
122
123        for def in &self.definitions {
124            if let schema::Definition::TypeDefinition(type_def) = def {
125                type_map.insert(type_def.name(), type_def);
126            }
127        }
128
129        type_map
130    }
131
132    pub fn is_named_subtype(&self, sub_type_name: &str, super_type_name: &str) -> bool {
133        if sub_type_name == super_type_name {
134            true
135        } else if let (Some(sub_type), Some(super_type)) = (
136            self.type_by_name(sub_type_name),
137            self.type_by_name(super_type_name),
138        ) {
139            super_type.is_abstract_type() && self.is_possible_type(super_type, sub_type)
140        } else {
141            false
142        }
143    }
144
145    fn is_possible_type(
146        &self,
147        abstract_type: &TypeDefinition,
148        possible_type: &TypeDefinition,
149    ) -> bool {
150        match abstract_type {
151            TypeDefinition::Union(union_typedef) => union_typedef
152                .types
153                .iter()
154                .any(|t| t == possible_type.name()),
155            TypeDefinition::Interface(interface_typedef) => {
156                let implementes_interfaces = possible_type.interfaces();
157
158                implementes_interfaces.contains(&interface_typedef.name)
159            }
160            _ => false,
161        }
162    }
163
164    pub fn is_subtype(&self, sub_type: &Type, super_type: &Type) -> bool {
165        // Equivalent type is a valid subtype
166        if sub_type == super_type {
167            return true;
168        }
169
170        // If superType is non-null, maybeSubType must also be non-null.
171        if super_type.is_non_null() {
172            if sub_type.is_non_null() {
173                return self.is_subtype(sub_type.of_type(), super_type.of_type());
174            }
175            return false;
176        }
177
178        if sub_type.is_non_null() {
179            // If superType is nullable, maybeSubType may be non-null or nullable.
180            return self.is_subtype(sub_type.of_type(), super_type);
181        }
182
183        // If superType type is a list, maybeSubType type must also be a list.
184        if super_type.is_list_type() {
185            if sub_type.is_list_type() {
186                return self.is_subtype(sub_type.of_type(), super_type.of_type());
187            }
188
189            return false;
190        }
191
192        if sub_type.is_list_type() {
193            // If superType is nullable, maybeSubType may be non-null or nullable.
194            return false;
195        }
196
197        // If superType type is an abstract type, check if it is super type of maybeSubType.
198        // Otherwise, the child type is not a valid subtype of the parent type.
199        if let (Some(sub_type), Some(super_type)) = (
200            self.type_by_name(sub_type.inner_type()),
201            self.type_by_name(super_type.inner_type()),
202        ) {
203            return super_type.is_abstract_type()
204                && (sub_type.is_interface_type() || sub_type.is_object_type())
205                && self.is_possible_type(super_type, sub_type);
206        }
207
208        false
209    }
210}
211
212impl Type {
213    pub fn inner_type(&self) -> &str {
214        match self {
215            Type::NamedType(name) => name.as_str(),
216            Type::ListType(child) => child.inner_type(),
217            Type::NonNullType(child) => child.inner_type(),
218        }
219    }
220
221    fn of_type(&self) -> &Type {
222        match self {
223            Type::ListType(child) => child,
224            Type::NonNullType(child) => child,
225            Type::NamedType(_) => self,
226        }
227    }
228
229    pub fn is_non_null(&self) -> bool {
230        matches!(self, Type::NonNullType(_))
231    }
232
233    fn is_list_type(&self) -> bool {
234        matches!(self, Type::ListType(_))
235    }
236
237    pub fn is_named_type(&self) -> bool {
238        matches!(self, Type::NamedType(_))
239    }
240}
241
242impl Value {
243    pub fn compare(&self, other: &Self) -> bool {
244        match (self, other) {
245            (Value::Null, Value::Null) => true,
246            (Value::Boolean(a), Value::Boolean(b)) => a == b,
247            (Value::Int(a), Value::Int(b)) => a == b,
248            (Value::Float(a), Value::Float(b)) => a == b,
249            (Value::String(a), Value::String(b)) => a.eq(b),
250            (Value::Enum(a), Value::Enum(b)) => a.eq(b),
251            (Value::List(a), Value::List(b)) => a.iter().zip(b.iter()).all(|(a, b)| a.compare(b)),
252            (Value::Object(a), Value::Object(b)) => {
253                if a.len() != b.len() {
254                    return false;
255                }
256                let mut matched = vec![false; b.len()];
257                for (k_a, v_a) in a.iter() {
258                    let found = b
259                        .iter()
260                        .enumerate()
261                        .find(|(idx, (k_b, v_b))| !matched[*idx] && k_a == k_b && v_a.compare(v_b));
262                    match found {
263                        Some((idx, _)) => matched[idx] = true,
264                        None => return false,
265                    }
266                }
267                true
268            }
269            (Value::Variable(a), Value::Variable(b)) => a.eq(b),
270            _ => false,
271        }
272    }
273
274    pub fn variables_in_use(&self) -> Vec<&str> {
275        match self {
276            Value::Variable(v) => vec![v],
277            Value::List(list) => list.iter().flat_map(|v| v.variables_in_use()).collect(),
278            Value::Object(object) => object
279                .iter()
280                .flat_map(|(_, v)| v.variables_in_use())
281                .collect(),
282            _ => vec![],
283        }
284    }
285}
286
287impl InputValue {
288    pub fn is_required(&self) -> bool {
289        if let Type::NonNullType(_inner_type) = &self.value_type {
290            if self.default_value.is_none() {
291                return true;
292            }
293        }
294
295        false
296    }
297}
298
299impl TypeDefinition {
300    fn interfaces(&self) -> Vec<String> {
301        match self {
302            schema::TypeDefinition::Object(o) => o.interfaces(),
303            schema::TypeDefinition::Interface(i) => i.interfaces(),
304            _ => vec![],
305        }
306    }
307
308    pub fn has_sub_type(&self, other_type: &TypeDefinition) -> bool {
309        match self {
310            TypeDefinition::Interface(interface_type) => {
311                interface_type.is_implemented_by(other_type)
312            }
313            TypeDefinition::Union(union_type) => union_type.has_sub_type(other_type.name()),
314            _ => false,
315        }
316    }
317
318    pub fn has_concrete_sub_type(&self, concrete_type: &TypeDefinition) -> bool {
319        match self {
320            TypeDefinition::Interface(interface_type) => {
321                interface_type.is_implemented_by(concrete_type)
322            }
323            TypeDefinition::Union(union_type) => union_type.has_sub_type(concrete_type.name()),
324            _ => false,
325        }
326    }
327}
328
329impl TypeDefinition {
330    pub fn possible_types<'a>(&self, schema: &'a schema::Document) -> Vec<&'a TypeDefinition> {
331        match self {
332            TypeDefinition::Object(_) => vec![],
333            TypeDefinition::InputObject(_) => vec![],
334            TypeDefinition::Enum(_) => vec![],
335            TypeDefinition::Scalar(_) => vec![],
336            TypeDefinition::Interface(i) => schema
337                .type_map()
338                .values()
339                .filter_map(|type_def| {
340                    if i.is_implemented_by(type_def) {
341                        return Some(*type_def);
342                    }
343
344                    None
345                })
346                .collect(),
347            TypeDefinition::Union(u) => u
348                .types
349                .iter()
350                .filter_map(|type_name| {
351                    if let Some(type_def) = schema.type_by_name(type_name) {
352                        return Some(type_def);
353                    }
354
355                    None
356                })
357                .collect(),
358        }
359    }
360}
361
362impl InterfaceType {
363    fn interfaces(&self) -> Vec<String> {
364        self.implements_interfaces.clone()
365    }
366
367    pub fn has_sub_type(&self, other_type: &TypeDefinition) -> bool {
368        self.is_implemented_by(other_type)
369    }
370
371    pub fn has_concrete_sub_type(&self, concrete_type: &TypeDefinition) -> bool {
372        self.is_implemented_by(concrete_type)
373    }
374}
375
376impl ObjectType {
377    fn interfaces(&self) -> Vec<String> {
378        self.implements_interfaces.clone()
379    }
380
381    pub fn has_sub_type(&self, _other_type: &TypeDefinition) -> bool {
382        false
383    }
384
385    pub fn has_concrete_sub_type(&self, _concrete_type: &ObjectType) -> bool {
386        false
387    }
388}
389
390impl UnionType {
391    pub fn has_sub_type(&self, other_type_name: &str) -> bool {
392        self.types.iter().any(|v| other_type_name.eq(v))
393    }
394}
395
396impl InterfaceType {
397    pub fn is_implemented_by(&self, other_type: &TypeDefinition) -> bool {
398        other_type.interfaces().iter().any(|v| self.name.eq(v))
399    }
400}
401
402impl schema::TypeDefinition {
403    pub fn name(&self) -> &str {
404        match self {
405            schema::TypeDefinition::Object(o) => &o.name,
406            schema::TypeDefinition::Interface(i) => &i.name,
407            schema::TypeDefinition::Union(u) => &u.name,
408            schema::TypeDefinition::Scalar(s) => &s.name,
409            schema::TypeDefinition::Enum(e) => &e.name,
410            schema::TypeDefinition::InputObject(i) => &i.name,
411        }
412    }
413
414    pub fn is_abstract_type(&self) -> bool {
415        matches!(
416            self,
417            schema::TypeDefinition::Interface(_) | schema::TypeDefinition::Union(_)
418        )
419    }
420
421    fn is_interface_type(&self) -> bool {
422        matches!(self, schema::TypeDefinition::Interface(_))
423    }
424
425    pub fn is_leaf_type(&self) -> bool {
426        matches!(
427            self,
428            schema::TypeDefinition::Scalar(_) | schema::TypeDefinition::Enum(_)
429        )
430    }
431
432    pub fn is_input_type(&self) -> bool {
433        matches!(
434            self,
435            schema::TypeDefinition::Scalar(_)
436                | schema::TypeDefinition::Enum(_)
437                | schema::TypeDefinition::InputObject(_)
438        )
439    }
440
441    pub fn is_composite_type(&self) -> bool {
442        matches!(
443            self,
444            schema::TypeDefinition::Object(_)
445                | schema::TypeDefinition::Interface(_)
446                | schema::TypeDefinition::Union(_)
447        )
448    }
449
450    pub fn is_object_type(&self) -> bool {
451        matches!(self, schema::TypeDefinition::Object(_o))
452    }
453
454    pub fn is_union_type(&self) -> bool {
455        matches!(self, schema::TypeDefinition::Union(_o))
456    }
457
458    pub fn is_enum_type(&self) -> bool {
459        matches!(self, schema::TypeDefinition::Enum(_o))
460    }
461
462    pub fn is_scalar_type(&self) -> bool {
463        matches!(self, schema::TypeDefinition::Scalar(_o))
464    }
465}
466
467pub trait AstNodeWithName {
468    fn node_name(&self) -> Option<&str>;
469}
470
471impl AstNodeWithName for query::OperationDefinition {
472    fn node_name(&self) -> Option<&str> {
473        match self {
474            query::OperationDefinition::Query(q) => q.name.as_deref(),
475            query::OperationDefinition::SelectionSet(_s) => None,
476            query::OperationDefinition::Mutation(m) => m.name.as_deref(),
477            query::OperationDefinition::Subscription(s) => s.name.as_deref(),
478        }
479    }
480}
481
482impl AstNodeWithName for query::FragmentDefinition {
483    fn node_name(&self) -> Option<&str> {
484        Some(&self.name)
485    }
486}
487
488impl AstNodeWithName for query::FragmentSpread {
489    fn node_name(&self) -> Option<&str> {
490        Some(&self.fragment_name)
491    }
492}
493
494impl query::SelectionSet {
495    pub fn get_recursive_fragment_spreads(&self) -> Vec<&FragmentSpread> {
496        self.items
497            .iter()
498            .flat_map(|v| match v {
499                query::Selection::FragmentSpread(f) => vec![f],
500                query::Selection::Field(f) => f.selection_set.get_fragment_spreads(),
501                query::Selection::InlineFragment(f) => f.selection_set.get_fragment_spreads(),
502            })
503            .collect()
504    }
505
506    fn get_fragment_spreads(&self) -> Vec<&FragmentSpread> {
507        self.items
508            .iter()
509            .flat_map(|v| match v {
510                query::Selection::FragmentSpread(f) => vec![f],
511                _ => vec![],
512            })
513            .collect()
514    }
515}
516
517impl query::Selection {
518    pub fn directives(&self) -> &[Directive] {
519        match self {
520            query::Selection::Field(f) => &f.directives,
521            query::Selection::FragmentSpread(f) => &f.directives,
522            query::Selection::InlineFragment(f) => &f.directives,
523        }
524    }
525    pub fn selection_set(&self) -> Option<&SelectionSet> {
526        match self {
527            query::Selection::Field(f) => Some(&f.selection_set),
528            query::Selection::FragmentSpread(_) => None,
529            query::Selection::InlineFragment(f) => Some(&f.selection_set),
530        }
531    }
532}
533
534impl schema::Definition<'static, String> {
535    pub fn name(&self) -> Option<&str> {
536        match self {
537            schema::Definition::SchemaDefinition(_) => None,
538            schema::Definition::TypeDefinition(type_def) => Some(type_def.name()),
539            schema::Definition::TypeExtension(type_ext) => Some(type_ext.name()),
540            schema::Definition::DirectiveDefinition(directive_def) => Some(&directive_def.name),
541        }
542    }
543    pub fn fields<'a>(&'a self) -> Option<TypeDefinitionFields<'a>> {
544        match self {
545            schema::Definition::SchemaDefinition(_) => None,
546            schema::Definition::TypeDefinition(type_def) => type_def.fields(),
547            schema::Definition::TypeExtension(type_ext) => type_ext.fields(),
548            schema::Definition::DirectiveDefinition(_) => None,
549        }
550    }
551    pub fn directives(&self) -> Option<&[Directive]> {
552        match self {
553            schema::Definition::SchemaDefinition(schema_def) => Some(&schema_def.directives),
554            schema::Definition::TypeDefinition(type_def) => type_def.directives(),
555            schema::Definition::TypeExtension(type_ext) => type_ext.directives(),
556            schema::Definition::DirectiveDefinition(_) => None,
557        }
558    }
559}
560
561pub enum TypeDefinitionFields<'a> {
562    Fields(&'a [Field]),
563    InputValues(&'a [InputValue]),
564    EnumValues(&'a [EnumValue]),
565}
566
567impl TypeDefinition {
568    pub fn fields<'a>(&'a self) -> Option<TypeDefinitionFields<'a>> {
569        match self {
570            TypeDefinition::Scalar(_) => None,
571            TypeDefinition::Object(object) => Some(TypeDefinitionFields::Fields(&object.fields)),
572            TypeDefinition::Interface(interface) => {
573                Some(TypeDefinitionFields::Fields(&interface.fields))
574            }
575            TypeDefinition::Union(_) => None,
576            TypeDefinition::Enum(enum_) => Some(TypeDefinitionFields::EnumValues(&enum_.values)),
577            TypeDefinition::InputObject(input_object) => {
578                Some(TypeDefinitionFields::InputValues(&input_object.fields))
579            }
580        }
581    }
582    pub fn directives(&self) -> Option<&[Directive]> {
583        match self {
584            TypeDefinition::Scalar(_) => None,
585            TypeDefinition::Object(object) => Some(&object.directives),
586            TypeDefinition::Interface(interface) => Some(&interface.directives),
587            TypeDefinition::Union(union) => Some(&union.directives),
588            TypeDefinition::Enum(enum_) => Some(&enum_.directives),
589            TypeDefinition::InputObject(input_object) => Some(&input_object.directives),
590        }
591    }
592}
593
594impl TypeExtension<'static, String> {
595    pub fn name(&self) -> &str {
596        match self {
597            TypeExtension::Object(object) => &object.name,
598            TypeExtension::Interface(interface) => &interface.name,
599            TypeExtension::Union(union) => &union.name,
600            TypeExtension::Scalar(scalar) => &scalar.name,
601            TypeExtension::Enum(enum_) => &enum_.name,
602            TypeExtension::InputObject(input_object) => &input_object.name,
603        }
604    }
605    pub fn fields<'a>(&'a self) -> Option<TypeDefinitionFields<'a>> {
606        match self {
607            TypeExtension::Object(object) => Some(TypeDefinitionFields::Fields(&object.fields)),
608            TypeExtension::Interface(interface) => {
609                Some(TypeDefinitionFields::Fields(&interface.fields))
610            }
611            _ => None,
612        }
613    }
614    pub fn directives(&self) -> Option<&[Directive]> {
615        match self {
616            TypeExtension::Object(object) => Some(&object.directives),
617            TypeExtension::Interface(interface) => Some(&interface.directives),
618            TypeExtension::Union(union) => Some(&union.directives),
619            TypeExtension::Enum(enum_) => Some(&enum_.directives),
620            TypeExtension::InputObject(input_object) => Some(&input_object.directives),
621            TypeExtension::Scalar(scalar) => Some(&scalar.directives),
622        }
623    }
624}