1515import graphql .schema .GraphQLFieldDefinition ;
1616import graphql .schema .GraphQLInterfaceType ;
1717import graphql .schema .GraphQLList ;
18- import graphql .schema .GraphQLNonNull ;
1918import graphql .schema .GraphQLObjectType ;
2019import graphql .schema .GraphQLScalarType ;
2120import graphql .schema .GraphQLSchema ;
3029import java .util .List ;
3130import java .util .Map ;
3231
32+ import static graphql .execution .TypeInfo .newTypeInfo ;
3333import static graphql .introspection .Introspection .SchemaMetaFieldDef ;
3434import static graphql .introspection .Introspection .TypeMetaFieldDef ;
3535import static graphql .introspection .Introspection .TypeNameMetaFieldDef ;
3636
3737public abstract class ExecutionStrategy {
38+
3839 private static final Logger log = LoggerFactory .getLogger (ExecutionStrategy .class );
3940
4041 protected final ValuesResolver valuesResolver = new ValuesResolver ();
4142 protected final FieldCollector fieldCollector = new FieldCollector ();
4243
43- public abstract ExecutionResult execute (ExecutionContext executionContext , GraphQLObjectType parentType , Object source , Map < String , List < Field >> fields ) ;
44+ public abstract ExecutionResult execute (ExecutionContext executionContext , ExecutionParameters parameters ) throws NonNullableFieldWasNullException ;
4445
45- protected ExecutionResult resolveField (ExecutionContext executionContext , GraphQLObjectType parentType , Object source , List <Field > fields ) {
46- GraphQLFieldDefinition fieldDef = getFieldDef (executionContext .getGraphQLSchema (), parentType , fields .get (0 ));
46+ protected ExecutionResult resolveField (ExecutionContext executionContext , ExecutionParameters parameters , List <Field > fields ) {
47+ GraphQLObjectType type = parameters .typeInfo ().castType (GraphQLObjectType .class );
48+ GraphQLFieldDefinition fieldDef = getFieldDef (executionContext .getGraphQLSchema (), type , fields .get (0 ));
4749
4850 Map <String , Object > argumentValues = valuesResolver .getArgumentValues (fieldDef .getArguments (), fields .get (0 ).getArguments (), executionContext .getVariables ());
4951 DataFetchingEnvironment environment = new DataFetchingEnvironmentImpl (
50- source ,
52+ parameters . source () ,
5153 argumentValues ,
5254 executionContext .getRoot (),
5355 fields ,
5456 fieldDef .getType (),
55- parentType ,
57+ type ,
5658 executionContext .getGraphQLSchema ()
5759 );
5860
@@ -73,25 +75,38 @@ protected ExecutionResult resolveField(ExecutionContext executionContext, GraphQ
7375 fetchCtx .onEnd (e );
7476 }
7577
76- ExecutionResult result = completeValue (executionContext , fieldDef .getType (), fields , resolvedValue );
78+ TypeInfo fieldType = newTypeInfo ()
79+ .type (fieldDef .getType ())
80+ .parentInfo (parameters .typeInfo ())
81+ .build ();
82+
83+
84+ ExecutionParameters newParameters = ExecutionParameters .newParameters ()
85+ .typeInfo (fieldType )
86+ .fields (parameters .fields ())
87+ .source (resolvedValue ).build ();
88+
89+ ExecutionResult result = completeValue (executionContext , newParameters , fields );
7790
7891 fieldCtx .onEnd (result );
7992 return result ;
8093 }
8194
82- protected ExecutionResult completeValue (ExecutionContext executionContext , GraphQLType fieldType , List <Field > fields , Object result ) {
83- if (fieldType instanceof GraphQLNonNull ) {
84- GraphQLNonNull graphQLNonNull = (GraphQLNonNull ) fieldType ;
85- ExecutionResult completed = completeValue (executionContext , graphQLNonNull .getWrappedType (), fields , result );
86- if (completed == null ) {
87- throw new GraphQLException ("Cannot return null for non-nullable type: " + fields );
88- }
89- return completed ;
95+ protected ExecutionResult completeValue (ExecutionContext executionContext , ExecutionParameters parameters , List <Field > fields ) {
96+ TypeInfo typeInfo = parameters .typeInfo ();
97+ Object result = parameters .source ();
98+ GraphQLType fieldType = parameters .typeInfo ().type ();
9099
91- } else if (result == null ) {
100+ if (result == null ) {
101+ if (typeInfo .typeIsNonNull ()) {
102+ // see http://facebook.github.io/graphql/#sec-Errors-and-Non-Nullability
103+ NonNullableFieldWasNullException nonNullException = new NonNullableFieldWasNullException (typeInfo );
104+ executionContext .addError (nonNullException );
105+ throw nonNullException ;
106+ }
92107 return null ;
93108 } else if (fieldType instanceof GraphQLList ) {
94- return completeValueForList (executionContext , ( GraphQLList ) fieldType , fields , result );
109+ return completeValueForList (executionContext , parameters , fields , toIterable ( result ) );
95110 } else if (fieldType instanceof GraphQLScalarType ) {
96111 return completeValueForScalar ((GraphQLScalarType ) fieldType , result );
97112 } else if (fieldType instanceof GraphQLEnumType ) {
@@ -115,18 +130,22 @@ protected ExecutionResult completeValue(ExecutionContext executionContext, Graph
115130 fieldCollector .collectFields (executionContext , resolvedType , field .getSelectionSet (), visitedFragments , subFields );
116131 }
117132
133+ ExecutionParameters newParameters = ExecutionParameters .newParameters ()
134+ .typeInfo (typeInfo .asType (resolvedType ))
135+ .fields (subFields )
136+ .source (result ).build ();
137+
118138 // Calling this from the executionContext to ensure we shift back from mutation strategy to the query strategy.
119139
120- return executionContext .getQueryStrategy ().execute (executionContext , resolvedType , result , subFields );
140+ return executionContext .getQueryStrategy ().execute (executionContext , newParameters );
121141 }
122142
123- private ExecutionResult completeValueForList ( ExecutionContext executionContext , GraphQLList fieldType , List < Field > fields , Object result ) {
143+ private Iterable < Object > toIterable ( Object result ) {
124144 if (result .getClass ().isArray ()) {
125145 result = Arrays .asList ((Object []) result );
126146 }
127-
128147 //noinspection unchecked
129- return completeValueForList ( executionContext , fieldType , fields , ( Iterable <Object >) result ) ;
148+ return ( Iterable <Object >) result ;
130149 }
131150
132151 protected GraphQLObjectType resolveType (GraphQLInterfaceType graphQLInterfaceType , Object value ) {
@@ -145,7 +164,6 @@ protected GraphQLObjectType resolveType(GraphQLUnionType graphQLUnionType, Objec
145164 return result ;
146165 }
147166
148-
149167 protected ExecutionResult completeValueForEnum (GraphQLEnumType enumType , Object result ) {
150168 return new ExecutionResultImpl (enumType .getCoercing ().serialize (result ), null );
151169 }
@@ -159,10 +177,18 @@ protected ExecutionResult completeValueForScalar(GraphQLScalarType scalarType, O
159177 return new ExecutionResultImpl (serialized , null );
160178 }
161179
162- protected ExecutionResult completeValueForList (ExecutionContext executionContext , GraphQLList fieldType , List <Field > fields , Iterable <Object > result ) {
180+ protected ExecutionResult completeValueForList (ExecutionContext executionContext , ExecutionParameters parameters , List <Field > fields , Iterable <Object > result ) {
163181 List <Object > completedResults = new ArrayList <>();
182+ TypeInfo typeInfo = parameters .typeInfo ();
183+ GraphQLList fieldType = typeInfo .castType (GraphQLList .class );
164184 for (Object item : result ) {
165- ExecutionResult completedValue = completeValue (executionContext , fieldType .getWrappedType (), fields , item );
185+
186+ ExecutionParameters newParameters = ExecutionParameters .newParameters ()
187+ .typeInfo (typeInfo .asType (fieldType .getWrappedType ()))
188+ .fields (parameters .fields ())
189+ .source (item ).build ();
190+
191+ ExecutionResult completedValue = completeValue (executionContext , newParameters , fields );
166192 completedResults .add (completedValue != null ? completedValue .getData () : null );
167193 }
168194 return new ExecutionResultImpl (completedResults , null );
0 commit comments