graphql.execution.batched.BatchedExecutionStrategy Maven / Gradle / Ivy
package graphql.execution.batched;
import graphql.ExceptionWhileDataFetching;
import graphql.ExecutionResult;
import graphql.ExecutionResultImpl;
import graphql.GraphQLException;
import graphql.execution.ExecutionContext;
import graphql.execution.ExecutionStrategy;
import graphql.language.Field;
import graphql.schema.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static java.util.Collections.singletonList;
/**
* Execution Strategy that minimizes calls to the data fetcher when used in conjunction with {@link DataFetcher}s that have
* {@link DataFetcher#get(DataFetchingEnvironment)} methods annotated with {@link Batched}. See the javadoc comment on
* {@link Batched} for a more detailed description of batched data fetchers.
*
* The strategy runs a BFS over terms of the query and passes a list of all the relevant sources to the batched data fetcher.
*
* Normal DataFetchers can be used, however they will not see benefits of batching as they expect a single source object
* at a time.
*/
public class BatchedExecutionStrategy extends ExecutionStrategy {
private static final Logger log = LoggerFactory.getLogger(BatchedExecutionStrategy.class);
private final BatchedDataFetcherFactory batchingFactory = new BatchedDataFetcherFactory();
@Override
public ExecutionResult execute(ExecutionContext executionContext, GraphQLObjectType parentType, Object source, Map> fields) {
GraphQLExecutionNodeDatum data = new GraphQLExecutionNodeDatum(new LinkedHashMap(), source);
GraphQLExecutionNode root = new GraphQLExecutionNode(parentType, fields, singletonList(data));
return execute(executionContext, root);
}
private ExecutionResult execute(ExecutionContext executionContext, GraphQLExecutionNode root) {
Queue nodes = new ArrayDeque();
nodes.add(root);
while (!nodes.isEmpty()) {
GraphQLExecutionNode node = nodes.poll();
for (String fieldName : node.getFields().keySet()) {
List fieldList = node.getFields().get(fieldName);
List childNodes = resolveField(executionContext, node.getParentType(),
node.getData(), fieldName, fieldList);
nodes.addAll(childNodes);
}
}
return new ExecutionResultImpl(getOnlyElement(root.getData()).getParentResult(), executionContext.getErrors());
}
private GraphQLExecutionNodeDatum getOnlyElement(List list) {
return list.get(0);
}
// Use the data.source objects to fetch
// Use the data.parentResult objects to put values into. These are either primitives or empty maps
// If they were empty maps, we need that list of nodes to process
private List resolveField(ExecutionContext executionContext, GraphQLObjectType parentType,
List nodeData, String fieldName, List fields) {
GraphQLFieldDefinition fieldDef = getFieldDef(executionContext.getGraphQLSchema(), parentType, fields.get(0));
if (fieldDef == null) {
return Collections.emptyList();
}
List values = fetchData(executionContext, parentType, nodeData, fields, fieldDef);
return completeValues(executionContext, parentType, values, fieldName, fields, fieldDef.getType());
}
/**
* Updates parents and returns new Nodes.
*/
private List completeValues(ExecutionContext executionContext, GraphQLObjectType parentType,
List values, String fieldName, List fields,
GraphQLOutputType outputType) {
GraphQLType fieldType = handleNonNullType(outputType, values, parentType, fields);
if (isPrimitive(fieldType)) {
handlePrimitives(values, fieldName, fieldType);
return Collections.emptyList();
} else if (isObject(fieldType)) {
return handleObject(executionContext, values, fieldName, fields, fieldType);
} else if (isList(fieldType)) {
return handleList(executionContext, values, fieldName, fields, parentType, (GraphQLList) fieldType);
} else {
throw new IllegalArgumentException("Unrecognized type: " + fieldType);
}
}
@SuppressWarnings("unchecked")
private List handleList(ExecutionContext executionContext,
List values, String fieldName, List fields,
GraphQLObjectType parentType, GraphQLList listType) {
List flattenedNodeValues = new ArrayList();
for (GraphQLExecutionNodeValue value : values) {
if (value.getValue() == null) {
value.getResultContainer().putResult(fieldName, null);
} else {
GraphQLExecutionResultList flattenedDatum = value.getResultContainer().createAndPutEmptyChildList(
fieldName);
for (Object rawValue : (List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy