--[[
Copyright (c) 2012-2015 Kaarle Ritvanen
See LICENSE file for license details
--]]
--- @module aconf.model
local M = {}
local model = require('aconf.model.model')
local node = require('aconf.model.node')
local object = require('aconf.object')
local pth = require('aconf.path')
local util = require('aconf.util')
local setdefault = util.setdefault
M.RootModel = model.new()
function M.RootModel:init(context)
object.super(self, M.RootModel):init(
util.update(context, {path='/', addr='/null'})
)
end
function M.RootModel:has_permission(user, permission)
return permission == 'read'
end
function M.RootModel:meta(path)
local obj = self:fetch(path, true)
if object.isinstance(obj, node.TreeNode) then return node.meta(obj) end
return node.mmeta(self:fetch(pth.parent(path), true), pth.name(path))
end
local order = 0
M.topology = setmetatable(
{},
{
__call=function(self, addr, create)
util.setdefaults(self, {members={}, paths={}, referrers={}})
if type(addr) == 'table' then addr = util.copy(addr)
else addr = pth.split(addr) end
if not addr[1] then return self end
local comp = pth.escape(addr[1])
local top
if create then
top = setdefault(self.members, comp, {order=order})
order = order + 1
else
top = self.members[comp] or self.members['*']
if not top then return end
end
table.remove(addr, 1)
return setmetatable(top, getmetatable(self))(addr, create)
end
}
)
--- inject a new field to the root model.
-- @tparam string name name of the field
-- @param field (@{Field} or [<Model>](#new)) type
-- of the field, specified by a subclass of @{Field} or an instance of
-- such. Can also be specified by a [<Model>](#new).
-- @tparam ?{[string]=any,...} params field parameters. Applicable
-- when field type is specified by a @{Field} subclass or
-- [<Model>](#new).
function M.register(name, field, params)
if not params then params = {} end
params.create = true
M.RootModel[name] = model.to_field(field, params)
local root = M.RootModel{}
for _, record in ipairs(node.topology(root:fetch(name))) do
local top = M.topology(record.addr, true)
local function set(k, v, t)
if not t then t = top end
setdefault(t, k, v)
assert(t[k] == v)
end
set('type', record.type)
set('subtype', record.subtype)
table.insert(top.paths, record.path)
local mode = record.be_mode
if mode then
if type(mode) == 'string' then mode = {['.']=mode} end
for addr, m in pairs(mode) do
set('mode', m, addr == '.' and top or top(addr, true))
end
end
if record.scope then
local scope = node.addr(
root:fetch(pth.to_absolute(record.scope, pth.parent(record.path)))
)
set('scope', scope)
table.insert(
M.topology(pth.rawjoin(scope, record.search), true).referrers,
record.path
)
end
end
end
return M