Skip to content

Commit 814d78f

Browse files
committed
refactor all the things
1 parent 08fea12 commit 814d78f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+831
-651
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package graphql.analysis;
2+
3+
import graphql.Internal;
4+
import graphql.language.Field;
5+
import graphql.language.FragmentDefinition;
6+
import graphql.language.FragmentSpread;
7+
import graphql.language.InlineFragment;
8+
import graphql.language.Node;
9+
import graphql.language.NodeTraverser;
10+
import graphql.language.NodeVisitorStub;
11+
import graphql.language.Selection;
12+
import graphql.language.SelectionSet;
13+
import graphql.util.TraversalControl;
14+
import graphql.util.TraverserContext;
15+
16+
import java.util.Collections;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
/**
21+
* QueryTraversal helper class responsible for obtaining Selection
22+
* nodes from selection parent.
23+
* Uses double dispatch in order to avoid reflection based {@code instanceof} check.
24+
*/
25+
@Internal
26+
public class ChildrenOfSelectionProvider extends NodeVisitorStub {
27+
28+
private Map<String, FragmentDefinition> fragmentDefinitionMap;
29+
30+
public ChildrenOfSelectionProvider(Map<String, FragmentDefinition> fragmentDefinitionMap) {
31+
this.fragmentDefinitionMap = fragmentDefinitionMap;
32+
}
33+
34+
@Override
35+
public TraversalControl visitInlineFragment(InlineFragment node, TraverserContext<Node> context) {
36+
getSelectionSetChildren(node.getSelectionSet(), context);
37+
return TraversalControl.CONTINUE;
38+
}
39+
40+
@Override
41+
public TraversalControl visitFragmentSpread(FragmentSpread fragmentSpread, TraverserContext<Node> context) {
42+
getSelectionSetChildren(fragmentDefinitionMap.get(fragmentSpread.getName()).getSelectionSet(), context);
43+
return TraversalControl.CONTINUE;
44+
}
45+
46+
@Override
47+
public TraversalControl visitField(Field node, TraverserContext<Node> context) {
48+
getSelectionSetChildren(node.getSelectionSet(), context);
49+
return TraversalControl.CONTINUE;
50+
}
51+
52+
@Override
53+
public TraversalControl visitSelectionSet(SelectionSet node, TraverserContext<Node> context) {
54+
context.setResult(node.getSelections());
55+
return TraversalControl.CONTINUE;
56+
}
57+
58+
private void getSelectionSetChildren(SelectionSet node, TraverserContext<Node> context) {
59+
if (node == null) {
60+
context.setResult(Collections.emptyList());
61+
} else {
62+
context.setResult(node.getSelections());
63+
}
64+
}
65+
66+
public List<Node> getSelections(Selection selection) {
67+
return NodeTraverser.oneVisitWithResult(selection, this);
68+
}
69+
}

src/main/java/graphql/analysis/QueryVisitor.java renamed to src/main/java/graphql/analysis/FieldVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import graphql.Internal;
44

