diff --git a/executor.go b/executor.go index d680d01f..e3245f45 100644 --- a/executor.go +++ b/executor.go @@ -782,7 +782,7 @@ func completeListValue(eCtx *executionContext, returnType *List, fieldASTs []*as parentTypeName = info.ParentType.Name() } err := invariantf( - resultVal.IsValid() && resultVal.Type().Kind() == reflect.Slice, + resultVal.IsValid() && isIterable(result), "User Error: expected iterable, but did not find one "+ "for field %v.%v.", parentTypeName, info.FieldName) diff --git a/lists_test.go b/lists_test.go index 7fd360c8..b58161a6 100644 --- a/lists_test.go +++ b/lists_test.go @@ -773,10 +773,27 @@ func TestLists_UserErrorExpectIterableButDidNotGetOne(t *testing.T) { }, Errors: []gqlerrors.FormattedError{ { - Message: "User Error: expected iterable, but did not find one for field DataType.test.", + Message: "User Error: aexpected iterable, but did not find one for field DataType.test.", Locations: []location.SourceLocation{}, }, }, } checkList(t, ttype, data, expected) } + +func TestLists_ArrayOfNullableObjects_ContainsValues(t *testing.T) { + ttype := graphql.NewList(graphql.Int) + data := [2]interface{}{ + 1, 2, + } + expected := &graphql.Result{ + Data: map[string]interface{}{ + "nest": map[string]interface{}{ + "test": []interface{}{ + 1, 2, + }, + }, + }, + } + checkList(t, ttype, data, expected) +} diff --git a/values.go b/values.go index 7453e394..8d0410b7 100644 --- a/values.go +++ b/values.go @@ -339,6 +339,15 @@ func isNullish(src interface{}) bool { return false } +// Returns true if src is a slice or an array +func isIterable(src interface{}) bool { + if src == nil { + return false + } + t := reflect.TypeOf(src) + return t.Kind() == reflect.Slice || t.Kind() == reflect.Array +} + /** * Produces a value given a GraphQL Value AST. * diff --git a/values_test.go b/values_test.go new file mode 100644 index 00000000..015599a5 --- /dev/null +++ b/values_test.go @@ -0,0 +1,18 @@ +package graphql + +import "testing" + +func TestIsIterable(t *testing.T) { + if !isIterable([]int{}) { + t.Fatal("expected isIterable to return true for a slice, got false") + } + if !isIterable([]int{}) { + t.Fatal("expected isIterable to return true for an array, got false") + } + if isIterable(1) { + t.Fatal("expected isIterable to return false for an int, got true") + } + if isIterable(nil) { + t.Fatal("expected isIterable to return false for nil, got true") + } +}