apollo_federation/query_plan/
display.rs1use std::fmt;
2
3use apollo_compiler::executable;
4
5use super::*;
6use crate::display_helpers::State;
7use crate::display_helpers::write_indented_lines;
8
9impl QueryPlan {
10 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
11 let Self {
12 node,
13 statistics: _,
14 } = self;
15 state.write("QueryPlan {")?;
16 if let Some(node) = node {
17 state.indent()?;
18 node.write_indented(state)?;
19 state.dedent()?;
20 }
21 state.write("}")
22 }
23}
24
25impl TopLevelPlanNode {
26 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
27 match self {
28 Self::Subscription(node) => node.write_indented(state),
29 Self::Fetch(node) => node.write_indented(state),
30 Self::Sequence(node) => node.write_indented(state),
31 Self::Parallel(node) => node.write_indented(state),
32 Self::Flatten(node) => node.write_indented(state),
33 Self::Defer(node) => node.write_indented(state),
34 Self::Condition(node) => node.write_indented(state),
35 }
36 }
37}
38
39impl PlanNode {
40 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
41 match self {
42 Self::Fetch(node) => node.write_indented(state),
43 Self::Sequence(node) => node.write_indented(state),
44 Self::Parallel(node) => node.write_indented(state),
45 Self::Flatten(node) => node.write_indented(state),
46 Self::Defer(node) => node.write_indented(state),
47 Self::Condition(node) => node.write_indented(state),
48 }
49 }
50}
51
52impl SubscriptionNode {
53 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
54 let Self { primary, rest } = self;
55 state.write("Subscription {")?;
56 state.indent()?;
57
58 state.write("Primary: {")?;
59 state.indent()?;
60 primary.write_indented(state)?;
61 state.dedent()?;
62 state.write("},")?;
63
64 if let Some(rest) = rest {
65 state.new_line()?;
66 state.write("Rest: {")?;
67 state.indent()?;
68 rest.write_indented(state)?;
69 state.dedent()?;
70 state.write("},")?;
71 }
72
73 state.dedent()?;
74 state.write("},")
75 }
76}
77
78impl FetchNode {
79 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
80 let Self {
81 subgraph_name,
82 id,
83 variable_usages: _,
84 requires,
85 operation_document,
86 operation_name: _,
87 operation_kind: _,
88 input_rewrites: _,
89 output_rewrites: _,
90 context_rewrites: _,
91 } = self;
92 state.write(format_args!("Fetch(service: {subgraph_name:?}"))?;
93 if let Some(id) = id {
94 state.write(format_args!(", id: {id:?}"))?;
95 }
96 state.write(") {")?;
97 state.indent()?;
98
99 if !requires.is_empty() {
100 write_requires_selections(state, requires)?;
101 state.write(" =>")?;
102 state.new_line()?;
103 }
104 write_operation(
105 state,
106 operation_document.as_parsed().map_err(|_| fmt::Error)?,
107 )?;
108
109 state.dedent()?;
110 state.write("},")
111 }
112}
113
114impl SequenceNode {
115 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
116 let Self { nodes } = self;
117 state.write("Sequence {")?;
118
119 write_indented_lines(state, nodes, |state, node| node.write_indented(state))?;
120
121 state.write("},")
122 }
123}
124
125impl ParallelNode {
126 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
127 let Self { nodes } = self;
128 state.write("Parallel {")?;
129
130 write_indented_lines(state, nodes, |state, node| node.write_indented(state))?;
131
132 state.write("},")
133 }
134}
135
136impl FlattenNode {
137 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
138 let Self { path, node } = self;
139 state.write("Flatten(path: \"")?;
140 if let Some((first, rest)) = path.split_first() {
141 state.write(first)?;
142 for element in rest {
143 state.write(".")?;
144 state.write(element)?;
145 }
146 }
147 state.write("\") {")?;
148 state.indent()?;
149
150 node.write_indented(state)?;
151
152 state.dedent()?;
153 state.write("},")
154 }
155}
156
157impl ConditionNode {
158 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
159 let Self {
160 condition_variable,
161 if_clause,
162 else_clause,
163 } = self;
164 match (if_clause, else_clause) {
165 (Some(if_clause), Some(else_clause)) => {
166 state.write(format_args!("Condition(if: ${condition_variable}) {{"))?;
167 state.indent()?;
168
169 state.write("Then {")?;
170 state.indent()?;
171 if_clause.write_indented(state)?;
172 state.dedent()?;
173 state.write("}")?;
174
175 state.write(" Else {")?;
176 state.indent()?;
177 else_clause.write_indented(state)?;
178 state.dedent()?;
179 state.write("},")?;
180
181 state.dedent()?;
182 state.write("},")
183 }
184
185 (Some(if_clause), None) => {
186 state.write(format_args!("Include(if: ${condition_variable}) {{"))?;
187 state.indent()?;
188
189 if_clause.write_indented(state)?;
190
191 state.dedent()?;
192 state.write("},")
193 }
194
195 (None, Some(else_clause)) => {
196 state.write(format_args!("Skip(if: ${condition_variable}) {{"))?;
197 state.indent()?;
198
199 else_clause.write_indented(state)?;
200
201 state.dedent()?;
202 state.write("},")
203 }
204
205 (None, None) => state.write("Condition {}"),
207 }
208 }
209}
210
211impl DeferNode {
212 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
213 let Self { primary, deferred } = self;
214 state.write("Defer {")?;
215 state.indent()?;
216
217 primary.write_indented(state)?;
218 if !deferred.is_empty() {
219 state.write(" [")?;
220 write_indented_lines(state, deferred, |state, deferred| {
221 deferred.write_indented(state)
222 })?;
223 state.write("]")?;
224 }
225
226 state.dedent()?;
227 state.write("},")
228 }
229}
230
231impl PrimaryDeferBlock {
232 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
233 let Self {
234 sub_selection,
235 node,
236 } = self;
237 state.write("Primary {")?;
238 if sub_selection.is_some() || node.is_some() {
239 if let Some(sub_selection) = sub_selection {
240 state.indent()?;
241 state.write(sub_selection)?;
242 if node.is_some() {
243 state.write(":")?;
244 state.new_line()?;
245 }
246 } else {
247 state.indent()?;
249 }
250
251 if let Some(node) = node {
252 node.write_indented(state)?;
253 }
254
255 state.dedent()?;
256 }
257 state.write("},")
258 }
259}
260
261impl DeferredDeferBlock {
262 fn write_indented(&self, state: &mut State<'_, '_>) -> fmt::Result {
263 let Self {
264 depends,
265 label,
266 query_path,
267 sub_selection,
268 node,
269 } = self;
270
271 state.write("Deferred(depends: [")?;
272 if let Some((DeferredDependency { id }, rest)) = depends.split_first() {
273 state.write(id)?;
274 for DeferredDependency { id } in rest {
275 state.write(", ")?;
276 state.write(id)?;
277 }
278 }
279 state.write("], path: \"")?;
280 if let Some((first, rest)) = query_path.split_first() {
281 state.write(first)?;
282 for element in rest {
283 state.write("/")?;
284 state.write(element)?;
285 }
286 }
287 state.write("\"")?;
288 if let Some(label) = label {
289 state.write_fmt(format_args!(r#", label: "{label}""#))?;
290 }
291 state.write(") {")?;
292
293 if sub_selection.is_some() || node.is_some() {
294 state.indent()?;
295
296 if let Some(sub_selection) = sub_selection {
297 state.write(sub_selection)?;
298 state.write(":")?;
299 }
300 if sub_selection.is_some() && node.is_some() {
301 state.new_line()?;
302 }
303 if let Some(node) = node {
304 node.write_indented(state)?;
305 }
306
307 state.dedent()?;
308 }
309
310 state.write("},")
311 }
312}
313
314fn write_operation(
318 state: &mut State<'_, '_>,
319 operation_document: &ExecutableDocument,
320) -> fmt::Result {
321 let operation = operation_document
322 .operations
323 .get(None)
324 .expect("expected a single-operation document");
325 write_selections(state, &operation.selection_set.selections)?;
326 for fragment in operation_document.fragments.values() {
327 state.write("\n\n")?; state.write(
329 fragment
330 .serialize()
331 .initial_indent_level(state.indent_level()),
332 )?
333 }
334 Ok(())
335}
336
337fn write_selections(
338 state: &mut State<'_, '_>,
339 mut selections: &[executable::Selection],
340) -> fmt::Result {
341 if let Some(executable::Selection::Field(field)) = selections.first() {
342 if field.name == "_entities" {
343 selections = &field.selection_set.selections
344 }
345 }
346 state.write("{")?;
347
348 state.indent_no_new_line();
351 for sel in selections {
352 state.write("\n")?;
353 state.write(sel.serialize().initial_indent_level(state.indent_level()))?;
354 }
355 state.dedent()?;
356
357 state.write("}")
358}
359
360fn write_requires_selections(
361 state: &mut State<'_, '_>,
362 selections: &[requires_selection::Selection],
363) -> fmt::Result {
364 state.write("{")?;
365
366 state.indent()?;
369 if let Some((first, rest)) = selections.split_first() {
370 write_requires_selection(state, first)?;
371 for sel in rest {
372 state.new_line()?;
373 write_requires_selection(state, sel)?;
374 }
375 }
376 state.dedent()?;
377
378 state.write("}")
379}
380
381fn write_requires_selection(
382 state: &mut State<'_, '_>,
383 selection: &requires_selection::Selection,
384) -> fmt::Result {
385 match selection {
386 requires_selection::Selection::Field(requires_selection::Field {
387 alias,
388 name,
389 selections,
390 }) => {
391 if let Some(alias) = alias {
392 state.write(alias)?;
393 state.write(": ")?;
394 }
395 state.write(name)?;
396 if !selections.is_empty() {
397 state.write(" ")?;
398 write_requires_selections(state, selections)?;
399 }
400 }
401 requires_selection::Selection::InlineFragment(requires_selection::InlineFragment {
402 type_condition,
403 selections,
404 }) => {
405 if let Some(type_name) = type_condition {
406 state.write("... on ")?;
407 state.write(type_name)?;
408 state.write(" ")?;
409 } else {
410 state.write("... ")?;
411 }
412 write_requires_selections(state, selections)?;
413 }
414 }
415 Ok(())
416}
417
418impl fmt::Display for requires_selection::Selection {
419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420 write_requires_selection(&mut State::new(f), self)
421 }
422}
423
424impl fmt::Display for FetchDataPathElement {
426 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427 match self {
428 Self::Key(name, conditions) => {
429 f.write_str(name)?;
430 write_conditions(conditions, f)
431 }
432 Self::AnyIndex(conditions) => {
433 f.write_str("@")?;
434 write_conditions(conditions, f)
435 }
436 Self::TypenameEquals(name) => write!(f, "... on {name}"),
437 Self::Parent => write!(f, ".."),
438 }
439 }
440}
441
442fn write_conditions(conditions: &Option<Vec<Name>>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 if let Some(conditions) = conditions {
444 write!(f, "|[{}]", conditions.join(","))
445 } else {
446 Ok(())
447 }
448}
449
450impl fmt::Display for QueryPathElement {
451 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452 match self {
453 Self::Field { response_key } => f.write_str(response_key),
454 Self::InlineFragment { type_condition } => write!(f, "... on {type_condition}"),
455 }
456 }
457}
458
459macro_rules! impl_display {
460 ($( $Ty: ty )+) => {
461 $(
462 impl fmt::Display for $Ty {
463 fn fmt(&self, output: &mut fmt::Formatter<'_>) -> fmt::Result {
464 self.write_indented(&mut State::new(output))
465 }
466 }
467 )+
468 };
469}
470
471impl_display! {
472 QueryPlan
473 TopLevelPlanNode
474 PlanNode
475 SubscriptionNode
476 FetchNode
477 SequenceNode
478 ParallelNode
479 FlattenNode
480 ConditionNode
481 DeferNode
482 PrimaryDeferBlock
483 DeferredDeferBlock
484}