22
33
44import graphql .GraphQLException ;
5- import graphql .language .*;
6- import graphql .schema .*;
5+ import graphql .language .Argument ;
6+ import graphql .language .ArrayValue ;
7+ import graphql .language .NullValue ;
8+ import graphql .language .ObjectField ;
9+ import graphql .language .ObjectValue ;
10+ import graphql .language .Value ;
11+ import graphql .language .VariableDefinition ;
12+ import graphql .language .VariableReference ;
13+ import graphql .schema .GraphQLArgument ;
14+ import graphql .schema .GraphQLEnumType ;
15+ import graphql .schema .GraphQLInputObjectField ;
16+ import graphql .schema .GraphQLInputObjectType ;
17+ import graphql .schema .GraphQLList ;
18+ import graphql .schema .GraphQLNonNull ;
19+ import graphql .schema .GraphQLScalarType ;
20+ import graphql .schema .GraphQLSchema ;
21+ import graphql .schema .GraphQLType ;
722
8- import java .util .*;
23+ import java .util .ArrayList ;
24+ import java .util .Collections ;
25+ import java .util .LinkedHashMap ;
26+ import java .util .List ;
27+ import java .util .Map ;
28+ import java .util .stream .Collectors ;
929
1030public class ValuesResolver {
1131
1232
13- public Map <String , Object > getVariableValues (GraphQLSchema schema , List <VariableDefinition > variableDefinitions , Map <String , Object > inputs ) {
33+ public Map <String , Object > getVariableValues (GraphQLSchema schema , List <VariableDefinition > variableDefinitions , Map <String , Object > args ) {
1434 Map <String , Object > result = new LinkedHashMap <>();
1535 for (VariableDefinition variableDefinition : variableDefinitions ) {
16- result .put (variableDefinition .getName (), getVariableValue (schema , variableDefinition , inputs .get (variableDefinition .getName ())));
36+ String varName = variableDefinition .getName ();
37+ // we transfer the variable as field arguments if its present as value
38+ if (args .containsKey (varName )) {
39+ Object arg = args .get (varName );
40+ Object variableValue = getVariableValue (schema , variableDefinition , arg );
41+ result .put (varName , variableValue );
42+ }
1743 }
1844 return result ;
1945 }
@@ -23,14 +49,19 @@ public Map<String, Object> getArgumentValues(List<GraphQLArgument> argumentTypes
2349 Map <String , Object > result = new LinkedHashMap <>();
2450 Map <String , Argument > argumentMap = argumentMap (arguments );
2551 for (GraphQLArgument fieldArgument : argumentTypes ) {
26- Argument argument = argumentMap .get (fieldArgument .getName ());
52+ String argName = fieldArgument .getName ();
53+ Argument argument = argumentMap .get (argName );
2754 Object value ;
2855 if (argument != null ) {
2956 value = coerceValueAst (fieldArgument .getType (), argument .getValue (), variables );
3057 } else {
3158 value = fieldArgument .getDefaultValue ();
3259 }
33- result .put (fieldArgument .getName (), value );
60+ // only put an arg into the result IF they specified a variable at all or
61+ // the default value ended up being something non null
62+ if (argumentMap .containsKey (argName ) || value != null ) {
63+ result .put (argName , value );
64+ }
3465 }
3566 return result ;
3667 }
@@ -48,6 +79,7 @@ private Map<String, Argument> argumentMap(List<Argument> arguments) {
4879 private Object getVariableValue (GraphQLSchema schema , VariableDefinition variableDefinition , Object inputValue ) {
4980 GraphQLType type = TypeFromAST .getTypeFromAST (schema , variableDefinition .getType ());
5081
82+ //noinspection ConstantConditions
5183 if (!isValid (type , inputValue )) {
5284 throw new GraphQLException ("Invalid value for type" );
5385 }
@@ -67,7 +99,7 @@ private Object coerceValue(GraphQLType graphQLType, Object value) {
6799 if (graphQLType instanceof GraphQLNonNull ) {
68100 Object returnValue = coerceValue (((GraphQLNonNull ) graphQLType ).getWrappedType (), value );
69101 if (returnValue == null ) {
70- throw new GraphQLException ( "Null value for NonNull type " + graphQLType );
102+ throw new NonNullableValueCoercedAsNullException ( graphQLType );
71103 }
72104 return returnValue ;
73105 }
@@ -81,6 +113,7 @@ private Object coerceValue(GraphQLType graphQLType, Object value) {
81113 } else if (graphQLType instanceof GraphQLList ) {
82114 return coerceValueForList ((GraphQLList ) graphQLType , value );
83115 } else if (graphQLType instanceof GraphQLInputObjectType && value instanceof Map ) {
116+ //noinspection unchecked
84117 return coerceValueForInputObjectType ((GraphQLInputObjectType ) graphQLType , (Map <String , Object >) value );
85118 } else if (graphQLType instanceof GraphQLInputObjectType ) {
86119 return value ;
@@ -91,7 +124,15 @@ private Object coerceValue(GraphQLType graphQLType, Object value) {
91124
92125 private Object coerceValueForInputObjectType (GraphQLInputObjectType inputObjectType , Map <String , Object > input ) {
93126 Map <String , Object > result = new LinkedHashMap <>();
94- for (GraphQLInputObjectField inputField : inputObjectType .getFields ()) {
127+ List <GraphQLInputObjectField > fields = inputObjectType .getFields ();
128+ List <String > fieldNames = fields .stream ().map (GraphQLInputObjectField ::getName ).collect (Collectors .toList ());
129+ for (String inputFieldName : input .keySet ()) {
130+ if (!fieldNames .contains (inputFieldName )) {
131+ throw new InputMapDefinesTooManyFieldsException (inputObjectType , inputFieldName );
132+ }
133+ }
134+
135+ for (GraphQLInputObjectField inputField : fields ) {
95136 if (input .containsKey (inputField .getName ()) || alwaysHasValue (inputField )) {
96137 Object value = coerceValue (inputField .getType (), input .get (inputField .getName ()));
97138 result .put (inputField .getName (), value == null ? inputField .getDefaultValue () : value );
@@ -129,6 +170,9 @@ private Object coerceValueAst(GraphQLType type, Value inputValue, Map<String, Ob
129170 if (inputValue instanceof VariableReference ) {
130171 return variables .get (((VariableReference ) inputValue ).getName ());
131172 }
173+ if (inputValue instanceof NullValue ) {
174+ return null ;
175+ }
132176 if (type instanceof GraphQLScalarType ) {
133177 return ((GraphQLScalarType ) type ).getCoercing ().parseLiteral (inputValue );
134178 }
@@ -167,22 +211,48 @@ private Object coerceValueAstForInputObject(GraphQLInputObjectType type, ObjectV
167211
168212 for (GraphQLInputObjectField inputTypeField : type .getFields ()) {
169213 if (inputValueFieldsByName .containsKey (inputTypeField .getName ())) {
214+ boolean putObjectInMap = true ;
215+
170216 ObjectField field = inputValueFieldsByName .get (inputTypeField .getName ());
171- Object fieldValue = coerceValueAst (inputTypeField .getType (), field .getValue (), variables );
172- if (fieldValue == null ) {
173- fieldValue = inputTypeField .getDefaultValue ();
217+ Value fieldInputValue = field .getValue ();
218+
219+ Object fieldObject = null ;
220+ if (fieldInputValue instanceof VariableReference ) {
221+ String varName = ((VariableReference ) fieldInputValue ).getName ();
222+ if (!variables .containsKey (varName )) {
223+ putObjectInMap = false ;
224+ } else {
225+ fieldObject = variables .get (varName );
226+ }
227+ } else {
228+ fieldObject = coerceValueAst (inputTypeField .getType (), fieldInputValue , variables );
229+ }
230+
231+ if (fieldObject == null ) {
232+ if (!field .getValue ().isEqualTo (NullValue .Null )) {
233+ fieldObject = inputTypeField .getDefaultValue ();
234+ }
235+ }
236+ if (putObjectInMap ) {
237+ result .put (field .getName (), fieldObject );
238+ } else {
239+ assertNonNullInputField (inputTypeField );
174240 }
175- result .put (field .getName (), fieldValue );
176241 } else if (inputTypeField .getDefaultValue () != null ) {
177242 result .put (inputTypeField .getName (), inputTypeField .getDefaultValue ());
178- } else if (inputTypeField .getType () instanceof GraphQLNonNull ) {
179- // Possibly overkill; an object literal with a missing non null field shouldn't pass validation
180- throw new GraphQLException ("Null value for NonNull type " + inputTypeField .getType ());
243+ } else {
244+ assertNonNullInputField (inputTypeField );
181245 }
182246 }
183247 return result ;
184248 }
185249
250+ private void assertNonNullInputField (GraphQLInputObjectField inputTypeField ) {
251+ if (inputTypeField .getType () instanceof GraphQLNonNull ) {
252+ throw new NonNullableValueCoercedAsNullException (inputTypeField .getType ());
253+ }
254+ }
255+
186256 private Map <String , ObjectField > mapObjectValueFieldsByName (ObjectValue inputValue ) {
187257 Map <String , ObjectField > inputValueFieldsByName = new LinkedHashMap <>();
188258 for (ObjectField objectField : inputValue .getObjectFields ()) {
0 commit comments