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