Skip to content

Fix returning gapped arrays #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 19, 2022
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
2 changes: 1 addition & 1 deletion graphql/execute.lua
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ local function completeValue(fieldType, result, subSelections, context, opts)

local innerType = fieldType.ofType
local values = {}
for i, value in ipairs(result) do
for i, value in pairs(result) do
values[i] = completeValue(innerType, value, subSelections, context)
end

Expand Down
44 changes: 15 additions & 29 deletions graphql/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -228,37 +228,23 @@ local function check(obj, obj_name, type_1, type_2, type_3)
end
end

--- Check whether table is an array.
---
--- Based on [that][1] implementation.
--- [1]: https://github.com/mpx/lua-cjson/blob/db122676/lua/cjson/util.lua
---
--- @tparam table table to check
--- @return[1] `true` if passed table is an array (includes the empty table
--- case)
--- @return[2] `false` otherwise
local function is_array(table)
if type(table) ~= 'table' then
return false
end

local max = 0
local count = 0
for k, _ in pairs(table) do
if type(k) == 'number' then
if k > max then
max = k
end
count = count + 1
else
return false
end
end
if max > count * 2 then
local function is_array(t)
if type(t) ~= 'table' then
return false
end
local n = #t
if n > 0 then
for k in next, t, n do
if type(k) ~= 'number' or k < 0 then return false end
end
return true
end
for k in pairs(t) do
if type(k) ~= 'number' or k < 0 then
return false
end

return max >= 0
end
return true
end

-- Copied from tarantool/tap
Expand Down
33 changes: 33 additions & 0 deletions test/integration/graphql_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2236,3 +2236,36 @@ function g.test_huge_cdata_number()
t.assert_equals(json.encode(res), v[2])
end
end

function g.test_gapped_arrays_output()
local query = [[
query ($x: [String]) { test(arg: $x) }
]]

local function callback(_, args)
setmetatable(args.arg, {__serialize='array'})
return args.arg
end

local query_schema = {
['test'] = {
kind = types.list(types.string),
arguments = {
arg = types.list(types.string),
},
resolve = callback,
}
}

local test_values = {
{[3] = 'a', [1] = 'b', [6] = 'c'},
{[3] = 'a', [1] = 'b', [7] = 'c'},
}

for _, v in ipairs(test_values) do
local variables = {x = v}
local res = check_request(query, query_schema, nil, nil, {variables = variables})
t.assert_type(res, 'table')
t.assert_equals(res.test, v)
end
end
15 changes: 15 additions & 0 deletions test/unit/graphql_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1092,3 +1092,18 @@ end
g.test_version = function()
t.assert_type(require('graphql').VERSION, 'string')
end

function g.test_is_array()
t.assert_equals(util.is_array({[3] = 'a', [1] = 'b', [6] = 'c'}), true)
t.assert_equals(util.is_array({[3] = 'a', [1] = 'b', [7] = 'c'}), true)
t.assert_equals(util.is_array({[3] = 'a', nil, [6] = 'c'}), true)
t.assert_equals(util.is_array({[3] = 'a', nil, [7] = 'c'}), true)
t.assert_equals(util.is_array({[0] = 'a', [1] = 'b', [6] = 'c'}), true)
t.assert_equals(util.is_array({[-1] = 'a', [1] = 'b', [6] = 'c'}), false)
t.assert_equals(util.is_array({[3] = 'a', b = 'b', [6] = 'c'}), false)
t.assert_equals(util.is_array({}), true)
t.assert_equals(util.is_array(), false)
t.assert_equals(util.is_array(''), false)
t.assert_equals(util.is_array({a = 'a', b = 'b', c = 'c'}), false)
t.assert_equals(util.is_array({a = 'a', nil, c = 'c'}), false)
end