1#![allow(clippy::too_many_arguments)]
2
3use std::collections::HashMap;
4
5use graphgate_schema::{ComposedSchema, KeyFields, MetaField, MetaType, TypeKind, ValueExt};
6use indexmap::IndexMap;
7use parser::types::{
8 BaseType, DocumentOperations, ExecutableDocument, Field, FragmentDefinition,
9 OperationDefinition, OperationType, Selection, SelectionSet, Type, VariableDefinition,
10};
11use parser::Positioned;
12use value::{ConstValue, Name, Value, Variables};
13
14use crate::plan::{
15 FetchNode, FlattenNode, IntrospectionDirective, IntrospectionField, IntrospectionNode,
16 IntrospectionSelectionSet, ParallelNode, PathSegment, PlanNode, ResponsePath, SequenceNode,
17};
18use crate::types::{
19 FetchEntity, FetchEntityGroup, FetchEntityKey, FetchQuery, FieldRef, MutationRootGroup,
20 QueryRootGroup, RequiredRef, RootGroup, SelectionRef, SelectionRefSet, VariableDefinitionsRef,
21 VariablesRef,
22};
23use crate::{Response, RootNode, ServerError, SubscribeNode};
24
25struct Context<'a> {
26 schema: &'a ComposedSchema,
27 fragments: &'a HashMap<Name, Positioned<FragmentDefinition>>,
28 variables: &'a Variables,
29 key_id: usize,
30}
31
32pub struct PlanBuilder<'a> {
34 schema: &'a ComposedSchema,
35 document: ExecutableDocument,
36 operation_name: Option<String>,
37 variables: Variables,
38}
39
40impl<'a> PlanBuilder<'a> {
41 pub fn new(schema: &'a ComposedSchema, document: ExecutableDocument) -> Self {
42 Self {
43 schema,
44 document,
45 operation_name: None,
46 variables: Default::default(),
47 }
48 }
49
50 pub fn operation_name(mut self, operation: impl Into<String>) -> Self {
51 self.operation_name = Some(operation.into());
52 self
53 }
54
55 pub fn variables(self, variables: Variables) -> Self {
56 Self { variables, ..self }
57 }
58
59 fn check_rules(&self) -> Result<(), Response> {
60 let rule_errors =
61 graphgate_validation::check_rules(self.schema, &self.document, &self.variables);
62 if !rule_errors.is_empty() {
63 return Err(Response {
64 data: ConstValue::Null,
65 errors: rule_errors
66 .into_iter()
67 .map(|err| ServerError {
68 message: err.message,
69 locations: err.locations,
70 })
71 .collect(),
72 extensions: Default::default(),
73 });
74 }
75 Ok(())
76 }
77
78 fn create_context(&self) -> Context<'_> {
79 let fragments = &self.document.fragments;
80 Context {
81 schema: self.schema,
82 fragments,
83 variables: &self.variables,
84 key_id: 1,
85 }
86 }
87
88 pub fn plan(&self) -> Result<RootNode, Response> {
89 self.check_rules()?;
90
91 let mut ctx = self.create_context();
92 let operation_definition = get_operation(&self.document, self.operation_name.as_deref());
93
94 let root_type = match operation_definition.node.ty {
95 OperationType::Query => ctx.schema.query_type(),
96 OperationType::Mutation => ctx
97 .schema
98 .mutation_type()
99 .expect("The query validator should find this error."),
100 OperationType::Subscription => ctx
101 .schema
102 .subscription_type()
103 .expect("The query validator should find this error."),
104 };
105
106 if let Some(root_type) = ctx.schema.types.get(root_type) {
107 match operation_definition.node.ty {
108 OperationType::Query => Ok(RootNode::Query(ctx.build_root_selection_set(
109 QueryRootGroup::default(),
110 operation_definition.node.ty,
111 &operation_definition.node.variable_definitions,
112 root_type,
113 &operation_definition.node.selection_set.node,
114 ))),
115 OperationType::Mutation => Ok(RootNode::Query(ctx.build_root_selection_set(
116 MutationRootGroup::default(),
117 operation_definition.node.ty,
118 &operation_definition.node.variable_definitions,
119 root_type,
120 &operation_definition.node.selection_set.node,
121 ))),
122 OperationType::Subscription => Ok(RootNode::Subscribe(ctx.build_subscribe(
123 &operation_definition.node.variable_definitions,
124 root_type,
125 &operation_definition.node.selection_set.node,
126 ))),
127 }
128 } else {
129 unreachable!("The query validator should find this error.")
130 }
131 }
132}
133
134impl<'a> Context<'a> {
135 fn build_root_selection_set(
136 &mut self,
137 mut root_group: impl RootGroup<'a>,
138 operation_type: OperationType,
139 variable_definitions: &'a [Positioned<VariableDefinition>],
140 parent_type: &'a MetaType,
141 selection_set: &'a SelectionSet,
142 ) -> PlanNode<'a> {
143 fn build_root_selection_set_rec<'a>(
144 ctx: &mut Context<'a>,
145 root_group: &mut impl RootGroup<'a>,
146 fetch_entity_group: &mut FetchEntityGroup<'a>,
147 inspection_selection_set: &mut IntrospectionSelectionSet,
148 parent_type: &'a MetaType,
149 selection_set: &'a SelectionSet,
150 ) {
151 for selection in &selection_set.items {
152 match &selection.node {
153 Selection::Field(field) => {
154 let field_name = field.node.name.node.as_str();
155 let field_definition = match parent_type.fields.get(field_name) {
156 Some(field_definition) => field_definition,
157 None => continue,
158 };
159 if is_introspection_field(field_name) {
160 ctx.build_introspection_field(inspection_selection_set, &field.node);
161 continue;
162 }
163
164 if let Some(service) = &field_definition.service {
165 let selection_ref_set = root_group.selection_set_mut(service);
166 let mut path = ResponsePath::default();
167 ctx.build_field(
168 &mut path,
169 selection_ref_set,
170 fetch_entity_group,
171 service,
172 parent_type,
173 &field.node,
174 );
175 }
176 }
177 Selection::FragmentSpread(fragment_spread) => {
178 if let Some(fragment) = ctx
179 .fragments
180 .get(fragment_spread.node.fragment_name.node.as_str())
181 {
182 build_root_selection_set_rec(
183 ctx,
184 root_group,
185 fetch_entity_group,
186 inspection_selection_set,
187 parent_type,
188 &fragment.node.selection_set.node,
189 );
190 }
191 }
192 Selection::InlineFragment(inline_fragment) => {
193 build_root_selection_set_rec(
194 ctx,
195 root_group,
196 fetch_entity_group,
197 inspection_selection_set,
198 parent_type,
199 &inline_fragment.node.selection_set.node,
200 );
201 }
202 }
203 }
204 }
205
206 let mut fetch_entity_group = FetchEntityGroup::default();
207 let mut inspection_selection_set = IntrospectionSelectionSet::default();
208 build_root_selection_set_rec(
209 self,
210 &mut root_group,
211 &mut fetch_entity_group,
212 &mut inspection_selection_set,
213 parent_type,
214 selection_set,
215 );
216
217 let mut nodes = Vec::new();
218 if !inspection_selection_set.0.is_empty() {
219 nodes.push(PlanNode::Introspection(IntrospectionNode {
220 selection_set: inspection_selection_set,
221 }));
222 }
223
224 let fetch_node = {
225 let mut nodes = Vec::new();
226 for (service, selection_set) in root_group.into_selection_set() {
227 let (variables, variable_definitions) =
228 referenced_variables(&selection_set, self.variables, variable_definitions);
229 nodes.push(PlanNode::Fetch(FetchNode {
230 service,
231 variables,
232 query: FetchQuery {
233 entity_type: None,
234 operation_type,
235 variable_definitions,
236 selection_set,
237 },
238 }));
239 }
240 if operation_type == OperationType::Query {
241 PlanNode::Parallel(ParallelNode { nodes }).flatten()
242 } else {
243 PlanNode::Sequence(SequenceNode { nodes }).flatten()
244 }
245 };
246 nodes.push(fetch_node);
247
248 while !fetch_entity_group.is_empty() {
249 let mut flatten_nodes = Vec::new();
250 let mut next_group = FetchEntityGroup::new();
251
252 for (
253 FetchEntityKey {
254 service, mut path, ..
255 },
256 FetchEntity {
257 parent_type,
258 prefix,
259 fields,
260 },
261 ) in fetch_entity_group
262 {
263 let mut selection_ref_set = SelectionRefSet::default();
264
265 for field in fields {
266 self.build_field(
267 &mut path,
268 &mut selection_ref_set,
269 &mut next_group,
270 service,
271 parent_type,
272 field,
273 );
274 }
275
276 let (variables, variable_definitions) =
277 referenced_variables(&selection_ref_set, self.variables, variable_definitions);
278 flatten_nodes.push(PlanNode::Flatten(FlattenNode {
279 path,
280 prefix,
281 service,
282 variables,
283 query: FetchQuery {
284 entity_type: Some(parent_type.name.as_str()),
285 operation_type: OperationType::Subscription,
286 variable_definitions,
287 selection_set: selection_ref_set,
288 },
289 }));
290 }
291
292 nodes.push(
293 PlanNode::Parallel(ParallelNode {
294 nodes: flatten_nodes,
295 })
296 .flatten(),
297 );
298 fetch_entity_group = next_group;
299 }
300
301 PlanNode::Sequence(SequenceNode { nodes }).flatten()
302 }
303
304 fn build_subscribe(
305 &mut self,
306 variable_definitions: &'a [Positioned<VariableDefinition>],
307 parent_type: &'a MetaType,
308 selection_set: &'a SelectionSet,
309 ) -> SubscribeNode<'a> {
310 let mut root_group = QueryRootGroup::default();
311 let mut fetch_entity_group = FetchEntityGroup::default();
312
313 for selection in &selection_set.items {
314 if let Selection::Field(field) = &selection.node {
315 let field_name = field.node.name.node.as_str();
316 let field_definition = match parent_type.fields.get(field_name) {
317 Some(field_definition) => field_definition,
318 None => continue,
319 };
320
321 if let Some(service) = &field_definition.service {
322 let selection_ref_set = root_group.selection_set_mut(service);
323 let mut path = ResponsePath::default();
324 self.build_field(
325 &mut path,
326 selection_ref_set,
327 &mut fetch_entity_group,
328 service,
329 parent_type,
330 &field.node,
331 );
332 }
333 }
334 }
335
336 let fetch_nodes = {
337 let mut nodes = Vec::new();
338 for (service, selection_ref_set) in root_group.into_selection_set() {
339 let (variables, variable_definitions) =
340 referenced_variables(&selection_ref_set, self.variables, variable_definitions);
341 nodes.push(FetchNode {
342 service,
343 variables,
344 query: FetchQuery {
345 entity_type: None,
346 operation_type: OperationType::Subscription,
347 variable_definitions,
348 selection_set: selection_ref_set,
349 },
350 });
351 }
352 nodes
353 };
354
355 let mut query_nodes = Vec::new();
356 while !fetch_entity_group.is_empty() {
357 let mut flatten_nodes = Vec::new();
358 let mut next_group = FetchEntityGroup::new();
359
360 for (
361 FetchEntityKey {
362 service, mut path, ..
363 },
364 FetchEntity {
365 parent_type,
366 prefix,
367 fields,
368 },
369 ) in fetch_entity_group
370 {
371 let mut selection_ref_set = SelectionRefSet::default();
372
373 for field in fields {
374 self.build_field(
375 &mut path,
376 &mut selection_ref_set,
377 &mut next_group,
378 service,
379 parent_type,
380 field,
381 );
382 }
383
384 let (variables, variable_definitions) =
385 referenced_variables(&selection_ref_set, self.variables, variable_definitions);
386 flatten_nodes.push(PlanNode::Flatten(FlattenNode {
387 path,
388 prefix,
389 service,
390 variables,
391 query: FetchQuery {
392 entity_type: Some(parent_type.name.as_str()),
393 operation_type: OperationType::Query,
394 variable_definitions,
395 selection_set: selection_ref_set,
396 },
397 }));
398 }
399
400 query_nodes.push(
401 PlanNode::Parallel(ParallelNode {
402 nodes: flatten_nodes,
403 })
404 .flatten(),
405 );
406 fetch_entity_group = next_group;
407 }
408
409 SubscribeNode {
410 subscribe_nodes: fetch_nodes,
411 flatten_node: if query_nodes.is_empty() {
412 None
413 } else {
414 Some(PlanNode::Sequence(SequenceNode { nodes: query_nodes }).flatten())
415 },
416 }
417 }
418
419 fn build_introspection_field(
420 &mut self,
421 introspection_selection_set: &mut IntrospectionSelectionSet,
422 field: &'a Field,
423 ) {
424 fn build_selection_set<'a>(
425 ctx: &mut Context<'a>,
426 introspection_selection_set: &mut IntrospectionSelectionSet,
427 selection_set: &'a SelectionSet,
428 ) {
429 for selection in &selection_set.items {
430 match &selection.node {
431 Selection::Field(field) => {
432 ctx.build_introspection_field(introspection_selection_set, &field.node);
433 }
434 Selection::FragmentSpread(fragment_spread) => {
435 if let Some(fragment) = ctx
436 .fragments
437 .get(fragment_spread.node.fragment_name.node.as_str())
438 {
439 build_selection_set(
440 ctx,
441 introspection_selection_set,
442 &fragment.node.selection_set.node,
443 );
444 }
445 }
446 Selection::InlineFragment(inline_fragment) => {
447 build_selection_set(
448 ctx,
449 introspection_selection_set,
450 &inline_fragment.node.selection_set.node,
451 );
452 }
453 }
454 }
455 }
456
457 fn convert_arguments(
458 ctx: &mut Context,
459 arguments: &[(Positioned<Name>, Positioned<Value>)],
460 ) -> IndexMap<Name, ConstValue> {
461 arguments
462 .iter()
463 .map(|(name, value)| {
464 (
465 name.node.clone(),
466 value
467 .node
468 .clone()
469 .into_const_with(|name| {
470 Ok::<_, std::convert::Infallible>(
471 ctx.variables.get(&name).unwrap().clone(),
472 )
473 })
474 .unwrap(),
475 )
476 })
477 .collect()
478 }
479
480 let mut sub_selection_set = IntrospectionSelectionSet::default();
481 build_selection_set(self, &mut sub_selection_set, &field.selection_set.node);
482 introspection_selection_set.0.push(IntrospectionField {
483 name: field.name.node.clone(),
484 alias: field.alias.clone().map(|alias| alias.node),
485 arguments: convert_arguments(self, &field.arguments),
486 directives: field
487 .directives
488 .iter()
489 .map(|directive| IntrospectionDirective {
490 name: directive.node.name.node.clone(),
491 arguments: convert_arguments(self, &directive.node.arguments),
492 })
493 .collect(),
494 selection_set: sub_selection_set,
495 });
496 }
497
498 fn build_field(
499 &mut self,
500 path: &mut ResponsePath<'a>,
501 selection_ref_set: &mut SelectionRefSet<'a>,
502 fetch_entity_group: &mut FetchEntityGroup<'a>,
503 current_service: &'a str,
504 parent_type: &'a MetaType,
505 field: &'a Field,
506 ) {
507 let field_name = field.name.node.as_str();
508
509 if field_name == "__typename" {
510 selection_ref_set
511 .0
512 .push(SelectionRef::IntrospectionTypename);
513 return;
514 }
515
516 let field_definition = match parent_type.fields.get(field_name) {
517 Some(field_definition) => field_definition,
518 None => return,
519 };
520 let field_type = match self.schema.get_type(&field_definition.ty) {
521 Some(field_type) => field_type,
522 None => return,
523 };
524
525 let service = match field_definition
526 .service
527 .as_deref()
528 .or_else(|| parent_type.owner.as_deref())
529 {
530 Some(service) => service,
531 None => current_service,
532 };
533
534 if service != current_service {
535 let mut keys = parent_type.keys.get(service).and_then(|x| x.get(0));
536 if keys.is_none() {
537 if let Some(owner) = &parent_type.owner {
538 keys = parent_type.keys.get(owner).and_then(|x| x.get(0));
539 }
540 }
541 let keys = match keys {
542 Some(keys) => keys,
543 None => return,
544 };
545 if !self.field_in_keys(field, keys) {
546 self.add_fetch_entity(
547 path,
548 selection_ref_set,
549 fetch_entity_group,
550 parent_type,
551 field,
552 &field_definition,
553 service,
554 keys,
555 );
556 return;
557 }
558 }
559
560 path.push(PathSegment {
561 name: field.response_key().node.as_str(),
562 is_list: is_list(&field_definition.ty),
563 possible_type: None,
564 });
565 let mut sub_selection_set = SelectionRefSet::default();
566
567 if matches!(field_type.kind, TypeKind::Interface | TypeKind::Union) {
568 self.build_abstract_selection_set(
569 path,
570 &mut sub_selection_set,
571 fetch_entity_group,
572 current_service,
573 &field_type,
574 &field.selection_set.node,
575 );
576 } else {
577 self.build_selection_set(
578 path,
579 &mut sub_selection_set,
580 fetch_entity_group,
581 current_service,
582 field_type,
583 &field.selection_set.node,
584 );
585 }
586
587 selection_ref_set.0.push(SelectionRef::FieldRef(FieldRef {
588 field,
589 selection_set: sub_selection_set,
590 }));
591 path.pop();
592 }
593
594 fn add_fetch_entity(
595 &mut self,
596 path: &mut ResponsePath<'a>,
597 selection_ref_set: &mut SelectionRefSet<'a>,
598 fetch_entity_group: &mut FetchEntityGroup<'a>,
599 parent_type: &'a MetaType,
600 field: &'a Field,
601 meta_field: &'a MetaField,
602 service: &'a str,
603 keys: &'a KeyFields,
604 ) {
605 let fetch_entity_key = FetchEntityKey {
606 service,
607 path: path.clone(),
608 ty: parent_type.name.as_str(),
609 };
610
611 match fetch_entity_group.get_mut(&fetch_entity_key) {
612 Some(fetch_entity) => {
613 fetch_entity.fields.push(field);
614 }
615 None => {
616 let prefix = self.take_key_prefix();
617 selection_ref_set
618 .0
619 .push(SelectionRef::RequiredRef(RequiredRef {
620 prefix,
621 fields: keys,
622 requires: meta_field.requires.as_ref(),
623 }));
624 fetch_entity_group.insert(
625 fetch_entity_key,
626 FetchEntity {
627 parent_type,
628 prefix,
629 fields: vec![field],
630 },
631 );
632 }
633 }
634 }
635
636 fn build_selection_set(
637 &mut self,
638 path: &mut ResponsePath<'a>,
639 selection_ref_set: &mut SelectionRefSet<'a>,
640 fetch_entity_group: &mut FetchEntityGroup<'a>,
641 current_service: &'a str,
642 parent_type: &'a MetaType,
643 selection_set: &'a SelectionSet,
644 ) {
645 for selection in &selection_set.items {
646 match &selection.node {
647 Selection::Field(field) => {
648 self.build_field(
649 path,
650 selection_ref_set,
651 fetch_entity_group,
652 current_service,
653 parent_type,
654 &field.node,
655 );
656 }
657 Selection::FragmentSpread(fragment_spread) => {
658 if let Some(fragment) = self
659 .fragments
660 .get(fragment_spread.node.fragment_name.node.as_str())
661 {
662 self.build_selection_set(
663 path,
664 selection_ref_set,
665 fetch_entity_group,
666 current_service,
667 parent_type,
668 &fragment.node.selection_set.node,
669 );
670 }
671 }
672 Selection::InlineFragment(inline_fragment) => {
673 self.build_selection_set(
674 path,
675 selection_ref_set,
676 fetch_entity_group,
677 current_service,
678 parent_type,
679 &inline_fragment.node.selection_set.node,
680 );
681 }
682 }
683 }
684 }
685
686 fn build_abstract_selection_set(
687 &mut self,
688 path: &mut ResponsePath<'a>,
689 selection_ref_set: &mut SelectionRefSet<'a>,
690 fetch_entity_group: &mut FetchEntityGroup<'a>,
691 current_service: &'a str,
692 parent_type: &'a MetaType,
693 selection_set: &'a SelectionSet,
694 ) {
695 fn build_fields<'a>(
696 ctx: &mut Context<'a>,
697 path: &mut ResponsePath<'a>,
698 selection_ref_set_group: &mut IndexMap<&'a str, SelectionRefSet<'a>>,
699 fetch_entity_group: &mut FetchEntityGroup<'a>,
700 current_service: &'a str,
701 selection_set: &'a SelectionSet,
702 possible_type: &'a MetaType,
703 ) {
704 let current_ty = possible_type.name.as_str();
705
706 for selection in &selection_set.items {
707 match &selection.node {
708 Selection::Field(field) => {
709 ctx.build_field(
710 path,
711 selection_ref_set_group.entry(current_ty).or_default(),
712 fetch_entity_group,
713 current_service,
714 possible_type,
715 &field.node,
716 );
717 }
718 Selection::FragmentSpread(fragment_spread) => {
719 if let Some(fragment) =
720 ctx.fragments.get(&fragment_spread.node.fragment_name.node)
721 {
722 if fragment.node.type_condition.node.on.node == current_ty {
723 build_fields(
724 ctx,
725 path,
726 selection_ref_set_group,
727 fetch_entity_group,
728 current_service,
729 &fragment.node.selection_set.node,
730 possible_type,
731 );
732 }
733 }
734 }
735 Selection::InlineFragment(inline_fragment) => {
736 match inline_fragment
737 .node
738 .type_condition
739 .as_ref()
740 .map(|node| &node.node)
741 {
742 Some(type_condition) if type_condition.on.node == current_ty => {
743 build_fields(
744 ctx,
745 path,
746 selection_ref_set_group,
747 fetch_entity_group,
748 current_service,
749 &inline_fragment.node.selection_set.node,
750 possible_type,
751 );
752 }
753 Some(_type_condition) => {
754 }
756 None => {
757 build_fields(
758 ctx,
759 path,
760 selection_ref_set_group,
761 fetch_entity_group,
762 current_service,
763 &inline_fragment.node.selection_set.node,
764 possible_type,
765 );
766 }
767 }
768 }
769 }
770 }
771 }
772
773 let mut selection_ref_set_group = IndexMap::new();
774 for possible_type in &parent_type.possible_types {
775 if let Some(ty) = self.schema.types.get(possible_type) {
776 path.last_mut().unwrap().possible_type = Some(ty.name.as_str());
777 build_fields(
778 self,
779 path,
780 &mut selection_ref_set_group,
781 fetch_entity_group,
782 current_service,
783 selection_set,
784 ty,
785 );
786 path.last_mut().unwrap().possible_type = None;
787 }
788 }
789
790 for (ty, sub_selection_ref_set) in selection_ref_set_group
791 .into_iter()
792 .filter(|(_, selection_ref_set)| !selection_ref_set.0.is_empty())
793 {
794 selection_ref_set.0.push(SelectionRef::InlineFragment {
795 type_condition: Some(ty),
796 selection_set: sub_selection_ref_set,
797 });
798 }
799 }
800
801 fn take_key_prefix(&mut self) -> usize {
802 let id = self.key_id;
803 self.key_id += 1;
804 id
805 }
806
807 fn field_in_keys(&self, field: &Field, keys: &KeyFields) -> bool {
808 fn selection_set_in_keys(
809 ctx: &Context<'_>,
810 selection_set: &SelectionSet,
811 keys: &KeyFields,
812 ) -> bool {
813 for selection in &selection_set.items {
814 match &selection.node {
815 Selection::Field(field) => {
816 if !ctx.field_in_keys(&field.node, keys) {
817 return false;
818 }
819 }
820 Selection::FragmentSpread(fragment_spread) => {
821 if let Some(fragment) = ctx
822 .fragments
823 .get(fragment_spread.node.fragment_name.node.as_str())
824 {
825 if !selection_set_in_keys(ctx, &fragment.node.selection_set.node, keys)
826 {
827 return false;
828 }
829 } else {
830 return false;
831 }
832 }
833 Selection::InlineFragment(inline_fragment) => {
834 if !selection_set_in_keys(
835 ctx,
836 &inline_fragment.node.selection_set.node,
837 keys,
838 ) {
839 return false;
840 }
841 }
842 }
843 }
844 true
845 }
846
847 if let Some(children) = keys.get(field.name.node.as_str()) {
848 selection_set_in_keys(self, &field.selection_set.node, children)
849 } else {
850 false
851 }
852 }
853}
854
855#[inline]
856fn is_list(ty: &Type) -> bool {
857 matches!(ty.base, BaseType::List(_))
858}
859
860fn get_operation<'a>(
861 document: &'a ExecutableDocument,
862 operation_name: Option<&str>,
863) -> &'a Positioned<OperationDefinition> {
864 let operation = if let Some(operation_name) = operation_name {
865 match &document.operations {
866 DocumentOperations::Single(_) => None,
867 DocumentOperations::Multiple(operations) => operations.get(operation_name),
868 }
869 } else {
870 match &document.operations {
871 DocumentOperations::Single(operation) => Some(operation),
872 DocumentOperations::Multiple(map) if map.len() == 1 => {
873 Some(map.iter().next().unwrap().1)
874 }
875 DocumentOperations::Multiple(_) => None,
876 }
877 };
878 operation.expect("The query validator should find this error.")
879}
880
881fn referenced_variables<'a>(
882 selection_set: &SelectionRefSet<'a>,
883 variables: &'a Variables,
884 variable_definitions: &'a [Positioned<VariableDefinition>],
885) -> (VariablesRef<'a>, VariableDefinitionsRef<'a>) {
886 fn referenced_variables_rec<'a>(
887 selection_set: &SelectionRefSet<'a>,
888 variables: &'a Variables,
889 variable_definitions: &'a [Positioned<VariableDefinition>],
890 variables_ref: &mut VariablesRef<'a>,
891 variables_definition_ref: &mut IndexMap<&'a str, &'a VariableDefinition>,
892 ) {
893 for selection in &selection_set.0 {
894 match selection {
895 SelectionRef::FieldRef(field) => {
896 for (_, value) in &field.field.arguments {
897 for name in value.node.referenced_variables() {
898 if let Some((value, definition)) = variables.get(name).zip(
899 variable_definitions
900 .iter()
901 .find(|d| d.node.name.node.as_str() == name),
902 ) {
903 variables_ref.variables.insert(name, value);
904 variables_definition_ref.insert(name, &definition.node);
905 }
906 }
907 }
908 }
909 SelectionRef::InlineFragment { selection_set, .. } => {
910 referenced_variables_rec(
911 selection_set,
912 variables,
913 variable_definitions,
914 variables_ref,
915 variables_definition_ref,
916 );
917 }
918 _ => {}
919 }
920 }
921 }
922
923 let mut variables_ref = VariablesRef::default();
924 let mut variable_definition_ref = IndexMap::new();
925 referenced_variables_rec(
926 selection_set,
927 variables,
928 variable_definitions,
929 &mut variables_ref,
930 &mut variable_definition_ref,
931 );
932 (
933 variables_ref,
934 VariableDefinitionsRef {
935 variables: variable_definition_ref
936 .into_iter()
937 .map(|(_, value)| value)
938 .collect(),
939 },
940 )
941}
942
943#[inline]
944fn is_introspection_field(name: &str) -> bool {
945 name == "__type" || name == "__schema"
946}