Skip to content

Commit 6e6f1dd

Browse files
author
Bojan Tomic
committed
closes graphql-java#122 Provide more information to TypeResolver
Allow richer resolution logic
1 parent 6581b27 commit 6e6f1dd

14 files changed

+437
-119
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package graphql;
2+
3+
import java.util.Map;
4+
5+
import graphql.language.Field;
6+
import graphql.schema.GraphQLSchema;
7+
import graphql.schema.GraphQLType;
8+
9+
public class TypeResolutionEnvironment {
10+
11+
private final Object object;
12+
private final Map<String, Object> arguments;
13+
private final Field field;
14+
private final GraphQLType fieldType;
15+
private final GraphQLSchema schema;
16+
17+
public TypeResolutionEnvironment(Object object, Map<String, Object> arguments, Field field, GraphQLType fieldType, GraphQLSchema schema) {
18+
this.object = object;
19+
this.arguments = arguments;
20+
this.field = field;
21+
this.fieldType = fieldType;
22+
this.schema = schema;
23+
}
24+
25+
public Object getObject() {
26+
return object;
27+
}
28+
29+
public Map<String, Object> getArguments() {
30+
return arguments;
31+
}
32+
33+
public Field getField() {
34+
return field;
35+
}
36+
37+
public GraphQLType getFieldType() {
38+
return fieldType;
39+
}
40+
41+
public GraphQLSchema getSchema() {
42+
return schema;
43+
}
44+
}

src/main/java/graphql/execution/ExecutionStrategy.java

Lines changed: 94 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import graphql.ExecutionResult;
55
import graphql.ExecutionResultImpl;
66
import graphql.GraphQLException;
7+
import graphql.TypeResolutionEnvironment;
78
import graphql.execution.instrumentation.Instrumentation;
89
import graphql.execution.instrumentation.InstrumentationContext;
910
import graphql.execution.instrumentation.parameters.FieldFetchParameters;
@@ -73,74 +74,115 @@ protected ExecutionResult resolveField(ExecutionContext executionContext, GraphQ
7374
fetchCtx.onEnd(e);
7475
}
7576

76-
ExecutionResult result = completeValue(executionContext, fieldDef.getType(), fields, resolvedValue);
77+
ExecutionResult result = completeValue(createCompletionParams(executionContext, fieldDef.getType(), fields, resolvedValue, argumentValues));
7778

7879
fieldCtx.onEnd(result);
7980
return result;
8081
}
8182

