@@ -14,6 +14,9 @@ import (
1414	"github.com/graphql-go/graphql/language/printer" 
1515)
1616
17+ // Used to detect the difference between a "null" literal and not present 
18+ type  nullValue  struct {}
19+ 
1720// Prepares an object map of variableValues of the correct type based on the 
1821// provided variable definitions and arbitrary input. If the input cannot be 
1922// parsed to match the variable definitions, a GraphQLError will be returned. 
@@ -27,7 +30,7 @@ func getVariableValues(
2730			continue 
2831		}
2932		varName  :=  defAST .Variable .Name .Value 
30- 		if  varValue , err  :=  getVariableValue (schema , defAST , inputs [ varName ] ); err  !=  nil  {
33+ 		if  varValue , err  :=  getVariableValue (schema , defAST , getValueOrNull ( inputs ,  varName ) ); err  !=  nil  {
3134			return  values , err 
3235		} else  {
3336			values [varName ] =  varValue 
@@ -36,6 +39,25 @@ func getVariableValues(
3639	return  values , nil 
3740}
3841
42+ func  getValueOrNull (values  map [string ]interface {}, name  string ) interface {} {
43+ 	if  tmp , ok  :=  values [name ]; ok  { // Is present 
44+ 		if  tmp  ==  nil  {
45+ 			return  nullValue {} // Null value 
46+ 		} else  {
47+ 			return  tmp 
48+ 		}
49+ 	}
50+ 	return  nil  // Not present 
51+ }
52+ 
53+ func  addValueOrNull (values  map [string ]interface {}, name  string , value  interface {}) {
54+ 	if  _ , ok  :=  value .(nullValue ); ok  { // Null value 
55+ 		values [name ] =  nil 
56+ 	} else  if  ! isNullish (value ) { // Not present 
57+ 		values [name ] =  value 
58+ 	}
59+ }
60+ 
3961// Prepares an object map of argument values given a list of argument 
4062// definitions and list of argument AST nodes. 
4163func  getArgumentValues (
@@ -60,9 +82,7 @@ func getArgumentValues(
6082		if  tmp  =  valueFromAST (value , argDef .Type , variableValues ); isNullish (tmp ) {
6183			tmp  =  argDef .DefaultValue 
6284		}
63- 		if  ! isNullish (tmp ) {
64- 			results [argDef .PrivateName ] =  tmp 
65- 		}
85+ 		addValueOrNull (results , argDef .PrivateName , tmp )
6686	}
6787	return  results 
6888}
@@ -97,7 +117,7 @@ func getVariableValue(schema Schema, definitionAST *ast.VariableDefinition, inpu
97117		}
98118		return  coerceValue (ttype , input ), nil 
99119	}
100- 	if  isNullish (input ) {
120+ 	if  _ ,  ok   :=   input .( nullValue );  ok   ||   isNullish (input ) {
101121		return  "" , gqlerrors .NewError (
102122			fmt .Sprintf (`Variable "$%v" of required type ` + 
103123				`"%v" was not provided.` , variable .Name .Value , printer .Print (definitionAST .Type )),
@@ -134,6 +154,11 @@ func coerceValue(ttype Input, value interface{}) interface{} {
134154	if  isNullish (value ) {
135155		return  nil 
136156	}
157+ 
158+ 	if  _ , ok  :=  value .(nullValue ); ok  {
159+ 		return  nullValue {}
160+ 	}
161+ 
137162	switch  ttype  :=  ttype .(type ) {
138163	case  * NonNull :
139164		return  coerceValue (ttype .OfType , value )
@@ -156,13 +181,11 @@ func coerceValue(ttype Input, value interface{}) interface{} {
156181		}
157182
158183		for  name , field  :=  range  ttype .Fields () {
159- 			fieldValue  :=  coerceValue (field .Type , valueMap [ name ] )
184+ 			fieldValue  :=  coerceValue (field .Type , getValueOrNull ( valueMap ,  name ) )
160185			if  isNullish (fieldValue ) {
161186				fieldValue  =  field .DefaultValue 
162187			}
163- 			if  ! isNullish (fieldValue ) {
164- 				obj [name ] =  fieldValue 
165- 			}
188+ 			addValueOrNull (obj , name , fieldValue )
166189		}
167190		return  obj 
168191	case  * Scalar :
@@ -212,7 +235,7 @@ func typeFromAST(schema Schema, inputTypeAST ast.Type) (Type, error) {
212235// accepted for that type. This is primarily useful for validating the 
213236// runtime values of query variables. 
214237func  isValidInputValue (value  interface {}, ttype  Input ) (bool , []string ) {
215- 	if  isNullish (value ) {
238+ 	if  _ ,  ok   :=   value .( nullValue );  ok   ||   isNullish (value ) {
216239		if  ttype , ok  :=  ttype .(* NonNull ); ok  {
217240			if  ttype .OfType .Name () !=  ""  {
218241				return  false , []string {fmt .Sprintf (`Expected "%v!", found null.` , ttype .OfType .Name ())}
@@ -233,9 +256,14 @@ func isValidInputValue(value interface{}, ttype Input) (bool, []string) {
233256			messagesReduce  :=  []string {}
234257			for  i  :=  0 ; i  <  valType .Len (); i ++  {
235258				val  :=  valType .Index (i ).Interface ()
236- 				_ , messages  :=  isValidInputValue (val , ttype .OfType )
237- 				for  idx , message  :=  range  messages  {
238- 					messagesReduce  =  append (messagesReduce , fmt .Sprintf (`In element #%v: %v` , idx + 1 , message ))
259+ 				var  messages  []string 
260+ 				if  _ , ok  :=  val .(nullValue ); ok  {
261+ 					messages  =  []string {"Unexpected null value." }
262+ 				} else  {
263+ 					_ , messages  =  isValidInputValue (val , ttype .OfType )
264+ 				}
265+ 				for  _ , message  :=  range  messages  {
266+ 					messagesReduce  =  append (messagesReduce , fmt .Sprintf (`In element #%v: %v` , i + 1 , message ))
239267				}
240268			}
241269			return  (len (messagesReduce ) ==  0 ), messagesReduce 
@@ -352,6 +380,11 @@ func valueFromAST(valueAST ast.Value, ttype Input, variables map[string]interfac
352380	if  valueAST  ==  nil  {
353381		return  nil 
354382	}
383+ 
384+ 	if  valueAST .GetKind () ==  kinds .NullValue  {
385+ 		return  nullValue {}
386+ 	}
387+ 
355388	// precedence: value > type 
356389	if  valueAST , ok  :=  valueAST .(* ast.Variable ); ok  {
357390		if  valueAST .Name  ==  nil  ||  variables  ==  nil  {
@@ -398,9 +431,7 @@ func valueFromAST(valueAST ast.Value, ttype Input, variables map[string]interfac
398431			} else  {
399432				value  =  field .DefaultValue 
400433			}
401- 			if  ! isNullish (value ) {
402- 				obj [name ] =  value 
403- 			}
434+ 			addValueOrNull (obj , name , value )
404435		}
405436		return  obj 
406437	case  * Scalar :
0 commit comments