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