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