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