Skip to content

Commit 65f43e5

Browse files
committed
feat(qp): introduce single/multi state for fetch-step and selections, replace output
1 parent 24e5e6b commit 65f43e5

26 files changed

+775
-544
lines changed

bin/dev-cli/src/main.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use query_planner::graph::PlannerOverrideContext;
99
use query_planner::planner::best::find_best_combination;
1010
use query_planner::planner::fetch::fetch_graph::build_fetch_graph_from_query_tree;
1111
use query_planner::planner::fetch::fetch_graph::FetchGraph;
12+
use query_planner::planner::fetch::state::MultiTypeFetchStep;
1213
use query_planner::planner::plan_nodes::QueryPlan;
1314
use query_planner::planner::query_plan::build_query_plan_from_fetch_graph;
1415
use query_planner::planner::tree::query_tree::QueryTree;
@@ -124,7 +125,10 @@ fn process_consumer_schema(path: &str) {
124125
println!("{}", consumer_schema.document);
125126
}
126127

127-
fn process_fetch_graph(supergraph_path: &str, operation_path: &str) -> FetchGraph {
128+
fn process_fetch_graph(
129+
supergraph_path: &str,
130+
operation_path: &str,
131+
) -> FetchGraph<MultiTypeFetchStep> {
128132
let (graph, query_tree, supergraph_state) =
129133
process_merged_tree(supergraph_path, operation_path);
130134

lib/query-planner/src/ast/minification/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ pub enum MinificationError {
66
FieldNotFound(String, String),
77
#[error("Unsupported fragment spread")]
88
UnsupportedFragmentSpread,
9-
#[error("Unsupported field in `_entities`: {0}")]
10-
UnsupportedFieldInEntities(String),
9+
#[error("Unsupported field in `_entities`: {0}.{1}")]
10+
UnsupportedFieldInEntities(String, String),
1111
}

lib/query-planner/src/ast/minification/stats.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ fn walk_and_collect_stats(
9090
}
9191

9292
return Err(MinificationError::UnsupportedFieldInEntities(
93+
type_def.name().to_string(),
9394
field.name.clone(),
9495
));
9596
}

lib/query-planner/src/ast/minification/transform.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ fn transform_field(
185185
}
186186

187187
return Err(MinificationError::UnsupportedFieldInEntities(
188+
type_name.to_string(),
188189
field.name.clone(),
189190
));
190191
}

lib/query-planner/src/ast/mismatch_finder.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::{
77
merge_path::{MergePath, Segment},
88
selection_item::SelectionItem,
99
selection_set::{FieldSelection, SelectionSet},
10-
type_aware_selection::TypeAwareSelection,
1110
},
11+
planner::fetch::{selections::FetchStepSelections, state::MultiTypeFetchStep},
1212
state::{
1313
subgraph_state::{SubgraphDefinition, SubgraphState},
1414
supergraph_state::{SubgraphName, SupergraphState, TypeNode},
@@ -20,46 +20,42 @@ pub struct SelectionMismatchFinder<'a> {
2020
supergraph_state: &'a SupergraphState,
2121
}
2222

23-
type MismatchesFound = Vec<MergePath>;
23+
type MismatchesFound = Vec<(String, MergePath)>;
2424

2525
impl<'a> SelectionMismatchFinder<'a> {
2626
pub fn new(supergraph_state: &'a SupergraphState) -> Self {
2727
Self { supergraph_state }
2828
}
2929

30-
#[instrument(level = "trace", skip_all, fields(
31-
subgraph_name,
32-
selection = format!("{}", selection_set)
33-
))]
30+
#[instrument(level = "trace", skip_all, fields(subgraph_name,))]
3431
pub fn find_mismatches_in_node(
3532
&self,
3633
subgraph_name: &SubgraphName,
37-
selection_set: &TypeAwareSelection,
34+
selections: &FetchStepSelections<MultiTypeFetchStep>,
3835
) -> MismatchesFound {
36+
let mut mismtaches_found = MismatchesFound::new();
3937
let subgraph_state = self
4038
.supergraph_state
4139
.subgraphs_state
4240
.get(subgraph_name)
4341
.unwrap();
4442

45-
let entrypoint_type = subgraph_state
46-
.definitions
47-
.get(&selection_set.type_name)
48-
.unwrap();
49-
50-
let mut mismtaches_found = MismatchesFound::new();
51-
let start_path = MergePath::default();
52-
53-
handle_selection_set(
54-
self.supergraph_state,
55-
subgraph_state,
56-
entrypoint_type,
57-
&selection_set.selection_set,
58-
start_path,
59-
&mut mismtaches_found,
60-
);
61-
62-
trace!("found total of {} mismatches", mismtaches_found.len(),);
43+
for (definition_name, selection_set) in selections.iter_selections() {
44+
let entrypoint_type = subgraph_state.definitions.get(definition_name).unwrap();
45+
let start_path = MergePath::default();
46+
47+
handle_selection_set(
48+
definition_name,
49+
self.supergraph_state,
50+
subgraph_state,
51+
entrypoint_type,
52+
selection_set,
53+
start_path,
54+
&mut mismtaches_found,
55+
);
56+
57+
trace!("found total of {} mismatches", mismtaches_found.len());
58+
}
6359

6460
mismtaches_found
6561
}
@@ -73,6 +69,7 @@ impl<'a> SelectionMismatchFinder<'a> {
7369
selection = format!("{}", selection_set)
7470
))]
7571
fn handle_selection_set<'field, 'schema>(
72+
root_def_type_name: &str,
7673
supergraph_state: &'schema SupergraphState,
7774
subgraph_state: &'schema SubgraphState,
7875
parent_def: &'schema SubgraphDefinition,
@@ -105,6 +102,7 @@ fn handle_selection_set<'field, 'schema>(
105102
));
106103

