Skip to content

Commit 6566a5a

Browse files
committed
setVisitFragmentSpreads flag for rules
1 parent 4b0f543 commit 6566a5a

9 files changed

Lines changed: 238 additions & 46 deletions

File tree

src/main/java/graphql/language/AbstractNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ public void setSourceLocation(SourceLocation sourceLocation) {
1212

1313
@Override
1414
public SourceLocation getSourceLocation() {
15-
return null;
15+
return sourceLocation;
1616
}
1717
}

src/main/java/graphql/validation/AbstractRule.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,24 @@ public class AbstractRule {
1010
private final ValidationContext validationContext;
1111
private final ValidationErrorCollector validationErrorCollector;
1212

13+
14+
private boolean visitFragmentSpreads;
15+
1316
private ValidationUtil validationUtil = new ValidationUtil();
1417

1518
public AbstractRule(ValidationContext validationContext, ValidationErrorCollector validationErrorCollector) {
1619
this.validationContext = validationContext;
1720
this.validationErrorCollector = validationErrorCollector;
1821
}
1922

23+
public boolean isVisitFragmentSpreads() {
24+
return visitFragmentSpreads;
25+
}
26+
27+
public void setVisitFragmentSpreads(boolean visitFragmentSpreads) {
28+
this.visitFragmentSpreads = visitFragmentSpreads;
29+
}
30+
2031

2132
public ValidationUtil getValidationUtil() {
2233
return validationUtil;
@@ -26,11 +37,11 @@ public void setValidationUtil(ValidationUtil validationUtil) {
2637
this.validationUtil = validationUtil;
2738
}
2839

29-
public void addError(ValidationError error){
40+
public void addError(ValidationError error) {
3041
validationErrorCollector.addError(error);
3142
}
3243

33-
public List<ValidationError> getErrors(){
44+
public List<ValidationError> getErrors() {
3445
return validationErrorCollector.getErrors();
3546
}
3647

@@ -59,7 +70,7 @@ public void checkInlineFragment(InlineFragment inlineFragment) {
5970

6071
}
6172

62-
public void checkDirective(Directive directive,List<Node> ancestors) {
73+
public void checkDirective(Directive directive, List<Node> ancestors) {
6374

6475
}
6576

@@ -75,6 +86,10 @@ public void checkOperationDefinition(OperationDefinition operationDefinition) {
7586

7687
}
7788

89+
public void leaveOperationDefinition(OperationDefinition operationDefinition) {
90+
91+
}
92+
7893
public void checkSelectionSet(SelectionSet selectionSet) {
7994

8095
}
@@ -83,7 +98,7 @@ public void checkVariable(VariableReference variableReference) {
8398

8499
}
85100

86-
public void documentFinished(Document document){
101+
public void documentFinished(Document document) {
87102

88103
}
89104

src/main/java/graphql/validation/LanguageTraversal.java

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

33

4-
import graphql.language.Document;
54
import graphql.language.Node;
65

76
import java.util.ArrayList;
@@ -10,9 +9,9 @@
109
public class LanguageTraversal {
1110

1211

13-
public void traverse(Document document, QueryLanguageVisitor queryLanguageVisitor) {
12+
public void traverse(Node root, QueryLanguageVisitor queryLanguageVisitor) {
1413
List<Node> path = new ArrayList<>();
15-
traverseImpl(document, queryLanguageVisitor, path);
14+
traverseImpl(root, queryLanguageVisitor, path);
1615
}
1716

1817

src/main/java/graphql/validation/RulesVisitor.java

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,110 +3,155 @@
33

44
import graphql.language.*;
55

6-
import java.util.ArrayList;
7-
import java.util.List;
6+
import java.util.*;
87

98
public class RulesVisitor implements QueryLanguageVisitor {
109

1110
private final List<AbstractRule> rules = new ArrayList<>();
1211
private ValidationContext validationContext;
12+
private boolean subVisitor;
13+
private List<AbstractRule> rulesVisitingFragmentSpreads = new ArrayList<>();
14+
private Map<Node, List<AbstractRule>> rulesToSkipByUntilNode = new IdentityHashMap<>();
15+
private Set<AbstractRule> rulesToSkip = new LinkedHashSet<>();
1316

1417
public RulesVisitor(ValidationContext validationContext, List<AbstractRule> rules) {
18+
this(validationContext, rules, false);
19+
}
20+
21+
public RulesVisitor(ValidationContext validationContext, List<AbstractRule> rules, boolean subVisitor) {
1522
this.validationContext = validationContext;
23+
this.subVisitor = subVisitor;
1624
this.rules.addAll(rules);
25+
this.subVisitor = subVisitor;
26+
findRulesVisitingFragmentSpreads();
27+
}
28+
29+
private void findRulesVisitingFragmentSpreads() {
30+
for (AbstractRule rule : rules) {
31+
if (rule.isVisitFragmentSpreads()) {
32+
rulesVisitingFragmentSpreads.add(rule);
33+
}
34+
}
1735
}
1836

1937
@Override
2038
public void enter(Node node, List<Node> ancestors) {
39+
// System.out.println("enter: " + node);
2140
validationContext.getTraversalContext().enter(node, ancestors);
41+
Set<AbstractRule> tmpRulesSet = new LinkedHashSet<>(this.rules);
42+
tmpRulesSet.removeAll(rulesToSkip);
43+
List<AbstractRule> rulesToConsider = new ArrayList<>(tmpRulesSet);
2244
if (node instanceof Argument) {
23-
checkArgument((Argument) node);
45+
checkArgument((Argument) node, rulesToConsider);
2446
} else if (node instanceof TypeName) {
25-
checkTypeName((TypeName) node);
47+
checkTypeName((TypeName) node, rulesToConsider);
2648
} else if (node instanceof VariableDefinition) {
27-
checkVariableDefinition((VariableDefinition) node);
49+
checkVariableDefinition((VariableDefinition) node, rulesToConsider);
2850
} else if (node instanceof Field) {
29-
checkField((Field) node);
51+
checkField((Field) node, rulesToConsider);
3052
} else if (node instanceof InlineFragment) {
31-
checkInlineFragment((InlineFragment) node);
53+
checkInlineFragment((InlineFragment) node, rulesToConsider);
3254
} else if (node instanceof Directive) {
33-
checkDirective((Directive) node, ancestors);
55+
checkDirective((Directive) node, ancestors, rulesToConsider);
3456
} else if (node instanceof FragmentSpread) {
35-
checkFragmentSpread((FragmentSpread) node);
57+
checkFragmentSpread((FragmentSpread) node, rulesToConsider);
3658
} else if (node instanceof FragmentDefinition) {
37-
checkFragmentDefinition((FragmentDefinition) node);
59+
checkFragmentDefinition((FragmentDefinition) node, rulesToConsider);
3860
} else if (node instanceof OperationDefinition) {
39-
checkOperationDefinition((OperationDefinition) node);
61+
checkOperationDefinition((OperationDefinition) node, rulesToConsider);
4062
} else if (node instanceof VariableReference) {
41-
checkVariable((VariableReference) node);
63+
checkVariable((VariableReference) node, rulesToConsider);
4264
} else if (node instanceof SelectionSet) {
43-
checkSelectionSet((SelectionSet) node);
65+
checkSelectionSet((SelectionSet) node, rulesToConsider);
4466
}
4567

4668
}
4769

48-
private void checkArgument(Argument node) {
70+
71+
private void checkArgument(Argument node, List<AbstractRule> rules) {
4972
for (AbstractRule rule : rules) {
5073
rule.checkArgument(node);
5174
}
5275
}
5376

54-
private void checkTypeName(TypeName node) {
77+
private void checkTypeName(TypeName node, List<AbstractRule> rules) {
5578
for (AbstractRule rule : rules) {
5679
rule.checkTypeName(node);
5780
}
5881
}
5982

6083

61-
private void checkVariableDefinition(VariableDefinition variableDefinition) {
84+
private void checkVariableDefinition(VariableDefinition variableDefinition, List<AbstractRule> rules) {
6285
for (AbstractRule rule : rules) {
6386
rule.checkVariableDefinition(variableDefinition);
6487
}
6588
}
6689

67-
private void checkField(Field field) {
90+
private void checkField(Field field, List<AbstractRule> rules) {
6891
for (AbstractRule rule : rules) {
6992
rule.checkField(field);
7093
}
7194
}
7295

73-
private void checkInlineFragment(InlineFragment inlineFragment) {
96+
private void checkInlineFragment(InlineFragment inlineFragment, List<AbstractRule> rules) {
7497
for (AbstractRule rule : rules) {
7598
rule.checkInlineFragment(inlineFragment);
7699
}
77100
}
78101

79-
private void checkDirective(Directive directive, List<Node> ancestors) {
102+
private void checkDirective(Directive directive, List<Node> ancestors, List<AbstractRule> rules) {
80103
for (AbstractRule rule : rules) {
81104
rule.checkDirective(directive, ancestors);
82105
}
83106
}
84107

85-
private void checkFragmentSpread(FragmentSpread fragmentSpread) {
108+
private void checkFragmentSpread(FragmentSpread fragmentSpread, List<AbstractRule> rules) {
86109
for (AbstractRule rule : rules) {
87110
rule.checkFragmentSpread(fragmentSpread);
88111
}
112+
List<AbstractRule> rulesVisitingFragmentSpreads = getRulesVisitingFragmentSpreads(rules);
113+
if (rulesVisitingFragmentSpreads.size() > 0) {
114+
FragmentDefinition fragment = validationContext.getFragment(fragmentSpread.getName());
115+
new LanguageTraversal().traverse(fragment, new RulesVisitor(validationContext, rulesVisitingFragmentSpreads, true));
116+
}
89117
}
90118

91-
private void checkFragmentDefinition(FragmentDefinition fragmentDefinition) {
119+
private List<AbstractRule> getRulesVisitingFragmentSpreads(List<AbstractRule> rules) {
120+
List<AbstractRule> result = new ArrayList<>();
92121
for (AbstractRule rule : rules) {
122+
if (rule.isVisitFragmentSpreads()) result.add(rule);
123+
}
124+
return result;
125+
}
126+
127+
128+
private void checkFragmentDefinition(FragmentDefinition fragmentDefinition, List<AbstractRule> rules) {
129+
if (!subVisitor) {
130+
rulesToSkipByUntilNode.put(fragmentDefinition, new ArrayList<>(rulesVisitingFragmentSpreads));
131+
rulesToSkip.addAll(rulesVisitingFragmentSpreads);
132+
}
133+
134+
135+
for (AbstractRule rule : rules) {
136+
if (!subVisitor && (rule.isVisitFragmentSpreads())) continue;
93137
rule.checkFragmentDefinition(fragmentDefinition);
94138
}
139+
95140
}
96141

97-
private void checkOperationDefinition(OperationDefinition operationDefinition) {
142+
private void checkOperationDefinition(OperationDefinition operationDefinition, List<AbstractRule> rules) {
98143
for (AbstractRule rule : rules) {
99144
rule.checkOperationDefinition(operationDefinition);
100145
}
101146
}
102147

103-
private void checkSelectionSet(SelectionSet selectionSet) {
148+
private void checkSelectionSet(SelectionSet selectionSet, List<AbstractRule> rules) {
104149
for (AbstractRule rule : rules) {
105150
rule.checkSelectionSet(selectionSet);
106151
}
107152
}
108153

109-
private void checkVariable(VariableReference variableReference) {
154+
private void checkVariable(VariableReference variableReference, List<AbstractRule> rules) {
110155
for (AbstractRule rule : rules) {
111156
rule.checkVariable(variableReference);
112157
}
@@ -115,11 +160,26 @@ private void checkVariable(VariableReference variableReference) {
115160

116161
@Override
117162
public void leave(Node node, List<Node> ancestors) {
163+
// System.out.println("Leave: " + node);
118164
validationContext.getTraversalContext().leave(node, ancestors);
119165
if (node instanceof Document) {
120166
documentFinished((Document) node);
167+
} else if (node instanceof OperationDefinition) {
168+
leaveOperationDefinition((OperationDefinition) node);
169+
}
170+
171+
if (rulesToSkipByUntilNode.containsKey(node)) {
172+
rulesToSkip.removeAll(rulesToSkipByUntilNode.get(node));
173+
rulesToSkipByUntilNode.remove(node);
121174
}
122175

176+
177+
}
178+
179+
private void leaveOperationDefinition(OperationDefinition operationDefinition) {
180+
for (AbstractRule rule : rules) {
181+
rule.leaveOperationDefinition(operationDefinition);
182+
}
123183
}
124184

125185
private void documentFinished(Document document) {

src/main/java/graphql/validation/rules/NoUndefinedVariables.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package graphql.validation.rules;
22

33

4+
import graphql.language.FragmentDefinition;
5+
import graphql.language.OperationDefinition;
46
import graphql.language.VariableDefinition;
57
import graphql.language.VariableReference;
68
import graphql.validation.*;
@@ -14,6 +16,17 @@ public class NoUndefinedVariables extends AbstractRule {
1416

1517
public NoUndefinedVariables(ValidationContext validationContext, ValidationErrorCollector validationErrorCollector) {
1618
super(validationContext, validationErrorCollector);
19+
setVisitFragmentSpreads(true);
20+
}
21+
22+
@Override
23+
public void checkOperationDefinition(OperationDefinition operationDefinition) {
24+
variableNames.clear();
25+
}
26+
27+
@Override
28+
public void checkFragmentDefinition(FragmentDefinition fragmentDefinition) {
29+
super.checkFragmentDefinition(fragmentDefinition);
1730
}
1831

1932
@Override
Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,41 @@
11
package graphql.validation.rules;
22

33

4+
import graphql.language.OperationDefinition;
5+
import graphql.language.VariableDefinition;
6+
import graphql.language.VariableReference;
47
import graphql.validation.AbstractRule;
58
import graphql.validation.ValidationContext;
69
import graphql.validation.ValidationErrorCollector;
710

11+
import java.util.ArrayList;
12+
import java.util.LinkedHashSet;
13+
import java.util.List;
14+
import java.util.Set;
15+
816
public class NoUnusedVariables extends AbstractRule{
917

10-
// TODO
18+
private List<VariableDefinition> variableDefinitions = new ArrayList<>();
19+
private Set<String> usedVariables = new LinkedHashSet<>();
20+
1121
public NoUnusedVariables(ValidationContext validationContext, ValidationErrorCollector validationErrorCollector) {
1222
super(validationContext, validationErrorCollector);
1323
}
24+
25+
26+
@Override
27+
public void checkOperationDefinition(OperationDefinition operationDefinition) {
28+
usedVariables.clear();
29+
variableDefinitions.clear();
30+
}
31+
32+
@Override
33+
public void checkVariableDefinition(VariableDefinition variableDefinition) {
34+
variableDefinitions.add(variableDefinition);
35+
}
36+
37+
@Override
38+
public void checkVariable(VariableReference variableReference) {
39+
usedVariables.add(variableReference.getName());
40+
}
1441
}

src/test/groovy/graphql/TestUtil.groovy

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,9 @@ class TestUtil {
1616
new GraphQLSchema(queryType)
1717
}
1818

19-
static dummyObjec
19+
static dummySchema = GraphQLSchema.newSchema()
20+
.query(GraphQLObjectType.newObject()
21+
.name("QueryType")
22+
.build())
23+
.build()
2024
}

0 commit comments

Comments
 (0)