55
@Internal
6-
public interface QueryVisitor {
6+
public interface FieldVisitor {
77

88
void visitField(QueryVisitorEnvironment queryVisitorEnvironment);
99

src/main/java/graphql/analysis/QueryTraversal.java

Lines changed: 68 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
import graphql.language.FragmentSpread;
1111
import graphql.language.InlineFragment;
1212
import graphql.language.Node;
13+
import graphql.language.NodeTraverser;
14+
import graphql.language.NodeTraverser.LeaveOrEnter;
1315
import graphql.language.NodeUtil;
14-
import graphql.language.NodeVisitor;
1516
import graphql.language.NodeVisitorStub;
1617
import graphql.language.OperationDefinition;
1718
import graphql.language.Selection;
@@ -23,20 +24,16 @@
2324
import graphql.schema.GraphQLSchema;
2425
import graphql.schema.GraphQLUnmodifiedType;
2526
import graphql.schema.SchemaUtil;
26-
import graphql.util.Traverser;
27+
import graphql.util.TraversalControl;
2728
import graphql.util.TraverserContext;
28-
import graphql.util.TraverserMarkers;
29-
import graphql.util.TraverserStack;
3029

30+
import java.util.LinkedHashMap;
3131
import java.util.List;
32-
import java.util.function.Consumer;
33-
import java.util.Collection;
3432
import java.util.Map;
3533

3634
import static graphql.Assert.assertNotNull;
3735
import static graphql.Assert.assertShouldNeverHappen;
38-
import java.util.Collections;
39-
import java.util.HashMap;
36+
import static graphql.language.NodeTraverser.LeaveOrEnter.LEAVE;
4037

4138
@Internal
4239
public class QueryTraversal {
@@ -49,26 +46,27 @@ public class QueryTraversal {
4946
private final ConditionalNodes conditionalNodes = new ConditionalNodes();
5047
private final ValuesResolver valuesResolver = new ValuesResolver();
5148
private final SchemaUtil schemaUtil = new SchemaUtil();
52-
private final SelectionProvider selectionProvider = new SelectionProvider();
49+
private final ChildrenOfSelectionProvider childrenOfSelectionProvider;
5350

5451
public QueryTraversal(GraphQLSchema schema,
5552
Document document,
5653
String operation,
5754
Map<String, Object> variables) {
5855
NodeUtil.GetOperationResult getOperationResult = NodeUtil.getOperation(document, operation);
59-
56+
6057
this.operationDefinition = getOperationResult.operationDefinition;
6158
this.fragmentsByName = getOperationResult.fragmentsByName;
59+
this.childrenOfSelectionProvider = new ChildrenOfSelectionProvider(fragmentsByName);
6260
this.schema = schema;
6361
this.variables = variables;
6462
}
6563

66-
public void visitPostOrder(QueryVisitor visitor) {
67-
visitImpl(visitor, operationDefinition.getSelectionSet(), getRootType(), null, false);
64+
public void visitPostOrder(FieldVisitor visitor) {
65+
visitImpl(visitor, operationDefinition.getSelectionSet(), getRootType(), false);
6866
}
6967

70-
public void visitPreOrder(QueryVisitor visitor) {
71-
visitImpl(visitor, operationDefinition.getSelectionSet(), getRootType(), null, true);
68+
public void visitPreOrder(FieldVisitor visitor) {
69+
visitImpl(visitor, operationDefinition.getSelectionSet(), getRootType(), true);
7270
}
7371

7472
private GraphQLObjectType getRootType() {
@@ -99,40 +97,36 @@ public <T> T reducePreOrder(QueryReducer<T> queryReducer, T initialValue) {
9997
visitPreOrder((env) -> acc[0] = queryReducer.reduceField(env, (T) acc[0]));
10098
return (T) acc[0];
10199
}
102-
103-
private List<Selection> childrenOf (Selection n) {
104-
return selectionProvider.getChildren(n, fragmentsByName);
100+
101+
private List<Node> childrenOf(Node selection) {
102+
return childrenOfSelectionProvider.getSelections((Selection) selection);
105103
}
106-
107-
private void visitImpl(QueryVisitor visitor, SelectionSet selectionSet, GraphQLCompositeType type, QueryVisitorEnvironment parent, boolean preOrder) {
108-
QueryTraversalContext context = new QueryTraversalContext(type, parent);
109-
QueryTraversalDelegate delegate = preOrder
110-
? new QueryTraversalDelegate(visitor::visitField, env -> {})
111-
: new QueryTraversalDelegate(env -> {}, visitor::visitField);
112-
113-
// in order not to check parentContext for null and guarantee that
114-
// we always can obtain the root QueryTraversalContext,
115-
// we are subclassing here TraverserStack to set up a BARRIER
116-
// parent that stores root QueryTraversalContext
117-
Traverser.depthFirst(this::childrenOf)
118-
.rootVar(QueryTraversalContext.class, context)
119-
.traverse(selectionSet.getSelections(), null, delegate);
104+
105+
private void visitImpl(FieldVisitor visitFieldCallback, SelectionSet selectionSet, GraphQLCompositeType type, boolean preOrder) {
106+
Map<Class<?>, Object> rootVars = new LinkedHashMap<>();
107+
rootVars.put(QueryTraversalContext.class, new QueryTraversalContext(type, null));
108+
109+
NodeTraverser nodeTraverser = new NodeTraverser(rootVars, this::childrenOf);
110+
nodeTraverser.depthFirst(new NodeVisitorImpl(visitFieldCallback, preOrder), selectionSet.getSelections());
120111
}
121-
122-
private class QueryTraversalDelegate extends NodeVisitorStub<TraverserContext<Selection>> {
123-
124-
final Consumer<QueryVisitorEnvironment> preOrder;
125-
final Consumer<QueryVisitorEnvironment> postOrder;
126-
127-
QueryTraversalDelegate (Consumer<QueryVisitorEnvironment> preOrder, Consumer<QueryVisitorEnvironment> postOrder) {
128-
this.preOrder = assertNotNull(preOrder);
129-
this.postOrder = assertNotNull(postOrder);
112+
113+
private class NodeVisitorImpl extends NodeVisitorStub {
114+
115+
private FieldVisitor visitFieldCallback;
116+
boolean preOrder;
117+
118+
NodeVisitorImpl(FieldVisitor visitFieldCallback, boolean preOrder) {
119+
this.visitFieldCallback = visitFieldCallback;
120+
this.preOrder = preOrder;
130121
}
131-
122+
132123
@Override
133-
public Object visitInlineFragment(InlineFragment inlineFragment, TraverserContext<Selection> context) {
124+
public TraversalControl visitInlineFragment(InlineFragment inlineFragment, TraverserContext<Node> context) {
125+
if (context.getVar(LeaveOrEnter.class) == LEAVE) {
126+
return TraversalControl.CONTINUE;
127+
}
134128
if (!conditionalNodes.shouldInclude(variables, inlineFragment.getDirectives()))
135-
return TraverserMarkers.ABORT;
129+
return TraversalControl.ABORT;
136130

137131
// inline fragments are allowed not have type conditions, if so the parent type counts
138132
QueryTraversalContext parentEnv = context
@@ -146,79 +140,67 @@ public Object visitInlineFragment(InlineFragment inlineFragment, TraverserContex
146140
} else {
147141
fragmentCondition = parentEnv.getType();
148142
}
149-
150143
// for unions we only have other fragments inside
151-
return context
152-
.setVar(QueryTraversalContext.class, new QueryTraversalContext(fragmentCondition, parentEnv.getEnvironment()));
144+
context.setVar(QueryTraversalContext.class, new QueryTraversalContext(fragmentCondition, parentEnv.getEnvironment()));
145+
return TraversalControl.CONTINUE;
153146
}
154147

155148
@Override
156-
public Object visitFragmentSpread(FragmentSpread fragmentSpread, TraverserContext<Selection> context) {
149+
public TraversalControl visitFragmentSpread(FragmentSpread fragmentSpread, TraverserContext<Node> context) {
150+
if (context.getVar(LeaveOrEnter.class) == LEAVE) {
151+
return TraversalControl.CONTINUE;
152+
}
157153
if (!conditionalNodes.shouldInclude(variables, fragmentSpread.getDirectives()))
158-
return TraverserMarkers.ABORT;
154+
return TraversalControl.ABORT;
159155

160156
FragmentDefinition fragmentDefinition = fragmentsByName.get(fragmentSpread.getName());
161157
if (!conditionalNodes.shouldInclude(variables, fragmentDefinition.getDirectives()))
162-
return TraverserMarkers.ABORT;
158+
return TraversalControl.ABORT;
163159

164160
QueryTraversalContext parentEnv = context
165161
.parentContext()
166162
.getVar(QueryTraversalContext.class);
167163

168164
GraphQLCompositeType typeCondition = (GraphQLCompositeType) schema.getType(fragmentDefinition.getTypeCondition().getName());
169165

170-
return context
171-
.setVar(QueryTraversalContext.class, new QueryTraversalContext(typeCondition, parentEnv.getEnvironment()));
166+
context
167+
.setVar(QueryTraversalContext.class, new QueryTraversalContext(typeCondition, parentEnv.getEnvironment()));
168+
return TraversalControl.CONTINUE;
172169
}
173170

174171
@Override
175-
public Object visitField(Field field, TraverserContext<Selection> context) {
176-
if (!conditionalNodes.shouldInclude(variables, field.getDirectives()))
177-
return TraverserMarkers.ABORT; // stop recursion
178-
172+
public TraversalControl visitField(Field field, TraverserContext<Node> context) {
179173
QueryTraversalContext parentEnv = context
180174
.parentContext()
181175
.getVar(QueryTraversalContext.class);
182176

183177
GraphQLFieldDefinition fieldDefinition = Introspection.getFieldDef(schema, parentEnv.getType(), field.getName());
184178
Map<String, Object> argumentValues = valuesResolver.getArgumentValues(schema.getFieldVisibility(), fieldDefinition.getArguments(), field.getArguments(), variables);
179+
QueryVisitorEnvironment environment = new QueryVisitorEnvironment(field, fieldDefinition, parentEnv.getType(), parentEnv.getEnvironment(), argumentValues);
180+
181+
LeaveOrEnter leaveOrEnter = context.getVar(LeaveOrEnter.class);
182+
if (leaveOrEnter == LEAVE) {
183+
if (!preOrder) {
184+
visitFieldCallback.visitField(environment);
185+
}
186+
return TraversalControl.CONTINUE;
187+
}
188+
if (preOrder) {
189+
visitFieldCallback.visitField(environment);
190+
}
191+
192+
if (!conditionalNodes.shouldInclude(variables, field.getDirectives()))
193+
return TraversalControl.ABORT; // stop recursion
185194

186-
QueryVisitorEnvironment environment = new QueryVisitorEnvironment(field, fieldDefinition, parentEnv.getType(), parentEnv.getEnvironment(), argumentValues);
187195
GraphQLUnmodifiedType unmodifiedType = schemaUtil.getUnmodifiedType(fieldDefinition.getType());
188196
QueryTraversalContext fieldEnv = (unmodifiedType instanceof GraphQLCompositeType)
189-
? new QueryTraversalContext((GraphQLCompositeType)unmodifiedType, environment)
190-
: new QueryTraversalContext(null, environment);// Terminal (scalar) node, EMPTY FRAME
191-
preOrder.accept(fieldEnv.getEnvironment());
192-
193-
return context
194-
.setVar(QueryTraversalContext.class, fieldEnv);
195-
}
197+
? new QueryTraversalContext((GraphQLCompositeType) unmodifiedType, environment)
198+
: new QueryTraversalContext(null, environment);// Terminal (scalar) node, EMPTY FRAME
196199

197-
@Override
198-
public Object enter(TraverserContext<Node> context, TraverserContext<Selection> data) {
199-
return context
200-
.thisNode()
201-
// it is important to pass current traversal context as NodeVisitor's parameter
202-
.accept(context, this);
203-
}
204200

205-
@Override
206-
public Object leave(TraverserContext<Node> context, TraverserContext<Selection> data) {
207-
return context
208-
.thisNode()
209-
// it is important to pass current traversal context as NodeVisitor's parameter
210-
.accept(context, postOrderVisitor);
201+
context.setVar(QueryTraversalContext.class, fieldEnv);
202+
return TraversalControl.CONTINUE;
211203
}
212204

213-
final NodeVisitor<TraverserContext<Selection>> postOrderVisitor = new NodeVisitorStub<TraverserContext<Selection>>() {
214-
@Override
215-
public Object visitField(Field field, TraverserContext<Selection> context) {
216-
QueryTraversalContext fieldEnv = context
217-
.getVar(QueryTraversalContext.class);
218-
postOrder.accept(fieldEnv.getEnvironment());
219-
220-
return context;
221-
}
222-
};
223205
}
224206
}

src/main/java/graphql/analysis/SelectionProvider.java

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/main/java/graphql/language/Argument.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package graphql.language;
22

33

4+
import graphql.util.TraversalControl;
5+
import graphql.util.TraverserContext;
6+
47
import java.util.ArrayList;
58
import java.util.List;
69

@@ -55,7 +58,7 @@ public String toString() {
5558
}
5659

5760
@Override
58-
public <U> Object accept(U data, NodeVisitor<U> visitor) {
59-
return visitor.visitArgument(this, data);
61+
public TraversalControl accept(TraverserContext<Node> context, NodeVisitor visitor) {
62+
return visitor.visitArgument(this, context);
6063
}
6164
}

0 commit comments

Comments
 (0)