Add tracking of the current type being resolved in the Executor
This is not 100% accurate - it will be set to the literal type of what a field returns, so it might be wrapped in non-null/list when it technically shouldn't. For this use-case it's fine, but if we want to (officially) add it to the public API surface, we should probably make it accurate.
This commit is contained in:
parent
8cf2707faa
commit
d0e9202f41
3 changed files with 50 additions and 10 deletions
|
@ -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,
|
||||
|
|
|
@ -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>>),
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue