Files
2026-07-13 12:32:21 +08:00

215 lines
4.4 KiB
Lua

local blueprints = require "spec.fixtures.blueprints"
local assert = require "luassert"
local cycle_aware_deep_copy = require("kong.tools.table").cycle_aware_deep_copy
local dc_blueprints = {}
local null = ngx.null
local function new_config()
return {
_format_version = "3.0"
}
end
local function remove_nulls(tbl)
for k,v in pairs(tbl) do
if v == null then
tbl[k] = nil
elseif type(v) == "table" then
tbl[k] = remove_nulls(v)
end
end
return tbl
end
-- tparam boolean expand_foreigns expand the complete "foreign"-type fields, not
-- replacing it with "string"-type fields
local function wrap_db(db, expand_foreigns)
local dc_as_db = {}
local config = new_config()
for name, _ in pairs(db.daos) do
dc_as_db[name] = {
insert = function(_, tbl)
tbl = cycle_aware_deep_copy(tbl)
if not config[name] then
config[name] = {}
end
local schema = db.daos[name].schema
tbl = schema:process_auto_fields(tbl, "insert")
for fname, field in schema:each_field() do
if not expand_foreigns and field.type == "foreign" then
tbl[fname] = type(tbl[fname]) == "table"
and tbl[fname].id
or nil
end
end
table.insert(config[name], remove_nulls(tbl))
return cycle_aware_deep_copy(tbl)
end,
update = function(_, id, tbl)
if not config[name] then
return nil, "not found"
end
tbl = cycle_aware_deep_copy(tbl)
local element
for _, e in ipairs(config[name]) do
if e.id == id then
element = e
break
end
end
if not element then
return nil, "not found"
end
for k,v in pairs(tbl) do
element[k] = v
end
return element
end,
remove = function(_, id)
assert(id, "id is required")
if type(id) == "table" then
id = assert(type(id.id) == "string" and id.id)
end
if not config[name] then
return nil, "not found"
end
for idx, entity in ipairs(config[name]) do
if entity.id == id then
table.remove(config[name], idx)
return entity
end
end
return nil, "not found"
end,
}
end
dc_as_db.export = function()
return cycle_aware_deep_copy(config)
end
dc_as_db.import = function(input)
config = cycle_aware_deep_copy(input)
end
dc_as_db.reset = function()
config = new_config()
end
return dc_as_db
end
function dc_blueprints.new(db, expand_foreigns)
local dc_as_db = wrap_db(db, expand_foreigns)
local save_dc = new_config()
local bp = blueprints.new(dc_as_db)
bp.done = function()
local ret = dc_as_db.export()
save_dc = ret
dc_as_db.reset()
return ret
end
bp.reset_back = function()
dc_as_db.import(save_dc)
end
return bp
end
function dc_blueprints.admin_api(db, forced_port)
-- lazy import to avoid cyclical dependency
local helpers = require "spec.helpers"
db = db or helpers.db
local dc_as_db = wrap_db(db)
local api = {}
local function update_config()
local client = helpers.admin_client(nil, forced_port)
local res = client:post("/config", {
headers = {
["Content-Type"] = "application/json",
},
body = dc_as_db.export(),
})
assert.response(res).has.status(201)
client:close()
return assert.response(res).has.jsonbody()
end
for name in pairs(db.daos) do
local dao = dc_as_db[name]
api[name] = {
insert = function(_, entity)
local res, err = dao:insert(entity)
if not res then
return nil, err
end
update_config()
return res
end,
update = function(_, id, updates)
local res, err = dao:update(id, updates)
if not res then
return nil, err
end
update_config()
return res
end,
remove = function(_, id)
local res, err = dao:remove(id)
if not res then
return nil, err
end
update_config()
return res
end,
truncate = function()
local config = dc_as_db.export()
config[name] = {}
dc_as_db.import(config)
update_config()
return true
end,
}
end
return blueprints.new(api)
end
return dc_blueprints