Skip to content

Commit 35524b1

Browse files
committed
graphql-java#427 added null support but have not added optional arguments yet
1 parent d8bfa00 commit 35524b1

File tree

10 files changed

+139
-0
lines changed

10 files changed

+139
-0
lines changed

src/main/antlr/Graphql.g4

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ IntValue |
6666
FloatValue |
6767
StringValue |
6868
BooleanValue |
69+
NullValue |
6970
enumValue |
7071
arrayValue |
7172
objectValue;
@@ -76,6 +77,7 @@ IntValue |
7677
FloatValue |
7778
StringValue |
7879
BooleanValue |
80+
NullValue |
7981
enumValue |
8082
arrayValueWithVariable |
8183
objectValueWithVariable;
@@ -176,6 +178,8 @@ directiveLocations '|' directiveLocation
176178

177179
BooleanValue: 'true' | 'false';
178180

181+
NullValue: 'null';
182+
179183
FRAGMENT: 'fragment';
180184
QUERY: 'query';
181185
MUTATION: 'mutation';

src/main/java/graphql/execution/ValuesResolver.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ private Object coerceValueAst(GraphQLType type, Value inputValue, Map<String, Ob
129129
if (inputValue instanceof VariableReference) {
130130
return variables.get(((VariableReference) inputValue).getName());
131131
}
132+
if (inputValue instanceof NullValue) {
133+
return null;
134+
}
132135
if (type instanceof GraphQLScalarType) {
133136
return ((GraphQLScalarType) type).getCoercing().parseLiteral(inputValue);
134137
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class AstPrinter {
2626
printers.put(Argument.class, argument());
2727
printers.put(ArrayValue.class, value());
2828
printers.put(BooleanValue.class, value());
29+
printers.put(NullValue.class, value());
2930
printers.put(Directive.class, directive());
3031
printers.put(DirectiveDefinition.class, directiveDefinition());
3132
printers.put(DirectiveLocation.class, directiveLocation());
@@ -378,6 +379,8 @@ static private String value(Value value) {
378379
return valueOf(((EnumValue) value).getName());
379380
} else if (value instanceof BooleanValue) {
380381
return valueOf(((BooleanValue) value).isValue());
382+
} else if (value instanceof NullValue) {
383+
return "null";
381384
} else if (value instanceof ArrayValue) {
382385
return "[" + join(((ArrayValue) value).getValues(), ", ") + "]";
383386
} else if (value instanceof ObjectValue) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package graphql.language;
2+
3+
4+
import java.util.Collections;
5+
import java.util.List;
6+
7+
public class NullValue extends AbstractNode implements Value {
8+
9+
public static NullValue Null = new NullValue();
10+
11+
private NullValue() {
12+
}
13+
14+
@Override
15+
public List<Node> getChildren() {
16+
return Collections.emptyList();
17+
}
18+
19+
@Override
20+
public boolean isEqualTo(Node o) {
21+
if (this == o) return true;
22+
if (o == null || getClass() != o.getClass()) return false;
23+
24+
return true;
25+
26+
}
27+
28+
@Override
29+
public String toString() {
30+
return "NullValue{" +
31+
'}';
32+
}
33+
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@
5858
import java.util.Deque;
5959
import java.util.List;
6060

61+
import static graphql.language.NullValue.Null;
62+
6163
@Internal
64+
6265
public class GraphqlAntlrToLanguage extends GraphqlBaseVisitor<Void> {
6366

6467
private final CommonTokenStream tokens;
@@ -668,6 +671,9 @@ private Value getValue(GraphqlParser.ValueWithVariableContext ctx) {
668671
BooleanValue booleanValue = new BooleanValue(Boolean.parseBoolean(ctx.BooleanValue().getText()));
669672
newNode(booleanValue, ctx);
670673
return booleanValue;
674+
} else if (ctx.NullValue() != null) {
675+
newNode(Null, ctx);
676+
return Null;
671677
} else if (ctx.StringValue() != null) {
672678
StringValue stringValue = new StringValue(parseString(ctx.StringValue().getText()));
673679
newNode(stringValue, ctx);
@@ -713,6 +719,9 @@ private Value getValue(GraphqlParser.ValueContext ctx) {
713719
BooleanValue booleanValue = new BooleanValue(Boolean.parseBoolean(ctx.BooleanValue().getText()));
714720
newNode(booleanValue, ctx);
715721
return booleanValue;
722+
} else if (ctx.NullValue() != null) {
723+
newNode(Null, ctx);
724+
return Null;
716725
} else if (ctx.StringValue() != null) {
717726
StringValue stringValue = new StringValue(parseString(ctx.StringValue().getText()));
718727
newNode(stringValue, ctx);

src/main/java/graphql/schema/idl/SchemaGenerator.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import graphql.language.IntValue;
1414
import graphql.language.InterfaceTypeDefinition;
1515
import graphql.language.Node;
16+
import graphql.language.NullValue;
1617
import graphql.language.ObjectTypeDefinition;
1718
import graphql.language.ObjectValue;
1819
import graphql.language.OperationTypeDefinition;
@@ -462,6 +463,8 @@ private Object buildValue(Value value) {
462463
result = arrayValue.getValues().stream().map(this::buildValue).toArray();
463464
} else if (value instanceof ObjectValue) {
464465
result = buildObjectValue((ObjectValue) value);
466+
} else if (value instanceof NullValue) {
467+
result = null;
465468
}
466469
return result;
467470

src/main/java/graphql/validation/ValidationUtil.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public boolean isValidLiteralValue(Value value, GraphQLType type) {
2525
if (value == null) {
2626
return !(type instanceof GraphQLNonNull);
2727
}
28+
if (value instanceof NullValue) {
29+
return !(type instanceof GraphQLNonNull);
30+
}
2831
if (value instanceof VariableReference) {
2932
return true;
3033
}

src/test/groovy/graphql/execution/ValuesResolverTest.groovy

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,4 +383,26 @@ class ValuesResolverTest extends Specification {
383383
[intKey: 10] | _
384384
[intKey: 10, requiredField: null] | _
385385
}
386+
387+
def "getVariableValues: simple types with values not provided in variables map"() {
388+
given:
389+
390+
def schema = TestUtil.schemaWithInputType(GraphQLString)
391+
VariableDefinition fooVarDef = new VariableDefinition("foo", new TypeName("String"))
392+
VariableDefinition barVarDef = new VariableDefinition("bar", new TypeName("String"))
393+
394+
when:
395+
def resolvedValues = resolver.getVariableValues(schema, [fooVarDef, barVarDef], InputValue)
396+
397+
then:
398+
resolvedValues == outputValue
399+
400+
where:
401+
InputValue || outputValue
402+
[foo: "added", bar: null] || [foo: "added", bar: null]
403+
404+
// later this will be true once we apply missing value code
405+
//[foo: "added"] || [foo: "added"]
406+
}
407+
386408
}

src/test/groovy/graphql/language/AstPrinterTest.groovy

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,4 +323,53 @@ query HeroNameAndFriends($episode: Episode = "JEDI") {
323323
'''
324324
}
325325

326+
//-------------------------------------------------
327+
def "ast printing of null"() {
328+
def query = '''
329+
query NullEpisodeQuery {
330+
hero(episode: null) {
331+
name
332+
}
333+
}
334+
'''
335+
def document = parse(query)
336+
String output = printAst(document)
337+
338+
expect:
339+
output == '''query NullEpisodeQuery {
340+
hero(episode: null) {
341+
name
342+
}
343+
}
344+
'''
345+
}
346+
347+
//-------------------------------------------------
348+
def "ast printing of default variables with null"() {
349+
def query = '''
350+
query NullVariableDefaultValueQuery($episode: Episode = null) {
351+
hero(episode: $episode) {
352+
name
353+
friends {
354+
name
355+
}
356+
}
357+
}
358+
'''
359+
def document = parse(query)
360+
String output = printAst(document)
361+
362+
expect:
363+
output == '''query NullVariableDefaultValueQuery($episode: Episode = null) {
364+
hero(episode: $episode) {
365+
name
366+
friends {
367+
name
368+
}
369+
}
370+
}
371+
'''
372+
}
373+
374+
326375
}

src/test/groovy/graphql/validation/ValidationUtilTest.groovy

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ class ValidationUtilTest extends Specification {
3939
!validationUtil.isValidLiteralValue(null, nonNull(GraphQLString))
4040
}
4141

42+
def "NullValue and NonNull is invalid"() {
43+
expect:
44+
!validationUtil.isValidLiteralValue(NullValue.Null, nonNull(GraphQLString))
45+
}
46+
4247
def "a nonNull value for a NonNull type is valid"() {
4348
expect:
4449
validationUtil.isValidLiteralValue(new StringValue("string"), nonNull(GraphQLString))
@@ -49,6 +54,11 @@ class ValidationUtilTest extends Specification {
4954
validationUtil.isValidLiteralValue(null, GraphQLString)
5055
}
5156

57+
def "NullValue is valid when type is NonNull"() {
58+
expect:
59+
validationUtil.isValidLiteralValue(NullValue.Null, GraphQLString)
60+
}
61+
5262
def "variables are valid"() {
5363
expect:
5464
validationUtil.isValidLiteralValue(new VariableReference("var"), GraphQLBoolean)

0 commit comments

Comments
 (0)