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