Skip to content

Commit 15a70e5

Browse files
authored
Parse input type correctly (graphql-java#2820)
* add new type parser * add more test coverage * test more argument parsing * add type parser tests * add type parser method in Parser * fix tests
1 parent 0869826 commit 15a70e5

8 files changed

Lines changed: 124 additions & 20 deletions

File tree

‎src/main/java/graphql/normalized/ValueToVariableValueCompiler.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
import graphql.language.ObjectField;
1212
import graphql.language.ObjectValue;
1313
import graphql.language.StringValue;
14-
import graphql.language.TypeName;
1514
import graphql.language.Value;
1615
import graphql.language.VariableDefinition;
1716
import graphql.language.VariableReference;
17+
import graphql.parser.Parser;
1818
import org.jetbrains.annotations.NotNull;
1919
import org.jetbrains.annotations.Nullable;
2020

@@ -35,7 +35,7 @@ static VariableValueWithDefinition normalizedInputValueToVariable(NormalizedInpu
3535
variableValue,
3636
VariableDefinition.newVariableDefinition()
3737
.name(varName)
38-
.type(TypeName.newTypeName(normalizedInputValue.getTypeName()).build())
38+
.type(Parser.parseType(normalizedInputValue.getTypeName()))
3939
.build(),
4040
VariableReference.newVariableReference().name(varName).build());
4141
}

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import graphql.language.Document;
55
import graphql.language.Node;
66
import graphql.language.SourceLocation;
7+
import graphql.language.Type;
78
import graphql.language.Value;
89
import graphql.parser.antlr.GraphqlBaseListener;
910
import graphql.parser.antlr.GraphqlLexer;
@@ -71,6 +72,19 @@ public static Value<?> parseValue(String input) throws InvalidSyntaxException {
7172
return new Parser().parseValueImpl(input);
7273
}
7374

