Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/main/java/graphql/execution/ExecutionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import graphql.language.Document;
import graphql.language.FragmentDefinition;
import graphql.language.OperationDefinition;
import graphql.normalized.NormalizedQueryTreeFactory;
import graphql.normalized.NormalizedQueryTree;
import graphql.schema.GraphQLSchema;
import graphql.util.FpKit;
import org.dataloader.DataLoaderRegistry;

import java.util.Collections;
Expand All @@ -21,6 +24,7 @@
import java.util.Set;
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.function.Supplier;

@SuppressWarnings("TypeParameterUnusedInFormals")
@PublicApi
Expand Down Expand Up @@ -112,6 +116,7 @@ public Map<String, Object> getVariables() {
public <T> T getContext() {
return (T) context;
}

@SuppressWarnings("unchecked")
public <T> T getLocalContext() {
return (T) localContext;
Expand Down Expand Up @@ -195,6 +200,10 @@ public ExecutionStrategy getSubscriptionStrategy() {
return subscriptionStrategy;
}

public Supplier<NormalizedQueryTree> getNormalizedQueryTree() {
return FpKit.interThreadMemoize(() -> NormalizedQueryTreeFactory.createNormalizedQuery(graphQLSchema, operationDefinition, fragmentsByName, variables));
}

/**
* This helps you transform the current ExecutionContext object into another one by starting a builder with all
* the current values and allows you to transform it how you want.
Expand Down
19 changes: 13 additions & 6 deletions src/main/java/graphql/execution/ExecutionStepInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class ExecutionStepInfo {

/**
* If this StepInfo represent a field the type is equal to fieldDefinition.getType()
*
* <p>
* if this StepInfo is a list element this type is the actual current list element. For example:
* Query.pets: [[Pet]] with Pet either a Dog or Cat and the actual result is [[Dog1],[[Cat1]]
* Then the type is (for a query "{pets{name}}"):
Expand All @@ -58,7 +58,7 @@ public class ExecutionStepInfo {

/**
* field, fieldDefinition, fieldContainer and arguments differ per field StepInfo.
*
* <p>
* But for list StepInfos these properties are the same as the field returning the list.
*/
private final MergedField field;
Expand All @@ -82,14 +82,23 @@ private ExecutionStepInfo(GraphQLOutputType type,
this.fieldContainer = fieldsContainer;
}

/**
* @return the GraphQLObjectType defining the {@link #getFieldDefinition()}
* @deprecated use {@link #getObjectType()} instead as it is named better
* @see ExecutionStepInfo#getObjectType()
*/
public GraphQLObjectType getFieldContainer() {
return fieldContainer;
}

/**
* The GraphQLObjectType where fieldDefinition is defined.
* Note:
* For the Introspection field __typename the returned object type doesn't actually contain the fieldDefinition.
*
* @return GraphQLObjectType defining {@link #getFieldDefinition()}
* @return the GraphQLObjectType defining the {@link #getFieldDefinition()}
*/
public GraphQLObjectType getFieldContainer() {
public GraphQLObjectType getObjectType() {
return fieldContainer;
}

Expand Down Expand Up @@ -163,7 +172,6 @@ public Map<String, Object> getArguments() {
*
* @param name the name of the argument
* @param <T> you decide what type it is
*
* @return the named argument or null if its not present
*/
@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -192,7 +200,6 @@ public boolean hasParent() {
* after type resolution has occurred
*
* @param newType the new type to be
*
* @return a new type info with the same
*/
public ExecutionStepInfo changeTypeWithPreservedNonNull(GraphQLOutputType newType) {
Expand Down
21 changes: 15 additions & 6 deletions src/main/java/graphql/execution/ExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import graphql.introspection.Introspection;
import graphql.language.Argument;
import graphql.language.Field;
import graphql.normalized.NormalizedField;
import graphql.normalized.NormalizedQueryTree;
import graphql.schema.CoercingSerializeException;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
Expand Down Expand Up @@ -190,7 +192,7 @@ protected CompletableFuture<ExecutionResult> resolveField(ExecutionContext execu
*/
protected CompletableFuture<FieldValueInfo> resolveFieldWithInfo(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
GraphQLFieldDefinition fieldDef = getFieldDef(executionContext, parameters, parameters.getField().getSingleField());
Supplier<ExecutionStepInfo> executionStepInfo = FpKit.memoize(() -> createExecutionStepInfo(executionContext, parameters, fieldDef, null));
Supplier<ExecutionStepInfo> executionStepInfo = FpKit.intraThreadMemoize(() -> createExecutionStepInfo(executionContext, parameters, fieldDef, null));

Instrumentation instrumentation = executionContext.getInstrumentation();
InstrumentationContext<ExecutionResult> fieldCtx = instrumentation.beginField(
Expand Down Expand Up @@ -235,15 +237,17 @@ protected CompletableFuture<FetchedValue> fetchField(ExecutionContext executionC
GraphQLCodeRegistry codeRegistry = executionContext.getGraphQLSchema().getCodeRegistry();
GraphQLOutputType fieldType = fieldDef.getType();

// DataFetchingFieldSelectionSet and QueryDirectives is a supplier of sorts - eg a lazy pattern
DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(executionContext, fieldType, parameters.getField());
QueryDirectives queryDirectives = new QueryDirectivesImpl(field, executionContext.getGraphQLSchema(), executionContext.getVariables());

// if the DF (like PropertyDataFetcher) does not use the arguments of execution step info then dont build any
Supplier<ExecutionStepInfo> executionStepInfo = FpKit.memoize(
Supplier<ExecutionStepInfo> executionStepInfo = FpKit.intraThreadMemoize(
() -> createExecutionStepInfo(executionContext, parameters, fieldDef, parentType));
Supplier<Map<String, Object>> argumentValues = () -> executionStepInfo.get().getArguments();

Supplier<NormalizedField> normalizedFieldSupplier = getNormalizedField(executionContext, parameters, executionStepInfo);

// DataFetchingFieldSelectionSet and QueryDirectives is a supplier of sorts - eg a lazy pattern
DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(fieldType, normalizedFieldSupplier);
QueryDirectives queryDirectives = new QueryDirectivesImpl(field, executionContext.getGraphQLSchema(), executionContext.getVariables());


DataFetchingEnvironment environment = newDataFetchingEnvironment(executionContext)
.source(parameters.getSource())
Expand Down Expand Up @@ -293,6 +297,11 @@ protected CompletableFuture<FetchedValue> fetchField(ExecutionContext executionC
.thenApply(result -> unboxPossibleDataFetcherResult(executionContext, parameters, result));
}

protected Supplier<NormalizedField> getNormalizedField(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Supplier<ExecutionStepInfo> executionStepInfo) {
Supplier<NormalizedQueryTree> normalizedQuery = executionContext.getNormalizedQueryTree();
return () -> normalizedQuery.get().getNormalizedField(parameters.getField(), executionStepInfo.get().getObjectType(), executionStepInfo.get().getPath());
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All made as Supplier to ensure its super lazy - lets not pay any cost unless some one asks for this.


protected FetchedValue unboxPossibleDataFetcherResult(ExecutionContext executionContext,
ExecutionStrategyParameters parameters,
Object result) {
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/graphql/execution/ResultPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,24 @@ public List<Object> toList() {
return list;
}

/**
* @return this path as a list of result keys, without any indices
*/
public List<String> getKeysOnly() {
if (parent == null) {
return new LinkedList<>();
}
LinkedList<String> list = new LinkedList<>();
ResultPath p = this;
while (p.segment != null) {
if (p.segment instanceof String) {
list.addFirst((String) p.segment);
}
p = p.parent;
}
return list;
}


/**
* @return the path as a string which represents the call hierarchy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters;
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters;
import graphql.execution.instrumentation.parameters.InstrumentationFieldParameters;
import graphql.normalized.NormalizedField;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.DataFetchingFieldSelectionSet;
Expand Down Expand Up @@ -52,6 +53,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.IntStream;

import static graphql.execution.ExecutionStepInfo.newExecutionStepInfo;
Expand Down Expand Up @@ -248,8 +250,10 @@ private CompletableFuture<FetchedValues> fetchData(ExecutionContext executionCon

QueryDirectivesImpl queryDirectives = new QueryDirectivesImpl(fields, executionContext.getGraphQLSchema(), executionContext.getVariables());

Supplier<NormalizedField> normalizedFieldSupplier = getNormalizedField(executionContext, parameters, parameters::getExecutionStepInfo);

GraphQLOutputType fieldType = fieldDef.getType();
DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(executionContext, fieldType, fields);
DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(fieldType, normalizedFieldSupplier);

DataFetchingEnvironment environment = newDataFetchingEnvironment(executionContext)
.source(node.getSources())
Expand Down
11 changes: 8 additions & 3 deletions src/main/java/graphql/execution/nextgen/ValueFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import graphql.execution.ValuesResolver;
import graphql.execution.directives.QueryDirectivesImpl;
import graphql.language.Field;
import graphql.normalized.NormalizedField;
import graphql.normalized.NormalizedQueryTree;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.DataFetchingFieldSelectionSet;
Expand Down Expand Up @@ -117,12 +119,15 @@ public CompletableFuture<FetchedValue> fetchValue(ExecutionContext executionCont
GraphQLCodeRegistry codeRegistry = executionContext.getGraphQLSchema().getCodeRegistry();
GraphQLFieldsContainer parentType = getFieldsContainer(executionInfo);

Supplier<Map<String, Object>> argumentValues = FpKit.memoize(() -> valuesResolver.getArgumentValues(codeRegistry, fieldDef.getArguments(), field.getArguments(), executionContext.getVariables()));
Supplier<Map<String, Object>> argumentValues = FpKit.intraThreadMemoize(() -> valuesResolver.getArgumentValues(codeRegistry, fieldDef.getArguments(), field.getArguments(), executionContext.getVariables()));

QueryDirectivesImpl queryDirectives = new QueryDirectivesImpl(sameFields, executionContext.getGraphQLSchema(), executionContext.getVariables());

GraphQLOutputType fieldType = fieldDef.getType();
DataFetchingFieldSelectionSet fieldCollector = DataFetchingFieldSelectionSetImpl.newCollector(executionContext, fieldType, sameFields);

Supplier<NormalizedQueryTree> normalizedQuery = executionContext.getNormalizedQueryTree();
Supplier<NormalizedField> normalisedField = () -> normalizedQuery.get().getNormalizedField(sameFields, executionInfo.getObjectType(), executionInfo.getPath());
DataFetchingFieldSelectionSet selectionSet = DataFetchingFieldSelectionSetImpl.newCollector(fieldType, normalisedField);

DataFetchingEnvironment environment = newDataFetchingEnvironment(executionContext)
.source(source)
Expand All @@ -133,7 +138,7 @@ public CompletableFuture<FetchedValue> fetchValue(ExecutionContext executionCont
.fieldType(fieldType)
.executionStepInfo(executionInfo)
.parentType(parentType)
.selectionSet(fieldCollector)
.selectionSet(selectionSet)
.queryDirectives(queryDirectives)
.build();

Expand Down
Loading