Skip to content

Commit 4c772c1

Browse files
authored
Merge pull request #413 from OuranosSkia/AlwaysCheckNil
Update logic to always check for nil pointer returns
2 parents c5bdf3b + 3152bd3 commit 4c772c1

File tree

2 files changed

+67
-19
lines changed

2 files changed

+67
-19
lines changed

graphql_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3635,3 +3635,52 @@ func TestSubscriptions_In_Exec(t *testing.T) {
36353635
},
36363636
})
36373637
}
3638+
3639+
type nilPointerReturnValue struct{}
3640+
3641+
func (r *nilPointerReturnValue) Value() *string {
3642+
return nil
3643+
}
3644+
3645+
type nilPointerReturnResolver struct{}
3646+
3647+
func (r *nilPointerReturnResolver) PointerReturn() *nilPointerReturnValue {
3648+
return &nilPointerReturnValue{}
3649+
}
3650+
3651+
func TestPointerReturnForNonNull(t *testing.T) {
3652+
gqltesting.RunTests(t, []*gqltesting.Test{
3653+
{
3654+
Schema: graphql.MustParseSchema(`
3655+
type Query {
3656+
pointerReturn: PointerReturnValue
3657+
}
3658+
3659+
type PointerReturnValue {
3660+
value: Hello!
3661+
}
3662+
enum Hello {
3663+
WORLD
3664+
}
3665+
`, &nilPointerReturnResolver{}),
3666+
Query: `
3667+
query {
3668+
pointerReturn {
3669+
value
3670+
}
3671+
}
3672+
`,
3673+
ExpectedResult: `
3674+
{
3675+
"pointerReturn": null
3676+
}
3677+
`,
3678+
ExpectedErrors: []*gqlerrors.QueryError{
3679+
{
3680+
Message: `graphql: got nil for non-null "Hello"`,
3681+
Path: []interface{}{"pointerReturn", "value"},
3682+
},
3683+
},
3684+
},
3685+
})
3686+
}

internal/exec/exec.go

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -239,31 +239,30 @@ func execFieldSelection(ctx context.Context, r *Request, s *resolvable.Schema, f
239239

240240
func (r *Request) execSelectionSet(ctx context.Context, sels []selected.Selection, typ common.Type, path *pathSegment, s *resolvable.Schema, resolver reflect.Value, out *bytes.Buffer) {
241241
t, nonNull := unwrapNonNull(typ)
242-
switch t := t.(type) {
243-
case *schema.Object, *schema.Interface, *schema.Union:
244-
// a reflect.Value of a nil interface will show up as an Invalid value
245-
if resolver.Kind() == reflect.Invalid || ((resolver.Kind() == reflect.Ptr || resolver.Kind() == reflect.Interface) && resolver.IsNil()) {
246-
// If a field of a non-null type resolves to null (either because the
247-
// function to resolve the field returned null or because an error occurred),
248-
// add an error to the "errors" list in the response.
249-
if nonNull {
250-
err := errors.Errorf("graphql: got nil for non-null %q", t)
251-
err.Path = path.toSlice()
252-
r.AddError(err)
253-
}
254-
out.WriteString("null")
255-
return
242+
243+
// a reflect.Value of a nil interface will show up as an Invalid value
244+
if resolver.Kind() == reflect.Invalid || ((resolver.Kind() == reflect.Ptr || resolver.Kind() == reflect.Interface) && resolver.IsNil()) {
245+
// If a field of a non-null type resolves to null (either because the
246+
// function to resolve the field returned null or because an error occurred),
247+
// add an error to the "errors" list in the response.
248+
if nonNull {
249+
err := errors.Errorf("graphql: got nil for non-null %q", t)
250+
err.Path = path.toSlice()
251+
r.AddError(err)
256252
}
253+
out.WriteString("null")
254+
return
255+
}
257256

257+
switch t.(type) {
258+
case *schema.Object, *schema.Interface, *schema.Union:
258259
r.execSelections(ctx, sels, path, s, resolver, out, false)
259260
return
260261
}
261262

262-
if !nonNull {
263-
if resolver.IsNil() {
264-
out.WriteString("null")
265-
return
266-
}
263+
// Any pointers or interfaces at this point should be non-nil, so we can get the actual value of them
264+
// for serialization
265+
if resolver.Kind() == reflect.Ptr || resolver.Kind() == reflect.Interface {
267266
resolver = resolver.Elem()
268267
}
269268

0 commit comments

Comments
 (0)