Skip to content

Commit 72d7caa

Browse files
committed
Fix list null
1 parent c5ca6e6 commit 72d7caa

File tree

3 files changed

+133
-6
lines changed

3 files changed

+133
-6
lines changed

executor_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,82 @@ func TestThreadsSourceCorrectly(t *testing.T) {
403403
}
404404
}
405405

406+
func TestCorrectlyListArgumentsWithNull(t *testing.T) {
407+
query := `
408+
query Example {
409+
b(listStringArg: null, listBoolArg: [true,false,null],listIntArg:[123,null,12],listStringNonNullArg:[null])
410+
}
411+
`
412+
var resolvedArgs map[string]interface{}
413+
schema, err := graphql.NewSchema(graphql.SchemaConfig{
414+
Query: graphql.NewObject(graphql.ObjectConfig{
415+
Name: "Type",
416+
Fields: graphql.Fields{
417+
"b": &graphql.Field{
418+
Args: graphql.FieldConfigArgument{
419+
"listStringArg": &graphql.ArgumentConfig{
420+
Type: graphql.NewList(graphql.String),
421+
},
422+
"listStringNonNullArg": &graphql.ArgumentConfig{
423+
Type: graphql.NewNonNull(graphql.NewList(graphql.String)),
424+
},
425+
"listBoolArg": &graphql.ArgumentConfig{
426+
Type: graphql.NewList(graphql.Boolean),
427+
},
428+
"listIntArg": &graphql.ArgumentConfig{
429+
Type: graphql.NewList(graphql.Int),
430+
},
431+
},
432+
Type: graphql.String,
433+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
434+
resolvedArgs = p.Args
435+
return resolvedArgs, nil
436+
},
437+
},
438+
},
439+
}),
440+
})
441+
if err != nil {
442+
t.Fatalf("Error in schema %v", err.Error())
443+
}
444+
ast := testutil.TestParse(t, query)
445+
446+
ep := graphql.ExecuteParams{
447+
Schema: schema,
448+
AST: ast,
449+
}
450+
result := testutil.TestExecute(t, ep)
451+
if len(result.Errors) > 0 {
452+
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
453+
}
454+
tests := []struct {
455+
key string
456+
expected interface{}
457+
}{
458+
{
459+
"listStringArg", nil,
460+
},
461+
462+
{
463+
"listStringNonNullArg", []interface{}{nil},
464+
},
465+
466+
{
467+
"listBoolArg", []interface{}{true, false, nil},
468+
},
469+
470+
{
471+
"listIntArg", []interface{}{123, nil, 12},
472+
},
473+
}
474+
for _, tt := range tests {
475+
t.Run(fmt.Sprintf("TestCorrectlyListArgumentsWithNull_%s", tt.key), func(t *testing.T) {
476+
if !reflect.DeepEqual(resolvedArgs[tt.key], tt.expected) {
477+
t.Fatalf("Expected args.%s to equal `%v`, got `%v`", tt.key, tt.expected, resolvedArgs[tt.key])
478+
}
479+
})
480+
}
481+
}
406482
func TestCorrectlyThreadsArguments(t *testing.T) {
407483

408484
query := `

values.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,34 @@ func getArgumentValues(
5757
if tmpValue, ok := argASTMap[argDef.PrivateName]; ok {
5858
value = tmpValue.Value
5959
}
60-
if tmp = valueFromAST(value, argDef.Type, variableValues); isNullish(tmp) {
61-
tmp = argDef.DefaultValue
62-
}
63-
if !isNullish(tmp) {
64-
results[argDef.PrivateName] = tmp
60+
// if ast value is NullValue, and keep args's key
61+
if value != nil && value.GetKind() == kinds.NullValue {
62+
results[argDef.PrivateName] = nil
63+
} else {
64+
if tmp = valueFromAST(value, argDef.Type, variableValues); isNullish(tmp) {
65+
tmp = argDef.DefaultValue
66+
}
67+
if !isNullish(tmp) {
68+
results[argDef.PrivateName] = tmp
69+
} else {
70+
if nullValueWithVairableProvided(value, argDef.PrivateName, variableValues) {
71+
results[argDef.PrivateName] = nil
72+
}
73+
}
6574
}
6675
}
6776
return results
6877
}
6978

79+
func nullValueWithVairableProvided(valueAST ast.Value, key string, variables map[string]interface{}) bool {
80+
if valueAST != nil && valueAST.GetKind() == kinds.Variable {
81+
if _, ok := variables[key]; ok {
82+
return true
83+
}
84+
}
85+
return false
86+
}
87+
7088
// Given a variable definition, and any value of input, return a value which
7189
// adheres to the variable definition, or throw an error.
7290
func getVariableValue(schema Schema, definitionAST *ast.VariableDefinition, input interface{}) (interface{}, error) {
@@ -349,7 +367,7 @@ func isIterable(src interface{}) bool {
349367
*
350368
*/
351369
func valueFromAST(valueAST ast.Value, ttype Input, variables map[string]interface{}) interface{} {
352-
if valueAST == nil {
370+
if valueAST == nil || valueAST.GetKind() == kinds.NullValue {
353371
return nil
354372
}
355373
// precedence: value > type

variables_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ func inputResolved(p graphql.ResolveParams) (interface{}, error) {
7070
if !ok {
7171
return nil, nil
7272
}
73+
if input == nil {
74+
return nil, nil
75+
}
7376
b, err := json.Marshal(input)
7477
if err != nil {
7578
return nil, nil
@@ -960,6 +963,36 @@ func TestVariables_ListsAndNullability_AllowsListsToBeNull(t *testing.T) {
960963
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
961964
}
962965
}
966+
967+
func TestVariables_ListsAndNullability_AllowsListsToBeNullWithMoreListValues(t *testing.T) {
968+
doc := `
969+
query q($input: [String]) {
970+
list(input: $input)
971+
}
972+
`
973+
params := map[string]interface{}{
974+
"input": []interface{}{nil, "ok", nil},
975+
}
976+
977+
expected := &graphql.Result{
978+
Data: map[string]interface{}{
979+
"list": `[null,"ok",null]`,
980+
},
981+
}
982+
ast := testutil.TestParse(t, doc)
983+
ep := graphql.ExecuteParams{
984+
Schema: variablesTestSchema,
985+
AST: ast,
986+
Args: params,
987+
}
988+
result := testutil.TestExecute(t, ep)
989+
if len(result.Errors) > 0 {
990+
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
991+
}
992+
if !reflect.DeepEqual(expected, result) {
993+
t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result))
994+
}
995+
}
963996
func TestVariables_ListsAndNullability_AllowsListsToContainValues(t *testing.T) {
964997
doc := `
965998
query q($input: [String]) {

0 commit comments

Comments
 (0)