diff --git a/juniper/src/executor.rs b/juniper/src/executor.rs index f3d1852c..5e84c4b7 100644 --- a/juniper/src/executor.rs +++ b/juniper/src/executor.rs @@ -14,7 +14,7 @@ use parser::SourcePosition; use schema::meta::{Argument, EnumMeta, EnumValue, Field, InputObjectMeta, InterfaceMeta, ListMeta, MetaType, NullableMeta, ObjectMeta, PlaceholderMeta, ScalarMeta, UnionMeta}; -use schema::model::{RootNode, SchemaType}; +use schema::model::{RootNode, SchemaType, TypeType}; use types::base::GraphQLType; use types::name::Name; @@ -46,6 +46,7 @@ where fragments: &'a HashMap<&'a str, &'a Fragment<'a>>, variables: &'a Variables, current_selection_set: Option<&'a [Selection<'a>]>, + current_type: TypeType<'a>, schema: &'a SchemaType<'a>, context: &'a CtxT, errors: &'a RwLock<Vec<ExecutionError>>, @@ -305,6 +306,7 @@ impl<'a, CtxT> Executor<'a, CtxT> { fragments: self.fragments, variables: self.variables, current_selection_set: self.current_selection_set, + current_type: self.current_type.clone(), schema: self.schema, context: ctx, errors: self.errors, @@ -313,9 +315,10 @@ impl<'a, CtxT> Executor<'a, CtxT> { } #[doc(hidden)] - pub fn sub_executor( + pub fn field_sub_executor( &self, - field_name: Option<&'a str>, + field_alias: &'a str, + field_name: &'a str, location: SourcePosition, selection_set: Option<&'a [Selection]>, ) -> Executor<CtxT> { @@ -323,13 +326,36 @@ impl<'a, CtxT> Executor<'a, CtxT> { fragments: self.fragments, variables: self.variables, current_selection_set: selection_set, + current_type: self.schema.make_type( + &self.current_type + .innermost_concrete() + .field_by_name(field_name).expect("Field not found on inner type") + .field_type), schema: self.schema, context: self.context, errors: self.errors, - field_path: match field_name { - Some(name) => FieldPath::Field(name, location, &self.field_path), - None => self.field_path.clone(), + field_path: FieldPath::Field(field_alias, location, &self.field_path), + } + } + + #[doc(hidden)] + pub fn type_sub_executor( + &self, + type_name: Option<&'a str>, + selection_set: Option<&'a [Selection]>, + ) -> Executor<CtxT> { + Executor { + fragments: self.fragments, + variables: self.variables, + current_selection_set: selection_set, + current_type: match type_name { + Some(type_name) => self.schema.type_by_name(type_name).expect("Type not found"), + None => self.current_type.clone(), }, + schema: self.schema, + context: self.context, + errors: self.errors, + field_path: self.field_path.clone(), } } @@ -346,6 +372,11 @@ impl<'a, CtxT> Executor<'a, CtxT> { self.schema } + #[doc(hidden)] + pub fn current_type(&self) -> &TypeType<'a> { + &self.current_type + } + #[doc(hidden)] pub fn variables(&self) -> &'a Variables { self.variables @@ -492,6 +523,11 @@ where final_vars = &all_vars; } + let root_type = match op.item.operation_type { + OperationType::Query => root_node.schema.query_type(), + OperationType::Mutation => root_node.schema.mutation_type().expect("No mutation type found") + }; + let executor = Executor { fragments: &fragments .iter() @@ -499,6 +535,7 @@ where .collect(), variables: final_vars, current_selection_set: Some(&op.item.selection_set[..]), + current_type: root_type, schema: &root_node.schema, context: context, errors: &errors, diff --git a/juniper/src/schema/model.rs b/juniper/src/schema/model.rs index 41fe51eb..6d2d2351 100644 --- a/juniper/src/schema/model.rs +++ b/juniper/src/schema/model.rs @@ -35,6 +35,7 @@ pub struct SchemaType<'a> { impl<'a> Context for SchemaType<'a> {} +#[derive(Clone)] pub enum TypeType<'a> { Concrete(&'a MetaType<'a>), NonNull(Box<TypeType<'a>>), diff --git a/juniper/src/types/base.rs b/juniper/src/types/base.rs index b88031e6..b1d29a70 100644 --- a/juniper/src/types/base.rs +++ b/juniper/src/types/base.rs @@ -367,8 +367,9 @@ fn resolve_selection_set_into<T, CtxT>( let exec_vars = executor.variables(); - let sub_exec = executor.sub_executor( - Some(response_name), + let sub_exec = executor.field_sub_executor( + response_name, + &f.name.item, start_pos.clone(), f.selection_set.as_ref().map(|v| &v[..]), ); @@ -434,8 +435,9 @@ fn resolve_selection_set_into<T, CtxT>( continue; } - let sub_exec = executor - .sub_executor(None, start_pos.clone(), Some(&fragment.selection_set[..])); + let sub_exec = executor.type_sub_executor( + fragment.type_condition.as_ref().map(|c| c.item), + Some(&fragment.selection_set[..])); if let Some(ref type_condition) = fragment.type_condition { let sub_result = instance.resolve_into_type(