apollo_router/query_planner/
convert.rs1use std::sync::Arc;
2
3use apollo_compiler::executable;
4use apollo_federation::query_plan as next;
5
6use crate::query_planner::fetch::SubgraphOperation;
7use crate::query_planner::plan;
8use crate::query_planner::rewrites;
9use crate::query_planner::selection;
10use crate::query_planner::subscription;
11
12pub(crate) fn convert_root_query_plan_node(js: &next::QueryPlan) -> Option<plan::PlanNode> {
13 let next::QueryPlan {
14 node,
15 statistics: _,
16 } = js;
17 option(node)
18}
19
20impl From<&'_ next::TopLevelPlanNode> for plan::PlanNode {
21 fn from(value: &'_ next::TopLevelPlanNode) -> Self {
22 match value {
23 next::TopLevelPlanNode::Subscription(node) => node.into(),
24 next::TopLevelPlanNode::Fetch(node) => node.into(),
25 next::TopLevelPlanNode::Sequence(node) => node.into(),
26 next::TopLevelPlanNode::Parallel(node) => node.into(),
27 next::TopLevelPlanNode::Flatten(node) => node.into(),
28 next::TopLevelPlanNode::Defer(node) => node.into(),
29 next::TopLevelPlanNode::Condition(node) => node.as_ref().into(),
30 }
31 }
32}
33
34impl From<&'_ next::PlanNode> for plan::PlanNode {
35 fn from(value: &'_ next::PlanNode) -> Self {
36 match value {
37 next::PlanNode::Fetch(node) => node.into(),
38 next::PlanNode::Sequence(node) => node.into(),
39 next::PlanNode::Parallel(node) => node.into(),
40 next::PlanNode::Flatten(node) => node.into(),
41 next::PlanNode::Defer(node) => node.into(),
42 next::PlanNode::Condition(node) => node.as_ref().into(),
43 }
44 }
45}
46impl From<&'_ Box<next::PlanNode>> for plan::PlanNode {
47 fn from(value: &'_ Box<next::PlanNode>) -> Self {
48 value.as_ref().into()
49 }
50}
51
52impl From<&'_ next::SubscriptionNode> for plan::PlanNode {
53 fn from(value: &'_ next::SubscriptionNode) -> Self {
54 let next::SubscriptionNode { primary, rest } = value;
55 Self::Subscription {
56 primary: primary.as_ref().into(),
57 rest: option(rest).map(Box::new),
58 }
59 }
60}
61
62impl From<&'_ Box<next::FetchNode>> for plan::PlanNode {
63 fn from(value: &'_ Box<next::FetchNode>) -> Self {
64 let next::FetchNode {
65 subgraph_name,
66 id,
67 variable_usages,
68 requires,
69 operation_document,
70 operation_name,
71 operation_kind,
72 input_rewrites,
73 output_rewrites,
74 context_rewrites,
75 } = &**value;
76 Self::Fetch(super::fetch::FetchNode {
77 service_name: subgraph_name.clone(),
78 requires: requires.as_deref().map(vec).unwrap_or_default(),
79 variable_usages: variable_usages.iter().map(|v| v.clone().into()).collect(),
80 operation: SubgraphOperation::from_parsed(Arc::new(operation_document.clone())),
82 operation_name: operation_name.clone().map(|n| n.into()),
83 operation_kind: (*operation_kind).into(),
84 id: id.map(|id| id.to_string()),
85 input_rewrites: option_vec(input_rewrites),
86 output_rewrites: option_vec(output_rewrites),
87 context_rewrites: option_vec(context_rewrites),
88 schema_aware_hash: Default::default(),
89 authorization: Default::default(),
90 })
91 }
92}
93
94impl From<&'_ next::SequenceNode> for plan::PlanNode {
95 fn from(value: &'_ next::SequenceNode) -> Self {
96 let next::SequenceNode { nodes } = value;
97 Self::Sequence { nodes: vec(nodes) }
98 }
99}
100
101impl From<&'_ next::ParallelNode> for plan::PlanNode {
102 fn from(value: &'_ next::ParallelNode) -> Self {
103 let next::ParallelNode { nodes } = value;
104 Self::Parallel { nodes: vec(nodes) }
105 }
106}
107
108impl From<&'_ next::FlattenNode> for plan::PlanNode {
109 fn from(value: &'_ next::FlattenNode) -> Self {
110 let next::FlattenNode { path, node } = value;
111 Self::Flatten(plan::FlattenNode {
112 path: crate::json_ext::Path(vec(path)),
113 node: Box::new(node.into()),
114 })
115 }
116}
117
118impl From<&'_ next::DeferNode> for plan::PlanNode {
119 fn from(value: &'_ next::DeferNode) -> Self {
120 let next::DeferNode { primary, deferred } = value;
121 Self::Defer {
122 primary: primary.into(),
123 deferred: vec(deferred),
124 }
125 }
126}
127
128impl From<&'_ next::ConditionNode> for plan::PlanNode {
129 fn from(value: &'_ next::ConditionNode) -> Self {
130 let next::ConditionNode {
131 condition_variable,
132 if_clause,
133 else_clause,
134 } = value;
135 Self::Condition {
136 condition: condition_variable.to_string(),
137 if_clause: if_clause.as_ref().map(Into::into).map(Box::new),
138 else_clause: else_clause.as_ref().map(Into::into).map(Box::new),
139 }
140 }
141}
142
143impl From<&'_ next::FetchNode> for subscription::SubscriptionNode {
144 fn from(value: &'_ next::FetchNode) -> Self {
145 let next::FetchNode {
146 subgraph_name,
147 id: _,
148 variable_usages,
149 requires: _,
150 operation_document,
151 operation_name,
152 operation_kind,
153 input_rewrites,
154 output_rewrites,
155 context_rewrites: _,
156 } = value;
157 Self {
158 service_name: subgraph_name.clone(),
159 variable_usages: variable_usages.iter().map(|v| v.clone().into()).collect(),
160 operation: SubgraphOperation::from_parsed(Arc::new(operation_document.clone())),
162 operation_name: operation_name.clone().map(|n| n.into()),
163 operation_kind: (*operation_kind).into(),
164 input_rewrites: option_vec(input_rewrites),
165 output_rewrites: option_vec(output_rewrites),
166 }
167 }
168}
169
170impl From<&'_ next::PrimaryDeferBlock> for plan::Primary {
171 fn from(value: &'_ next::PrimaryDeferBlock) -> Self {
172 let next::PrimaryDeferBlock {
173 sub_selection,
174 node,
175 } = value;
176 Self {
177 node: option(node).map(Box::new),
178 subselection: sub_selection.as_ref().map(|s| s.to_string()),
179 }
180 }
181}
182
183impl From<&'_ next::DeferredDeferBlock> for plan::DeferredNode {
184 fn from(value: &'_ next::DeferredDeferBlock) -> Self {
185 let next::DeferredDeferBlock {
186 depends,
187 label,
188 query_path,
189 sub_selection,
190 node,
191 } = value;
192 Self {
193 depends: vec(depends),
194 label: label.clone(),
195 query_path: crate::json_ext::Path(
196 query_path
197 .iter()
198 .filter_map(|e| match e {
199 next::QueryPathElement::Field(field) => Some(
200 crate::graphql::JsonPathElement::Key(
202 field.response_key().to_string(),
203 None,
204 ),
205 ),
206 next::QueryPathElement::InlineFragment(inline) => {
207 inline.type_condition.as_ref().map(|cond| {
208 crate::graphql::JsonPathElement::Fragment(cond.to_string())
209 })
210 }
211 })
212 .collect(),
213 ),
214 node: option(node).map(Arc::new),
215 subselection: sub_selection.as_ref().map(|s| s.to_string()),
216 }
217 }
218}
219
220impl From<&'_ next::DeferredDependency> for plan::Depends {
221 fn from(value: &'_ next::DeferredDependency) -> Self {
222 let next::DeferredDependency { id } = value;
223 Self { id: id.clone() }
224 }
225}
226
227impl From<&'_ executable::Selection> for selection::Selection {
228 fn from(value: &'_ executable::Selection) -> Self {
229 match value {
230 executable::Selection::Field(field) => Self::Field(field.as_ref().into()),
231 executable::Selection::InlineFragment(inline) => {
232 Self::InlineFragment(inline.as_ref().into())
233 }
234 executable::Selection::FragmentSpread(_) => unreachable!(),
235 }
236 }
237}
238
239impl From<&'_ executable::Field> for selection::Field {
240 fn from(value: &'_ executable::Field) -> Self {
241 let executable::Field {
242 definition: _,
243 alias,
244 name,
245 arguments: _,
246 directives: _,
247 selection_set,
248 } = value;
249 Self {
250 alias: alias.clone(),
251 name: name.clone(),
252 selections: if selection_set.selections.is_empty() {
253 None
254 } else {
255 Some(vec(&selection_set.selections))
256 },
257 }
258 }
259}
260
261impl From<&'_ executable::InlineFragment> for selection::InlineFragment {
262 fn from(value: &'_ executable::InlineFragment) -> Self {
263 let executable::InlineFragment {
264 type_condition,
265 directives: _,
266 selection_set,
267 } = value;
268 Self {
269 type_condition: type_condition.clone(),
270 selections: vec(&selection_set.selections),
271 }
272 }
273}
274
275impl From<&'_ Arc<next::FetchDataRewrite>> for rewrites::DataRewrite {
276 fn from(value: &'_ Arc<next::FetchDataRewrite>) -> Self {
277 match value.as_ref() {
278 next::FetchDataRewrite::ValueSetter(setter) => Self::ValueSetter(setter.into()),
279 next::FetchDataRewrite::KeyRenamer(renamer) => Self::KeyRenamer(renamer.into()),
280 }
281 }
282}
283
284impl From<&'_ next::FetchDataValueSetter> for rewrites::DataValueSetter {
285 fn from(value: &'_ next::FetchDataValueSetter) -> Self {
286 let next::FetchDataValueSetter { path, set_value_to } = value;
287 Self {
288 path: crate::json_ext::Path(vec(path)),
289 set_value_to: set_value_to.clone(),
290 }
291 }
292}
293
294impl From<&'_ next::FetchDataKeyRenamer> for rewrites::DataKeyRenamer {
295 fn from(value: &'_ next::FetchDataKeyRenamer) -> Self {
296 let next::FetchDataKeyRenamer {
297 path,
298 rename_key_to,
299 } = value;
300 Self {
301 path: crate::json_ext::Path(vec(path)),
302 rename_key_to: rename_key_to.clone(),
303 }
304 }
305}
306
307impl From<&'_ next::FetchDataPathElement> for crate::json_ext::PathElement {
308 fn from(value: &'_ next::FetchDataPathElement) -> Self {
309 match value {
311 next::FetchDataPathElement::Key(name, conditions) => Self::Key(
312 name.to_string(),
313 conditions
314 .as_ref()
315 .map(|conditions| conditions.iter().map(|c| c.to_string()).collect()),
316 ),
317 next::FetchDataPathElement::AnyIndex(conditions) => Self::Flatten(
318 conditions
319 .as_ref()
320 .map(|conditions| conditions.iter().map(|c| c.to_string()).collect()),
321 ),
322 next::FetchDataPathElement::TypenameEquals(value) => Self::Fragment(value.to_string()),
323 next::FetchDataPathElement::Parent => Self::Key("..".to_owned(), None),
324 }
325 }
326}
327
328fn vec<'a, T, U>(value: &'a [T]) -> Vec<U>
329where
330 U: From<&'a T>,
331{
332 value.iter().map(Into::into).collect()
333}
334
335fn option<'a, T, U>(value: &'a Option<T>) -> Option<U>
336where
337 U: From<&'a T>,
338{
339 value.as_ref().map(Into::into)
340}
341
342fn option_vec<'a, T, U>(value: &'a [T]) -> Option<Vec<U>>
343where
344 U: From<&'a T>,
345{
346 if value.is_empty() {
347 None
348 } else {
349 Some(vec(value))
350 }
351}