75+
/**
76+
* Parses a string input into a graphql AST Type
77+
*
78+
* @param input the input to parse
79+
*
80+
* @return an AST {@link Type}
81+
*
82+
* @throws InvalidSyntaxException if the input is not valid graphql syntax
83+
*/
84+
public static Type<?> parseType(String input) throws InvalidSyntaxException {
85+
return new Parser().parseTypeImpl(input);
86+
}
87+
7488
/**
7589
* Parses a string input into a graphql AST {@link Document}
7690
*
@@ -169,6 +183,19 @@ private Value<?> parseValueImpl(String input) throws InvalidSyntaxException {
169183
return (Value<?>) parseImpl(multiSourceReader, nodeFunction, null);
170184
}
171185

186+
private Type<?> parseTypeImpl(String input) throws InvalidSyntaxException {
187+
BiFunction<GraphqlParser, GraphqlAntlrToLanguage, Object[]> nodeFunction = (parser, toLanguage) -> {
188+
final GraphqlParser.TypeContext documentContext = parser.type();
189+
Type<?> value = toLanguage.createType(documentContext);
190+
return new Object[]{documentContext, value};
191+
};
192+
MultiSourceReader multiSourceReader = MultiSourceReader.newMultiSourceReader()
193+
.string(input, null)
194+
.trackData(true)
195+
.build();
196+
return (Type<?>) parseImpl(multiSourceReader, nodeFunction, null);
197+
}
198+
172199
private Node<?> parseImpl(Reader reader, BiFunction<GraphqlParser, GraphqlAntlrToLanguage, Object[]> nodeFunction, ParserOptions parserOptions) throws InvalidSyntaxException {
173200
MultiSourceReader multiSourceReader;
174201
if (reader instanceof MultiSourceReader) {

src/test/java/graphql/introspection/IntrospectionWithDirectivesSupportTest.groovy renamed to src/test/groovy/graphql/introspection/IntrospectionWithDirectivesSupportTest.groovy

File renamed without changes.

‎src/test/groovy/graphql/normalized/ExecutableNormalizedOperationToAstCompilerTest.groovy‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import graphql.TestUtil
55
import graphql.language.AstPrinter
66
import graphql.language.AstSorter
77
import graphql.language.Document
8+
import graphql.language.IntValue
9+
import graphql.language.StringValue
810
import graphql.schema.GraphQLSchema
911
import graphql.schema.idl.RuntimeWiring
1012
import graphql.schema.idl.TestLiveMockedWiringFactory
@@ -1138,6 +1140,41 @@ class ExecutableNormalizedOperationToAstCompilerTest extends Specification {
11381140
'''
11391141
}
11401142

1143+
1144+
def "test input object arguments 2"() {
1145+
def sdl = '''
1146+
type Query {
1147+
foo1(arg: Outer): String
1148+
}
1149+
input Outer {
1150+
a : Inner
1151+
}
1152+
input Inner {
1153+
b : InnerInner
1154+
}
1155+
input InnerInner {
1156+
c : Int
1157+
d : String
1158+
}
1159+
'''
1160+
def query = '''query something($v : Int){
1161+
foo1(arg: { a : { b : { c :$v, d :"ast" }}})
1162+
}
1163+
'''
1164+
GraphQLSchema schema = mkSchema(sdl)
1165+
def fields = createNormalizedFields(schema, query,["v":123])
1166+
when:
1167+
def result = compileToDocument(schema, QUERY, null, fields, allVariables)
1168+
def documentPrinted = AstPrinter.printAst(new AstSorter().sort(result.document))
1169+
1170+
then:
1171+
fields[0].normalizedArguments["arg"].value["a"].value["b"].value["c"].value.isEqualTo(IntValue.of(123))
1172+
fields[0].normalizedArguments["arg"].value["a"].value["b"].value["d"].value.isEqualTo(StringValue.of("ast"))
1173+
documentPrinted.trim() == '''query ($v0: Outer) {
1174+
foo1(arg: $v0)
1175+
}'''
1176+
}
1177+
11411178
def "test mutations"() {
11421179
def sdl = '''
11431180
type Query {

src/test/java/graphql/normalized/NormalizedInputValueTest.groovy renamed to src/test/groovy/graphql/normalized/NormalizedInputValueTest.groovy

File renamed without changes.

src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy renamed to src/test/groovy/graphql/normalized/ValueToVariableValueCompilerTest.groovy

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ import graphql.language.BooleanValue
55
import graphql.language.EnumValue
66
import graphql.language.FloatValue
77
import graphql.language.IntValue
8+
import graphql.language.ListType
9+
import graphql.language.NonNullType
810
import graphql.language.NullValue
911
import graphql.language.ObjectField
1012
import graphql.language.ObjectValue
1113
import graphql.language.StringValue
14+
import graphql.language.Type
15+
import graphql.language.TypeName
1216
import graphql.schema.idl.TypeUtil
1317
import spock.lang.Specification
1418

@@ -93,26 +97,27 @@ class ValueToVariableValueCompilerTest extends Specification {
9397
actual.value == expectedValue
9498
actual.variableReference.name == expectedVarName
9599
actual.definition.name == expectedVarName
96-
TypeUtil.simplePrint(actual.definition.type) == typeName
100+
// compare actual type
101+
def actualType = actual.definition.type
102+
actualType.isEqualTo(expectedType)
103+
if(actualType instanceof NonNullType || actualType instanceof ListType){
104+
actualType.type.isEqualTo(expectedType.type)
105+
}
106+
TypeUtil.simplePrint(actualType) == typeName
97107

98108
where:
99-
value | varCount | typeName | expectedValue | expectedVarName
100-
NullValue.newNullValue().build() | 1 | "ID" | null | "v1"
101-
IntValue.of(666) | 2 | "Int!" | 666 | "v2"
102-
StringValue.of("str") | 3 | "String" | "str" | "v3"
103-
BooleanValue.of(true) | 4 | "Boolean!" | true | "v4"
104-
FloatValue.of(999d) | 5 | "Float" | 999d | "v5"
105-
EnumValue.of("enumValue") | 6 | "Foo!" | "enumValue" | "v6"
106-
ObjectValue.newObjectValue()
107-
.objectField(ObjectField.newObjectField().name("a").value(IntValue.of(64)).build())
108-
.objectField(ObjectField.newObjectField().name("b").value(StringValue.of("65")).build())
109-
.build() | 7 | "ObjectType" | [a: 64, b: "65"] | "v7"
110-
ArrayValue.newArrayValue()
111-
.value(IntValue.of(9))
112-
.value(StringValue.of("10"))
113-
.value(EnumValue.of("enum"))
114-
.build() | 8 | "ArrayType" | [9, "10", "enum"] | "v8"
115-
109+
value | varCount | typeName | expectedValue | expectedVarName | expectedType
110+
NullValue.newNullValue().build() | 1 | "ID" | null | "v1" | new TypeName("ID")
111+
IntValue.of(666) | 2 | "Int!" | 666 | "v2" | new NonNullType(new TypeName("Int"))
112+
StringValue.of("str") | 3 | "String" | "str" | "v3" | new TypeName("String")
113+
BooleanValue.of(true) | 4 | "Boolean!" | true | "v4" | new NonNullType(new TypeName("Boolean"))
114+
FloatValue.of(999d) | 5 | "Float" | 999d | "v5" | new TypeName("Float")
115+
EnumValue.of("enumValue") | 6 | "Foo!" | "enumValue" | "v6" | new NonNullType(new TypeName("Foo"))
116+
["a" : IntValue.of(64),
117+
"b":IntValue.of(65) ] | 7 | "ObjectType" | [a: 64, b: 65] | "v7" | new TypeName("ObjectType")
118+
[StringValue.of("9"),
119+
StringValue.of("10"),
120+
StringValue.of("11")] | 8 | "[String]" | ["9", "10", "11"] | "v8" | new ListType((new TypeName("String")))
116121

117122
}
118123
}

‎src/test/groovy/graphql/parser/ParserTest.groovy‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,41 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases"""
961961
'{string : "s", integer : 1, boolean : true}' | ObjectValue.class
962962
}
963963

964+
@Unroll
965+
def 'parse type literals #typeLiteral'() {
966+
expect:
967+
Parser.parseType(typeLiteral).isEqualTo(expectedType)
968+
969+
where:
970+
typeLiteral | expectedType
971+
"Foo" | new TypeName("Foo")
972+
"String" | new TypeName("String")
973+
"[String]" | new ListType(new TypeName("String"))
974+
"Boolean!" | new NonNullType(new TypeName("Boolean"))
975+
"Boolean !" | new NonNullType(new TypeName("Boolean"))
976+
"Boolean, !" | new NonNullType(new TypeName("Boolean"))
977+
"[Int]!" | new NonNullType(new ListType(new TypeName("Int")))
978+
"[[String!]]" | new ListType(new ListType(new NonNullType(new TypeName("String"))))
979+
}
980+
981+
@Unroll
982+
def 'parse invalid type literal #typeLiteral'() {
983+
when:
984+
Parser.parseType(typeLiteral)
985+
986+
then:
987+
thrown(InvalidSyntaxException)
988+
989+
where:
990+
typeLiteral | _
991+
"[String" | _
992+
"[[Int]" | _
993+
"![Foo]" | _
994+
"!Boolean" | _
995+
"[Int!" | _
996+
"[String]]" | _
997+
}
998+
964999
def "ignored chars can be set on or off"() {
9651000
def s = '''
9661001

src/test/java/graphql/schema/validation/AppliedDirectivesAreValidTest.groovy renamed to src/test/groovy/graphql/schema/validation/AppliedDirectivesAreValidTest.groovy

File renamed without changes.

0 commit comments

Comments
 (0)