From 8f200382922d83cb73fb46702eb67305ef1cae43 Mon Sep 17 00:00:00 2001 From: Brad Baker Date: Thu, 7 Apr 2022 15:34:35 +1000 Subject: [PATCH] Variable document compilation now handles enums properly AND also that some values can be null --- src/main/java/graphql/language/EnumValue.java | 4 + src/main/java/graphql/language/NullValue.java | 4 + .../ValueToVariableValueCompiler.java | 17 ++- .../ValueToVariableValueCompilerTest.groovy | 118 ++++++++++++++++++ 4 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy diff --git a/src/main/java/graphql/language/EnumValue.java b/src/main/java/graphql/language/EnumValue.java index 08eea9672d..999b58712f 100644 --- a/src/main/java/graphql/language/EnumValue.java +++ b/src/main/java/graphql/language/EnumValue.java @@ -40,6 +40,10 @@ public EnumValue(String name) { this(name, null, emptyList(), IgnoredChars.EMPTY, emptyMap()); } + public static EnumValue of(String name) { + return newEnumValue().name(name).build(); + } + @Override public String getName() { return name; diff --git a/src/main/java/graphql/language/NullValue.java b/src/main/java/graphql/language/NullValue.java index e69fc40542..6808b3caa5 100644 --- a/src/main/java/graphql/language/NullValue.java +++ b/src/main/java/graphql/language/NullValue.java @@ -26,6 +26,10 @@ protected NullValue(SourceLocation sourceLocation, List comments, Ignor super(sourceLocation, comments, ignoredChars, additionalData); } + public static NullValue of() { + return NullValue.newNullValue().build(); + } + @Override public List getChildren() { return Collections.emptyList(); diff --git a/src/main/java/graphql/normalized/ValueToVariableValueCompiler.java b/src/main/java/graphql/normalized/ValueToVariableValueCompiler.java index 1743f78713..14e975bbab 100644 --- a/src/main/java/graphql/normalized/ValueToVariableValueCompiler.java +++ b/src/main/java/graphql/normalized/ValueToVariableValueCompiler.java @@ -4,6 +4,7 @@ import graphql.Internal; import graphql.language.ArrayValue; import graphql.language.BooleanValue; +import graphql.language.EnumValue; import graphql.language.FloatValue; import graphql.language.IntValue; import graphql.language.NullValue; @@ -41,7 +42,7 @@ static VariableValueWithDefinition normalizedInputValueToVariable(NormalizedInpu @SuppressWarnings("unchecked") @Nullable - private static Object normalisedValueToVariableValue(Object maybeValue) { + static Object normalisedValueToVariableValue(Object maybeValue) { Object variableValue; if (maybeValue instanceof NormalizedInputValue) { NormalizedInputValue normalizedInputValue = (NormalizedInputValue) maybeValue; @@ -52,8 +53,10 @@ private static Object normalisedValueToVariableValue(Object maybeValue) { variableValue = normalisedValueToVariableValues((List) inputValue); } else if (inputValue instanceof Map) { variableValue = normalisedValueToVariableValues((Map) inputValue); + } else if (inputValue == null) { + variableValue = null; } else { - throw new AssertException("Should never happen. Did not expect NormalizedInputValue.getValue() of type: " + inputValue.getClass()); + throw new AssertException("Should never happen. Did not expect NormalizedInputValue.getValue() of type: " + maybeClass(inputValue)); } } else if (maybeValue instanceof Value) { Value value = (Value) maybeValue; @@ -63,7 +66,7 @@ private static Object normalisedValueToVariableValue(Object maybeValue) { } else if (maybeValue instanceof Map) { variableValue = normalisedValueToVariableValues((Map) maybeValue); } else { - throw new AssertException("Should never happen. Did not expect type: " + maybeValue.getClass()); + throw new AssertException("Should never happen. Did not expect type: " + maybeClass(maybeValue)); } return variableValue; } @@ -115,10 +118,16 @@ private static Object toVariableValue(Value value) { return ((IntValue) value).getValue(); } else if (value instanceof BooleanValue) { return ((BooleanValue) value).isValue(); + } else if (value instanceof EnumValue) { + return ((EnumValue) value).getName(); } else if (value instanceof NullValue) { return null; } - throw new AssertException("Should never happen. Cannot handle node of type: " + value.getClass()); + throw new AssertException("Should never happen. Cannot handle node of type: " + maybeClass(value)); + } + + private static Object maybeClass(Object maybe) { + return maybe == null ? "null" : maybe.getClass(); } private static String getVarName(int variableOrdinal) { diff --git a/src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy b/src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy new file mode 100644 index 0000000000..58143c5b2c --- /dev/null +++ b/src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy @@ -0,0 +1,118 @@ +package graphql.normalized + +import graphql.language.ArrayValue +import graphql.language.BooleanValue +import graphql.language.EnumValue +import graphql.language.FloatValue +import graphql.language.IntValue +import graphql.language.NullValue +import graphql.language.ObjectField +import graphql.language.ObjectValue +import graphql.language.StringValue +import graphql.schema.idl.TypeUtil +import spock.lang.Specification + +class ValueToVariableValueCompilerTest extends Specification { + + def "cam handle different ast Value objects"() { + + expect: + def actual = ValueToVariableValueCompiler.normalisedValueToVariableValue(value) + actual == expected + + where: + value | expected + NullValue.of() | null + IntValue.of(666) | 666 + StringValue.of("str") | "str" + BooleanValue.of(true) | true + FloatValue.of(999d) | 999d + EnumValue.of("enumValue") | "enumValue" + ObjectValue.newObjectValue() + .objectField(ObjectField.newObjectField().name("a").value(IntValue.of(64)).build()) + .objectField(ObjectField.newObjectField().name("b").value(StringValue.of("65")).build()) + .build() | [a: 64, b: "65"] + ArrayValue.newArrayValue() + .value(IntValue.of(9)) + .value(StringValue.of("10")) + .value(EnumValue.of("enum")) + .build() | [9, "10", "enum"] + + } + + def "can handle NormalizedInputValue values that are literals"() { + expect: + def niv = new NormalizedInputValue("TypeName", value) + def actual = ValueToVariableValueCompiler.normalisedValueToVariableValue(niv) + actual == expected + + where: + value | expected + NullValue.of() | null + IntValue.of(666) | 666 + StringValue.of("str") | "str" + BooleanValue.of(true) | true + FloatValue.of(999d) | 999d + EnumValue.of("enumValue") | "enumValue" + ObjectValue.newObjectValue() + .objectField(ObjectField.newObjectField().name("a").value(IntValue.of(64)).build()) + .objectField(ObjectField.newObjectField().name("b").value(StringValue.of("65")).build()) + .build() | [a: 64, b: "65"] + ArrayValue.newArrayValue() + .value(IntValue.of(9)) + .value(StringValue.of("10")) + .value(EnumValue.of("enum")) + .build() | [9, "10", "enum"] + + + } + + def "can handle NormalizedInputValue values that are not literals"() { + expect: + def niv = new NormalizedInputValue("TypeName", value) + def actual = ValueToVariableValueCompiler.normalisedValueToVariableValue(niv) + actual == expected + + where: + value | expected + null | null + [IntValue.of(666), IntValue.of(664)] | [666, 664] + [a: IntValue.of(666), b: IntValue.of(664)] | [a: 666, b: 664] + + // at present we dont handle straight up java objects like 123 because + // the ValueResolver never produces them during + // ValueResolver.getNormalizedVariableValues say - this is debatable behavior + // but for now this is what we do + } + + + def "can print variables as expected"() { + expect: + def niv = new NormalizedInputValue(typeName, value) + def actual = ValueToVariableValueCompiler.normalizedInputValueToVariable(niv, varCount) + actual.value == expectedValue + actual.variableReference.name == expectedVarName + actual.definition.name == expectedVarName + TypeUtil.simplePrint(actual.definition.type) == typeName + + where: + value | varCount | typeName | expectedValue | expectedVarName + NullValue.newNullValue().build() | 1 | "ID" | null | "v1" + IntValue.of(666) | 2 | "Int!" | 666 | "v2" + StringValue.of("str") | 3 | "String" | "str" | "v3" + BooleanValue.of(true) | 4 | "Boolean!" | true | "v4" + FloatValue.of(999d) | 5 | "Float" | 999d | "v5" + EnumValue.of("enumValue") | 6 | "Foo!" | "enumValue" | "v6" + ObjectValue.newObjectValue() + .objectField(ObjectField.newObjectField().name("a").value(IntValue.of(64)).build()) + .objectField(ObjectField.newObjectField().name("b").value(StringValue.of("65")).build()) + .build() | 7 | "ObjectType" | [a: 64, b: "65"] | "v7" + ArrayValue.newArrayValue() + .value(IntValue.of(9)) + .value(StringValue.of("10")) + .value(EnumValue.of("enum")) + .build() | 8 | "ArrayType" | [9, "10", "enum"] | "v8" + + + } +}