Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
0ba108b
- DependencyGraph initial implementation
gkesler Dec 29, 2018
17f6a30
- simplified Vertex definition not to rely on a DependencyGraph
gkesler Dec 29, 2018
77a20a2
- refactored DependencyGraph.edges set to be backed by its vertices m…
gkesler Dec 29, 2018
61ae699
- further simplified implementation, added Edge.connectEndpoints and …
gkesler Dec 30, 2018
73cfcbc
- some code cleanup
gkesler Dec 30, 2018
4a4340d
- removed redundant check when calculating next closure of vertices t…
gkesler Dec 30, 2018
931b7fe
- added accessor to Edge.action property
gkesler Dec 31, 2018
1788694
- initial implementation of ExecuitonPlanBuilder
gkesler Jan 9, 2019
700b2ac
- saving current state
gkesler Jan 10, 2019
231d4fb
- saving current state
gkesler Jan 10, 2019
c6d8f04
- saving current state
gkesler Jan 11, 2019
5a43f28
- added computeXXXIfAbsent methods to TraverserContext to search recu…
gkesler Jan 11, 2019
f00e617
- code cleanu
gkesler Jan 11, 2019
8a918f6
- added TriXXX functors
gkesler Jan 11, 2019
9b98db9
- saving current state
gkesler Jan 11, 2019
15a3204
- updated traverse managers to allow custom implementations of Traver…
gkesler Jan 11, 2019
b26d5f4
- refactored traversal in ExecutionPlanBuilder to use custom Traverse…
gkesler Jan 11, 2019
6f7cd5e
- saving current state
gkesler Jan 11, 2019
5d06db0
- removed newly introduced unused funators
gkesler Jan 11, 2019
48f4d5d
eaned up ExecutionPlanBuilder implementation
gkesler Jan 11, 2019
60ae13b
- saving current state
gkesler Jan 12, 2019
e74310a
- code cleanup
gkesler Jan 12, 2019
ef8d638
- some code/expressions simplifications
gkesler Jan 14, 2019
882b99d
- saving current state
gkesler Jan 14, 2019
4125068
- Created ExecutionPlan class as a subclass of DependencyGraph and mo…
gkesler Jan 15, 2019
c2a94c0
- introduced DocumentVertex that passes its [root] data to the FieldV…
gkesler Jan 15, 2019
5790160
- added functional interfaces
gkesler Jan 16, 2019
d96e7f1
- added @FunctionalInterface annotation to TernaryOPerator
gkesler Jan 16, 2019
1fb8f7f
- added DependencyGraphContext interface
gkesler Jan 17, 2019
03e052d
- saving current state
gkesler Jan 17, 2019
771dbc8
- modified Vertex.dependsOn signature to allow brroader range of BiCo…
gkesler Jan 17, 2019
db43359
- simplified Vertex resolution protocol. Got read of canResolve method
gkesler Jan 17, 2019
f7683f7
- saving current state
gkesler Jan 17, 2019
73e7611
- saving current state
gkesler Jan 20, 2019
3425c9e
- Improved Async performance
gkesler Jan 24, 2019
8ddb8fe
- saving current state
gkesler Jan 25, 2019
23b8aeb
- saving current state
gkesler Jan 25, 2019
e53d011
- saving current state
gkesler Jan 26, 2019
40b2a80
- cleaned up propagation of the result holder across non-Field vertices
gkesler Jan 26, 2019
2f71c45
- implemented DAGExecutionStrategy based on DependencyGraph evaluation
gkesler Jan 26, 2019
f8c024f
- code cleanup
gkesler Jan 26, 2019
3fe624b
- overriden ExecutionPlan.orderDependecies method to create thread-sa…
gkesler Jan 26, 2019
83b9e8e
- synchronization optimization in EntityPlan.IteratorImpl
gkesler Jan 26, 2019
4af8a2f
- code cleanup
gkesler Jan 27, 2019
be7dad8
- simplifications and code cleanup
gkesler Jan 28, 2019
48cd644
- code cleanup
gkesler Jan 29, 2019
7eabd64
- code cleanup
gkesler Jan 29, 2019
48a1eb2
Merge branch 'master' into gkesler-dependency-graph
gkesler Jan 30, 2019
cb3f38f
- fixed formatting to reduce number of really changed files
gkesler Jan 30, 2019
92f5071
- corrected DependencyGraph traverser to automatically excluide unres…
gkesler Jan 30, 2019
32da077
Merge branch 'master' into gkesler-dependency-graph
gkesler Feb 21, 2019
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
Prev Previous commit
Next Next commit
- code cleanup
- added javadoc comments
  • Loading branch information
