FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Add executable description support (#4392) · Talank/graphql-java_graphql-java@3b03d75 · GitHub

Commit 3b03d75

Browse files
authored
Add executable description support (graphql-java#4392)
1 parent 2f200f8 commit 3b03d75

9 files changed

Lines changed: 195 additions & 22 deletions

File tree

‎src/main/antlr/GraphqlOperation.g4‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import GraphqlCommon;
33

44
operationDefinition:
55
selectionSet |
6-
operationType name? variableDefinitions? directives? selectionSet;
6+
description? operationType name? variableDefinitions? directives? selectionSet;
77

88
variableDefinitions : '(' variableDefinition+ ')';
99

10-
variableDefinition : variable ':' type defaultValue? directives?;
10+
variableDefinition : description? variable ':' type defaultValue? directives?;
1111

1212

1313
selectionSet : '{' selection+ '}';
@@ -27,7 +27,7 @@ fragmentSpread : '...' fragmentName directives?;
2727

2828
inlineFragment : '...' typeCondition? directives? selectionSet;
2929

30-
fragmentDefinition : FRAGMENT fragmentName typeCondition directives? selectionSet;
30+
fragmentDefinition : description? FRAGMENT fragmentName typeCondition directives? selectionSet;
3131

3232

3333
typeCondition : ON_KEYWORD typeName;

‎src/main/java/graphql/language/AstPrinter.java‎

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,13 @@ private static boolean hasDescription(Node<?> node) {
249249
return false;
250250
}
251251

252+
private static boolean hasDescription(List<? extends Node<?>> nodes) {
253+
return nodes.stream().anyMatch(AstPrinter::hasDescription);
254+
}
255+
252256
private NodePrinter<FragmentDefinition> fragmentDefinition() {
253257
return (out, node) -> {
258+
description(out, node);
254259
out.append("fragment ");
255260
out.append(node.getName());
256261
out.append(" on ");
@@ -367,24 +372,17 @@ private NodePrinter<OperationDefinition> operationDefinition() {
367372
String name = node.getName();
368373
// Anonymous queries with no directives or variable definitions can use
369374
// the query short form.
370-
if (isEmpty(name) && isEmpty(node.getDirectives()) && isEmpty(node.getVariableDefinitions())
371-
&& node.getOperation() == OperationDefinition.Operation.QUERY) {
375+
if (canUseQueryShortForm(node)) {
372376
node(out, node.getSelectionSet());
373377
} else {
378+
description(out, node);
374379
OperationDefinition.Operation op = node.getOperation();
375380
out.append(op.toString().toLowerCase());
376381
if (!isEmpty(name)) {
377382
out.append(' ');
378383
out.append(name);
379384
}
380-
if (!isEmpty(node.getVariableDefinitions())) {
381-
if (isEmpty(name)) {
382-
out.append(' ');
383-
}
384-
out.append('(');
385-
join(out, node.getVariableDefinitions(), argSep);
386-
out.append(')');
387-
}
385+
variableDefinitions(out, node, argSep);
388386
if (!isEmpty(node.getDirectives())) {
389387
out.append(' ');
390388
directives(out, node.getDirectives());
@@ -397,6 +395,34 @@ private NodePrinter<OperationDefinition> operationDefinition() {
397395
};
398396
}
399397

398+
private boolean canUseQueryShortForm(OperationDefinition node) {
399+
return (compactMode || !hasDescription(node))
400+
&& isEmpty(node.getName())
401+
&& isEmpty(node.getDirectives())
402+
&& isEmpty(node.getVariableDefinitions())
403+
&& node.getOperation() == OperationDefinition.Operation.QUERY;
404+
}
405+
406+
private void variableDefinitions(StringBuilder out, OperationDefinition node, String argSep) {
407+
if (isEmpty(node.getVariableDefinitions())) {
408+
return;
409+
}
410+
if (isEmpty(node.getName())) {
411+
out.append(' ');
412+
}
413+
if (!compactMode && hasDescription(node.getVariableDefinitions())) {
414+
int offset = out.length();
415+
out.append("(\n");
416+
join(out, node.getVariableDefinitions(), "\n");
417+
indent(out, offset);
418+
out.append("\n)");
419+
return;
420+
}
421+
out.append('(');
422+
join(out, node.getVariableDefinitions(), argSep);
423+
out.append(')');
424+
}
425+
400426
private NodePrinter<OperationTypeDefinition> operationTypeDefinition() {
401427
String nameTypeSep = compactMode ? ":" : ": ";
402428
return (out, node) -> {
@@ -546,6 +572,7 @@ private NodePrinter<VariableDefinition> variableDefinition() {
546572
String nameTypeSep = compactMode ? ":" : ": ";
547573
String defaultValueEquals = compactMode ? "=" : " = ";
548574
return (out, node) -> {
575+
description(out, node);
549576
out.append('$');
550577
out.append(node.getName());
551578
out.append(nameTypeSep);

‎src/main/java/graphql/language/FragmentDefinition.java‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
*/
2828
@PublicApi
2929
@NullMarked
30-
public class FragmentDefinition extends AbstractNode<FragmentDefinition> implements Definition<FragmentDefinition>, SelectionSetContainer<FragmentDefinition>, DirectivesContainer<FragmentDefinition>, NamedNode<FragmentDefinition> {
30+
public class FragmentDefinition extends AbstractDescribedNode<FragmentDefinition> implements Definition<FragmentDefinition>, SelectionSetContainer<FragmentDefinition>, DirectivesContainer<FragmentDefinition>, NamedNode<FragmentDefinition> {
3131

3232
private final String name;
3333
private final TypeName typeCondition;
@@ -43,11 +43,12 @@ protected FragmentDefinition(String name,
4343
TypeName typeCondition,
4444
List<Directive> directives,
4545
SelectionSet selectionSet,
46+
@Nullable Description description,
4647
@Nullable SourceLocation sourceLocation,
4748
List<Comment> comments,
4849
IgnoredChars ignoredChars,
4950
Map<String, String> additionalData) {
50-
super(sourceLocation, comments, ignoredChars, additionalData);
51+
super(sourceLocation, comments, ignoredChars, additionalData, description);
5152
this.name = name;
5253
this.typeCondition = typeCondition;
5354
this.directives = NodeUtil.DirectivesHolder.of(directives);
@@ -136,6 +137,7 @@ public FragmentDefinition deepCopy() {
136137
assertNotNull(deepCopy(typeCondition)),
137138
assertNotNull(deepCopy(directives.getDirectives())),
138139
assertNotNull(deepCopy(selectionSet)),
140+
description,
139141
getSourceLocation(),
140142
getComments(),
141143
getIgnoredChars(),
@@ -174,6 +176,7 @@ public static final class Builder implements NodeDirectivesBuilder {
174176

175177
private String name;
176178
private TypeName typeCondition;
179+
private Description description;
177180
private ImmutableList<Directive> directives = emptyList();
178181
private SelectionSet selectionSet;
179182
private IgnoredChars ignoredChars = IgnoredChars.EMPTY;
@@ -187,6 +190,7 @@ private Builder(FragmentDefinition existing) {
187190
this.comments = ImmutableList.copyOf(existing.getComments());
188191
this.name = existing.getName();
189192
this.typeCondition = existing.getTypeCondition();
193+
this.description = existing.getDescription();
190194
this.directives = ImmutableList.copyOf(existing.getDirectives());
191195
this.selectionSet = existing.getSelectionSet();
192196
this.ignoredChars = existing.getIgnoredChars();
@@ -214,6 +218,11 @@ public Builder typeCondition(TypeName typeCondition) {
214218
return this;
215219
}
216220

221+
public Builder description(Description description) {
222+
this.description = description;
223+
return this;
224+
}
225+
217226
@Override
218227
public Builder directives(List<Directive> directives) {
219228
this.directives = ImmutableList.copyOf(directives);
@@ -247,7 +256,7 @@ public Builder additionalData(String key, String value) {
247256

248257

249258
public FragmentDefinition build() {
250-
return new FragmentDefinition(assertNotNull(name), assertNotNull(typeCondition), directives, assertNotNull(selectionSet), sourceLocation, comments, ignoredChars, additionalData);
259+
return new FragmentDefinition(assertNotNull(name), assertNotNull(typeCondition), directives, assertNotNull(selectionSet), description, sourceLocation, comments, ignoredChars, additionalData);
251260
}
252261
}
253262
}

‎src/main/java/graphql/language/OperationDefinition.java‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
@PublicApi
2828
@NullMarked
29-
public class OperationDefinition extends AbstractNode<OperationDefinition> implements Definition<OperationDefinition>, SelectionSetContainer<OperationDefinition>, DirectivesContainer<OperationDefinition>, NamedNode<OperationDefinition> {
29+
public class OperationDefinition extends AbstractDescribedNode<OperationDefinition> implements Definition<OperationDefinition>, SelectionSetContainer<OperationDefinition>, DirectivesContainer<OperationDefinition>, NamedNode<OperationDefinition> {
3030

3131
public enum Operation {
3232
QUERY, MUTATION, SUBSCRIPTION
@@ -49,11 +49,12 @@ protected OperationDefinition(@Nullable String name,
4949
List<VariableDefinition> variableDefinitions,
5050
List<Directive> directives,
5151
SelectionSet selectionSet,
52+
@Nullable Description description,
5253
@Nullable SourceLocation sourceLocation,
5354
List<Comment> comments,
5455
IgnoredChars ignoredChars,
5556
Map<String, String> additionalData) {
56-
super(sourceLocation, comments, ignoredChars, additionalData);
57+
super(sourceLocation, comments, ignoredChars, additionalData, description);
5758
this.name = name;
5859
this.operation = operation;
5960
this.variableDefinitions = ImmutableList.copyOf(variableDefinitions);
@@ -147,6 +148,7 @@ public OperationDefinition deepCopy() {
147148
assertNotNull(deepCopy(variableDefinitions), "variableDefinitions deepCopy should not return null"),
148149
assertNotNull(deepCopy(directives.getDirectives()), "directives deepCopy should not return null"),
149150
assertNotNull(deepCopy(selectionSet), "selectionSet deepCopy should not return null"),
151+
description,
150152
getSourceLocation(),
151153
getComments(),
152154
getIgnoredChars(),
@@ -185,6 +187,7 @@ public static final class Builder implements NodeDirectivesBuilder {
185187
private ImmutableList<Comment> comments = emptyList();
186188
private String name;
187189
private Operation operation = Operation.QUERY;
190+
private Description description;
188191
private ImmutableList<VariableDefinition> variableDefinitions = emptyList();
189192
private ImmutableList<Directive> directives = emptyList();
190193
private SelectionSet selectionSet;
@@ -199,6 +202,7 @@ private Builder(OperationDefinition existing) {
199202
this.comments = ImmutableList.copyOf(existing.getComments());
200203
this.name = existing.getName();
201204
this.operation = existing.getOperation();
205+
this.description = existing.getDescription();
202206
this.variableDefinitions = ImmutableList.copyOf(existing.getVariableDefinitions());
203207
this.directives = ImmutableList.copyOf(existing.getDirectives());
204208
this.selectionSet = existing.getSelectionSet();
@@ -227,6 +231,11 @@ public Builder operation(Operation operation) {
227231
return this;
228232
}
229233

234+
public Builder description(Description description) {
235+
this.description = description;
236+
return this;
237+
}
238+
230239
public Builder variableDefinitions(List<VariableDefinition> variableDefinitions) {
231240
this.variableDefinitions = ImmutableList.copyOf(variableDefinitions);
232241
return this;
@@ -275,6 +284,7 @@ public OperationDefinition build() {
275284
variableDefinitions,
276285
directives,
277286
selectionSet,
287+
description,
278288
sourceLocation,
279289
comments,
280290
ignoredChars,

‎src/main/java/graphql/language/VariableDefinition.java‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import static graphql.language.NodeChildrenContainer.newNodeChildrenContainer;
2222

2323
@PublicApi
24-
public class VariableDefinition extends AbstractNode<VariableDefinition> implements DirectivesContainer<VariableDefinition>, NamedNode<VariableDefinition> {
24+
public class VariableDefinition extends AbstractDescribedNode<VariableDefinition> implements DirectivesContainer<VariableDefinition>, NamedNode<VariableDefinition> {
2525

2626
private final String name;
2727
private final Type type;
@@ -37,11 +37,12 @@ protected VariableDefinition(String name,
3737
Type type,
3838
Value defaultValue,
3939
List<Directive> directives,
40+
Description description,
4041
SourceLocation sourceLocation,
4142
List<Comment> comments,
4243
IgnoredChars ignoredChars,
4344
Map<String, String> additionalData) {
44-
super(sourceLocation, comments, ignoredChars, additionalData);
45+
super(sourceLocation, comments, ignoredChars, additionalData, description);
4546
this.name = name;
4647
this.type = type;
4748
this.defaultValue = defaultValue;
@@ -58,7 +59,7 @@ protected VariableDefinition(String name,
5859
public VariableDefinition(String name,
5960
Type type,
6061
Value defaultValue) {
61-
this(name, type, defaultValue, emptyList(), null, emptyList(), IgnoredChars.EMPTY, emptyMap());
62+
this(name, type, defaultValue, emptyList(), null, null, emptyList(), IgnoredChars.EMPTY, emptyMap());
6263
}
6364

6465
/**
@@ -69,7 +70,7 @@ public VariableDefinition(String name,
6970
*/
7071
public VariableDefinition(String name,
7172
Type type) {
72-
this(name, type, null, emptyList(), null, emptyList(), IgnoredChars.EMPTY, emptyMap());
73+
this(name, type, null, emptyList(), null, null, emptyList(), IgnoredChars.EMPTY, emptyMap());
7374
}
7475

7576
public Value getDefaultValue() {
@@ -154,6 +155,7 @@ public VariableDefinition deepCopy() {
154155
deepCopy(type),
155156
deepCopy(defaultValue),
156157
deepCopy(directives.getDirectives()),
158+
description,
157159
getSourceLocation(),
158160
getComments(),
159161
getIgnoredChars(),
@@ -204,6 +206,7 @@ public static final class Builder implements NodeDirectivesBuilder {
204206
private ImmutableList<Comment> comments = emptyList();
205207
private Type type;
206208
private Value defaultValue;
209+
private Description description;
207210
private ImmutableList<Directive> directives = emptyList();
208211
private IgnoredChars ignoredChars = IgnoredChars.EMPTY;
209212
private Map<String, String> additionalData = new LinkedHashMap<>();
@@ -217,6 +220,7 @@ private Builder(VariableDefinition existing) {
217220
this.name = existing.getName();
218221
this.type = existing.getType();
219222
this.defaultValue = existing.getDefaultValue();
223+
this.description = existing.getDescription();
220224
this.directives = ImmutableList.copyOf(existing.getDirectives());
221225
this.ignoredChars = existing.getIgnoredChars();
222226
this.additionalData = new LinkedHashMap<>(existing.getAdditionalData());
@@ -247,6 +251,11 @@ public Builder defaultValue(Value defaultValue) {
247251
return this;
248252
}
249253

254+
public Builder description(Description description) {
255+
this.description = description;
256+
return this;
257+
}
258+
250259
@Override
251260
public Builder directives(List<Directive> directives) {
252261
this.directives = ImmutableList.copyOf(directives);
@@ -279,6 +288,7 @@ public VariableDefinition build() {
279288
type,
280289
defaultValue,
281290
directives,
291+
description,
282292
sourceLocation,
283293
comments,
284294
ignoredChars,

‎src/main/java/graphql/parser/GraphqlAntlrToLanguage.java‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ protected OperationDefinition createOperationDefinition(GraphqlParser.OperationD
142142
if (ctx.name() != null) {
143143
operationDefinition.name(ctx.name().getText());
144144
}
145+
operationDefinition.description(newDescription(ctx.description()));
145146
operationDefinition.variableDefinitions(createVariableDefinitions(ctx.variableDefinitions()));
146147
operationDefinition.selectionSet(createSelectionSet(ctx.selectionSet()));
147148
operationDefinition.directives(createDirectives(ctx.directives()));
@@ -178,6 +179,7 @@ protected List<VariableDefinition> createVariableDefinitions(GraphqlParser.Varia
178179
protected VariableDefinition createVariableDefinition(GraphqlParser.VariableDefinitionContext ctx) {
179180
VariableDefinition.Builder variableDefinition = VariableDefinition.newVariableDefinition();
180181
addCommonData(variableDefinition, ctx);
182+
variableDefinition.description(newDescription(ctx.description()));
181183
variableDefinition.name(ctx.variable().name().getText());
182184
if (ctx.defaultValue() != null) {
183185
Value value = createValue(ctx.defaultValue().value());
@@ -192,6 +194,7 @@ protected VariableDefinition createVariableDefinition(GraphqlParser.VariableDefi
192194
protected FragmentDefinition createFragmentDefinition(GraphqlParser.FragmentDefinitionContext ctx) {
193195
FragmentDefinition.Builder fragmentDefinition = FragmentDefinition.newFragmentDefinition();
194196
addCommonData(fragmentDefinition, ctx);
197+
fragmentDefinition.description(newDescription(ctx.description()));
195198
fragmentDefinition.name(ctx.fragmentName().getText());
196199
fragmentDefinition.typeCondition(TypeName.newTypeName().name(ctx.typeCondition().typeName().getText()).build());
197200
fragmentDefinition.directives(createDirectives(ctx.directives()));

‎src/test/groovy/graphql/ParseAndValidateTest.groovy‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,33 @@ class ParseAndValidateTest extends Specification {
5959
errors.isEmpty()
6060
}
6161

62+
def "executable descriptions do not affect validation"() {
63+
def input = ExecutionInput.newExecutionInput('''
64+
"Fetches a hero"
65+
query HeroName(
66+
"The target episode"
67+
$episode: Episode = JEDI
68+
) {
69+
hero(episode: $episode) {
70+
...heroFields
71+
}
72+
}
73+
74+
"Reusable hero fields"
75+
fragment heroFields on Character {
76+
name
77+
}
78+
''').build()
79+
def result = ParseAndValidate.parse(input)
80+
81+
when:
82+
def errors = ParseAndValidate.validate(StarWarsSchema.starWarsSchema, result.getDocument(), input.getLocale())
83+
84+
then:
85+
!result.isFailure()
86+
errors.isEmpty()
87+
}
88+
6289
def "will validate documents with actual problems"() {
6390

6491
def input = ExecutionInput.newExecutionInput("query { hero }").variables([var1: 1]).build()

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL