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                if a.len() != b.len() {
316                    return false;
317                }
318                let mut matched = vec![false; b.len()];
319                for (k_a, v_a) in a.iter() {
320                    let found = b
321                        .iter()
322                        .enumerate()
323                        .find(|(idx, (k_b, v_b))| !matched[*idx] && k_a == k_b && v_a.compare(v_b));
324                    match found {
325                        Some((idx, _)) => matched[idx] = true,
326                        None => return false,
327                    }
328                }
329                true
330            }
331            (Value::Variable(a), Value::Variable(b)) => a.eq(b),
332            _ => false,
333        }
334    }
335
336    pub fn variables_in_use(&self) -> Vec<&str> {
337        match self {
338            Value::Variable(v) => vec![v],
339            Value::List(list) => list.iter().flat_map(|v| v.variables_in_use()).collect(),
340            Value::Object(object) => object
341                .iter()
342                .flat_map(|(_, v)| v.variables_in_use())
343                .collect(),
344            _ => vec![],
345        }
346    }
347}
348
349impl InputValue {
350    pub fn is_required(&self) -> bool {
351        if let Type::NonNullType(_inner_type) = &self.value_type {
352            if self.default_value.is_none() {
353                return true;
354            }
355        }
356
357        false
358    }
359}
360
361impl TypeDefinition {
362    fn interfaces(&self) -> Vec<String> {
363        match self {
364            schema::TypeDefinition::Object(o) => o.interfaces(),
365            schema::TypeDefinition::Interface(i) => i.interfaces(),
366            _ => vec![],
367        }
368    }
369
370    pub fn has_sub_type(&self, other_type: &TypeDefinition) -> bool {
371        match self {
372            TypeDefinition::Interface(interface_type) => {
373                interface_type.is_implemented_by(other_type)
374            }
375            TypeDefinition::Union(union_type) => union_type.has_sub_type(other_type.name()),
376            _ => false,
377        }
378    }
379
380    pub fn has_concrete_sub_type(&self, concrete_type: &TypeDefinition) -> bool {
381        match self {
382            TypeDefinition::Interface(interface_type) => {
383                interface_type.is_implemented_by(concrete_type)
384            }
385            TypeDefinition::Union(union_type) => union_type.has_sub_type(concrete_type.name()),
386            _ => false,
387        }
388    }
389}
390
391impl TypeDefinition {
392    pub fn possible_types<'a>(&self, schema: &'a schema::Document) -> Vec<&'a TypeDefinition> {
393        match self {
394            TypeDefinition::Object(_) => vec![],
395            TypeDefinition::InputObject(_) => vec![],
396            TypeDefinition::Enum(_) => vec![],
397            TypeDefinition::Scalar(_) => vec![],
398            TypeDefinition::Interface(i) => schema
399                .type_map()
400                .values()
401                .filter_map(|type_def| {
402                    if i.is_implemented_by(type_def) {
403                        return Some(*type_def);
404                    }
405
406                    None
407                })
408                .collect(),
409            TypeDefinition::Union(u) => u
410                .types
411                .iter()
412                .filter_map(|type_name| {
413                    if let Some(type_def) = schema.type_by_name(type_name) {
414                        return Some(type_def);
415                    }
416
417                    None
418                })
419                .collect(),
420        }
421    }
422}
423
424impl InterfaceType {
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        self.is_implemented_by(other_type)
431    }
432
433    pub fn has_concrete_sub_type(&self, concrete_type: &TypeDefinition) -> bool {
434        self.is_implemented_by(concrete_type)
435    }
436}
437
438impl ObjectType {
439    fn interfaces(&self) -> Vec<String> {
440        self.implements_interfaces.clone()
441    }
442
443    pub fn has_sub_type(&self, _other_type: &TypeDefinition) -> bool {
444        false
445    }
446
447    pub fn has_concrete_sub_type(&self, _concrete_type: &ObjectType) -> bool {
448        false
449    }
450}
451
452impl UnionType {
453    pub fn has_sub_type(&self, other_type_name: &str) -> bool {
454        self.types.iter().any(|v| other_type_name.eq(v))
455    }
456}
457
458impl InterfaceType {
459    pub fn is_implemented_by(&self, other_type: &TypeDefinition) -> bool {
460        other_type.interfaces().iter().any(|v| self.name.eq(v))
461    }
462}
463
464impl schema::TypeDefinition {
465    pub fn name(&self) -> &str {
466        match self {
467            schema::TypeDefinition::Object(o) => &o.name,
468            schema::TypeDefinition::Interface(i) => &i.name,
469            schema::TypeDefinition::Union(u) => &u.name,
470            schema::TypeDefinition::Scalar(s) => &s.name,
471            schema::TypeDefinition::Enum(e) => &e.name,
472            schema::TypeDefinition::InputObject(i) => &i.name,
473        }
474    }
475
476    pub fn is_abstract_type(&self) -> bool {
477        matches!(
478            self,
479            schema::TypeDefinition::Interface(_) | schema::TypeDefinition::Union(_)
480        )
481    }
482
483    fn is_interface_type(&self) -> bool {
484        matches!(self, schema::TypeDefinition::Interface(_))
485    }
486
487    pub fn is_leaf_type(&self) -> bool {
488        matches!(
489            self,
490            schema::TypeDefinition::Scalar(_) | schema::TypeDefinition::Enum(_)
491        )
492    }
493
494    pub fn is_input_type(&self) -> bool {
495        matches!(
496            self,
497            schema::TypeDefinition::Scalar(_)
498                | schema::TypeDefinition::Enum(_)
499                | schema::TypeDefinition::InputObject(_)
500        )
501    }
502
503    pub fn is_composite_type(&self) -> bool {
504        matches!(
505            self,
506            schema::TypeDefinition::Object(_)
507                | schema::TypeDefinition::Interface(_)
508                | schema::TypeDefinition::Union(_)
509        )
510    }
511
512    pub fn is_object_type(&self) -> bool {
513        matches!(self, schema::TypeDefinition::Object(_o))
514    }
515
516    pub fn is_union_type(&self) -> bool {
517        matches!(self, schema::TypeDefinition::Union(_o))
518    }
519
520    pub fn is_enum_type(&self) -> bool {
521        matches!(self, schema::TypeDefinition::Enum(_o))
522    }
523
524    pub fn is_scalar_type(&self) -> bool {
525        matches!(self, schema::TypeDefinition::Scalar(_o))
526    }
527}
528
529pub trait AstNodeWithName {
530    fn node_name(&self) -> Option<&str>;
531}
532
533impl AstNodeWithName for query::OperationDefinition {
534    fn node_name(&self) -> Option<&str> {
535        match self {
536            query::OperationDefinition::Query(q) => q.name.as_deref(),
537            query::OperationDefinition::SelectionSet(_s) => None,
538            query::OperationDefinition::Mutation(m) => m.name.as_deref(),
539            query::OperationDefinition::Subscription(s) => s.name.as_deref(),
540        }
541    }
542}
543
544impl AstNodeWithName for query::FragmentDefinition {
545    fn node_name(&self) -> Option<&str> {
546        Some(&self.name)
547    }
548}
549
550impl AstNodeWithName for query::FragmentSpread {
551    fn node_name(&self) -> Option<&str> {
552        Some(&self.fragment_name)
553    }
554}
555
556impl query::SelectionSet {
557    pub fn get_recursive_fragment_spreads(&self) -> Vec<&FragmentSpread> {
558        self.items
559            .iter()
560            .flat_map(|v| match v {
561                query::Selection::FragmentSpread(f) => vec![f],
562                query::Selection::Field(f) => f.selection_set.get_fragment_spreads(),
563                query::Selection::InlineFragment(f) => f.selection_set.get_fragment_spreads(),
564            })
565            .collect()
566    }
567
568    fn get_fragment_spreads(&self) -> Vec<&FragmentSpread> {
569        self.items
570            .iter()
571            .flat_map(|v| match v {
572                query::Selection::FragmentSpread(f) => vec![f],
573                _ => vec![],
574            })
575            .collect()
576    }
577}
578
579impl query::Selection {
580    pub fn directives(&self) -> &[Directive] {
581        match self {
582            query::Selection::Field(f) => &f.directives,
583            query::Selection::FragmentSpread(f) => &f.directives,
584            query::Selection::InlineFragment(f) => &f.directives,
585        }
586    }
587    pub fn selection_set(&self) -> Option<&SelectionSet> {
588        match self {
589            query::Selection::Field(f) => Some(&f.selection_set),
590            query::Selection::FragmentSpread(_) => None,
591            query::Selection::InlineFragment(f) => Some(&f.selection_set),
592        }
593    }
594}
595
596impl schema::Definition<'static, String> {
597    pub fn name(&self) -> Option<&str> {
598        match self {
599            schema::Definition::SchemaDefinition(_) => None,
600            schema::Definition::TypeDefinition(type_def) => Some(type_def.name()),
601            schema::Definition::TypeExtension(type_ext) => Some(type_ext.name()),
602            schema::Definition::DirectiveDefinition(directive_def) => Some(&directive_def.name),
603        }
604    }
605    pub fn fields<'a>(&'a self) -> Option<TypeDefinitionFields<'a>> {
606        match self {
607            schema::Definition::SchemaDefinition(_) => None,
608            schema::Definition::TypeDefinition(type_def) => type_def.fields(),
609            schema::Definition::TypeExtension(type_ext) => type_ext.fields(),
610            schema::Definition::DirectiveDefinition(_) => None,
611        }
612    }
613    pub fn directives(&self) -> Option<&[Directive]> {
614        match self {
615            schema::Definition::SchemaDefinition(schema_def) => Some(&schema_def.directives),
616            schema::Definition::TypeDefinition(type_def) => type_def.directives(),
617            schema::Definition::TypeExtension(type_ext) => type_ext.directives(),
618            schema::Definition::DirectiveDefinition(_) => None,
619        }
620    }
621}
622
623pub enum TypeDefinitionFields<'a> {
624    Fields(&'a [Field]),
625    InputValues(&'a [InputValue]),
626    EnumValues(&'a [EnumValue]),
627}
628
629impl TypeDefinition {
630    pub fn fields<'a>(&'a self) -> Option<TypeDefinitionFields<'a>> {
631        match self {
632            TypeDefinition::Scalar(_) => None,
633            TypeDefinition::Object(object) => Some(TypeDefinitionFields::Fields(&object.fields)),
634            TypeDefinition::Interface(interface) => {
635                Some(TypeDefinitionFields::Fields(&interface.fields))
636            }
637            TypeDefinition::Union(_) => None,
638            TypeDefinition::Enum(enum_) => Some(TypeDefinitionFields::EnumValues(&enum_.values)),
639            TypeDefinition::InputObject(input_object) => {
640                Some(TypeDefinitionFields::InputValues(&input_object.fields))
641            }
642        }
643    }
644    pub fn directives(&self) -> Option<&[Directive]> {
645        match self {
646            TypeDefinition::Scalar(_) => None,
647            TypeDefinition::Object(object) => Some(&object.directives),
648            TypeDefinition::Interface(interface) => Some(&interface.directives),
649            TypeDefinition::Union(union) => Some(&union.directives),
650            TypeDefinition::Enum(enum_) => Some(&enum_.directives),
651            TypeDefinition::InputObject(input_object) => Some(&input_object.directives),
652        }
653    }
654}
655
656impl TypeExtension<'static, String> {
657    pub fn name(&self) -> &str {
658        match self {
659            TypeExtension::Object(object) => &object.name,
660            TypeExtension::Interface(interface) => &interface.name,
661            TypeExtension::Union(union) => &union.name,
662            TypeExtension::Scalar(scalar) => &scalar.name,
663            TypeExtension::Enum(enum_) => &enum_.name,
664            TypeExtension::InputObject(input_object) => &input_object.name,
665        }
666    }
667    pub fn fields<'a>(&'a self) -> Option<TypeDefinitionFields<'a>> {
668        match self {
669            TypeExtension::Object(object) => Some(TypeDefinitionFields::Fields(&object.fields)),
670            TypeExtension::Interface(interface) => {
671                Some(TypeDefinitionFields::Fields(&interface.fields))
672            }
673            _ => None,
674        }
675    }
676    pub fn directives(&self) -> Option<&[Directive]> {
677        match self {
678            TypeExtension::Object(object) => Some(&object.directives),
679            TypeExtension::Interface(interface) => Some(&interface.directives),
680            TypeExtension::Union(union) => Some(&union.directives),
681            TypeExtension::Enum(enum_) => Some(&enum_.directives),
682            TypeExtension::InputObject(input_object) => Some(&input_object.directives),
683            TypeExtension::Scalar(scalar) => Some(&scalar.directives),
684        }
685    }
686}