Skip to content

Commit 3dff821

Browse files
authored
Support for a more powerful way to get argument and input field values (graphql-java#2363)
* Support for a more powerful way to get argument and input field values * PR feedback on maming * PR feedback on documentation
1 parent 9808fa3 commit 3dff821

6 files changed

Lines changed: 209 additions & 4 deletions

File tree

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ public static Object valueToInternalValue(InputValueWithState inputValueWithStat
223223
return assertShouldNeverHappen("unexpected value state " + inputValueWithState);
224224
}
225225

226+
227+
@Nullable
228+
@SuppressWarnings("unchecked")
229+
public static <T> T getInputValueImpl(GraphQLInputType inputType, InputValueWithState inputValue) {
230+
if (inputValue.isNotSet()) {
231+
return null;
232+
}
233+
return (T) valueToInternalValue(inputValue, inputType);
234+
}
235+
226236
/**
227237
* No validation: the external value is assumed to be valid.
228238
*/

src/main/java/graphql/language/FloatValue.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ public Builder value(BigDecimal value) {
133133
return this;
134134
}
135135

136+
public Builder value(double value) {
137+
this.value = BigDecimal.valueOf(value);
138+
return this;
139+
}
140+
141+
public Builder value(long value) {
142+
this.value = BigDecimal.valueOf(value);
143+
return this;
144+
}
145+
136146
public Builder comments(List<Comment> comments) {
137147
this.comments = ImmutableList.copyOf(comments);
138148
return this;

src/main/java/graphql/schema/GraphQLArgument.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static graphql.Assert.assertNotNull;
1919
import static graphql.Assert.assertValidName;
20+
import static graphql.execution.ValuesResolver.getInputValueImpl;
2021

2122
/**
2223
* This defines an argument that can be supplied to a graphql field (via {@link graphql.schema.GraphQLFieldDefinition}.
@@ -94,7 +95,7 @@ public GraphQLInputType getType() {
9495
/**
9596
* The default value of this argument.
9697
*
97-
* @return
98+
* @return a {@link InputValueWithState} that represents the arguments default value
9899
*/
99100
public @NotNull InputValueWithState getArgumentDefaultValue() {
100101
return defaultValue;
@@ -116,6 +117,45 @@ public boolean hasSetValue() {
116117
return value;
117118
}
118119

120+
/**
121+
* This static helper method will give out a java value based on the semantics captured
122+
* in the {@link InputValueWithState} from {@link GraphQLArgument#getArgumentValue()}
123+
*
124+
* Note : You MUST only call this on a {@link GraphQLArgument} that is part of a fully formed schema. We need
125+
* all of the types to be resolved in order for this work correctly.
126+
*
127+
* Note: This method will return null if the value is not set or explicitly set to null. If you you to know the difference
128+
* when "not set" and "set to null" then you cant use this method. Rather you should use {@link GraphQLArgument#getArgumentValue()}
129+
* and use the {@link InputValueWithState#isNotSet()} methods to decide how to handle those values.
130+
*
131+
* @param argument the fully formed {@link GraphQLArgument}
132+
* @param <T> the type you want it cast as
133+
*
134+
* @return a value of type T which is the java value of the argument
135+
*/
136+
public static <T> T getArgumentValue(GraphQLArgument argument) {
137+
return getInputValueImpl(argument.getType(), argument.getArgumentValue());
138+
}
139+
140+
/**
141+
* This static helper method will give out a java value based on the semantics captured
142+
* in the {@link InputValueWithState} from {@link GraphQLArgument#getArgumentDefaultValue()}
143+
*
144+
* Note : You MUST only call this on a {@link GraphQLArgument} that is part of a fully formed schema. We need
145+
* all of the types to be resolved in order for this work correctly.
146+
*
147+
* Note: This method will return null if the value is not set or explicitly set to null. If you you to know the difference
148+
* when "not set" and "set to null" then you cant use this method. Rather you should use {@link GraphQLArgument#getArgumentDefaultValue()}
149+
* and use the {@link InputValueWithState#isNotSet()} methods to decide how to handle those values.
150+
*
151+
* @param argument the fully formed {@link GraphQLArgument}
152+
* @param <T> the type you want it cast as
153+
*
154+
* @return a value of type T which is the java value of the argument default
155+
*/
156+
public static <T> T getArgumentDefaultValue(GraphQLArgument argument) {
157+
return getInputValueImpl(argument.getType(), argument.getArgumentDefaultValue());
158+
}
119159

120160
public String getDescription() {
121161
return description;

src/main/java/graphql/schema/GraphQLInputObjectField.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import static graphql.Assert.assertNotNull;
1818
import static graphql.Assert.assertValidName;
19+
import static graphql.execution.ValuesResolver.getInputValueImpl;
1920

2021
/**
2122
* Input objects defined via {@link graphql.schema.GraphQLInputObjectType} contains these input fields.
@@ -80,14 +81,35 @@ public GraphQLInputType getType() {
8081
/**
8182
* The default value of this input field.
8283
*
83-
* The semantics of the returned Object depend on getDefaultValueState.
84+
* The semantics of the returned Object depend on how the {@link InputValueWithState} was created.
8485
*
85-
* @return
86+
* @return a input value with captured state
8687
*/
8788
public @NotNull InputValueWithState getInputFieldDefaultValue() {
8889
return defaultValue;
8990
}
9091

92+
/**
93+
* This static helper method will give out a java value based on the semantics captured
94+
* in the {@link InputValueWithState} from {@link GraphQLInputObjectField#getInputFieldDefaultValue()}
95+
*
96+
* Note : You MUST only call this on a {@link GraphQLInputObjectField} that is part of a fully formed schema. We need
97+
* all of the types to be resolved in order for this work correctly.
98+
*
99+
* Note: This method will return null if the value is not set or explicitly set to null. If you you to know the difference
100+
* when "not set" and "set to null" then you cant use this method. Rather you should use {@link GraphQLInputObjectField#getInputFieldDefaultValue()}
101+
* and use the {@link InputValueWithState#isNotSet()} methods to decide how to handle those values.
102+
*
103+
* @param inputObjectField the fully formed {@link GraphQLInputObjectField}
104+
* @param <T> the type you want it cast as
105+
*
106+
* @return a value of type T which is the java value of the input field default
107+
*/
108+
public static <T> T getInputFieldDefaultValue(GraphQLInputObjectField inputObjectField) {
109+
return getInputValueImpl(inputObjectField.getType(), inputObjectField.getInputFieldDefaultValue());
110+
}
111+
112+
91113
public boolean hasSetDefaultValue() {
92114
return defaultValue.isSet();
93115
}

src/test/groovy/graphql/schema/GraphQLArgumentTest.groovy

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package graphql.schema
22

3+
import graphql.language.FloatValue
34
import spock.lang.Specification
45

6+
import static graphql.Scalars.GraphQLFloat
57
import static graphql.Scalars.GraphQLInt
68
import static graphql.Scalars.GraphQLString
79
import static graphql.schema.GraphQLDirective.newDirective
@@ -112,4 +114,78 @@ class GraphQLArgumentTest extends Specification {
112114
argument.getDirective("directive2") != null
113115
argument.getDirective("directive3") != null
114116
}
117+
118+
def "can get values statically"() {
119+
when:
120+
GraphQLArgument startingArg = GraphQLArgument.newArgument()
121+
.name("F1")
122+
.type(GraphQLFloat)
123+
.description("F1_description")
124+
.valueProgrammatic(4.56d)
125+
.defaultValueProgrammatic(1.23d)
126+
.build()
127+
def inputValue = startingArg.getArgumentValue()
128+
def resolvedValue = GraphQLArgument.getArgumentValue(startingArg)
129+
130+
def inputDefaultValue = startingArg.getArgumentDefaultValue()
131+
def resolvedDefaultValue = GraphQLArgument.getArgumentDefaultValue(startingArg)
132+
133+
then:
134+
inputValue.isExternal()
135+
inputValue.getValue() == 4.56d
136+
resolvedValue == 4.56d
137+
138+
inputDefaultValue.isExternal()
139+
inputDefaultValue.getValue() == 1.23d
140+
resolvedDefaultValue == 1.23d
141+
142+
when:
143+
startingArg = GraphQLArgument.newArgument()
144+
.name("F1")
145+
.type(GraphQLFloat)
146+
.description("F1_description")
147+
.valueLiteral(FloatValue.newFloatValue().value(4.56d).build())
148+
.defaultValueLiteral(FloatValue.newFloatValue().value(1.23d).build())
149+
.build()
150+
151+
inputValue = startingArg.getArgumentValue()
152+
resolvedValue = GraphQLArgument.getArgumentValue(startingArg)
153+
154+
inputDefaultValue = startingArg.getArgumentDefaultValue()
155+
resolvedDefaultValue = GraphQLArgument.getArgumentDefaultValue(startingArg)
156+
157+
then:
158+
159+
inputValue.isLiteral()
160+
(inputValue.getValue() as FloatValue).getValue().toDouble() == 4.56d
161+
resolvedValue == 4.56d
162+
163+
inputDefaultValue.isLiteral()
164+
(inputDefaultValue.getValue() as FloatValue).getValue().toDouble() == 1.23d
165+
resolvedDefaultValue == 1.23d
166+
167+
when:
168+
startingArg = GraphQLArgument.newArgument()
169+
.name("F1")
170+
.type(GraphQLFloat)
171+
.description("F1_description")
172+
.build()
173+
174+
inputValue = startingArg.getArgumentValue()
175+
resolvedValue = GraphQLArgument.getArgumentValue(startingArg)
176+
177+
inputDefaultValue = startingArg.getArgumentDefaultValue()
178+
resolvedDefaultValue = GraphQLArgument.getArgumentDefaultValue(startingArg)
179+
180+
then:
181+
182+
inputValue.isNotSet()
183+
inputValue.getValue() == null
184+
resolvedValue == null
185+
186+
inputDefaultValue.isNotSet()
187+
inputDefaultValue.getValue() == null
188+
resolvedDefaultValue == null
189+
}
190+
115191
}

src/test/groovy/graphql/schema/GraphQLInputObjectFieldTest.groovy

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package graphql.schema
22

3+
import graphql.language.FloatValue
34
import spock.lang.Specification
45

56
import static graphql.Scalars.GraphQLFloat
@@ -46,12 +47,58 @@ class GraphQLInputObjectFieldTest extends Specification {
4647
transformedField.type == GraphQLInt
4748
transformedField.description == "F1_description" // left alone
4849

49-
! transformedField.isDeprecated()
50+
!transformedField.isDeprecated()
5051
transformedField.getDeprecationReason() == null
5152

5253
transformedField.getDirectives().size() == 3
5354
transformedField.getDirective("directive1") != null
5455
transformedField.getDirective("directive2") != null
5556
transformedField.getDirective("directive3") != null
5657
}
58+
59+
def "can get default values statically"() {
60+
when:
61+
def startingField = newInputObjectField()
62+
.name("F1")
63+
.type(GraphQLFloat)
64+
.description("F1_description")
65+
.defaultValueProgrammatic(1.23d)
66+
.build()
67+
def inputValue = startingField.getInputFieldDefaultValue()
68+
def resolvedValue = GraphQLInputObjectField.getInputFieldDefaultValue(startingField)
69+
70+
then:
71+
inputValue.isExternal()
72+
inputValue.getValue() == 1.23d
73+
resolvedValue == 1.23d
74+
75+
when:
76+
startingField = newInputObjectField()
77+
.name("F1")
78+
.type(GraphQLFloat)
79+
.description("F1_description")
80+
.defaultValueLiteral(FloatValue.newFloatValue().value(1.23d).build())
81+
.build()
82+
inputValue = startingField.getInputFieldDefaultValue()
83+
resolvedValue = GraphQLInputObjectField.getInputFieldDefaultValue(startingField)
84+
85+
then:
86+
inputValue.isLiteral()
87+
(inputValue.getValue() as FloatValue).getValue().toDouble() == 1.23d
88+
resolvedValue == 1.23d
89+
90+
when: " we have no values "
91+
startingField = newInputObjectField()
92+
.name("F1")
93+
.type(GraphQLFloat)
94+
.description("F1_description")
95+
.build()
96+
inputValue = startingField.getInputFieldDefaultValue()
97+
resolvedValue = GraphQLInputObjectField.getInputFieldDefaultValue(startingField)
98+
99+
then:
100+
inputValue.isNotSet()
101+
inputValue.getValue() == null
102+
resolvedValue == null
103+
}
57104
}

0 commit comments

Comments
 (0)