Skip to content

Commit 61a7bbd

Browse files
committed
Merge pull request graphql-java#21 from nfl/master
Initial execution strategy work
2 parents eca9167 + 38c6daa commit 61a7bbd

8 files changed

Lines changed: 249 additions & 169 deletions

src/main/java/graphql/GraphQL.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import graphql.execution.Execution;
5+
import graphql.execution.ExecutionStrategy;
56
import graphql.language.Document;
67
import graphql.language.SourceLocation;
78
import graphql.parser.Parser;
@@ -24,7 +25,7 @@ public class GraphQL {
2425

2526

2627
private final GraphQLSchema graphQLSchema;
27-
private final ExecutorService executorService;
28+
private final ExecutionStrategy executionStrategy;
2829

2930
private static final Logger log = LoggerFactory.getLogger(GraphQL.class);
3031

@@ -33,9 +34,9 @@ public GraphQL(GraphQLSchema graphQLSchema) {
3334
}
3435

3536

36-
public GraphQL(GraphQLSchema graphQLSchema, ExecutorService executorService) {
37+
public GraphQL(GraphQLSchema graphQLSchema, ExecutionStrategy executionStrategy) {
3738
this.graphQLSchema = graphQLSchema;
38-
this.executorService = executorService;
39+
this.executionStrategy = executionStrategy;
3940
}
4041

4142
public ExecutionResult execute(String requestString) {
@@ -72,7 +73,7 @@ public ExecutionResult execute(String requestString, String operationName, Objec
7273
if (validationErrors.size() > 0) {
7374
return new ExecutionResultImpl(validationErrors);
7475
}
75-
Execution execution = new Execution(executorService);
76+
Execution execution = new Execution(executionStrategy);
7677
return execution.execute(graphQLSchema, context, document, operationName, arguments);
7778
}
7879

src/main/java/graphql/execution/Execution.java

Lines changed: 10 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,20 @@
2525

2626
public class Execution {
2727

28-
private FieldCollector fieldCollector;
29-
private ValuesResolver valuesResolver;
30-
private ExecutorService executorService;
28+
private FieldCollector fieldCollector = new FieldCollector();
29+
private ExecutionStrategy strategy;
3130

31+
public Execution(ExecutionStrategy strategy) {
32+
this.strategy = strategy;
3233

33-
private static final Logger log = LoggerFactory.getLogger(Execution.class);
34-
35-
public Execution(ExecutorService executorService) {
36-
fieldCollector = new FieldCollector();
37-
valuesResolver = new ValuesResolver();
38-
this.executorService = executorService;
34+
if (this.strategy == null) {
35+
this.strategy = new SimpleExecutionStrategy();
36+
}
3937
}
4038

4139
public ExecutionResult execute(GraphQLSchema graphQLSchema, Object root, Document document, String operationName, Map<String, Object> args) {
4240
ExecutionContextBuilder executionContextBuilder = new ExecutionContextBuilder(new ValuesResolver());
43-
ExecutionContext executionContext = executionContextBuilder.build(graphQLSchema, root, document, operationName, args);
41+
ExecutionContext executionContext = executionContextBuilder.build(graphQLSchema, strategy, root, document, operationName, args);
4442
return executeOperation(executionContext, root, executionContext.getOperationDefinition());
4543
}
4644

@@ -65,162 +63,10 @@ private ExecutionResult executeOperation(
6563
Map<String, List<Field>> fields = new LinkedHashMap<>();
6664
fieldCollector.collectFields(executionContext, operationRootType, operationDefinition.getSelectionSet(), new ArrayList<String>(), fields);
6765

68-
Map<String, Object> result;
6966
if (operationDefinition.getOperation() == OperationDefinition.Operation.MUTATION) {
70-
result = executeFieldsSerially(executionContext, operationRootType, root, fields);
67+
return new SimpleExecutionStrategy().execute(executionContext, operationRootType, root, fields);
7168
} else {
72-
result = executeFieldsParallel(executionContext, operationRootType, root, fields);
69+
return strategy.execute(executionContext, operationRootType, root, fields);
7370
}
74-
return new ExecutionResultImpl(result, executionContext.getErrors());
75-
}
76-
77-
private Map<String, Object> executeFieldsSerially(ExecutionContext executionContext, GraphQLObjectType parentType, Object source, Map<String, List<Field>> fields) {
78-
Map<String, Object> results = new LinkedHashMap<>();
79-
for (String fieldName : fields.keySet()) {
80-
List<Field> fieldList = fields.get(fieldName);
81-
Object resolvedResult = resolveField(executionContext, parentType, source, fieldList);
82-
results.put(fieldName, resolvedResult);
83-
}
84-
return results;
85-
}
86-
87-
88-
private Map<String, Object> executeFieldsParallel(final ExecutionContext executionContext, final GraphQLObjectType parentType, final Object source, Map<String, List<Field>> fields) {
89-
if (executorService == null) return executeFieldsSerially(executionContext, parentType, source, fields);
90-
91-
Map<String, Future<Object>> futures = new LinkedHashMap<>();
92-
for (String fieldName : fields.keySet()) {
93-
final List<Field> fieldList = fields.get(fieldName);
94-
Callable<Object> resolveField = new Callable<Object>() {
95-
@Override
96-
public Object call() throws Exception {
97-
return resolveField(executionContext, parentType, source, fieldList);
98-
99-
}
100-
};
101-
futures.put(fieldName, executorService.submit(resolveField));
102-
}
103-
try {
104-
Map<String, Object> results = new LinkedHashMap<>();
105-
for (String fieldName : futures.keySet()) {
106-
results.put(fieldName, futures.get(fieldName).get());
107-
}
108-
return results;
109-
} catch (InterruptedException | ExecutionException e) {
110-
throw new GraphQLException(e);
111-
}
112-
11371
}
114-
115-
private Object resolveField(ExecutionContext executionContext, GraphQLObjectType parentType, Object source, List<Field> fields) {
116-
GraphQLFieldDefinition fieldDef = getFieldDef(executionContext.getGraphQLSchema(), parentType, fields.get(0));
117-
if (fieldDef == null) return null;
118-
119-
Map<String, Object> argumentValues = valuesResolver.getArgumentValues(fieldDef.getArguments(), fields.get(0).getArguments(), executionContext.getVariables());
120-
DataFetchingEnvironment environment = new DataFetchingEnvironment(
121-
source,
122-
argumentValues,
123-
executionContext.getRoot(),
124-
fields,
125-
fieldDef.getType(),
126-
parentType,
127-
executionContext.getGraphQLSchema()
128-
);
129-
130-
Object resolvedValue = null;
131-
try {
132-
resolvedValue = fieldDef.getDataFetcher().get(environment);
133-
} catch (Exception e) {
134-
log.info("Exception while fetching data", e);
135-
executionContext.addError(new ExceptionWhileDataFetching(e));
136-
}
137-
138-
139-
return completeValue(executionContext, fieldDef.getType(), fields, resolvedValue);
140-
}
141-
142-
private Object completeValue(ExecutionContext executionContext, GraphQLType fieldType, List<Field> fields, Object result) {
143-
if (fieldType instanceof GraphQLNonNull) {
144-
GraphQLNonNull graphQLNonNull = (GraphQLNonNull) fieldType;
145-
Object completed = completeValue(executionContext, graphQLNonNull.getWrappedType(), fields, result);
146-
if (completed == null) throw new GraphQLException("Cannot return null for non-nullable type: " + fields);
147-
return completed;
148-
149-
} else if (result == null) {
150-
return null;
151-
} else if (fieldType instanceof GraphQLList) {
152-
return completeValueForList(executionContext, (GraphQLList) fieldType, fields, (List<Object>) result);
153-
} else if (fieldType instanceof GraphQLScalarType) {
154-
return completeValueForScalar((GraphQLScalarType) fieldType, result);
155-
} else if (fieldType instanceof GraphQLEnumType) {
156-
return completeValueForEnum((GraphQLEnumType) fieldType, result);
157-
}
158-
159-
160-
GraphQLObjectType resolvedType;
161-
if (fieldType instanceof GraphQLInterfaceType) {
162-
resolvedType = resolveType((GraphQLInterfaceType) fieldType, result);
163-
} else if (fieldType instanceof GraphQLUnionType) {
164-
resolvedType = resolveType((GraphQLUnionType) fieldType, result);
165-
} else {
166-
resolvedType = (GraphQLObjectType) fieldType;
167-
}
168-
169-
Map<String, List<Field>> subFields = new LinkedHashMap<>();
170-
List<String> visitedFragments = new ArrayList<>();
171-
for (Field field : fields) {
172-
if (field.getSelectionSet() == null) continue;
173-
fieldCollector.collectFields(executionContext, resolvedType, field.getSelectionSet(), visitedFragments, subFields);
174-
}
175-
return executeFieldsParallel(executionContext, resolvedType, result, subFields);
176-
}
177-
178-
private GraphQLObjectType resolveType(GraphQLInterfaceType graphQLInterfaceType, Object value) {
179-
GraphQLObjectType result = graphQLInterfaceType.getTypeResolver().getType(value);
180-
if (result == null) throw new GraphQLException("could not determine type");
181-
return result;
182-
}
183-
184-
private GraphQLObjectType resolveType(GraphQLUnionType graphQLUnionType, Object value) {
185-
GraphQLObjectType result = graphQLUnionType.getTypeResolver().getType(value);
186-
if (result == null) throw new GraphQLException("could not determine type");
187-
return result;
188-
}
189-
190-
191-
private Object completeValueForEnum(GraphQLEnumType enumType, Object result) {
192-
return enumType.getCoercing().coerce(result);
193-
}
194-
195-
private Object completeValueForScalar(GraphQLScalarType scalarType, Object result) {
196-
return scalarType.getCoercing().coerce(result);
197-
}
198-
199-
private Object completeValueForList(ExecutionContext executionContext, GraphQLList fieldType, List<Field> fields, List<Object> result) {
200-
List<Object> completedResults = new ArrayList<>();
201-
for (Object item : result) {
202-
completedResults.add(completeValue(executionContext, fieldType.getWrappedType(), fields, item));
203-
}
204-
return completedResults;
205-
}
206-
207-
private GraphQLFieldDefinition getFieldDef(GraphQLSchema schema, GraphQLObjectType parentType, Field field) {
208-
if (schema.getQueryType() == parentType) {
209-
if (field.getName().equals(SchemaMetaFieldDef.getName())) {
210-
return SchemaMetaFieldDef;
211-
}
212-
if (field.getName().equals(TypeMetaFieldDef.getName())) {
213-
return TypeMetaFieldDef;
214-
}
215-
}
216-
if (field.getName().equals(TypeNameMetaFieldDef.getName())) {
217-
return TypeNameMetaFieldDef;
218-
}
219-
220-
GraphQLFieldDefinition fieldDefinition = parentType.getFieldDefinition(field.getName());
221-
if (fieldDefinition == null) throw new GraphQLException("unknown field " + field.getName());
222-
return fieldDefinition;
223-
}
224-
225-
22672
}

src/main/java/graphql/execution/ExecutionContext.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
public class ExecutionContext {
1515

1616
private GraphQLSchema graphQLSchema;
17+
private ExecutionStrategy executionStrategy;
1718
private Map<String, FragmentDefinition> fragmentsByName = new LinkedHashMap<>();
1819
private OperationDefinition operationDefinition;
1920
private Map<String, Object> variables = new LinkedHashMap<>();
@@ -71,4 +72,12 @@ public void addError(GraphQLError error) {
7172
public List<GraphQLError> getErrors(){
7273
return errors;
7374
}
75+
76+
public ExecutionStrategy getExecutionStrategy() {
77+
return executionStrategy;
78+
}
79+
80+
public void setExecutionStrategy(ExecutionStrategy executionStrategy) {
81+
this.executionStrategy = executionStrategy;
82+
}
7483
}

src/main/java/graphql/execution/ExecutionContextBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public ExecutionContextBuilder(ValuesResolver valuesResolver) {
1818
this.valuesResolver = valuesResolver;
1919
}
2020

21-
public ExecutionContext build(GraphQLSchema graphQLSchema, Object root, Document document, String operationName, Map<String, Object> args) {
21+
public ExecutionContext build(GraphQLSchema graphQLSchema, ExecutionStrategy executionStrategy, Object root, Document document, String operationName, Map<String, Object> args) {
2222
Map<String, FragmentDefinition> fragmentsByName = new LinkedHashMap<>();
2323
Map<String, OperationDefinition> operationsByName = new LinkedHashMap<>();
2424

@@ -48,6 +48,7 @@ public ExecutionContext build(GraphQLSchema graphQLSchema, Object root, Document
4848

4949
ExecutionContext executionContext = new ExecutionContext();
5050
executionContext.setGraphQLSchema(graphQLSchema);
51+
executionContext.setExecutionStrategy(executionStrategy);
5152
executionContext.setOperationDefinition(operation);
5253
executionContext.setRoot(root);
5354
executionContext.setFragmentsByName(fragmentsByName);

0 commit comments

Comments
 (0)