Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions cartridge/graphql/execute.lua
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,16 @@ local function completeValue(fieldType, result, subSelections, context, opts)
end

if fieldTypeName == 'List' then
local innerType = fieldType.ofType

if type(result) ~= 'table' then
error('Expected a table for ' .. innerType.name .. ' list')
if not util.is_array(result) then
local resultType = type(result)
if resultType == 'table' then
resultType = 'map'
end
local message = ('Expected %q to be an "array", got %q'):format(fieldName, resultType)
error(message)
end

local innerType = fieldType.ofType
local values = {}
for i, value in ipairs(result) do
values[i] = completeValue(innerType, value, subSelections, context)
Expand All @@ -213,6 +217,10 @@ local function completeValue(fieldType, result, subSelections, context, opts)
end

if fieldTypeName == 'Object' then
if type(result) ~= 'table' then
local message = ('Expected %q to be a "map", got %q'):format(fieldName, type(result))
error(message)
end
local completed = evaluateSelections(fieldType, result, subSelections, context)
setmetatable(completed, serializemap)
return completed
Expand Down
4 changes: 3 additions & 1 deletion cartridge/graphql/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@ end
--- case)
--- @return[2] `false` otherwise
local function is_array(table)
check(table, 'table', 'table')
if type(table) ~= 'table' then
return false
end

local max = 0
local count = 0
Expand Down
148 changes: 147 additions & 1 deletion test/integration/graphql_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ g.test_reread_request = function()
end


g.test_enum = function()
g.test_enum_input = function()
local server = cluster.main_server

server.net_box:eval([[
Expand Down Expand Up @@ -343,6 +343,53 @@ g.test_enum = function()
end)
end

g.test_enum_output = function()
local server = cluster.main_server

server.net_box:eval([[
package.loaded['test'] = package.loaded['test'] or {}
package.loaded['test']['test_enum_output'] = function(_, _)
return {value = 'a'}
end

local graphql = require('cartridge.graphql')
local types = require('cartridge.graphql.types')

local simple_enum = types.enum {
name = 'simple_enum_output',
values = {
a = { value = 'a' },
b = { value = 'b' },
},
}

local object = types.object({
name = 'simple_object',
fields = {
value = simple_enum,
}
})

graphql.add_callback({
name = 'test_enum_output',
args = {},
kind = object,
callback = 'test.test_enum_output',
})
]])

t.assert_equals(
server:graphql({
query = [[
query {
test_enum_output{ value }
}
]],
variables = {}}
).data.test_enum_output.value, 'a'
)
end

g.test_unknown_query_mutation = function()
local server = cluster.main_server
t.assert_error_msg_equals(
Expand Down Expand Up @@ -687,6 +734,105 @@ g.test_custom_type_scalar_variables = function()
end)
end

g.test_output_type_mismatch_error = function()
local server = cluster.main_server

server.net_box:eval([[
package.loaded['test'] = {}
package.loaded['test']['callback'] = function(_, _)
return true
end

package.loaded['test']['callback_for_nested'] = function(_, _)
return { values = true }
end

local graphql = require('cartridge.graphql')
local types = require('cartridge.graphql.types')

local obj_type = types.object({
name = 'ObjectWithValue',
fields = {
value = types.string,
},
})

local nested_obj_type = types.object({
name = 'NestedObjectWithValue',
fields = {
value = types.string,
},
})

local complex_obj_type = types.object({
name = 'ComplexObjectWithValue',
fields = {
values = types.list(nested_obj_type),
},
})

graphql.add_callback({
name = 'expected_nonnull_list',
kind = types.list(types.int.nonNull),
callback = 'test.callback',
})

graphql.add_callback({
name = 'expected_obj',
kind = obj_type,
callback = 'test.callback',
})

graphql.add_callback({
name = 'expected_list',
kind = types.list(types.int),
callback = 'test.callback',
})

graphql.add_callback({
name = 'expected_list_with_nested',
kind = types.list(complex_obj_type),
callback = 'test.callback_for_nested',
})
]])

t.assert_error_msg_equals('Expected "expected_nonnull_list" to be an "array", got "boolean"', function()
return server:graphql({
query = [[
query {
expected_nonnull_list
}
]]})
end)

t.assert_error_msg_equals('Expected "expected_obj" to be a "map", got "boolean"', function()
return server:graphql({
query = [[
query {
expected_obj { value }
}
]]})
end)

t.assert_error_msg_equals('Expected "expected_list" to be an "array", got "boolean"', function()
return server:graphql({
query = [[
query {
expected_list
}
]]})
end)

t.assert_error_msg_equals('Expected "expected_list_with_nested" to be an "array", got "map"', function()
return server:graphql({
query = [[
query {
expected_list_with_nested { values { value } }
}
]]})
end)
end

function g.test_error_extensions()
local request = {
query = [[mutation($uuids: [String!]) {
Expand Down