Skip to content

Commit

Permalink
fix(schema) fix errors when encoding default empty arrays & sets
Browse files Browse the repository at this point in the history
Previously, a schema such as this:
```
{ type = "array",
  default = {},
  elements = { type = "string" },
}
```
Would be encoded in json as a `{}` instead of as a `[]` (the Lua table given for the default value would be copied, and its metatable would remain)

A similar thing would happen with sets.

This change sets the metatable to `cjson.array_mt` and also adds tests for other possible values given to the default (i.e. `cjson.empty_array`).
  • Loading branch information
kikito committed Jan 30, 2019
1 parent 6005ff0 commit a54e807
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
9 changes: 8 additions & 1 deletion kong/db/schema/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,14 @@ end
-- @param field The field definition table.
local function handle_missing_field(field, value)
if field.default ~= nil then
return tablex.deepcopy(field.default)
local copy = tablex.deepcopy(field.default)
if (field.type == "array" or field.type == "set")
and type(copy) == "table"
and not getmetatable(copy)
then
setmetatable(copy, cjson.array_mt)
end
return copy
end

-- If `nilable` (metaschema only), a default value is not necessary.
Expand Down
61 changes: 61 additions & 0 deletions spec/01-unit/01-db/01-schema/01-schema_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2004,6 +2004,67 @@ describe("schema", function()
assert.same({ r = { a = "nr", b = 123, }}, data.nested_record)
end)

it("detects an empty Lua table as a default for an set and marks it as a json array", function()
local Test = Schema.new({
fields = {
{ s = { type = "set",
elements = { type = "string" },
default = {} }, },
}
})
local data = Test:process_auto_fields({})
assert.equals('{"s":[]}', cjson.encode(data))
end)


it("detects an empty Lua table as a default for an array and marks it as a json array", function()
local Test = Schema.new({
fields = {
{ a = { type = "array",
elements = { type = "string" },
default = {} }, },
}
})
local data = Test:process_auto_fields({})
assert.equals('{"a":[]}', cjson.encode(data))
end)

it("accepts cjson.empty_array as a default for an array", function()
local Test = Schema.new({
fields = {
{ b = { type = "array",
elements = { type = "string" },
default = cjson.empty_array }, },
}
})
local data = Test:process_auto_fields({})
assert.equals('{"b":[]}', cjson.encode(data))
end)

it("accepts a table marked with cjson.empty_array_mt as a default for an array", function()
local Test = Schema.new({
fields = {
{ c = { type = "array",
elements = { type = "string" },
default = setmetatable({}, cjson.empty_array_mt) }, },
}
})
local data = Test:process_auto_fields({})
assert.equals('{"c":[]}', cjson.encode(data))
end)

it("accepts a table marked with cjson.array_mt as a default for an array", function()
local Test = Schema.new({
fields = {
{ d = { type = "array",
elements = { type = "string" },
default = setmetatable({}, cjson.array_mt) }, },
}
})
local data = Test:process_auto_fields({})
assert.equals('{"d":[]}', cjson.encode(data))
end)

it("nested defaults in required records produce a default record", function()
local Test = Schema.new({
fields = {
Expand Down

0 comments on commit a54e807

Please sign in to comment.