From c4d03b7033f39c7e1eb1ab90a000fac8d35ca97a Mon Sep 17 00:00:00 2001 From: Yaroslav Shumakov Date: Sun, 3 Oct 2021 13:42:42 +0300 Subject: [PATCH] Fix returning data and error for multiple resolvers 32c97f0 introduced returning data and errors acc. spec #7.1.2 but previous implementation didn't take into account that execution may include multiple resolvers and each of them may return both data and errors. This PR fixes the logic to collect all errors from all resolvers into a single array that can be returned to requester. Based on PR #19 by @no1seman --- graphql/execute.lua | 7 +++-- test/integration/graphql_test.lua | 45 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/graphql/execute.lua b/graphql/execute.lua index 493b157..773b7c0 100644 --- a/graphql/execute.lua +++ b/graphql/execute.lua @@ -313,7 +313,6 @@ end evaluateSelections = function(objectType, object, selections, context) local result = {} - local errors local err local fields = collectFields(objectType, selections, {}, {}, context) for _, field in ipairs(fields) do @@ -322,14 +321,14 @@ evaluateSelections = function(objectType, object, selections, context) result[field.name], err = getFieldEntry(objectType, object, {field.selection}, context) if err ~= nil then - errors = errors or {} - table.insert(errors, err) + context.errors = context.errors or {} + table.insert(context.errors, err) end if result[field.name] == nil then result[field.name] = box.NULL end end - return result, errors + return result, context.errors end local function execute(schema, tree, rootValue, variables, operationName) diff --git a/test/integration/graphql_test.lua b/test/integration/graphql_test.lua index a4d11e8..b7a0841 100644 --- a/test/integration/graphql_test.lua +++ b/test/integration/graphql_test.lua @@ -1158,4 +1158,49 @@ function g.test_both_data_and_error_result() {message = 'Simple error A'}, {message = 'Simple error B'}, }) + + query = [[{ + prefix { + test_A: test(arg: "A") + test_B: test(arg: "B") + } + }]] + + local function callback_external() + return {}, {message = 'Simple error from external resolver'} + end + + local function callback_internal(_, args) + return args[1].value, {message = 'Simple error from internal resolver ' .. args[1].value} + end + + query_schema = { + ['prefix'] = { + kind = types.object({ + name = 'prefix', + fields = { + ['test'] = { + kind = types.string.nonNull, + arguments = { + arg = types.string.nonNull, + arg2 = types.string, + arg3 = types.int, + arg4 = types.long, + }, + resolve = callback_internal, + } + }, + }), + arguments = {}, + resolve = callback_external, + } + } + + data, errors = check_request(query, query_schema) + t.assert_equals(data, {prefix = {test_A = 'A', test_B = 'B'}}) + t.assert_equals(errors, { + {message = "Simple error from internal resolver A"}, + {message = "Simple error from internal resolver B"}, + {message = "Simple error from external resolver"}, + }, "Errors from each resolver were returned") end