apollo_router/query_planner/
convert.rs

1use 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                        // TODO: type conditioned fetching once it s available in the rust planner
196                        {
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        // TODO: Go all in on Name eventually
254        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}