--[[ Copyright (c) 2012-2016 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>](#Field_constructors) or -- [<Model>](#new)) type of the field, specified by a -- field constructor or instance. Can also be specified by a model. -- @tparam ?{[string]=any,...} params field parameters. Applicable -- when the type of the field is specified by a model or a field -- constructor. 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