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

View file

@ -83,7 +83,7 @@ macro_rules! graphql_enum {
.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 {
$(
&graphql_enum!(@as_pattern, $eval) =>

View file

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

View file

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

View file

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

View file

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

View file

@ -53,7 +53,7 @@ impl<'a> GraphQLType for &'a str {
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)
}
}