1use std::collections::HashMap;
2
3use crate::parser::query::TypeCondition;
4
5use crate::static_graphql::{
6 query::{self, *},
7 schema::{self},
8};
9
10pub struct OperationVisitorContext<'a> {
12 pub schema: &'a schema::Document,
13 pub operation: &'a query::Document,
14 pub known_fragments: HashMap<&'a str, &'a FragmentDefinition>,
15 pub directives: HashMap<String, schema::DirectiveDefinition>,
16
17 type_stack: Vec<Option<&'a schema::TypeDefinition>>,
18 parent_type_stack: Vec<Option<&'a schema::TypeDefinition>>,
19 input_type_stack: Vec<Option<&'a schema::TypeDefinition>>,
20 type_literal_stack: Vec<Option<Type>>,
21 input_type_literal_stack: Vec<Option<&'a Type>>,
22 input_type_default_stack: Vec<bool>,
23 field_stack: Vec<Option<&'a schema::Field>>,
24}
25
26impl<'a> OperationVisitorContext<'a> {
27 pub fn new(operation: &'a Document, schema: &'a schema::Document) -> Self {
28 OperationVisitorContext {
29 schema,
30 operation,
31 type_stack: vec![],
32 parent_type_stack: vec![],
33 input_type_stack: vec![],
34 type_literal_stack: vec![],
35 input_type_literal_stack: vec![],
36 input_type_default_stack: vec![],
37 field_stack: vec![],
38 known_fragments: HashMap::from_iter(operation.definitions.iter().filter_map(|def| {
39 match def {
40 Definition::Fragment(fragment) => Some((fragment.name.as_str(), fragment)),
41 _ => None,
42 }
43 })),
44 directives: HashMap::<String, schema::DirectiveDefinition>::from_iter(
45 schema.definitions.iter().filter_map(|def| match def {
46 schema::Definition::DirectiveDefinition(directive_def) => {
47 Some((directive_def.name.clone(), directive_def.clone()))
48 }
49 _ => None,
50 }),
51 ),
52 }
53 }
54
55 pub fn with_type<Func>(&mut self, t: Option<&Type>, func: Func)
56 where
57 Func: FnOnce(&mut OperationVisitorContext<'a>),
58 {
59 if let Some(t) = t {
60 self.type_stack
61 .push(self.schema.type_by_name(t.inner_type()));
62 } else {
63 self.type_stack.push(None);
64 }
65
66 self.type_literal_stack.push(t.cloned());
67 func(self);
68 self.type_literal_stack.pop();
69 self.type_stack.pop();
70 }
71
72 pub fn with_parent_type<Func>(&mut self, func: Func)
73 where
74 Func: FnOnce(&mut OperationVisitorContext<'a>),
75 {
76 self.parent_type_stack
77 .push(*self.type_stack.last().unwrap_or(&None));
78 func(self);
79 self.parent_type_stack.pop();
80 }
81
82 pub fn with_field<'f, Func>(&mut self, f: Option<&'f schema::Field>, func: Func)
83 where
84 Func: FnOnce(&mut OperationVisitorContext<'a>),
85 'f: 'a,
86 {
87 if let Some(f) = f {
88 self.field_stack.push(Some(f));
89 } else {
90 self.field_stack.push(None);
91 }
92
93 func(self);
94 self.field_stack.pop();
95 }
96
97 pub fn with_input_type<Func>(&mut self, t: Option<&'a Type>, func: Func)
98 where
99 Func: FnOnce(&mut OperationVisitorContext<'a>),
100 {
101 self.with_input_type_and_default(t, false, func);
102 }
103
104 pub fn with_input_type_and_default<Func>(
105 &mut self,
106 t: Option<&'a Type>,
107 has_default: bool,
108 func: Func,
109 ) where
110 Func: FnOnce(&mut OperationVisitorContext<'a>),
111 {
112 if let Some(t) = t {
113 self.input_type_stack
114 .push(self.schema.type_by_name(t.inner_type()));
115 } else {
116 self.input_type_stack.push(None);
117 }
118
119 self.input_type_literal_stack.push(t);
120 self.input_type_default_stack.push(has_default);
121 func(self);
122 self.input_type_default_stack.pop();
123 self.input_type_literal_stack.pop();
124 self.input_type_stack.pop();
125 }
126
127 pub fn current_input_type_has_default(&self) -> bool {
128 *self.input_type_default_stack.last().unwrap_or(&false)
129 }
130
131 pub fn current_type(&self) -> Option<&schema::TypeDefinition> {
132 self.type_stack.last().unwrap_or(&None).as_deref()
133 }
134
135 pub fn current_input_type(&self) -> Option<&schema::TypeDefinition> {
136 self.input_type_stack.last().unwrap_or(&None).as_deref()
137 }
138
139 pub fn current_parent_type(&self) -> Option<&'a schema::TypeDefinition> {
140 *self.parent_type_stack.last().unwrap_or(&None)
141 }
142
143 pub fn current_type_literal(&self) -> Option<&Type> {
144 self.type_literal_stack.last().unwrap_or(&None).as_ref()
145 }
146
147 pub fn current_input_type_literal(&self) -> Option<&'a Type> {
148 *self.input_type_literal_stack.last().unwrap_or(&None)
149 }
150
151 pub fn current_field(&self) -> Option<&schema::Field> {
152 self.field_stack.last().unwrap_or(&None).as_deref()
153 }
154}
155
156pub fn visit_document<'a, Visitor, UserContext>(
157 visitor: &mut Visitor,
158 document: &'a Document,
159 context: &mut OperationVisitorContext<'a>,
160 user_context: &mut UserContext,
161) where
162 Visitor: OperationVisitor<'a, UserContext>,
163{
164 visitor.enter_document(context, user_context, document);
165 visit_definitions(visitor, &document.definitions, context, user_context);
166 visitor.leave_document(context, user_context, document);
167}
168
169fn visit_definitions<'a, Visitor, UserContext>(
170 visitor: &mut Visitor,
171 definitions: &'a Vec<Definition>,
172 context: &mut OperationVisitorContext<'a>,
173 user_context: &mut UserContext,
174) where
175 Visitor: OperationVisitor<'a, UserContext>,
176{
177 for definition in definitions {
178 let schema_type_name = match definition {
179 Definition::Fragment(fragment) => {
180 let TypeCondition::On(name) = &fragment.type_condition;
181 Some(name)
182 }
183 Definition::Operation(operation) => match operation {
184 OperationDefinition::Query(_) => Some(&context.schema.query_type().name),
185 OperationDefinition::SelectionSet(_) => Some(&context.schema.query_type().name),
186 OperationDefinition::Mutation(_) => {
187 context.schema.mutation_type().map(|t| &t.name).or_else(|| {
188 if let Some(type_definition) = context.schema.type_by_name("Mutation") {
191 return match type_definition {
192 crate::parser::schema::TypeDefinition::Object(object_type) => {
193 Some(&object_type.name)
194 }
195 _ => None,
196 };
197 }
198
199 None
200 })
201 }
202 OperationDefinition::Subscription(_) => {
203 context
204 .schema
205 .subscription_type()
206 .map(|t| &t.name)
207 .or_else(|| {
208 if let Some(type_definition) =
211 context.schema.type_by_name("Subscription")
212 {
213 return match type_definition {
214 crate::parser::schema::TypeDefinition::Object(object_type) => {
215 Some(&object_type.name)
216 }
217 _ => None,
218 };
219 }
220
221 None
222 })
223 }
224 },
225 };
226
227 let schema_type = schema_type_name.map(|v| Type::NamedType(v.clone()));
228 context.with_type(schema_type.as_ref(), |context| match definition {
229 Definition::Fragment(fragment) => {
230 visit_fragment_definition(visitor, fragment, context, user_context)
231 }
232 Definition::Operation(operation) => {
233 visit_operation_definition(visitor, operation, context, user_context)
234 }
235 });
236 }
237}
238
239fn visit_directives<'a, Visitor, UserContext>(
240 visitor: &mut Visitor,
241 directives: &'a [Directive],
242 context: &mut OperationVisitorContext<'a>,
243 user_context: &mut UserContext,
244) where
245 Visitor: OperationVisitor<'a, UserContext>,
246{
247 for directive in directives {
248 let directive_def_args = context
249 .schema
250 .directive_by_name(&directive.name)
251 .map(|def| &def.arguments);
252
253 visitor.enter_directive(context, user_context, directive);
254 visit_arguments(
255 visitor,
256 directive_def_args,
257 &directive.arguments,
258 context,
259 user_context,
260 );
261 visitor.leave_directive(context, user_context, directive);
262 }
263}
264
265fn visit_arguments<'a, Visitor, UserContext>(
266 visitor: &mut Visitor,
267 arguments_definition: Option<&'a Vec<schema::InputValue>>,
268 arguments: &'a Vec<(String, Value)>,
269 context: &mut OperationVisitorContext<'a>,
270 user_context: &mut UserContext,
271) where
272 Visitor: OperationVisitor<'a, UserContext>,
273{
274 for argument in arguments {
275 let arg_def = arguments_definition
276 .and_then(|argument_defs| argument_defs.iter().find(|a| a.name.eq(&argument.0)));
277
278 let arg_type = arg_def.map(|a| &a.value_type);
279 let has_default = arg_def.and_then(|a| a.default_value.as_ref()).is_some();
280
281 context.with_input_type_and_default(arg_type, has_default, |context| {
282 visitor.enter_argument(context, user_context, argument);
283 visit_input_value(visitor, &argument.1, context, user_context);
284 visitor.leave_argument(context, user_context, argument);
285 })
286 }
287}
288
289fn visit_input_value<'a, Visitor, UserContext>(
290 visitor: &mut Visitor,
291 input_value: &'a Value,
292 context: &mut OperationVisitorContext<'a>,
293 user_context: &mut UserContext,
294) where
295 Visitor: OperationVisitor<'a, UserContext>,
296{
297 match input_value {
298 Value::Boolean(_) | Value::Float(_) | Value::Int(_) | Value::String(_) => {
299 visitor.enter_scalar_value(context, user_context, input_value);
300 visitor.leave_scalar_value(context, user_context, input_value);
301 }
302 Value::Null => {
303 visitor.enter_null_value(context, user_context, ());
304 visitor.leave_null_value(context, user_context, ());
305 }
306 Value::Enum(v) => {
307 visitor.enter_enum_value(context, user_context, v);
308 visitor.leave_enum_value(context, user_context, v);
309 }
310 Value::List(v) => {
311 visitor.enter_list_value(context, user_context, v);
312
313 let input_type = context.current_input_type_literal().and_then(|t| match t {
314 Type::ListType(inner_type) => Some(inner_type.as_ref()),
315 _ => None,
316 });
317
318 context.with_input_type(input_type, |context| {
319 for item in v {
320 visit_input_value(visitor, item, context, user_context)
321 }
322 });
323
324 visitor.leave_list_value(context, user_context, v);
325 }
326 Value::Object(v) => {
327 visitor.enter_object_value(context, user_context, v);
328
329 for pair in v {
330 let input_field = context
331 .current_input_type_literal()
332 .and_then(|v| context.schema.type_by_name(v.inner_type()))
333 .and_then(|v| v.input_field_by_name(&pair.0));
334 let input_type = input_field.map(|field| &field.value_type);
335 let has_default = input_field
336 .and_then(|field| field.default_value.as_ref())
337 .is_some();
338
339 context.with_input_type_and_default(input_type, has_default, |context| {
340 visitor.enter_object_field(context, user_context, pair);
341 visit_input_value(visitor, &pair.1, context, user_context);
342 visitor.leave_object_field(context, user_context, pair);
343 });
344 }
345
346 visitor.leave_object_value(context, user_context, v);
347 }
348 Value::Variable(v) => {
349 visitor.enter_variable_value(context, user_context, v);
350 visitor.leave_variable_value(context, user_context, v);
351 }
352 }
353}
354
355fn visit_variable_definitions<'a, Visitor, UserContext>(
356 visitor: &mut Visitor,
357 variables: &'a [VariableDefinition],
358 context: &mut OperationVisitorContext<'a>,
359 user_context: &mut UserContext,
360) where
361 Visitor: OperationVisitor<'a, UserContext>,
362{
363 for variable in variables {
364 context.with_input_type(Some(&variable.var_type), |context| {
365 visitor.enter_variable_definition(context, user_context, variable);
366
367 if let Some(default_value) = &variable.default_value {
368 visit_input_value(visitor, default_value, context, user_context);
369 }
370
371 visitor.leave_variable_definition(context, user_context, variable);
374 })
375 }
376}
377
378fn visit_selection<'a, Visitor, UserContext>(
379 visitor: &mut Visitor,
380 selection: &'a Selection,
381 context: &mut OperationVisitorContext<'a>,
382 user_context: &mut UserContext,
383) where
384 Visitor: OperationVisitor<'a, UserContext>,
385{
386 match selection {
387 Selection::Field(field) => {
388 let parent_type_def = context
389 .current_parent_type()
390 .and_then(|t| t.field_by_name(&field.name));
391
392 let field_type = parent_type_def.map(|f| &f.field_type);
393 let field_args = parent_type_def.map(|f| &f.arguments);
394
395 context.with_type(field_type, |context| {
396 visitor.enter_field(context, user_context, field);
397 context.with_field(
398 context
399 .current_parent_type()
400 .and_then(|t| t.field_by_name(&field.name)),
401 |context| {
402 visit_arguments(
403 visitor,
404 field_args,
405 &field.arguments,
406 context,
407 user_context,
408 );
409 visit_directives(visitor, &field.directives, context, user_context);
410 visit_selection_set(visitor, &field.selection_set, context, user_context);
411 },
412 );
413 visitor.leave_field(context, user_context, field);
414 });
415 }
416 Selection::FragmentSpread(fragment_spread) => {
417 visitor.enter_fragment_spread(context, user_context, fragment_spread);
418 visit_directives(visitor, &fragment_spread.directives, context, user_context);
419 visitor.leave_fragment_spread(context, user_context, fragment_spread);
420 }
421 Selection::InlineFragment(inline_fragment) => {
422 if let Some(TypeCondition::On(fragment_condition)) = &inline_fragment.type_condition {
423 context.with_type(
424 Some(&Type::NamedType(fragment_condition.clone())),
425 |context| {
426 visitor.enter_inline_fragment(context, user_context, inline_fragment);
427 visit_directives(
428 visitor,
429 &inline_fragment.directives,
430 context,
431 user_context,
432 );
433 visit_selection_set(
434 visitor,
435 &inline_fragment.selection_set,
436 context,
437 user_context,
438 );
439 visitor.leave_inline_fragment(context, user_context, inline_fragment);
440 },
441 );
442 } else {
443 visitor.enter_inline_fragment(context, user_context, inline_fragment);
444 visit_directives(visitor, &inline_fragment.directives, context, user_context);
445 visit_selection_set(
446 visitor,
447 &inline_fragment.selection_set,
448 context,
449 user_context,
450 );
451 visitor.leave_inline_fragment(context, user_context, inline_fragment);
452 }
453 }
454 }
455}
456
457fn visit_selection_set<'a, Visitor, UserContext>(
458 visitor: &mut Visitor,
459 selection_set: &'a SelectionSet,
460 context: &mut OperationVisitorContext<'a>,
461 user_context: &mut UserContext,
462) where
463 Visitor: OperationVisitor<'a, UserContext>,
464{
465 context.with_parent_type(|context| {
466 visitor.enter_selection_set(context, user_context, selection_set);
467
468 for selection in &selection_set.items {
469 visit_selection(visitor, selection, context, user_context);
470 }
471
472 visitor.leave_selection_set(context, user_context, selection_set);
473 });
474}
475
476fn visit_fragment_definition<'a, Visitor, UserContext>(
477 visitor: &mut Visitor,
478 fragment: &'a FragmentDefinition,
479 context: &mut OperationVisitorContext<'a>,
480 user_context: &mut UserContext,
481) where
482 Visitor: OperationVisitor<'a, UserContext>,
483{
484 visitor.enter_fragment_definition(context, user_context, fragment);
485 visit_directives(visitor, &fragment.directives, context, user_context);
486 visit_selection_set(visitor, &fragment.selection_set, context, user_context);
487 visitor.leave_fragment_definition(context, user_context, fragment);
488}
489
490fn visit_operation_definition<'a, Visitor, UserContext>(
491 visitor: &mut Visitor,
492 operation: &'a OperationDefinition,
493 context: &mut OperationVisitorContext<'a>,
494 user_context: &mut UserContext,
495) where
496 Visitor: OperationVisitor<'a, UserContext>,
497{
498 visitor.enter_operation_definition(context, user_context, operation);
499 visit_directives(visitor, operation.directives(), context, user_context);
500 visit_variable_definitions(
501 visitor,
502 operation.variable_definitions(),
503 context,
504 user_context,
505 );
506 visit_selection_set(visitor, operation.selection_set(), context, user_context);
507 visitor.leave_operation_definition(context, user_context, operation);
508}
509
510pub trait OperationVisitor<'a, UserContext = ()> {
512 fn enter_document(
513 &mut self,
514 _: &mut OperationVisitorContext<'a>,
515 _: &mut UserContext,
516 _: &'a Document,
517 ) {
518 }
519 fn leave_document(
520 &mut self,
521 _: &mut OperationVisitorContext<'a>,
522 _: &mut UserContext,
523 _: &Document,
524 ) {
525 }
526
527 fn enter_operation_definition(
528 &mut self,
529 _: &mut OperationVisitorContext<'a>,
530 _: &mut UserContext,
531 _: &'a OperationDefinition,
532 ) {
533 }
534 fn leave_operation_definition(
535 &mut self,
536 _: &mut OperationVisitorContext<'a>,
537 _: &mut UserContext,
538 _: &OperationDefinition,
539 ) {
540 }
541
542 fn enter_fragment_definition(
543 &mut self,
544 _: &mut OperationVisitorContext<'a>,
545 _: &mut UserContext,
546 _: &'a FragmentDefinition,
547 ) {
548 }
549 fn leave_fragment_definition(
550 &mut self,
551 _: &mut OperationVisitorContext<'a>,
552 _: &mut UserContext,
553 _: &FragmentDefinition,
554 ) {
555 }
556
557 fn enter_variable_definition(
558 &mut self,
559 _: &mut OperationVisitorContext<'a>,
560 _: &mut UserContext,
561 _: &'a VariableDefinition,
562 ) {
563 }
564 fn leave_variable_definition(
565 &mut self,
566 _: &mut OperationVisitorContext<'a>,
567 _: &mut UserContext,
568 _: &VariableDefinition,
569 ) {
570 }
571
572 fn enter_directive(
573 &mut self,
574 _: &mut OperationVisitorContext<'a>,
575 _: &mut UserContext,
576 _: &Directive,
577 ) {
578 }
579 fn leave_directive(
580 &mut self,
581 _: &mut OperationVisitorContext<'a>,
582 _: &mut UserContext,
583 _: &Directive,
584 ) {
585 }
586
587 fn enter_argument(
588 &mut self,
589 _: &mut OperationVisitorContext<'a>,
590 _: &mut UserContext,
591 _: &'a (String, Value),
592 ) {
593 }
594 fn leave_argument(
595 &mut self,
596 _: &mut OperationVisitorContext<'a>,
597 _: &mut UserContext,
598 _: &(String, Value),
599 ) {
600 }
601
602 fn enter_selection_set(
603 &mut self,
604 _: &mut OperationVisitorContext<'a>,
605 _: &mut UserContext,
606 _: &'a SelectionSet,
607 ) {
608 }
609 fn leave_selection_set(
610 &mut self,
611 _: &mut OperationVisitorContext<'a>,
612 _: &mut UserContext,
613 _: &SelectionSet,
614 ) {
615 }
616
617 fn enter_field(&mut self, _: &mut OperationVisitorContext<'a>, _: &mut UserContext, _: &Field) {
618 }
619 fn leave_field(&mut self, _: &mut OperationVisitorContext<'a>, _: &mut UserContext, _: &Field) {
620 }
621
622 fn enter_fragment_spread(
623 &mut self,
624 _: &mut OperationVisitorContext<'a>,
625 _: &mut UserContext,
626 _: &'a FragmentSpread,
627 ) {
628 }
629 fn leave_fragment_spread(
630 &mut self,
631 _: &mut OperationVisitorContext<'a>,
632 _: &mut UserContext,
633 _: &FragmentSpread,
634 ) {
635 }
636
637 fn enter_inline_fragment(
638 &mut self,
639 _: &mut OperationVisitorContext<'a>,
640 _: &mut UserContext,
641 _: &InlineFragment,
642 ) {
643 }
644 fn leave_inline_fragment(
645 &mut self,
646 _: &mut OperationVisitorContext<'a>,
647 _: &mut UserContext,
648 _: &InlineFragment,
649 ) {
650 }
651
652 fn enter_null_value(
653 &mut self,
654 _: &mut OperationVisitorContext<'a>,
655 _: &mut UserContext,
656 _: (),
657 ) {
658 }
659 fn leave_null_value(
660 &mut self,
661 _: &mut OperationVisitorContext<'a>,
662 _: &mut UserContext,
663 _: (),
664 ) {
665 }
666
667 fn enter_scalar_value(
668 &mut self,
669 _: &mut OperationVisitorContext<'a>,
670 _: &mut UserContext,
671 _: &Value,
672 ) {
673 }
674 fn leave_scalar_value(
675 &mut self,
676 _: &mut OperationVisitorContext<'a>,
677 _: &mut UserContext,
678 _: &Value,
679 ) {
680 }
681
682 fn enter_enum_value(
683 &mut self,
684 _: &mut OperationVisitorContext<'a>,
685 _: &mut UserContext,
686 _: &String,
687 ) {
688 }
689 fn leave_enum_value(
690 &mut self,
691 _: &mut OperationVisitorContext<'a>,
692 _: &mut UserContext,
693 _: &String,
694 ) {
695 }
696
697 fn enter_variable_value(
698 &mut self,
699 _: &mut OperationVisitorContext<'a>,
700 _: &mut UserContext,
701 _: &'a str,
702 ) {
703 }
704 fn leave_variable_value(
705 &mut self,
706 _: &mut OperationVisitorContext<'a>,
707 _: &mut UserContext,
708 _: &String,
709 ) {
710 }
711
712 fn enter_list_value(
713 &mut self,
714 _: &mut OperationVisitorContext<'a>,
715 _: &mut UserContext,
716 _: &Vec<Value>,
717 ) {
718 }
719 fn leave_list_value(
720 &mut self,
721 _: &mut OperationVisitorContext<'a>,
722 _: &mut UserContext,
723 _: &Vec<Value>,
724 ) {
725 }
726
727 fn enter_object_value(
728 &mut self,
729 _: &mut OperationVisitorContext<'a>,
730 _: &mut UserContext,
731 _: &[(String, Value)],
732 ) {
733 }
734 fn leave_object_value(
735 &mut self,
736 _: &mut OperationVisitorContext<'a>,
737 _: &mut UserContext,
738 _: &[(String, Value)],
739 ) {
740 }
741
742 fn enter_object_field(
743 &mut self,
744 _: &mut OperationVisitorContext<'a>,
745 _: &mut UserContext,
746 _: &(String, Value),
747 ) {
748 }
749 fn leave_object_field(
750 &mut self,
751 _: &mut OperationVisitorContext<'a>,
752 _: &mut UserContext,
753 _: &(String, Value),
754 ) {
755 }
756}