gkesler committed Jan 29, 2019
commit 48cd644fcf217fc445318821c25e8e2f8dc55dd1
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ public class ExecutionStepInfoFactory {

public ExecutionStepInfo newExecutionStepInfoForSubField(ExecutionContext executionContext, List<Field> sameFields, ExecutionStepInfo parentInfo) {
Field field = sameFields.get(0);
// GraphQLObjectType parentType = (GraphQLObjectType) parentInfo.getUnwrappedNonNullType();
GraphQLObjectType parentType = (GraphQLObjectType) GraphQLTypeUtil.unwrapAll(parentInfo.getType());
GraphQLObjectType parentType = (GraphQLObjectType) parentInfo.getUnwrappedNonNullType();
GraphQLFieldDefinition fieldDefinition = Introspection.getFieldDef(executionContext.getGraphQLSchema(), parentType, field.getName());
GraphQLOutputType fieldType = fieldDefinition.getType();
List<Argument> fieldArgs = field.getArguments();
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/graphql/execution3/DAGExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import graphql.language.Node;
import graphql.schema.GraphQLOutputType;
import graphql.schema.GraphQLType;
import graphql.schema.GraphQLTypeUtil;
import graphql.util.DependenciesIterator;
import graphql.util.Edge;
import graphql.util.TriFunction;
Expand All @@ -32,6 +33,8 @@
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
Expand All @@ -48,6 +51,15 @@ public DAGExecutionStrategy (ExecutionContext executionContext) {
this.valueFetcher = new ValueFetcher(executionContext);
}

/**
* Executes a graphql request according to the schedule
* provided by executionPlan
*
* @param executionPlan a {@code graphql.util.DependencyGraph} specialization that provides
* order of field resolution requests
*
* @return a CompletableFuture holding the result of execution.
*/
@Override
public CompletableFuture<ExecutionResult> execute(ExecutionPlan executionPlan) {
assertNotNull(executionPlan);
Expand Down Expand Up @@ -146,8 +158,14 @@ private CompletableFuture<NodeVertex<Node, GraphQLType>> fetchNode (NodeVertex<N

FieldVertex fieldNode = node.as(FieldVertex.class);
List<Field> sameFields = Collections.singletonList(fieldNode.getNode());
ExecutionStepInfo sourceExecutionStepInfo = node.getParentExecutionStepInfo();
GraphQLOutputType parentType = (GraphQLOutputType)GraphQLTypeUtil.unwrapAll(sourceExecutionStepInfo.getType());
ExecutionStepInfo parentExecutionStepInfo = sourceExecutionStepInfo
.transform(builder -> builder
.parentInfo(sourceExecutionStepInfo.getParent())
.type(parentType));
ExecutionStepInfo executionStepInfo = executionInfoFactory
.newExecutionStepInfoForSubField(executionContext, sameFields, node.getParentExecutionStepInfo());
.newExecutionStepInfoForSubField(executionContext, sameFields, parentExecutionStepInfo);

TriFunction<FieldVertex, List<Field>, ExecutionStepInfo, CompletableFuture<List<FetchedValue>>> valuesFetcher =
fieldNode.isRoot() ? this::fetchRootValues : this::fetchBatchedValues;
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/graphql/execution3/DocumentVertex.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@

import graphql.execution.ExecutionStepInfo;
import graphql.language.Document;
import graphql.language.Node;
import graphql.schema.GraphQLType;
import graphql.util.DependencyGraphContext;
import java.util.Objects;

/**
*
* @author gkesler
* ExecutionPlan Vertex created around Document node
*/
public class DocumentVertex extends NodeVertex<Document, GraphQLType> {
public DocumentVertex(Document node) {
Expand Down
30 changes: 24 additions & 6 deletions src/main/java/graphql/execution3/Execution.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,34 @@
import java.util.function.Function;
import static graphql.execution3.ExecutionPlan.newExecutionPlanBuilder;

/**
*
* @author gkesler
*/
public class Execution {
/**
* Executes GraphQL request using {@link graphql.execution3.ExecutionStrategy} class
* to instantiate ExecutionStrategy
*
* @param strategyClass ExecutionStrategy class to instantiate
* @param document root of GraphQL AST
* @param schema GraphQL schema
* @param executionId assigned execution id
* @param executionInput input parameters, variables, etc.
* @return CompletableFuture that when completes holds result of this execution
*/
public CompletableFuture<ExecutionResult> execute (Class<? extends ExecutionStrategy> strategyClass, Document document,
GraphQLSchema schema, ExecutionId executionId, ExecutionInput executionInput) {
return execute(executionContext -> newExecutionStrategy(strategyClass, executionContext), document, schema, executionId, executionInput);
}

/**
* Executes GraphQL request using {@link graphql.execution3.ExecutionStrategy} class
* to instantiate ExecutionStrategy
*
* @param strategyCreator ExecutionStrategy factory
* @param document root of GraphQL AST
* @param schema GraphQL schema
* @param executionId assigned execution id
* @param executionInput input parameters, variables, etc.
* @return CompletableFuture that when completes holds result of this execution
*/
public CompletableFuture<ExecutionResult> execute (Function<? super ExecutionContext, ? extends ExecutionStrategy> strategyCreator, Document document,
GraphQLSchema schema, ExecutionId executionId, ExecutionInput executionInput) {
try {
Expand Down Expand Up @@ -66,8 +84,8 @@ private CompletableFuture<ExecutionResult> doExecute (Function<? super Execution
private static ExecutionStrategy newExecutionStrategy (Class<? extends ExecutionStrategy> strategyClass, ExecutionContext executionContext) {
try {
return strategyClass
.getConstructor(ExecutionContext.class)
.newInstance(executionContext);
.getConstructor(ExecutionContext.class)
.newInstance(executionContext);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
Expand Down
65 changes: 61 additions & 4 deletions src/main/java/graphql/execution3/ExecutionPlan.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,33 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
*
* @author gkesler
*/
class ExecutionPlan extends DependencyGraph<NodeVertex<Node, GraphQLType>> {
/**
* Retrieves GraphQL schema associated with this execution plan
*
* @return GraphQL schema
*/
public GraphQLSchema getSchema() {
return schema;
}

/**
* Retrieves GraphQL AST root Node associated with this execution plan
*
* @return AST root
*/
public Document getDocument() {
return document;
}

/**
* Locates an OperationDefinition corresponding to the specified openationName
* https://facebook.github.io/graphql/June2018/#sec-Executing-Requests
*
* @param operationName name of operation to execute, could be null
* @return OperationDefinition for the specified operation name
* @throws UnknownOperationException if OperationDefinition could not be found
*/
public OperationDefinition getOperation (String operationName) {
if (operationName == null && operationsByName.size() > 1)
throw new UnknownOperationException("Must provide operation name if query contains multiple operations.");
Expand All @@ -72,14 +86,31 @@ public OperationDefinition getOperation (String operationName) {
.orElseThrow(() -> new UnknownOperationException(String.format("Unknown operation named '%s'.", operationName)));
}

/**
* Retrieves all OperationDefinitions that exist in the document keyed off
* their operation names
*
* @return a map containing OperationDefinitions
*/
public Map<String, OperationDefinition> getOperationsByName() {
return Collections.unmodifiableMap(operationsByName);
}

/**
* Retrieves all FragmentDefinitions that exist in the document keyed off
* their fragment names
*
* @return a map containing FragmentDefinitions
*/
public Map<String, FragmentDefinition> getFragmentsByName() {
return Collections.unmodifiableMap(fragmentsByName);
}

/**
* After the ExecutionPLan is built, retrieves coerced variables for the selected operation
*
* @return variables map
*/
public Map<String, Object> getVariables() {
return Collections.unmodifiableMap(variables);
}
Expand Down Expand Up @@ -114,6 +145,12 @@ public synchronized void close(Collection<NodeVertex<Node, GraphQLType>> resolve

}

/**
* Creates and initializes ExecutionContextBuilder
*
* @param operationName selected operation name for this execution
* @return new ExecutionContextBuilder
*/
public ExecutionContextBuilder newExecutionContextBuilder (String operationName) {
return ExecutionContextBuilder.newExecutionContextBuilder()
.graphQLSchema(schema)
Expand Down Expand Up @@ -165,11 +202,25 @@ public TraversalControl visitFragmentDefinition(FragmentDefinition node, Travers
return this;
}

/**
* Adds an operation to the list of selected operations
*
* @param operationName operation name to select
* @return this instance
* @throws {@link graphql.execution.UnknownOperationException} in case the operation is not found
*/
public Builder operation (String operationName) {
operations.add(executionPlan.getOperation(operationName));
return this;
}

/**
* Stores variables for the coercion.
* Note! Coercion happens <b>only</b> at the time of building the execution plan
*
* @param variables variables map
* @return this instance
*/
public Builder variables (Map<String, Object> variables) {
executionPlan.variables = Objects.requireNonNull(variables);
return this;
Expand Down Expand Up @@ -197,6 +248,12 @@ protected TraversalControl visitNode(Node node, TraverserContext<Node> context)
});
}

/**
* Builds execution plan according to the input query document,
* GraphQL schema, selected operations and provided variables
*
* @return execution plan to execute the query document
*/
public ExecutionPlan build () {
Objects.requireNonNull(executionPlan.schema);

Expand Down
24 changes: 20 additions & 4 deletions src/main/java/graphql/execution3/ExecutionPlanContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,28 @@
import graphql.util.DependencyGraphContext;
import graphql.util.Edge;

/**
*
* @author gkesler
*/
public interface ExecutionPlanContext extends DependencyGraphContext {
/**
* A callback method called when ExecutionPlan needs to prepare edge vertices for execution.
* For instance, propagate &amp; transform results from source vertex to become sources in sink vertex
*
* @param edge the edge being followed (source -- to --&gt; sink)
*/
void prepareResolve (Edge<? extends NodeVertex<? extends Node, ? extends GraphQLType>, ?> edge);
/**
* A callback method called when ExecutionPlan has finished resolving the edge.
* Resolution results are stored in the edge source vertex results
* Edge sink is a vertex that may accumulate the overall result.
*
* @param edge the edge being followed
*/
void whenResolved (Edge<? extends NodeVertex<? extends Node, ? extends GraphQLType>, ?> edge);
/**
* A callback method called when ExecutionPlan attempts to auto resolve a vertex,
* i.e. without invoking external data fetcher
*
* @param node vertex to attempt to auto resolve
* @return {@code true} if auto resolved, {@code false} otherwise
*/
boolean resolve (NodeVertex<? extends Node, ? extends GraphQLType> node);
}
6 changes: 1 addition & 5 deletions src/main/java/graphql/execution3/ExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@
import graphql.ExecutionResult;
import java.util.concurrent.CompletableFuture;

/**
*
* @author gkesler
*/
public interface ExecutionStrategy {
/**
* Executes a graphql request according to the schedule
* provided by executionPlan
*
* @param executionPlan a {@code graphql.util.DependencyGraph} specialization that provides
* order of field resolution requets
* order of field resolution requests
*
* @return a CompletableFuture holding the result of execution.
*/
Expand Down
42 changes: 40 additions & 2 deletions src/main/java/graphql/execution3/FieldVertex.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
import java.util.Optional;

/**
*
* @author gkesler
* A vertex wrapping Field AST node
*/
public class FieldVertex extends NodeVertex<Field, GraphQLOutputType> {
public FieldVertex(Field node, GraphQLOutputType type, GraphQLFieldsContainer definedIn) {
Expand Down Expand Up @@ -74,30 +73,69 @@ public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserCont
this.inScopeOf = inScopeOf;
}

/**
* Parent container where this Field is defined
*
* @return parent GraphQL type
*/
public GraphQLFieldsContainer getDefinedIn() {
return definedIn;
}

/**
* If a direct or indirect parent (source) of this vertex has alias,
* retrieves that aliased source.
*
* @return aliased direct or indirect aliased source of this vertex
*/
public Object getInScopeOf() {
return inScopeOf;
}

/**
* Retrieves result of analysis on the kind of object this Field represents
*
* @return analysis result of this Field
*/
public Kind getKind() {
return kind;
}

/**
* Retrieves cardinality of this Field
*
* @return cardinality analysis result
*/
public Cardinality getCardinality() {
return cardinality;
}

/**
* Verifies if this Field value <b>must not</b> be null.
* If this constraint is not satisfied, the parent result is null.
*
* @return "not null" constraint for this field
*/
public boolean isNotNull() {
return notNull;
}

/**
* Verifies if this Field element value (if this Field is a GraphQLList) <b>must not</b> be null.
* If this constraint is not satisfied, the result for the entire list is null.
*
* @return "not null" constraint for a list item
*/
public boolean isNotNullItems() {
return notNullItems;
}

/**
* Key to store this field in the parent result
* https://facebook.github.io/graphql/June2018/#CollectFields()
*
* @return response key
*/
public String getResponseKey () {
return Optional
.ofNullable(node.getAlias())
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/graphql/execution3/NodeEdge.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
import java.util.function.BiConsumer;

/**
*
* @author gkesler
* A specialization of Edge class used occasionally wen building ExecutionPlan
*/
public class NodeEdge extends Edge<NodeVertex<Node, GraphQLType>, NodeEdge> {
public <N extends NodeVertex<? extends Node, ? extends GraphQLType>> NodeEdge(N source, N sink) {
Expand Down
Loading