graphql.nadel.engine.execution.ServiceResultToResultNodes Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nadel-engine Show documentation
Show all versions of nadel-engine Show documentation
Nadel is a Java library that combines multiple GrahpQL services together into one API.
The newest version!
package graphql.nadel.engine.execution;
import graphql.GraphQLError;
import graphql.Scalars;
import graphql.SerializationError;
import graphql.TypeMismatchError;
import graphql.execution.ExecutionContext;
import graphql.execution.ResultPath;
import graphql.nadel.ServiceExecutionResult;
import graphql.nadel.engine.NadelContext;
import graphql.nadel.engine.result.ElapsedTime;
import graphql.nadel.engine.result.ExecutionResultNode;
import graphql.nadel.engine.result.LeafExecutionResultNode;
import graphql.nadel.engine.result.ListExecutionResultNode;
import graphql.nadel.engine.result.NonNullableFieldWasNullError;
import graphql.nadel.engine.result.ObjectExecutionResultNode;
import graphql.nadel.engine.result.RootExecutionResultNode;
import graphql.nadel.normalized.NormalizedQueryField;
import graphql.nadel.normalized.NormalizedQueryFromAst;
import graphql.nadel.util.ErrorUtil;
import graphql.schema.CoercingSerializeException;
import graphql.schema.GraphQLEnumType;
import graphql.schema.GraphQLList;
import graphql.schema.GraphQLNonNull;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLOutputType;
import graphql.schema.GraphQLScalarType;
import graphql.schema.GraphQLType;
import graphql.schema.GraphQLTypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertTrue;
import static graphql.nadel.engine.result.LeafExecutionResultNode.newLeafExecutionResultNode;
import static graphql.nadel.engine.result.ObjectExecutionResultNode.newObjectExecutionResultNode;
import static graphql.schema.GraphQLTypeUtil.isList;
public class ServiceResultToResultNodes {
private static final Logger log = LoggerFactory.getLogger(ServiceResultToResultNodes.class);
/**
* Creates a {@link RootExecutionResultNode} with the specified top level field
* set to null and with the given GraphQL errors and extensions put in the result.
*
* @param query the query being executed (can be overall query)
* @param topLevelField the top level field to null out
* @param errors the errors to put into the overall result
* @param extensions the extensions to put into the overall result
* @return the overall result constructed as per the above description
*/
public RootExecutionResultNode createResultWithNullTopLevelField(NormalizedQueryFromAst query,
NormalizedQueryField topLevelField,
List errors,
Map extensions) {
// Get random data that's required
ElapsedTime zeroElapsedTime = ElapsedTime.newElapsedTime().start().stop().build();
List fieldIds = query.getFieldIds(topLevelField);
ResultPath path = ResultPath.rootPath().segment(topLevelField.getResultKey());
LeafExecutionResultNode nullTopLevelField = createNullERN(topLevelField, path, fieldIds, zeroElapsedTime);
return RootExecutionResultNode.newRootExecutionResultNode()
.errors(errors)
.extensions(extensions)
.elapsedTime(zeroElapsedTime)
.addChild(nullTopLevelField)
.build();
}
public RootExecutionResultNode resultToResultNode(ExecutionContext executionContext,
ServiceExecutionResult serviceExecutionResult,
ElapsedTime elapsedTimeForServiceCall,
NormalizedQueryFromAst normalizedQueryFromAst) {
long startTime = System.currentTimeMillis();
RootExecutionResultNode rootExecutionResultNodeNoData = resultNodeWithoutData(serviceExecutionResult, elapsedTimeForServiceCall);
RootExecutionResultNode rootExecutionResultNode = fetchTopLevelFields(rootExecutionResultNodeNoData, executionContext, serviceExecutionResult, elapsedTimeForServiceCall, normalizedQueryFromAst);
long elapsedTime = System.currentTimeMillis() - startTime;
log.debug("ServiceResultToResultNodes time: {} ms, executionId: {}", elapsedTime, executionContext.getExecutionId());
return rootExecutionResultNode;
}
private RootExecutionResultNode resultNodeWithoutData(ServiceExecutionResult serviceExecutionResult, ElapsedTime elapsedTimeForServiceCall) {
List errors = ErrorUtil.createGraphQlErrorsFromRawErrors(serviceExecutionResult.getErrors());
Map extensions = serviceExecutionResult.getExtensions();
return RootExecutionResultNode.newRootExecutionResultNode()
.errors(errors)
.extensions(extensions)
.elapsedTime(elapsedTimeForServiceCall)
.build();
}
private RootExecutionResultNode fetchTopLevelFields(RootExecutionResultNode rootNode,
ExecutionContext executionContext,
ServiceExecutionResult serviceExecutionResult,
ElapsedTime elapsedTime,
NormalizedQueryFromAst normalizedQueryFromAst) {
List topLevelFields = normalizedQueryFromAst.getTopLevelFields();
ResultPath rootPath = ResultPath.rootPath();
Object source = serviceExecutionResult.getData();
List children = new ArrayList<>(topLevelFields.size());
for (NormalizedQueryField topLevelField : topLevelFields) {
ResultPath path = rootPath.segment(topLevelField.getResultKey());
List fieldIds = normalizedQueryFromAst.getFieldIds(topLevelField);
ExecutionResultNode executionResultNode = fetchAndAnalyzeField(executionContext, source, topLevelField, normalizedQueryFromAst, path, fieldIds, elapsedTime);
children.add(executionResultNode);
}
return (RootExecutionResultNode) rootNode.withNewChildren(children);
}
private ExecutionResultNode fetchAndAnalyzeField(ExecutionContext context,
Object source,
NormalizedQueryField normalizedQueryField,
NormalizedQueryFromAst normalizedQueryFromAst,
ResultPath executionPath,
List fieldIds,
ElapsedTime elapsedTime) {
Object fetchedValue = fetchValue(source, normalizedQueryField.getResultKey());
return analyzeValue(context, fetchedValue, normalizedQueryField, normalizedQueryFromAst, executionPath, fieldIds, elapsedTime);
}
private Object fetchValue(Object source, String key) {
if (source == null) {
return null;
}
@SuppressWarnings("unchecked")
Map map = (Map) source;
return map.get(key);
}
private ExecutionResultNode analyzeValue(ExecutionContext executionContext,
Object fetchedValue,
NormalizedQueryField normalizedQueryField,
NormalizedQueryFromAst normalizedQueryFromAst,
ResultPath executionPath,
List fieldIds,
ElapsedTime elapsedTime) {
return analyzeFetchedValueImpl(executionContext, fetchedValue, normalizedQueryField, normalizedQueryFromAst, normalizedQueryField.getFieldDefinition().getType(), executionPath, fieldIds, elapsedTime);
}
private ExecutionResultNode analyzeFetchedValueImpl(ExecutionContext executionContext,
Object toAnalyze,
NormalizedQueryField normalizedQueryField,
NormalizedQueryFromAst normalizedQueryFromAst,
GraphQLOutputType curType,
ResultPath executionPath,
List fieldIds,
ElapsedTime elapsedTime) {
boolean isNonNull = GraphQLTypeUtil.isNonNull(curType);
if (toAnalyze == null && isNonNull) {
NonNullableFieldWasNullError nonNullableFieldWasNullError = new NonNullableFieldWasNullError((GraphQLNonNull) curType, executionPath);
return createNullERNWithNullableError(normalizedQueryField, executionPath, fieldIds, elapsedTime, nonNullableFieldWasNullError);
} else if (toAnalyze == null) {
return createNullERN(normalizedQueryField, executionPath, fieldIds, elapsedTime);
}
curType = (GraphQLOutputType) GraphQLTypeUtil.unwrapNonNull(curType);
if (isList(curType)) {
return analyzeList(executionContext, toAnalyze, (GraphQLList) curType, normalizedQueryField, normalizedQueryFromAst, executionPath, fieldIds, elapsedTime);
} else if (curType instanceof GraphQLScalarType) {
return analyzeScalarValue(toAnalyze, (GraphQLScalarType) curType, normalizedQueryField, executionPath, fieldIds, elapsedTime);
} else if (curType instanceof GraphQLEnumType) {
return analyzeEnumValue(toAnalyze, (GraphQLEnumType) curType, normalizedQueryField, executionPath, fieldIds, elapsedTime);
}
GraphQLObjectType resolvedObjectType = resolveType(executionContext, toAnalyze, curType);
return resolveObject(executionContext, normalizedQueryField, fieldIds, normalizedQueryFromAst, resolvedObjectType, toAnalyze, executionPath, elapsedTime);
}
private ObjectExecutionResultNode resolveObject(ExecutionContext context,
NormalizedQueryField normalizedField,
List objectFieldIds,
NormalizedQueryFromAst normalizedQueryFromAst,
GraphQLObjectType resolvedType,
Object completedValue,
ResultPath executionPath,
ElapsedTime elapsedTime) {
List nodeChildren = new ArrayList<>(normalizedField.getChildren().size());
for (NormalizedQueryField child : normalizedField.getChildren()) {
if (child.getObjectType() == resolvedType) {
ResultPath pathForChild = executionPath.segment(child.getResultKey());
List fieldIds = normalizedQueryFromAst.getFieldIds(child);
ExecutionResultNode childNode = fetchAndAnalyzeField(context, completedValue, child, normalizedQueryFromAst, pathForChild, fieldIds, elapsedTime);
nodeChildren.add(childNode);
}
}
return newObjectExecutionResultNode()
.resultPath(executionPath)
.alias(normalizedField.getAlias())
.fieldIds(objectFieldIds)
.objectType(normalizedField.getObjectType())
.fieldDefinition(normalizedField.getFieldDefinition())
.completedValue(completedValue)
.children(nodeChildren)
.elapsedTime(elapsedTime)
.build();
}
private ExecutionResultNode analyzeList(ExecutionContext executionContext,
Object toAnalyze,
GraphQLList curType,
NormalizedQueryField normalizedQueryField,
NormalizedQueryFromAst normalizedQueryFromAst,
ResultPath executionPath,
List fieldIds,
ElapsedTime elapsedTime) {
if (toAnalyze instanceof List) {
return createListImpl(executionContext, toAnalyze, (List