107104
let next_parent_type_name = handle_field(
105+
root_def_type_name,
108106
supergraph_state,
109107
type_def,
110108
field,
@@ -117,6 +115,7 @@ fn handle_selection_set<'field, 'schema>(
117115
next_parent_type_name.and_then(|n| subgraph_state.definitions.get(n))
118116
{
119117
handle_selection_set(
118+
root_def_type_name,
120119
supergraph_state,
121120
subgraph_state,
122121
next_parent_def,
@@ -156,6 +155,7 @@ fn handle_selection_set<'field, 'schema>(
156155
///
157156
/// Returns the return type of the selection, if the inner selection needs to be processed (in case nested selections are defined).
158157
fn handle_field<'field, 'schema>(
158+
root_def_type_name: &str,
159159
state: &'schema SupergraphState,
160160
parent_def: &'schema SubgraphDefinition,
161161
field: &'field FieldSelection,
@@ -201,7 +201,7 @@ fn handle_field<'field, 'schema>(
201201
field_path,
202202
);
203203

204-
mismatches_found.push(field_path.clone());
204+
mismatches_found.push((root_def_type_name.to_string(), field_path.clone()));
205205
}
206206
}
207207
} else {

lib/query-planner/src/ast/type_aware_selection.rs

Lines changed: 2 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,11 @@ use std::{fmt::Display, hash::Hash};
22

33
use crate::ast::{
44
merge_path::{Condition, Segment},
5-
safe_merge::{AliasesRecords, SafeSelectionSetMerger},
65
selection_set::{FieldSelection, InlineFragmentSelection},
76
};
87

98
use super::{merge_path::MergePath, selection_item::SelectionItem, selection_set::SelectionSet};
109

11-
#[derive(Debug, Clone, thiserror::Error)]
12-
pub enum TypeAwareSelectionError {
13-
#[error("Failed to locate path '{0}' in selection set '{1}'")]
14-
PathNotFound(String, String),
15-
}
16-
1710
#[derive(Debug, Clone)]
1811
pub struct TypeAwareSelection {
1912
pub type_name: String,
@@ -75,62 +68,6 @@ impl TypeAwareSelection {
7568
pub fn add(&mut self, to_add: &Self) {
7669
merge_selection_set(&mut self.selection_set, &to_add.selection_set, false);
7770
}
78-
79-
pub fn add_at_path(
80-
&mut self,
81-
to_add: &Self,
82-
add_at_fetch_path: MergePath,
83-
as_first: bool,
84-
) -> Result<(), TypeAwareSelectionError> {
85-
if let Some(source) =
86-
find_selection_set_by_path_mut(&mut self.selection_set, &add_at_fetch_path)
87-
{
88-
merge_selection_set(source, &to_add.selection_set, as_first);
89-
90-
Ok(())
91-
} else {
92-
Err(TypeAwareSelectionError::PathNotFound(
93-
add_at_fetch_path.to_string(),
94-
self.selection_set.to_string(),
95-
))
96-
}
97-
}
98-
99-
pub fn add_at_path_and_solve_conflicts(
100-
&mut self,
101-
to_add: &Self,
102-
add_at_fetch_path: MergePath,
103-
(self_used_for_requires, other_used_for_requires): (bool, bool),
104-
as_first: bool,
105-
) -> Option<AliasesRecords> {
106-
if let Some(source) =
107-
find_selection_set_by_path_mut(&mut self.selection_set, &add_at_fetch_path)
108-
{
109-
let mut merger = SafeSelectionSetMerger::default();
110-
let aliases_made = merger.merge_selection_set(
111-
source,
112-
&to_add.selection_set,
113-
(self_used_for_requires, other_used_for_requires),
114-
as_first,
115-
);
116-
117-
if !aliases_made.is_empty() {
118-
return Some(aliases_made);
119-
}
120-
}
121-
122-
None
123-
}
124-
125-
pub fn has_typename_at_path(&self, lookup_path: &MergePath) -> bool {
126-
find_selection_set_by_path(
127-
&self.selection_set,
128-
// We pass None for the condition, because we are checking
129-
// the presence of __typename at the given path, not type __typename with a condition.
130-
&lookup_path.push(Segment::Field("__typename".to_string(), 0, None)),
131-
)
132-
.is_some()
133-
}
13471
}
13572

13673
fn selection_item_is_subset_of(source: &SelectionItem, target: &SelectionItem) -> bool {
@@ -154,15 +91,15 @@ fn selection_item_is_subset_of(source: &SelectionItem, target: &SelectionItem) -
15491
}
15592
}
15693

157-
fn selection_items_are_subset_of(source: &[SelectionItem], target: &[SelectionItem]) -> bool {
94+
pub fn selection_items_are_subset_of(source: &[SelectionItem], target: &[SelectionItem]) -> bool {
15895
target.iter().all(|target_node| {
15996
source
16097
.iter()
16198
.any(|source_node| selection_item_is_subset_of(source_node, target_node))
16299
})
163100
}
164101

165-
fn merge_selection_set(target: &mut SelectionSet, source: &SelectionSet, as_first: bool) {
102+
pub fn merge_selection_set(target: &mut SelectionSet, source: &SelectionSet, as_first: bool) {
166103
if source.items.is_empty() {
167104
return;
168105
}
@@ -217,80 +154,6 @@ fn merge_selection_set(target: &mut SelectionSet, source: &SelectionSet, as_firs
217154
}
218155
}
219156

220-
pub fn find_selection_set_by_path<'a>(
221-
root_selection_set: &'a SelectionSet,
222-
path: &MergePath,
223-
) -> Option<&'a SelectionSet> {
224-
let mut current_selection_set = root_selection_set;
225-
226-
for path_element in path.inner.iter() {
227-
match path_element {
228-
Segment::List => {
229-
continue;
230-
}
231-
Segment::Cast(type_name, condition) => {
232-
let next_selection_set_option =
233-
current_selection_set
234-
.items
235-
.iter()
236-
.find_map(|item| match item {
237-
SelectionItem::Field(_) => None,
238-
SelectionItem::InlineFragment(f) => {
239-
if f.type_condition.eq(type_name)
240-
&& fragment_condition_equal(condition, f)
241-
{
242-
Some(&f.selections)
243-
} else {
244-
None
245-
}
246-
}
247-
SelectionItem::FragmentSpread(_) => None,
248-
});
249-
250-
match next_selection_set_option {
251-
Some(next_set) => {
252-
current_selection_set = next_set;
253-
}
254-
None => {
255-
return None;
256-
}
257-
}
258-
}
259-
Segment::Field(field_name, args_hash, condition) => {
260-
let next_selection_set_option =
261-
current_selection_set
262-
.items
263-
.iter()
264-
.find_map(|item| match item {
265-
SelectionItem::Field(field) => {
266-
if &field.name == field_name
267-
&& field.arguments_hash() == *args_hash
268-
&& field_condition_equal(condition, field)
269-
{
270-
Some(&field.selections)
271-
} else {
272-
None
273-
}
274-
}
275-
SelectionItem::InlineFragment(..) => None,
276-
SelectionItem::FragmentSpread(_) => None,
277-
});
278-
279-
match next_selection_set_option {
280-
Some(next_set) => {
281-
current_selection_set = next_set;
282-
}
283-
None => {
284-
return None;
285-
}
286-
}
287-
}
288-
}
289-
}
290-
291-
Some(current_selection_set)
292-
}
293-
294157
pub fn find_selection_set_by_path_mut<'a>(
295158
root_selection_set: &'a mut SelectionSet,
296159
path: &MergePath,

lib/query-planner/src/planner/fetch/error.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::{
2-
ast::type_aware_selection::TypeAwareSelectionError,
32
graph::{error::GraphError, node::Node},
4-
planner::walker::error::WalkOperationError,
3+
planner::{fetch::selections::FetchStepSelectionsError, walker::error::WalkOperationError},
54
};
65

76
#[derive(Debug, thiserror::Error)]
@@ -47,7 +46,7 @@ pub enum FetchGraphError {
4746
#[error("Expected @requires")]
4847
MissingRequires,
4948
#[error(transparent)]
50-
SelectionSetManipulationError(#[from] TypeAwareSelectionError),
49+
SelectionSetManipulationError(#[from] FetchStepSelectionsError),
5150
}
5251

5352
impl From<GraphError> for FetchGraphError {

0 commit comments

Comments
 (0)