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.
* query {
* friends {
* id
* name
* friends {
* id
* name
* }
* }
* enemies {
* id
* name
* allies {
* id
* name
* }
* }
* }
*
*
*
* Given the graphql query above, an execution strategy will be called for the top level fields 'friends' and 'enemies' and it will be asked to find an object
* to describe them. Because they are both complex object types, it needs to descend down that query and start fetching and completing
* fields such as 'id','name' and other complex fields such as 'friends' and 'allies', by recursively calling to itself to execute these lower
* field layers
*
* The execution of a field has two phases, first a raw object must be fetched for a field via a {@link DataFetcher} which
* is defined on the {@link GraphQLFieldDefinition}. This object must then be 'completed' into a suitable value, either as a scalar/enum type via
* coercion or if its a complex object type by recursively calling the execution strategy for the lower level fields.
*
* The first phase (data fetching) is handled by the method {@link #fetchField(ExecutionContext, ExecutionStrategyParameters)}
*
* The second phase (value completion) is handled by the methods {@link #completeField(ExecutionContext, ExecutionStrategyParameters, FetchedValue)}
* and the other "completeXXX" methods.
*
* Normally the executor can execute the entries in a grouped field set in whatever order it chooses (often in parallel). Because
* the resolution of fields other than top-level mutation fields must always be side effect-free and idempotent, the
* execution order must not affect the result, and hence the server has the freedom to execute the
* field entries in whatever order it deems optimal.
*
*
* So in the case above you could execute the fields depth first ('friends' and its sub fields then do 'enemies' and its sub fields or it
* could do breadth first ('fiends' and 'enemies' data fetch first and then all the sub fields) or in parallel via asynchronous
* facilities like {@link CompletableFuture}s.
*
* {@link #execute(ExecutionContext, ExecutionStrategyParameters)} is the entry point of the execution strategy.
*/
@PublicSpi
@SuppressWarnings("FutureReturnValueIgnored")
public abstract class ExecutionStrategy {
private static final Logger log = LoggerFactory.getLogger(ExecutionStrategy.class);
protected final ValuesResolver valuesResolver = new ValuesResolver();
protected final FieldCollector fieldCollector = new FieldCollector();
private final ExecutionStepInfoFactory executionStepInfoFactory = new ExecutionStepInfoFactory();
private final ResolveType resolvedType = new ResolveType();
protected final DataFetcherExceptionHandler dataFetcherExceptionHandler;
/**
* The default execution strategy constructor uses the {@link SimpleDataFetcherExceptionHandler}
* for data fetching errors.
*/
protected ExecutionStrategy() {
dataFetcherExceptionHandler = new SimpleDataFetcherExceptionHandler();
}
/**
* The consumers of the execution strategy can pass in a {@link DataFetcherExceptionHandler} to better
* decide what do when a data fetching error happens
*
* @param dataFetcherExceptionHandler the callback invoked if an exception happens during data fetching
*/
protected ExecutionStrategy(DataFetcherExceptionHandler dataFetcherExceptionHandler) {
this.dataFetcherExceptionHandler = dataFetcherExceptionHandler;
}
/**
* This is the entry point to an execution strategy. It will be passed the fields to execute and get values for.
*
* @param executionContext contains the top level execution parameters
* @param parameters contains the parameters holding the fields to be executed and source object
*
* @return a promise to an {@link ExecutionResult}
*
* @throws NonNullableFieldWasNullException in the future if a non null field resolves to a null value
*/
public abstract CompletableFuture execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException;
/**
* Called to fetch a value for a field and resolve it further in terms of the graphql query. This will call
* #fetchField followed by #completeField and the completed {@link ExecutionResult} is returned.
*
* An execution strategy can iterate the fields to be executed and call this method for each one
*
* Graphql fragments mean that for any give logical field can have one or more {@link Field} values associated with it
* in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
*
* @param executionContext contains the top level execution parameters
* @param parameters contains the parameters holding the fields to be executed and source object
*
* @return a promise to an {@link ExecutionResult}
*
* @throws NonNullableFieldWasNullException in the future if a non null field resolves to a null value
*/
protected CompletableFuture resolveField(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
return resolveFieldWithInfo(executionContext, parameters).thenCompose(FieldValueInfo::getFieldValue);
}
/**
* Called to fetch a value for a field and its extra runtime info and resolve it further in terms of the graphql query. This will call
* #fetchField followed by #completeField and the completed {@link graphql.execution.FieldValueInfo} is returned.
*
* An execution strategy can iterate the fields to be executed and call this method for each one
*
* Graphql fragments mean that for any give logical field can have one or more {@link Field} values associated with it
* in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
*
* @param executionContext contains the top level execution parameters
* @param parameters contains the parameters holding the fields to be executed and source object
*
* @return a promise to a {@link FieldValueInfo}
*
* @throws NonNullableFieldWasNullException in the {@link FieldValueInfo#getFieldValue()} future if a non null field resolves to a null value
*/
protected CompletableFuture resolveFieldWithInfo(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
GraphQLFieldDefinition fieldDef = getFieldDef(executionContext, parameters, parameters.getField().getSingleField());
Instrumentation instrumentation = executionContext.getInstrumentation();
InstrumentationContext fieldCtx = instrumentation.beginField(
new InstrumentationFieldParameters(executionContext, fieldDef, createExecutionStepInfo(executionContext, parameters, fieldDef, null))
);
CompletableFuture fetchFieldFuture = fetchField(executionContext, parameters);
CompletableFuture result = fetchFieldFuture.thenApply((fetchedValue) ->
completeField(executionContext, parameters, fetchedValue));
CompletableFuture executionResultFuture = result.thenCompose(FieldValueInfo::getFieldValue);
fieldCtx.onDispatched(executionResultFuture);
executionResultFuture.whenComplete(fieldCtx::onCompleted);
return result;
}
protected CompletableFuture resolveFieldWithInfoToNull(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
FetchedValue fetchedValue = FetchedValue.newFetchedValue().build();
FieldValueInfo fieldValueInfo = completeField(executionContext, parameters, fetchedValue);
return CompletableFuture.completedFuture(fieldValueInfo);
}
/**
* Called to fetch a value for a field from the {@link DataFetcher} associated with the field
* {@link GraphQLFieldDefinition}.
*
* Graphql fragments mean that for any give logical field can have one or more {@link Field} values associated with it
* in the query, hence the fieldList. However the first entry is representative of the field for most purposes.
*
* @param executionContext contains the top level execution parameters
* @param parameters contains the parameters holding the fields to be executed and source object
*
* @return a promise to a fetched object
*
* @throws NonNullableFieldWasNullException in the future if a non null field resolves to a null value
*/
protected CompletableFuture fetchField(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
MergedField field = parameters.getField();
GraphQLObjectType parentType = (GraphQLObjectType) parameters.getExecutionStepInfo().getUnwrappedNonNullType();
GraphQLFieldDefinition fieldDef = getFieldDef(executionContext.getGraphQLSchema(), parentType, field.getSingleField());
GraphQLCodeRegistry codeRegistry = executionContext.getGraphQLSchema().getCodeRegistry();
Map argumentValues = valuesResolver.getArgumentValues(codeRegistry, fieldDef.getArguments(), field.getArguments(), executionContext.getVariables());
QueryDirectivesImpl queryDirectives = new QueryDirectivesImpl(field, executionContext.getGraphQLSchema(), executionContext.getVariables());
GraphQLOutputType fieldType = fieldDef.getType();
DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(executionContext, fieldType, parameters.getField());
ExecutionStepInfo executionStepInfo = createExecutionStepInfo(executionContext, parameters, fieldDef, parentType);
DataFetchingEnvironment environment = newDataFetchingEnvironment(executionContext)
.source(parameters.getSource())
.localContext(parameters.getLocalContext())
.arguments(argumentValues)
.fieldDefinition(fieldDef)
.mergedField(parameters.getField())
.fieldType(fieldType)
.executionStepInfo(executionStepInfo)
.parentType(parentType)
.selectionSet(fieldCollector)
.queryDirectives(queryDirectives)
.build();
DataFetcher dataFetcher = codeRegistry.getDataFetcher(parentType, fieldDef);
Instrumentation instrumentation = executionContext.getInstrumentation();
InstrumentationFieldFetchParameters instrumentationFieldFetchParams = new InstrumentationFieldFetchParameters(executionContext, fieldDef, environment, parameters, dataFetcher instanceof TrivialDataFetcher);
InstrumentationContext