From ae2787987720868490c6200467ee623a9acd7ad2 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 17 Jul 2024 05:47:28 +0300 Subject: [PATCH] Allow null element in list (#271) bubbleUpNullValuesInPlaceRec was incorrectly marking a nil as an error and attempting to bubble up errors to the next field in places where a null object was acceptable. --- execution_result.go | 5 +++ execution_result_test.go | 74 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/execution_result.go b/execution_result.go index c6540488..ff945890 100644 --- a/execution_result.go +++ b/execution_result.go @@ -287,6 +287,11 @@ func bubbleUpNullValuesInPlaceRec(schema *ast.Schema, currentType *ast.Type, sel } errs = append(errs, lowerErrs...) } + case nil: + if currentType.Elem.NonNull { + return nil, false, fmt.Errorf("bubbleUpNullValuesInPlaceRec: unxpected result type '%T'", result) + } + return default: return nil, false, fmt.Errorf("bubbleUpNullValuesInPlaceRec: unxpected result type '%T'", result) } diff --git a/execution_result_test.go b/execution_result_test.go index d0626eab..f2cc770a 100644 --- a/execution_result_test.go +++ b/execution_result_test.go @@ -1171,6 +1171,80 @@ func TestBubbleUpNullValuesInPlace(t *testing.T) { }}), errs) require.Equal(t, jsonToInterfaceMap(`{ "critters": [ { "id": "GIZMO1", "color": "RED", "_bramble__typename": "Gizmo" }, { "id": "GREMLIN1", "name": "Spikey", "_bramble__typename": "Gremlin" }, null ] }`), result) }) + + t.Run("works with nullable null in array", func(t *testing.T) { + ddl := ` + type Gizmo { + id: ID! + color: String! + } + + type Query { + gizmos: [Gizmo]! + }` + + result := jsonToInterfaceMap(` + { + "gizmos": [ + { "id": "GIZMO1", "color": "RED" }, + null, + { "id": "GIZMO2", "color": "GREEN" } + ] + } + `) + + schema := gqlparser.MustLoadSchema(&ast.Source{Name: "fixture", Input: ddl}) + + query := ` + { + gizmos { + id + color + } + }` + + document := gqlparser.MustLoadQuery(schema, query) + errs, err := bubbleUpNullValuesInPlace(schema, document.Operations[0].SelectionSet, result) + require.NoError(t, err) + require.Equal(t, []*gqlerror.Error(nil), errs) + require.Equal(t, jsonToInterfaceMap(`{ "gizmos": [ { "id": "GIZMO1", "color": "RED" }, null, { "id": "GIZMO2", "color": "GREEN" } ] }`), result) + }) + t.Run("works with not nullable null in array", func(t *testing.T) { + ddl := ` + type Gizmo { + id: ID! + color: String! + } + + type Query { + gizmos: [Gizmo!]! + }` + + result := jsonToInterfaceMap(` + { + "gizmos": [ + { "id": "GIZMO1", "color": "RED" }, + null, + { "id": "GIZMO2", "color": "GREEN" } + ] + } + `) + + schema := gqlparser.MustLoadSchema(&ast.Source{Name: "fixture", Input: ddl}) + + query := ` + { + gizmos { + id + color + } + }` + + document := gqlparser.MustLoadQuery(schema, query) + errs, err := bubbleUpNullValuesInPlace(schema, document.Operations[0].SelectionSet, result) + require.Error(t, err) + require.Equal(t, []*gqlerror.Error(nil), errs) + }) } func TestFormatResponseBody(t *testing.T) {