Don't clone selection sets during execution

This commit is contained in:
Magnus Hallin 2016-12-28 11:28:48 +01:00
parent 6a4b883b97
commit 13903d7628
9 changed files with 41 additions and 46 deletions

View file

@ -37,7 +37,7 @@ pub enum FieldPath<'a> {
pub struct Executor<'a, CtxT> where CtxT: 'a { pub struct Executor<'a, CtxT> where CtxT: 'a {
fragments: &'a HashMap<&'a str, &'a Fragment>, fragments: &'a HashMap<&'a str, &'a Fragment>,
variables: &'a HashMap<String, InputValue>, variables: &'a HashMap<String, InputValue>,
current_selection_set: Option<Vec<Selection>>, current_selection_set: Option<&'a [Selection]>,
schema: &'a SchemaType, schema: &'a SchemaType,
context: &'a CtxT, context: &'a CtxT,
errors: &'a RwLock<Vec<ExecutionError>>, errors: &'a RwLock<Vec<ExecutionError>>,
@ -151,12 +151,7 @@ impl<'a, CtxT> Executor<'a, CtxT> {
/// Resolve a single arbitrary value into an `ExecutionResult` /// Resolve a single arbitrary value into an `ExecutionResult`
pub fn resolve<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> ExecutionResult { pub fn resolve<T: GraphQLType<Context=CtxT>>(&self, value: &T) -> ExecutionResult {
Ok(value.resolve( Ok(value.resolve(self.current_selection_set, self))
match self.current_selection_set {
Some(ref sel) => Some(sel.clone()),
None => None,
},
self))
} }
/// Resolve a single arbitrary value into a return value /// Resolve a single arbitrary value into a return value
@ -194,7 +189,7 @@ impl<'a, CtxT> Executor<'a, CtxT> {
&self, &self,
field_name: Option<String>, field_name: Option<String>,
location: SourcePosition, location: SourcePosition,
selection_set: Option<Vec<Selection>>, selection_set: Option<&'a [Selection]>,
) )
-> Executor<CtxT> -> Executor<CtxT>
{ {
@ -339,7 +334,7 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
let executor = Executor { let executor = Executor {
fragments: &fragments.iter().map(|f| (f.item.name.item.as_str(), &f.item)).collect(), fragments: &fragments.iter().map(|f| (f.item.name.item.as_str(), &f.item)).collect(),
variables: variables, variables: variables,
current_selection_set: Some(op.item.selection_set), current_selection_set: Some(&op.item.selection_set[..]),
schema: &root_node.schema, schema: &root_node.schema,
context: context, context: context,
errors: &errors, errors: &errors,

View file

@ -83,7 +83,7 @@ macro_rules! graphql_enum {
.into_meta() .into_meta()
} }
fn resolve(&self, _: Option<Vec<$crate::Selection>>, _: &$crate::Executor<Self::Context>) -> $crate::Value { fn resolve(&self, _: Option<&[$crate::Selection]>, _: &$crate::Executor<Self::Context>) -> $crate::Value {
match self { match self {
$( $(
&graphql_enum!(@as_pattern, $eval) => &graphql_enum!(@as_pattern, $eval) =>

View file

@ -268,7 +268,7 @@ macro_rules! graphql_interface {
fn resolve_into_type( fn resolve_into_type(
&$mainself, &$mainself,
type_name: &str, type_name: &str,
_: Option<Vec<$crate::Selection>>, _: Option<&[$crate::Selection]>,
executor: &$crate::Executor<Self::Context>, executor: &$crate::Executor<Self::Context>,
) )
-> $crate::ExecutionResult -> $crate::ExecutionResult

View file

@ -77,7 +77,7 @@ macro_rules! graphql_scalar {
fn resolve( fn resolve(
&$resolve_selfvar, &$resolve_selfvar,
_: Option<Vec<$crate::Selection>>, _: Option<&[$crate::Selection]>,
_: &$crate::Executor<Self::Context>) -> $crate::Value { _: &$crate::Executor<Self::Context>) -> $crate::Value {
$resolve_body $resolve_body
} }

View file

@ -137,7 +137,7 @@ macro_rules! graphql_union {
fn resolve_into_type( fn resolve_into_type(
&$mainself, &$mainself,
type_name: &str, type_name: &str,
_: Option<Vec<$crate::Selection>>, _: Option<&[$crate::Selection]>,
executor: &$crate::Executor<Self::Context>, executor: &$crate::Executor<Self::Context>,
) )
-> $crate::ExecutionResult -> $crate::ExecutionResult

View file

@ -248,7 +248,7 @@ pub trait GraphQLType: Sized {
/// ///
/// The default implementation panics. /// The default implementation panics.
#[allow(unused_variables)] #[allow(unused_variables)]
fn resolve_into_type(&self, type_name: &str, selection_set: Option<Vec<Selection>>, executor: &Executor<Self::Context>) -> ExecutionResult { fn resolve_into_type(&self, type_name: &str, selection_set: Option<&[Selection]>, executor: &Executor<Self::Context>) -> ExecutionResult {
if Self::name().unwrap() == type_name { if Self::name().unwrap() == type_name {
Ok(self.resolve(selection_set, executor)) Ok(self.resolve(selection_set, executor))
} else { } else {
@ -274,7 +274,7 @@ pub trait GraphQLType: Sized {
/// The default implementation uses `resolve_field` to resolve all fields, /// The default implementation uses `resolve_field` to resolve all fields,
/// including those through fragment expansion, for object types. For /// including those through fragment expansion, for object types. For
/// non-object types, this method panics. /// non-object types, this method panics.
fn resolve(&self, selection_set: Option<Vec<Selection>>, executor: &Executor<Self::Context>) -> Value { fn resolve(&self, selection_set: Option<&[Selection]>, executor: &Executor<Self::Context>) -> Value {
if let Some(selection_set) = selection_set { if let Some(selection_set) = selection_set {
let mut result = HashMap::new(); let mut result = HashMap::new();
resolve_selection_set_into(self, selection_set, executor, &mut result); resolve_selection_set_into(self, selection_set, executor, &mut result);
@ -288,7 +288,7 @@ pub trait GraphQLType: Sized {
fn resolve_selection_set_into<T, CtxT>( fn resolve_selection_set_into<T, CtxT>(
instance: &T, instance: &T,
selection_set: Vec<Selection>, selection_set: &[Selection],
executor: &Executor<CtxT>, executor: &Executor<CtxT>,
result: &mut HashMap<String, Value>) result: &mut HashMap<String, Value>)
where T: GraphQLType<Context=CtxT> where T: GraphQLType<Context=CtxT>
@ -299,11 +299,11 @@ fn resolve_selection_set_into<T, CtxT>(
for selection in selection_set { for selection in selection_set {
match selection { match selection {
Selection::Field(Spanning { item: f, start: start_pos, .. }) => { &Selection::Field(Spanning { item: ref f, start: ref start_pos, .. }) => {
if is_excluded( if is_excluded(
&match f.directives { &match &f.directives {
Some(sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), &Some(ref sel) => Some(sel.iter().cloned().map(|s| s.item).collect()),
None => None, &None => None,
}, },
executor.variables()) { executor.variables()) {
continue; continue;
@ -327,13 +327,13 @@ fn resolve_selection_set_into<T, CtxT>(
let mut sub_exec = executor.sub_executor( let mut sub_exec = executor.sub_executor(
Some(response_name.clone()), Some(response_name.clone()),
start_pos.clone(), start_pos.clone(),
f.selection_set); f.selection_set.as_ref().map(|v| &v[..]));
let field_result = instance.resolve_field( let field_result = instance.resolve_field(
&f.name.item, &f.name.item,
&Arguments::new( &Arguments::new(
f.arguments.map(|m| f.arguments.as_ref().map(|m|
m.item.into_iter().map(|(k, v)| m.item.iter().cloned().map(|(k, v)|
(k.item, v.item.into_const(exec_vars))).collect()), (k.item, v.item.into_const(exec_vars))).collect()),
&meta_field.arguments), &meta_field.arguments),
&mut sub_exec); &mut sub_exec);
@ -341,16 +341,16 @@ fn resolve_selection_set_into<T, CtxT>(
match field_result { match field_result {
Ok(v) => merge_key_into(result, response_name.clone(), v), Ok(v) => merge_key_into(result, response_name.clone(), v),
Err(e) => { Err(e) => {
sub_exec.push_error(e, start_pos); sub_exec.push_error(e, start_pos.clone());
result.insert(response_name.clone(), Value::null()); result.insert(response_name.clone(), Value::null());
} }
} }
}, },
Selection::FragmentSpread(Spanning { item: spread, .. }) => { &Selection::FragmentSpread(Spanning { item: ref spread, .. }) => {
if is_excluded( if is_excluded(
&match spread.directives { &match &spread.directives {
Some(sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), &Some(ref sel) => Some(sel.iter().cloned().map(|s| s.item).collect()),
None => None, &None => None,
}, },
executor.variables()) { executor.variables()) {
continue; continue;
@ -360,13 +360,13 @@ fn resolve_selection_set_into<T, CtxT>(
.expect("Fragment could not be found"); .expect("Fragment could not be found");
resolve_selection_set_into( resolve_selection_set_into(
instance, fragment.selection_set.clone(), executor, result); instance, &fragment.selection_set[..], executor, result);
}, },
Selection::InlineFragment(Spanning { item: fragment, start: start_pos, .. }) => { &Selection::InlineFragment(Spanning { item: ref fragment, start: ref start_pos, .. }) => {
if is_excluded( if is_excluded(
&match fragment.directives { &match &fragment.directives {
Some(sel) => Some(sel.iter().cloned().map(|s| s.item).collect()), &Some(ref sel) => Some(sel.iter().cloned().map(|s| s.item).collect()),
None => None &None => None
}, },
executor.variables()) { executor.variables()) {
continue; continue;
@ -375,12 +375,12 @@ fn resolve_selection_set_into<T, CtxT>(
let mut sub_exec = executor.sub_executor( let mut sub_exec = executor.sub_executor(
None, None,
start_pos.clone(), start_pos.clone(),
Some(fragment.selection_set.clone())); Some(&fragment.selection_set[..]));
if let Some(type_condition) = fragment.type_condition { if let &Some(ref type_condition) = &fragment.type_condition {
let sub_result = instance.resolve_into_type( let sub_result = instance.resolve_into_type(
&type_condition.item, &type_condition.item,
Some(fragment.selection_set.clone()), Some(&fragment.selection_set[..]),
&mut sub_exec); &mut sub_exec);
if let Ok(Value::Object(mut hash_map)) = sub_result { if let Ok(Value::Object(mut hash_map)) = sub_result {
@ -389,13 +389,13 @@ fn resolve_selection_set_into<T, CtxT>(
} }
} }
else if let Err(e) = sub_result { else if let Err(e) = sub_result {
sub_exec.push_error(e, start_pos); sub_exec.push_error(e, start_pos.clone());
} }
} }
else { else {
resolve_selection_set_into( resolve_selection_set_into(
instance, instance,
fragment.selection_set.clone(), &fragment.selection_set[..],
&mut sub_exec, &mut sub_exec,
result); result);
} }

View file

@ -16,7 +16,7 @@ impl<T, CtxT> GraphQLType for Option<T> where T: GraphQLType<Context=CtxT> {
registry.build_nullable_type::<T>().into_meta() registry.build_nullable_type::<T>().into_meta()
} }
fn resolve(&self, _: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> Value { fn resolve(&self, _: Option<&[Selection]>, executor: &Executor<CtxT>) -> Value {
match *self { match *self {
Some(ref obj) => executor.resolve_into_value(obj), Some(ref obj) => executor.resolve_into_value(obj),
None => Value::null(), None => Value::null(),
@ -56,7 +56,7 @@ impl<T, CtxT> GraphQLType for Vec<T> where T: GraphQLType<Context=CtxT> {
registry.build_list_type::<T>().into_meta() registry.build_list_type::<T>().into_meta()
} }
fn resolve(&self, _: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> Value { fn resolve(&self, _: Option<&[Selection]>, executor: &Executor<CtxT>) -> Value {
Value::list( Value::list(
self.iter().map(|e| executor.resolve_into_value(e)).collect() self.iter().map(|e| executor.resolve_into_value(e)).collect()
) )
@ -103,7 +103,7 @@ impl<'a, T, CtxT> GraphQLType for &'a [T] where T: GraphQLType<Context=CtxT> {
registry.build_list_type::<T>().into_meta() registry.build_list_type::<T>().into_meta()
} }
fn resolve(&self, _: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> Value { fn resolve(&self, _: Option<&[Selection]>, executor: &Executor<CtxT>) -> Value {
Value::list( Value::list(
self.iter().map(|e| executor.resolve_into_value(e)).collect() self.iter().map(|e| executor.resolve_into_value(e)).collect()
) )

View file

@ -16,7 +16,7 @@ impl<T, CtxT> GraphQLType for Box<T> where T: GraphQLType<Context=CtxT> {
T::meta(registry) T::meta(registry)
} }
fn resolve_into_type(&self, name: &str, selection_set: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> ExecutionResult { fn resolve_into_type(&self, name: &str, selection_set: Option<&[Selection]>, executor: &Executor<CtxT>) -> ExecutionResult {
(**self).resolve_into_type(name, selection_set, executor) (**self).resolve_into_type(name, selection_set, executor)
} }
@ -25,7 +25,7 @@ impl<T, CtxT> GraphQLType for Box<T> where T: GraphQLType<Context=CtxT> {
(**self).resolve_field(field, args, executor) (**self).resolve_field(field, args, executor)
} }
fn resolve(&self, selection_set: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> Value { fn resolve(&self, selection_set: Option<&[Selection]>, executor: &Executor<CtxT>) -> Value {
(**self).resolve(selection_set, executor) (**self).resolve(selection_set, executor)
} }
} }
@ -56,7 +56,7 @@ impl<'a, T, CtxT> GraphQLType for &'a T where T: GraphQLType<Context=CtxT> {
T::meta(registry) T::meta(registry)
} }
fn resolve_into_type(&self, name: &str, selection_set: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> ExecutionResult { fn resolve_into_type(&self, name: &str, selection_set: Option<&[Selection]>, executor: &Executor<CtxT>) -> ExecutionResult {
(**self).resolve_into_type(name, selection_set, executor) (**self).resolve_into_type(name, selection_set, executor)
} }
@ -65,7 +65,7 @@ impl<'a, T, CtxT> GraphQLType for &'a T where T: GraphQLType<Context=CtxT> {
(**self).resolve_field(field, args, executor) (**self).resolve_field(field, args, executor)
} }
fn resolve(&self, selection_set: Option<Vec<Selection>>, executor: &Executor<CtxT>) -> Value { fn resolve(&self, selection_set: Option<&[Selection]>, executor: &Executor<CtxT>) -> Value {
(**self).resolve(selection_set, executor) (**self).resolve(selection_set, executor)
} }
} }

View file

@ -53,7 +53,7 @@ impl<'a> GraphQLType for &'a str {
registry.build_scalar_type::<String>().into_meta() registry.build_scalar_type::<String>().into_meta()
} }
fn resolve(&self, _: Option<Vec<Selection>>, _: &Executor<Self::Context>) -> Value { fn resolve(&self, _: Option<&[Selection]>, _: &Executor<Self::Context>) -> Value {
Value::string(self) Value::string(self)
} }
} }