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 if sub_type == super_type {
188 return true;
189 }
190
191 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 return self.is_subtype(sub_type.of_type(), super_type);
202 }
203
204 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 return false;
216 }
217
218 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}