Don't clone selection sets during execution
This commit is contained in:
parent
6a4b883b97
commit
13903d7628
9 changed files with 41 additions and 46 deletions
|
@ -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,
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue