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