83+
/**
84+
* @deprecated Use {@link #completeValue(ValueCompletionParameters)} instead
85+
*/
86+
@Deprecated
8287
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);
88+
return completeValue(createCompletionParams(executionContext, fieldType, fields, result, null));
89+
}
90+
91+
protected ExecutionResult completeValue(ValueCompletionParameters params) {
92+
if (params.getFieldType() instanceof GraphQLNonNull) {
93+
ValueCompletionParameters unwrapped = createCompletionParams(params.getExecutionContext(), params.<GraphQLNonNull>getFieldType().getWrappedType(),
94+
params.getFields(), params.getResult(), params.getArgumentValues()
95+
);
96+
ExecutionResult completed = completeValue(unwrapped);
8697
if (completed == null) {
87-
throw new GraphQLException("Cannot return null for non-nullable type: " + fields);
98+
throw new GraphQLException("Cannot return null for non-nullable type: " + params.getFields());
8899
}
89100
return completed;
90101

91-
} else if (result == null) {
102+
} else if (params.getResult() == null) {
92103
return null;
93-
} else if (fieldType instanceof GraphQLList) {
94-
return completeValueForList(executionContext, (GraphQLList) fieldType, fields, result);
95-
} else if (fieldType instanceof GraphQLScalarType) {
96-
return completeValueForScalar((GraphQLScalarType) fieldType, result);
97-
} else if (fieldType instanceof GraphQLEnumType) {
98-
return completeValueForEnum((GraphQLEnumType) fieldType, result);
104+
} else if (params.getFieldType() instanceof GraphQLList) {
105+
return completeValueForListOrArray(params);
106+
} else if (params.getFieldType() instanceof GraphQLScalarType) {
107+
return completeValueForScalar(params.getFieldType(), params.getResult());
108+
} else if (params.getFieldType() instanceof GraphQLEnumType) {
109+
return completeValueForEnum(params.getFieldType(), params.getResult());
99110
}
100111

101112

102113
GraphQLObjectType resolvedType;
103-
if (fieldType instanceof GraphQLInterfaceType) {
104-
resolvedType = resolveType((GraphQLInterfaceType) fieldType, result);
105-
} else if (fieldType instanceof GraphQLUnionType) {
106-
resolvedType = resolveType((GraphQLUnionType) fieldType, result);
114+
if (params.getFieldType() instanceof GraphQLInterfaceType) {
115+
TypeResolutionParameters resolutionParams = TypeResolutionParameters.newParameters()
116+
.graphQLInterfaceType(params.getFieldType())
117+
.field(params.getFields().get(0))
118+
.value(params.getResult())
119+
.argumentValues(params.getArgumentValues())
120+
.schema(params.getExecutionContext().getGraphQLSchema()).build();
121+
resolvedType = resolveTypeForInterface(resolutionParams);
122+
} else if (params.getFieldType() instanceof GraphQLUnionType) {
123+
TypeResolutionParameters resolutionParams = TypeResolutionParameters.newParameters()
124+
.graphQLUnionType(params.getFieldType())
125+
.field(params.getFields().get(0))
126+
.value(params.getResult())
127+
.argumentValues(params.getArgumentValues())
128+
.schema(params.getExecutionContext().getGraphQLSchema()).build();
129+
resolvedType = resolveTypeForUnion(resolutionParams);
107130
} else {
108-
resolvedType = (GraphQLObjectType) fieldType;
131+
resolvedType = params.getFieldType();
109132
}
110133

111134
Map<String, List<Field>> subFields = new LinkedHashMap<>();
112135
List<String> visitedFragments = new ArrayList<>();
113-
for (Field field : fields) {
136+
for (Field field : params.getFields()) {
114137
if (field.getSelectionSet() == null) continue;
115-
fieldCollector.collectFields(executionContext, resolvedType, field.getSelectionSet(), visitedFragments, subFields);
138+
fieldCollector.collectFields(params.getExecutionContext(), resolvedType, field.getSelectionSet(), visitedFragments, subFields);
116139
}
117140

118141
// Calling this from the executionContext to ensure we shift back from mutation strategy to the query strategy.
119142

120-
return executionContext.getQueryStrategy().execute(executionContext, resolvedType, result, subFields);
143+
return params.getExecutionContext().getQueryStrategy().execute(params.getExecutionContext(), resolvedType, params.getResult(), subFields);
121144
}
122145

123-
private ExecutionResult completeValueForList(ExecutionContext executionContext, GraphQLList fieldType, List<Field> fields, Object result) {
124-
if (result.getClass().isArray()) {
125-
result = Arrays.asList((Object[]) result);
146+
private ExecutionResult completeValueForListOrArray(ValueCompletionParameters params) {
147+
if (params.getResult().getClass().isArray()) {
148+
List<Object> result = Arrays.asList((Object[]) params.getResult());
149+
params = createCompletionParams(params.getExecutionContext(), params.getFieldType(), params.getFields(), result, params.getArgumentValues());
126150
}
127151

128152
//noinspection unchecked
129-
return completeValueForList(executionContext, fieldType, fields, (Iterable<Object>) result);
153+
return completeValueForList(params);
130154
}
131155

156+
/**
157+
* @deprecated Use {@link #resolveTypeForInterface(TypeResolutionParameters)}
158+
*/
159+
@Deprecated
132160
protected GraphQLObjectType resolveType(GraphQLInterfaceType graphQLInterfaceType, Object value) {
133-
GraphQLObjectType result = graphQLInterfaceType.getTypeResolver().getType(value);
161+
return resolveTypeForInterface(TypeResolutionParameters.newParameters().graphQLInterfaceType(graphQLInterfaceType).value(value).build());
162+
}
163+
164+
protected GraphQLObjectType resolveTypeForInterface(TypeResolutionParameters params) {
165+
TypeResolutionEnvironment env = new TypeResolutionEnvironment(params.getValue(), params.getArgumentValues(), params.getField(), params.getGraphQLInterfaceType(), params.getSchema());
166+
GraphQLObjectType result = params.getGraphQLInterfaceType().getTypeResolver().getType(env);
134167
if (result == null) {
135-
throw new GraphQLException("could not determine type");
168+
throw new GraphQLException("Could not determine the exact type of " + params.getGraphQLInterfaceType().getName());
136169
}
137170
return result;
138171
}
139172

173+
/**
174+
* @deprecated Use {@link #resolveTypeForUnion(TypeResolutionParameters)}
175+
*/
176+
@Deprecated
140177
protected GraphQLObjectType resolveType(GraphQLUnionType graphQLUnionType, Object value) {
141-
GraphQLObjectType result = graphQLUnionType.getTypeResolver().getType(value);
178+
return resolveTypeForUnion(TypeResolutionParameters.newParameters().graphQLUnionType(graphQLUnionType).value(value).build());
179+
}
180+
181+
protected GraphQLObjectType resolveTypeForUnion(TypeResolutionParameters params) {
182+
TypeResolutionEnvironment env = new TypeResolutionEnvironment(params.getValue(), params.getArgumentValues(), params.getField(), params.getGraphQLUnionType(), params.getSchema());
183+
GraphQLObjectType result = params.getGraphQLUnionType().getTypeResolver().getType(env);
142184
if (result == null) {
143-
throw new GraphQLException("could not determine type");
185+
throw new GraphQLException("Could not determine the exact type of " + params.getGraphQLUnionType().getName());
144186
}
145187
return result;
146188
}
@@ -159,10 +201,21 @@ protected ExecutionResult completeValueForScalar(GraphQLScalarType scalarType, O
159201
return new ExecutionResultImpl(serialized, null);
160202
}
161203

204+
/**
205+
* @deprecated Use {@link #completeValueForList(ValueCompletionParameters)}
206+
*/
207+
@Deprecated
162208
protected ExecutionResult completeValueForList(ExecutionContext executionContext, GraphQLList fieldType, List<Field> fields, Iterable<Object> result) {
209+
return completeValueForList(createCompletionParams(executionContext, fieldType, fields, result, null));
210+
}
211+
212+
protected ExecutionResult completeValueForList(ValueCompletionParameters params) {
163213
List<Object> completedResults = new ArrayList<>();
164-
for (Object item : result) {
165-
ExecutionResult completedValue = completeValue(executionContext, fieldType.getWrappedType(), fields, item);
214+
for (Object item : params.<Iterable<Object>>getResult()) {
215+
ValueCompletionParameters unwrapped = createCompletionParams(params.getExecutionContext(), params.<GraphQLList>getFieldType().getWrappedType(),
216+
params.getFields(), item, params.getArgumentValues()
217+
);
218+
ExecutionResult completedValue = completeValue(unwrapped);
166219
completedResults.add(completedValue != null ? completedValue.getData() : null);
167220
}
168221
return new ExecutionResultImpl(completedResults, null);
@@ -183,10 +236,19 @@ protected GraphQLFieldDefinition getFieldDef(GraphQLSchema schema, GraphQLObject
183236

184237
GraphQLFieldDefinition fieldDefinition = parentType.getFieldDefinition(field.getName());
185238
if (fieldDefinition == null) {
186-
throw new GraphQLException("unknown field " + field.getName());
239+
throw new GraphQLException("Unknown field " + field.getName());
187240
}
188241
return fieldDefinition;
189242
}
190243

191-
244+
private ValueCompletionParameters createCompletionParams(ExecutionContext executionContext, GraphQLType fieldType,
245+
List<Field> fields, Object result, Map<String, Object> argumentValues) {
246+
return ValueCompletionParameters.newParameters()
247+
.executionContext(executionContext)
248+
.fieldType(fieldType)
249+
.fields(fields)
250+
.result(result)
251+
.argumentValues(argumentValues)
252+
.build();
253+
}
192254
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package graphql.execution;
2+
3+
import java.util.Map;
4+
5+
import graphql.language.Field;
6+
import graphql.schema.GraphQLInterfaceType;
7+
import graphql.schema.GraphQLSchema;
8+
import graphql.schema.GraphQLUnionType;
9+
10+
public class TypeResolutionParameters {
11+
12+
private final GraphQLInterfaceType graphQLInterfaceType;
13+
private final GraphQLUnionType graphQLUnionType;
14+
private final Field field;
15+
private final Object value;
16+
private final Map<String, Object> argumentValues;
17+
private final GraphQLSchema schema;
18+
19+
private TypeResolutionParameters(GraphQLInterfaceType graphQLInterfaceType, GraphQLUnionType graphQLUnionType,
20+
Field field, Object value, Map<String, Object> argumentValues, GraphQLSchema schema) {
21+
this.graphQLInterfaceType = graphQLInterfaceType;
22+
this.graphQLUnionType = graphQLUnionType;
23+
this.field = field;
24+
this.value = value;
25+
this.argumentValues = argumentValues;
26+
this.schema = schema;
27+
}
28+
29+
public GraphQLInterfaceType getGraphQLInterfaceType() {
30+
return graphQLInterfaceType;
31+
}
32+
33+
public GraphQLUnionType getGraphQLUnionType() {
34+
return graphQLUnionType;
35+
}
36+
37+
public Field getField() {
38+
return field;
39+
}
40+
41+
public Object getValue() {
42+
return value;
43+
}
44+
45+
public Map<String, Object> getArgumentValues() {
46+
return argumentValues;
47+
}
48+
49+
public GraphQLSchema getSchema() {
50+
return schema;
51+
}
52+
53+
public static Builder newParameters() {
54+
return new Builder();
55+
}
56+
57+
public static class Builder {
58+
59+
private Field field;
60+
private GraphQLInterfaceType graphQLInterfaceType;
61+
private GraphQLUnionType graphQLUnionType;
62+
private Object value;
63+
private Map<String, Object> argumentValues;
64+
private GraphQLSchema schema;
65+
66+
public Builder field(Field field) {
67+
this.field = field;
68+
return this;
69+
}
70+
71+
public Builder graphQLInterfaceType(GraphQLInterfaceType graphQLInterfaceType) {
72+
this.graphQLInterfaceType = graphQLInterfaceType;
73+
return this;
74+
}
75+
76+
public Builder graphQLUnionType(GraphQLUnionType graphQLUnionType) {
77+
this.graphQLUnionType = graphQLUnionType;
78+
return this;
79+
}
80+
81+
public Builder value(Object value) {
82+
this.value = value;
83+
return this;
84+
}
85+
86+
public Builder argumentValues(Map<String, Object> argumentValues) {
87+
this.argumentValues = argumentValues;
88+
return this;
89+
}
90+
91+
public Builder schema(GraphQLSchema schema) {
92+
this.schema = schema;
93+
return this;
94+
}
95+
96+
public TypeResolutionParameters build() {
97+
return new TypeResolutionParameters(graphQLInterfaceType, graphQLUnionType, field, value, argumentValues, schema);
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)