Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
graphql.execution2.ValueFetcher Maven / Gradle / Ivy
package graphql.execution2;
import graphql.Assert;
import graphql.ExceptionWhileDataFetching;
import graphql.GraphQLError;
import graphql.Internal;
import graphql.execution.AbsoluteGraphQLError;
import graphql.execution.Async;
import graphql.execution.DataFetcherResult;
import graphql.execution.ExecutionContext;
import graphql.execution.ExecutionId;
import graphql.execution.ExecutionPath;
import graphql.execution.ExecutionStepInfo;
import graphql.execution.UnboxPossibleOptional;
import graphql.execution.ValuesResolver;
import graphql.language.Field;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.DataFetchingFieldSelectionSet;
import graphql.schema.DataFetchingFieldSelectionSetImpl;
import graphql.schema.GraphQLCodeRegistry;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLFieldsContainer;
import graphql.schema.GraphQLOutputType;
import graphql.schema.GraphQLTypeUtil;
import graphql.schema.visibility.GraphqlFieldVisibility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
import static graphql.schema.DataFetchingEnvironmentBuilder.newDataFetchingEnvironment;
@Internal
public class ValueFetcher {
private final ExecutionContext executionContext;
ValuesResolver valuesResolver = new ValuesResolver();
private static final Logger log = LoggerFactory.getLogger(ValueFetcher.class);
public static final Object NULL_VALUE = new Object();
public ValueFetcher(ExecutionContext executionContext) {
this.executionContext = executionContext;
}
public CompletableFuture> fetchBatchedValues(List sources, List sameFields, List executionInfos) {
System.out.println("Fetch batch values size: " + sources.size());
ExecutionStepInfo executionStepInfo = executionInfos.get(0);
if (isDataFetcherBatched(executionStepInfo)) {
//TODO: the stepInfo is not correct for all values: how to give the DF all executionInfos?
return fetchValue(sources, sameFields, executionStepInfo)
.thenApply(fetchedValue -> extractBatchedValues(fetchedValue, sources.size()));
} else {
List> fetchedValues = new ArrayList<>();
for (int i = 0; i < sources.size(); i++) {
fetchedValues.add(fetchValue(sources.get(i), sameFields, executionInfos.get(i)));
}
return Async.each(fetchedValues);
}
}
private List extractBatchedValues(FetchedValue fetchedValueContainingList, int expectedSize) {
List list = (List) fetchedValueContainingList.getFetchedValue();
Assert.assertTrue(list.size() == expectedSize, "Unexpected result size");
List result = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
List errors;
if (i == 0) {
errors = fetchedValueContainingList.getErrors();
} else {
errors = Collections.emptyList();
}
FetchedValue fetchedValue = new FetchedValue(list.get(0), fetchedValueContainingList.getRawFetchedValue(), errors);
result.add(fetchedValue);
}
return result;
}
private GraphQLFieldsContainer getFieldsContainer(ExecutionStepInfo executionStepInfo) {
GraphQLOutputType type = executionStepInfo.getParent().getType();
return (GraphQLFieldsContainer) GraphQLTypeUtil.unwrapAll(type);
}
private boolean isDataFetcherBatched(ExecutionStepInfo executionStepInfo) {
GraphQLFieldsContainer parentType = getFieldsContainer(executionStepInfo);
GraphQLFieldDefinition fieldDef = executionStepInfo.getFieldDefinition();
DataFetcher dataFetcher = executionContext.getGraphQLSchema().getCodeRegistry().getDataFetcher(parentType, fieldDef);
return dataFetcher instanceof BatchedDataFetcher;
}
public CompletableFuture fetchValue(Object source, List sameFields, ExecutionStepInfo executionInfo) {
Field field = sameFields.get(0);
GraphQLFieldDefinition fieldDef = executionInfo.getFieldDefinition();
GraphQLCodeRegistry codeRegistry = executionContext.getGraphQLSchema().getCodeRegistry();
GraphqlFieldVisibility fieldVisibility = codeRegistry.getFieldVisibility();
GraphQLFieldsContainer parentType = getFieldsContainer(executionInfo);
Map argumentValues = valuesResolver.getArgumentValues(fieldVisibility, fieldDef.getArguments(), field.getArguments(), executionContext.getVariables());
GraphQLOutputType fieldType = fieldDef.getType();
DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(executionContext, fieldType, sameFields);
DataFetchingEnvironment environment = newDataFetchingEnvironment(executionContext)
.source(source)
.arguments(argumentValues)
.fieldDefinition(fieldDef)
.fields(sameFields)
.fieldType(fieldType)
.executionStepInfo(executionInfo)
.parentType(parentType)
.selectionSet(fieldCollector)
.build();
ExecutionId executionId = executionContext.getExecutionId();
ExecutionPath path = executionInfo.getPath();
return callDataFetcher(codeRegistry, parentType, fieldDef, environment, executionId, path)
.thenApply(rawFetchedValue -> new FetchedValue(rawFetchedValue, rawFetchedValue, Collections.emptyList()))
.exceptionally(exception -> handleExceptionWhileFetching(field, path, exception))
.thenApply(result -> unboxPossibleDataFetcherResult(sameFields, path, result))
.thenApply(this::unboxPossibleOptional);
}
private FetchedValue handleExceptionWhileFetching(Field field, ExecutionPath path, Throwable exception) {
ExceptionWhileDataFetching exceptionWhileDataFetching = new ExceptionWhileDataFetching(path, exception, field.getSourceLocation());
FetchedValue fetchedValue = new FetchedValue(
null,
null,
Collections.singletonList(exceptionWhileDataFetching));
return fetchedValue;
}
private FetchedValue unboxPossibleOptional(FetchedValue result) {
return new FetchedValue(UnboxPossibleOptional.unboxPossibleOptional(result.getFetchedValue()), result.getRawFetchedValue(), result.getErrors());
}
private CompletableFuture callDataFetcher(GraphQLCodeRegistry codeRegistry, GraphQLFieldsContainer parentType, GraphQLFieldDefinition fieldDef, DataFetchingEnvironment environment, ExecutionId executionId, ExecutionPath path) {
CompletableFuture result = new CompletableFuture<>();
try {
DataFetcher dataFetcher = codeRegistry.getDataFetcher(parentType, fieldDef);
log.debug("'{}' fetching field '{}' using data fetcher '{}'...", executionId, path, dataFetcher.getClass().getName());
Object fetchedValueRaw = dataFetcher.get(environment);
log.debug("'{}' field '{}' fetch returned '{}'", executionId, path, fetchedValueRaw == null ? "null" : fetchedValueRaw.getClass().getName());
handleFetchedValue(fetchedValueRaw, result);
} catch (Exception e) {
log.debug(String.format("'%s', field '%s' fetch threw exception", executionId, path), e);
result.completeExceptionally(e);
}
return result;
}
private void handleFetchedValue(Object fetchedValue, CompletableFuture cf) {
if (fetchedValue == null) {
cf.complete(NULL_VALUE);
return;
}
if (fetchedValue instanceof CompletionStage) {
((CompletionStage) fetchedValue).whenComplete((value, throwable) -> {
if (throwable != null) {
cf.completeExceptionally(throwable);
} else {
cf.complete(value);
}
});
return;
}
cf.complete(fetchedValue);
}
private FetchedValue unboxPossibleDataFetcherResult(List sameField, ExecutionPath executionPath, FetchedValue result) {
if (result.getFetchedValue() instanceof DataFetcherResult) {
DataFetcherResult> dataFetcherResult = (DataFetcherResult) result.getFetchedValue();
List addErrors = dataFetcherResult.getErrors().stream()
.map(relError -> new AbsoluteGraphQLError(sameField, executionPath, relError))
.collect(Collectors.toList());
List newErrors = new ArrayList<>(result.getErrors());
newErrors.addAll(addErrors);
return new FetchedValue(dataFetcherResult.getData(), result.getRawFetchedValue(), newErrors);
} else {
return result;
}
}
}