Skip to content

Commit 89103dc

Browse files
committed
graphql: Remove merge_selection_sets
1 parent 1009aea commit 89103dc

File tree

3 files changed

+223
-240
lines changed

3 files changed

+223
-240
lines changed

graphql/src/execution/execution.rs

Lines changed: 103 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use lazy_static::lazy_static;
55
use stable_hash::crypto::SetHasher;
66
use stable_hash::prelude::*;
77
use stable_hash::utils::stable_hash;
8-
use std::cmp;
98
use std::collections::{BTreeMap, HashMap, HashSet};
9+
use std::iter;
1010
use std::time::Instant;
1111

1212
use graph::prelude::*;
@@ -159,7 +159,7 @@ where
159159
let introspection_resolver = IntrospectionResolver::new(&self.logger, &self.query.schema);
160160

161161
ExecutionContext {
162-
logger: self.logger.clone(),
162+
logger: self.logger.cheap_clone(),
163163
resolver: Arc::new(introspection_resolver),
164164
query: self.query.as_introspection_query(),
165165
deadline: self.deadline,
@@ -210,7 +210,7 @@ pub fn execute_root_selection_set(
210210
items: Vec::new(),
211211
};
212212

213-
for (_, fields) in collect_fields(ctx, query_type, selection_set, None) {
213+
for (_, fields) in collect_fields(ctx, query_type, iter::once(selection_set), None) {
214214
let name = fields[0].name.clone();
215215
let selections = fields.into_iter().map(|f| q::Selection::Field(f.clone()));
216216
// See if this is an introspection or data field. We don't worry about
@@ -228,7 +228,7 @@ pub fn execute_root_selection_set(
228228
BTreeMap::default()
229229
} else {
230230
let initial_data = ctx.resolver.prefetch(&ctx, selection_set)?;
231-
execute_selection_set_to_map(&ctx, &data_set, query_type, initial_data)?
231+
execute_selection_set_to_map(&ctx, iter::once(&data_set), query_type, initial_data)?
232232
};
233233

234234
// Resolve introspection fields, if there are any
@@ -237,7 +237,7 @@ pub fn execute_root_selection_set(
237237

238238
values.extend(execute_selection_set_to_map(
239239
&ictx,
240-
&intro_set,
240+
iter::once(&intro_set),
241241
&*INTROSPECTION_QUERY_TYPE,
242242
None,
243243
)?);
@@ -255,23 +255,23 @@ pub fn execute_root_selection_set(
255255
/// Executes a selection set, requiring the result to be of the given object type.
256256
///
257257
/// Allows passing in a parent value during recursive processing of objects and their fields.
258-
pub fn execute_selection_set(
259-
ctx: &ExecutionContext<impl Resolver>,
260-
selection_set: &q::SelectionSet,
258+
pub fn execute_selection_set<'a>(
259+
ctx: &'a ExecutionContext<impl Resolver>,
260+
selection_sets: impl Iterator<Item = &'a q::SelectionSet>,
261261
object_type: &s::ObjectType,
262262
prefetched_value: Option<q::Value>,
263263
) -> Result<q::Value, Vec<QueryExecutionError>> {
264264
Ok(q::Value::Object(execute_selection_set_to_map(
265265
ctx,
266-
selection_set,
266+
selection_sets,
267267
object_type,
268268
prefetched_value,
269269
)?))
270270
}
271271

272-
fn execute_selection_set_to_map(
273-
ctx: &ExecutionContext<impl Resolver>,
274-
selection_set: &q::SelectionSet,
272+
fn execute_selection_set_to_map<'a>(
273+
ctx: &'a ExecutionContext<impl Resolver>,
274+
selection_sets: impl Iterator<Item = &'a q::SelectionSet>,
275275
object_type: &s::ObjectType,
276276
prefetched_value: Option<q::Value>,
277277
) -> Result<BTreeMap<String, q::Value>, Vec<QueryExecutionError>> {
@@ -284,7 +284,7 @@ fn execute_selection_set_to_map(
284284
let mut result_map: BTreeMap<String, q::Value> = BTreeMap::new();
285285

286286
// Group fields with the same response key, so we can execute them together
287-
let grouped_field_set = collect_fields(ctx, object_type, selection_set, None);
287+
let grouped_field_set = collect_fields(ctx, object_type, selection_sets, None);
288288

289289
// Gather fields that appear more than once with the same response key.
290290
let multiple_response_keys = {
@@ -356,101 +356,106 @@ fn execute_selection_set_to_map(
356356
}
357357
}
358358

359-
/// Collects fields of a selection set.
359+
/// Collects fields from selection sets.
360360
pub fn collect_fields<'a>(
361361
ctx: &'a ExecutionContext<impl Resolver>,
362362
object_type: &s::ObjectType,
363-
selection_set: &'a q::SelectionSet,
363+
selection_sets: impl Iterator<Item = &'a q::SelectionSet>,
364364
visited_fragments: Option<HashSet<&'a q::Name>>,
365365
) -> IndexMap<&'a String, Vec<&'a q::Field>> {
366366
let mut visited_fragments = visited_fragments.unwrap_or_default();
367367
let mut grouped_fields: IndexMap<_, Vec<_>> = IndexMap::new();
368368

369-
// Only consider selections that are not skipped and should be included
370-
let selections: Vec<_> = selection_set
371-
.items
372-
.iter()
373-
.filter(|selection| !qast::skip_selection(selection, &ctx.query.variables))
374-
.filter(|selection| qast::include_selection(selection, &ctx.query.variables))
375-
.collect();
376-
377-
for selection in selections {
378-
match selection {
379-
q::Selection::Field(ref field) => {
380-
// Obtain the response key for the field
381-
let response_key = qast::get_response_key(field);
382-
383-
// Create a field group for this response key on demand and
384-
// append the selection field to this group.
385-
grouped_fields.entry(response_key).or_default().push(field);
386-
}
387-
388-
q::Selection::FragmentSpread(spread) => {
389-
// Only consider the fragment if it hasn't already been included,
390-
// as would be the case if the same fragment spread ...Foo appeared
391-
// twice in the same selection set
392-
if !visited_fragments.contains(&spread.fragment_name) {
393-
visited_fragments.insert(&spread.fragment_name);
394-
395-
// Resolve the fragment using its name and, if it applies, collect
396-
// fields for the fragment and group them
397-
ctx.query
398-
.get_fragment(&spread.fragment_name)
399-
.and_then(|fragment| {
400-
// We have a fragment, only pass it on if it applies to the
401-
// current object type
402-
if does_fragment_type_apply(ctx, object_type, &fragment.type_condition)
403-
{
404-
Some(fragment)
405-
} else {
406-
None
407-
}
408-
})
409-
.map(|fragment| {
410-
// We have a fragment that applies to the current object type,
411-
// collect its fields into response key groups
412-
let fragment_grouped_field_set = collect_fields(
413-
ctx,
414-
object_type,
415-
&fragment.selection_set,
416-
Some(visited_fragments.clone()),
417-
);
418-
419-
// Add all items from each fragments group to the field group
420-
// with the corresponding response key
421-
for (response_key, mut fragment_group) in fragment_grouped_field_set {
422-
grouped_fields
423-
.entry(response_key)
424-
.or_default()
425-
.append(&mut fragment_group);
426-
}
427-
});
369+
for selection_set in selection_sets {
370+
// Only consider selections that are not skipped and should be included
371+
let selections = selection_set
372+
.items
373+
.iter()
374+
.filter(|selection| !qast::skip_selection(selection, &ctx.query.variables))
375+
.filter(|selection| qast::include_selection(selection, &ctx.query.variables));
376+
377+
for selection in selections {
378+
match selection {
379+
q::Selection::Field(ref field) => {
380+
// Obtain the response key for the field
381+
let response_key = qast::get_response_key(field);
382+
383+
// Create a field group for this response key on demand and
384+
// append the selection field to this group.
385+
grouped_fields.entry(response_key).or_default().push(field);
428386
}
429-
}
430-
431-
q::Selection::InlineFragment(fragment) => {
432-
let applies = match &fragment.type_condition {
433-
Some(cond) => does_fragment_type_apply(ctx, object_type, &cond),
434-
None => true,
435-
};
436387

437-
if applies {
438-
let fragment_grouped_field_set = collect_fields(
439-
ctx,
440-
object_type,
441-
&fragment.selection_set,
442-
Some(visited_fragments.clone()),
443-
);
388+
q::Selection::FragmentSpread(spread) => {
389+
// Only consider the fragment if it hasn't already been included,
390+
// as would be the case if the same fragment spread ...Foo appeared
391+
// twice in the same selection set
392+
if !visited_fragments.contains(&spread.fragment_name) {
393+
visited_fragments.insert(&spread.fragment_name);
394+
395+
// Resolve the fragment using its name and, if it applies, collect
396+
// fields for the fragment and group them
397+
ctx.query
398+
.get_fragment(&spread.fragment_name)
399+
.and_then(|fragment| {
400+
// We have a fragment, only pass it on if it applies to the
401+
// current object type
402+
if does_fragment_type_apply(
403+
ctx,
404+
object_type,
405+
&fragment.type_condition,
406+
) {
407+
Some(fragment)
408+
} else {
409+
None
410+
}
411+
})
412+
.map(|fragment| {
413+
// We have a fragment that applies to the current object type,
414+
// collect its fields into response key groups
415+
let fragment_grouped_field_set = collect_fields(
416+
ctx,
417+
object_type,
418+
iter::once(&fragment.selection_set),
419+
Some(visited_fragments.clone()),
420+
);
421+
422+
// Add all items from each fragments group to the field group
423+
// with the corresponding response key
424+
for (response_key, mut fragment_group) in fragment_grouped_field_set
425+
{
426+
grouped_fields
427+
.entry(response_key)
428+
.or_default()
429+
.append(&mut fragment_group);
430+
}
431+
});
432+
}
433+
}
444434

445-
for (response_key, mut fragment_group) in fragment_grouped_field_set {
446-
grouped_fields
447-
.entry(response_key)
448-
.or_default()
449-
.append(&mut fragment_group);
435+
q::Selection::InlineFragment(fragment) => {
436+
let applies = match &fragment.type_condition {
437+
Some(cond) => does_fragment_type_apply(ctx, object_type, &cond),
438+
None => true,
439+
};
440+
441+
if applies {
442+
let fragment_grouped_field_set = collect_fields(
443+
ctx,
444+
object_type,
445+
iter::once(&fragment.selection_set),
446+
Some(visited_fragments.clone()),
447+
);
448+
449+
for (response_key, mut fragment_group) in fragment_grouped_field_set {
450+
grouped_fields
451+
.entry(response_key)
452+
.or_default()
453+
.append(&mut fragment_group);
454+
}
450455
}
451456
}
452-
}
453-
};
457+
};
458+
}
454459
}
455460

456461
grouped_fields
@@ -776,7 +781,7 @@ fn complete_value(
776781
// Complete object types recursively
777782
s::TypeDefinition::Object(object_type) => execute_selection_set(
778783
ctx,
779-
&merge_selection_sets(fields),
784+
fields.iter().map(|f| &f.selection_set),
780785
object_type,
781786
Some(resolved_value),
782787
),
@@ -787,7 +792,7 @@ fn complete_value(
787792

788793
execute_selection_set(
789794
ctx,
790-
&merge_selection_sets(fields),
795+
fields.iter().map(|f| &f.selection_set),
791796
object_type,
792797
Some(resolved_value),
793798
)
@@ -799,7 +804,7 @@ fn complete_value(
799804

800805
execute_selection_set(
801806
ctx,
802-
&merge_selection_sets(fields),
807+
fields.iter().map(|f| &f.selection_set),
803808
object_type,
804809
Some(resolved_value),
805810
)
@@ -830,34 +835,6 @@ fn resolve_abstract_type<'a>(
830835
})
831836
}
832837

833-
/// Merges the selection sets of several fields into a single selection set.
834-
pub fn merge_selection_sets(fields: &Vec<&q::Field>) -> q::SelectionSet {
835-
let (span, items) = fields
836-
.iter()
837-
.fold((None, vec![]), |(span, mut items), field| {
838-
(
839-
// The overal span is the min/max spans of all merged selection sets
840-
match span {
841-
None => Some(field.selection_set.span),
842-
Some((start, end)) => Some((
843-
cmp::min(start, field.selection_set.span.0),
844-
cmp::max(end, field.selection_set.span.1),
845-
)),
846-
},
847-
// The overall selection is the result of merging the selections of all fields
848-
{
849-
items.extend_from_slice(field.selection_set.items.as_slice());
850-
items
851-
},
852-
)
853-
});
854-
855-
q::SelectionSet {
856-
span: span.unwrap(),
857-
items,
858-
}
859-
}
860-
861838
/// Coerces argument values into GraphQL values.
862839
pub fn coerce_argument_values<'a>(
863840
ctx: &ExecutionContext<impl Resolver>,

0 commit comments

Comments
 (0)