Repository navigation
add dependency graph #1594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add dependency graph #1594
Changes from all commits
154ec9e
8adc7ab
f7e77f5
146f807
c38f50c
0b1cfca
90b0838
dd798f5
501c54d
08ab833
576a87b
7bfbbd8
fb3326d
b033739
599e5ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| package graphql.execution.nextgen.depgraph; | ||
|
|
||
| import graphql.language.OperationDefinition; | ||
| import graphql.schema.GraphQLSchema; | ||
| import graphql.util.TraversalControl; | ||
| import graphql.util.Traverser; | ||
| import graphql.util.TraverserContext; | ||
| import graphql.util.TraverserVisitorStub; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.LinkedHashSet; | ||
| import java.util.List; | ||
| import java.util.Set; | ||
| import java.util.function.Function; | ||
|
|
||
| public class DependencyGraph { | ||
|
|
||
|
|
||
| public DependencyGraph createDependencyGraph(GraphQLSchema graphQLSchema, OperationDefinition operationDefinition) { | ||
|
|
||
| FieldCollectorWTC fieldCollector = new FieldCollectorWTC(); | ||
| FieldCollectorParameters parameters = FieldCollectorParameters | ||
| .newParameters() | ||
| .schema(graphQLSchema) | ||
| .build(); | ||
|
|
||
| Function<MergedFieldWithType, List<MergedFieldWithType>> getChildren = mergedFieldWithType -> { | ||
| List<MergedFieldWithType> childs = fieldCollector.collectFields(parameters, mergedFieldWithType); | ||
| return childs; | ||
| }; | ||
|
|
||
|
|
||
| Set<FieldVertex> allVertices = new LinkedHashSet<>(); | ||
|
|
||
| Traverser<MergedFieldWithType> traverser = Traverser.depthFirst(getChildren); | ||
| FieldVertex rootVertex = new FieldVertex(null, null, null, null, null); | ||
| traverser.rootVar(FieldVertex.class, rootVertex); | ||
| allVertices.add(rootVertex); | ||
| List<MergedFieldWithType> roots = fieldCollector.collectFromOperation(parameters, operationDefinition, graphQLSchema.getQueryType()); | ||
| traverser.traverse(roots, new TraverserVisitorStub<MergedFieldWithType>() { | ||
| @Override | ||
| public TraversalControl enter(TraverserContext<MergedFieldWithType> context) { | ||
| MergedFieldWithType mergedFieldWithType = context.thisNode(); | ||
| System.out.println(mergedFieldWithType.getName() + "" + mergedFieldWithType.getObjectType().getName()); | ||
|
|
||
| FieldVertex fieldVertex = createFieldVertex(mergedFieldWithType, graphQLSchema); | ||
| FieldVertex parentVertex = context.getVarFromParents(FieldVertex.class); | ||
| fieldVertex.addDependency(parentVertex); | ||
| parentVertex.addDependsOnMe(fieldVertex); | ||
| allVertices.add(fieldVertex); | ||
| context.setVar(FieldVertex.class, fieldVertex); | ||
|
|
||
| return TraversalControl.CONTINUE; | ||
| } | ||
|
|
||
| }); | ||
|
|
||
| List<Set<FieldVertex>> listOfClosures = new ArrayList<>(); | ||
| Set<FieldVertex> allClosed = new LinkedHashSet<>(); | ||
| allClosed.add(rootVertex); | ||
| Set<FieldVertex> curSourceSet = new LinkedHashSet<>(); | ||
| curSourceSet.add(rootVertex); | ||
|
|
||
| while (!curSourceSet.isEmpty()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @andimarek |
||
| Set<FieldVertex> nextClosure = new LinkedHashSet<>(); | ||
| allClosed.addAll(curSourceSet); | ||
| for (FieldVertex source : curSourceSet) { | ||
| for (FieldVertex dependsOnSource : source.getDependsOnMe()) { | ||
| if (allClosed.containsAll(dependsOnSource.getDependencies())) { | ||
| nextClosure.add(dependsOnSource); | ||
| } | ||
| } | ||
| } | ||
| listOfClosures.add(nextClosure); | ||
| curSourceSet = nextClosure; | ||
| } | ||
|
|
||
| System.out.println(listOfClosures); | ||
|
|
||
| StringBuilder dotFile = new StringBuilder(); | ||
| dotFile.append("digraph G{\n"); | ||
| Traverser<FieldVertex> traverserVertex = Traverser.depthFirst(FieldVertex::getDependsOnMe); | ||
|
|
||
| traverserVertex.traverse(rootVertex, new TraverserVisitorStub<FieldVertex>() { | ||
| @Override | ||
| public TraversalControl enter(TraverserContext<FieldVertex> context) { | ||
| FieldVertex fieldVertex = context.thisNode(); | ||
| FieldVertex parentVertex = context.getParentNode(); | ||
| if (parentVertex != null) { | ||
| String vertexId = fieldVertex.getClass().getSimpleName() + Integer.toHexString(fieldVertex.hashCode()); | ||
| String parentVertexId = parentVertex.getClass().getSimpleName() + Integer.toHexString(parentVertex.hashCode()); | ||
| dotFile.append(vertexId).append(" -> ").append(parentVertexId).append(";\n"); | ||
| } | ||
| allVertices.add(context.thisNode()); | ||
| return TraversalControl.CONTINUE; | ||
| } | ||
| }); | ||
|
|
||
| for (FieldVertex fieldVertex : allVertices) { | ||
| dotFile.append(fieldVertex.getClass().getSimpleName()).append(Integer.toHexString(fieldVertex.hashCode())).append("[label=\"") | ||
| .append(fieldVertex.toString()).append("\"];\n"); | ||
| } | ||
|
|
||
| dotFile.append("}"); | ||
| System.out.println(dotFile); | ||
| return null; | ||
| } | ||
|
|
||
| private FieldVertex createFieldVertex(MergedFieldWithType mergedFieldWithType, GraphQLSchema graphQLSchemas) { | ||
| return new FieldVertex(mergedFieldWithType.getFields(), | ||
| mergedFieldWithType.getFieldDefinition(), | ||
| mergedFieldWithType.getFieldsContainer(), | ||
| mergedFieldWithType.getParentType(), | ||
| mergedFieldWithType.getObjectType() | ||
| ); | ||
|
|
||
| } | ||
|
|
||
|
|
||
| public static void main(String[] args) { | ||
|
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package graphql.execution.nextgen.depgraph; | ||
|
|
||
| public class Edge { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package graphql.execution.nextgen.depgraph; | ||
|
|
||
| import graphql.Assert; | ||
| import graphql.Internal; | ||
| import graphql.language.FragmentDefinition; | ||
| import graphql.schema.GraphQLSchema; | ||
|
|
||
| import java.util.LinkedHashMap; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Internal because FieldCollectorWTC is internal. | ||
| */ | ||
| @Internal | ||
| public class FieldCollectorParameters { | ||
| private final GraphQLSchema graphQLSchema; | ||
| private final Map<String, FragmentDefinition> fragmentsByName; | ||
| private final Map<String, Object> variables; | ||
|
|
||
| public GraphQLSchema getGraphQLSchema() { | ||
| return graphQLSchema; | ||
| } | ||
|
|
||
| public Map<String, FragmentDefinition> getFragmentsByName() { | ||
| return fragmentsByName; | ||
| } | ||
|
|
||
| public Map<String, Object> getVariables() { | ||
| return variables; | ||
| } | ||
|
|
||
|
|
||
| private FieldCollectorParameters(GraphQLSchema graphQLSchema, | ||
| Map<String, Object> variables, | ||
| Map<String, FragmentDefinition> fragmentsByName) { | ||
| this.fragmentsByName = fragmentsByName; | ||
| this.graphQLSchema = graphQLSchema; | ||
| this.variables = variables; | ||
| } | ||
|
|
||
| public static Builder newParameters() { | ||
| return new Builder(); | ||
| } | ||
|
|
||
| public static class Builder { | ||
| private GraphQLSchema graphQLSchema; | ||
| private final Map<String, FragmentDefinition> fragmentsByName = new LinkedHashMap<>(); | ||
| private final Map<String, Object> variables = new LinkedHashMap<>(); | ||
|
|
||
| /** | ||
| * @see FieldCollectorParameters#newParameters() | ||
| */ | ||
| private Builder() { | ||
|
|
||
| } | ||
|
|
||
| public Builder schema(GraphQLSchema graphQLSchema) { | ||
| this.graphQLSchema = graphQLSchema; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder fragments(Map<String, FragmentDefinition> fragmentsByName) { | ||
| this.fragmentsByName.putAll(fragmentsByName); | ||
| return this; | ||
| } | ||
|
|
||
| public Builder variables(Map<String, Object> variables) { | ||
| this.variables.putAll(variables); | ||
| return this; | ||
| } | ||
|
|
||
| public FieldCollectorParameters build() { | ||
| Assert.assertNotNull(graphQLSchema, "You must provide a schema"); | ||
| return new FieldCollectorParameters(graphQLSchema, variables, fragmentsByName); | ||
| } | ||
|
|
||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think recursive collecting fields (graph traversal!) and then traversing collected fields again to build a graph is quite redundant. I would suggest to build the graph in 1 traverse cycle, incrementally with field collection.