From 07a0eb180872401b271de40190603df8f3ab3db2 Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Fri, 30 Jan 2015 00:09:23 +0200 Subject: specify search pattern for references --- aconf/model/init.lua | 43 ++++++++++++++------------ aconf/model/model.lua | 2 ++ aconf/model/node.lua | 76 +++++++++++++++++++++++++--------------------- aconf/model/root.lua | 7 +++-- aconf/path.lua | 6 ++-- aconf/transaction/init.lua | 9 +++--- 6 files changed, 81 insertions(+), 62 deletions(-) diff --git a/aconf/model/init.lua b/aconf/model/init.lua index 663c7f8..01b4791 100644 --- a/aconf/model/init.lua +++ b/aconf/model/init.lua @@ -74,7 +74,8 @@ M.Reference = class(Field) function M.Reference:init(params) super(self, M.Reference):init( util.setdefaults( - params, {on_delete='restrict', scope='/', widget='reference'} + params, + {on_delete='restrict', scope='/', search='*', widget='reference'} ) ) self.dtype = 'reference' @@ -84,7 +85,7 @@ end function M.Reference:topology(context) local res = super(self, M.Reference):topology(context) - res[1].scope = self.scope + update(res[1], {scope=self.scope, search=self.search}) return res end @@ -92,34 +93,38 @@ function M.Reference:abs_scope(context) return M.path.to_absolute(self.scope, node.path(context.parent)) end --- assume one-level refs for now function M.Reference:_choice(context) local res = {} + local onelevel = self.search == '*' - local obj = relabel( - 'system', node.fetch, context.parent, self:abs_scope(context) - ) - assert(isinstance(obj, node.Collection)) + local obj = relabel('system', node.fetch, context.parent, self.scope) + assert(isinstance(obj, node.TreeNode)) - for k, v in pairs(obj) do + for _, v in ipairs(node.search(obj, self.search)) do local ch = {enabled=true} - if isinstance(v, node.TreeNode) then - ch.ref = node.path(v) - if M.path.is_subordinate(context.path, ch.ref) then ch = nil end - if ch then - ch['ui-value'] = M.path.name(ch.ref) - ch.be_value = M.path.escape(ch['ui-value']) - ch.value = self.dereference and ch.ref or ch.be_value + if isinstance(v.value, node.TreeNode) then + ch.ref = node.path(v.value) + if M.path.is_subordinate(context.path, ch.ref) then ch = nil + else + update( + ch, + { + be_value=v.path, + value=self.dereference and ch.ref or v.path, + ['ui-value']=onelevel and M.path.name(v.path) or v.path + } + ) if self.filter then - assert(isinstance(v, model.Model)) - if not v:match(self.filter) then ch.enabled = false end + assert(isinstance(v.value, model.Model)) + if not v.value:match(self.filter) then ch.enabled = false end end end else - local ep = M.path.escape(v) - update(ch, {be_value=ep, value=ep, ['ui-value']=v}) + assert(onelevel) + local ep = M.path.escape(v.value) + update(ch, {be_value=ep, value=ep, ['ui-value']=v.value}) end if ch then table.insert(res, ch) end diff --git a/aconf/model/model.lua b/aconf/model/model.lua index 8ad2cda..a1780c9 100644 --- a/aconf/model/model.lua +++ b/aconf/model/model.lua @@ -239,6 +239,8 @@ function M.Model:fetch(path, create) return getmetatable(self).fetch(path, create) end +function M.Model:search(path) return getmetatable(self).search(path) end + function M.Model:match(filter) local tload = getmetatable(getmetatable(self).escalate).load for k, v in pairs(filter) do diff --git a/aconf/model/node.lua b/aconf/model/node.lua index 0b4d36d..91f0256 100644 --- a/aconf/model/node.lua +++ b/aconf/model/node.lua @@ -135,6 +135,47 @@ function M.TreeNode:init(context, params) end + function mt._search(path, prefix) + if #path == 0 then return {{path=prefix, value=self}} end + + local mt = getmetatable(self) + + local name = path[1] + table.remove(path, 1) + + local function collect(name) + local next = mt.load(name, {dereference=false}) + if not next then return {} end + + if isinstance(next, M.TreeNode) then + return getmetatable(next)._search( + copy(path), pth.join(prefix, name) + ) + end + + assert(#path == 0) + return { + { + value=next, + deleted=function(path) mt.member(name):deleted(path) end + } + } + end + + if name == pth.wildcard then + local res = {} + for _, member in ipairs(mt.members()) do + util.extend(res, collect(member)) + end + return res + end + + return collect(name) + end + + function mt.search(path) return mt._search(pth.split(path), '') end + + local permissions = {} function mt._has_permission(permission) end @@ -221,39 +262,6 @@ function M.TreeNode:init(context, params) mt.txn.validable[mt.path] = mt.addr end -function M.TreeNode:search_refs(path) - if type(path) == 'string' then path = pth.split(path) end - - if #path == 0 then return {} end - - local mt = getmetatable(getmetatable(self).escalate) - - local name = path[1] - table.remove(path, 1) - - local function collect(name) - local next = mt.load(name, {dereference=false}) - if not next then return {} end - - local member = mt.member(name) - if member.deleted then return {member} end - - return isinstance(next, M.TreeNode) and M.TreeNode.search_refs( - next, path - ) or {} - end - - if name == pth.wildcard then - local res = {} - for _, member in ipairs(mt.members()) do - util.extend(res, collect(member)) - end - return res - end - - return collect(name) -end - M.Collection = class(M.TreeNode) @@ -263,7 +271,6 @@ function M.Collection:init(context, params) ) self.init = nil - self.search_refs = nil local mt = getmetatable(self) local field = M.BoundMember(self, pth.wildcard, params.field) @@ -447,6 +454,7 @@ for _, mf in ipairs{ 'parent', 'path', 'save', + 'search', 'topology' } do M[mf] = meta_func(mf) end diff --git a/aconf/model/root.lua b/aconf/model/root.lua index d92ac2d..9b05488 100644 --- a/aconf/model/root.lua +++ b/aconf/model/root.lua @@ -1,5 +1,5 @@ --[[ -Copyright (c) 2012-2014 Kaarle Ritvanen +Copyright (c) 2012-2015 Kaarle Ritvanen See LICENSE file for license details --]] @@ -82,7 +82,10 @@ function M.register(name, field, params) root:fetch(pth.to_absolute(record.scope, pth.parent(record.path))) ) set('scope', scope) - table.insert(M.topology(scope, true).referrers, record.path) + table.insert( + M.topology(pth.rawjoin(scope, record.search), true).referrers, + record.path + ) end end end diff --git a/aconf/path.lua b/aconf/path.lua index e13f17c..85fc347 100644 --- a/aconf/path.lua +++ b/aconf/path.lua @@ -1,5 +1,5 @@ --[[ -Copyright (c) 2012-2014 Kaarle Ritvanen +Copyright (c) 2012-2015 Kaarle Ritvanen See LICENSE file for license details --]] @@ -33,7 +33,9 @@ function M.rawjoin(p1, p2, ...) end function M.join(parent, ...) - return M.rawjoin(parent, table.unpack(map(M.escape, {...}))) + local args = map(M.escape, {...}) + if parent > '' then table.insert(args, 1, parent) end + return M.rawjoin(table.unpack(args)) end diff --git a/aconf/transaction/init.lua b/aconf/transaction/init.lua index faa5d7e..2aabec5 100644 --- a/aconf/transaction/init.lua +++ b/aconf/transaction/init.lua @@ -1,5 +1,5 @@ --[[ -Copyright (c) 2012-2014 Kaarle Ritvanen +Copyright (c) 2012-2015 Kaarle Ritvanen See LICENSE file for license details --]] @@ -68,13 +68,12 @@ function ModelTransaction:set_multiple(mods) end function ModelTransaction:check_deleted(path) - -- assume one-level refs for now - local top = root.topology(pth.parent(path)) + local top = root.topology(path) if top then local errors = ErrorDict() for _, refs in ipairs(top.referrers) do - for _, ref in ipairs(self.root:search_refs(refs)) do - errors:collect(ref.deleted, ref, path) + for _, ref in ipairs(getmetatable(self.root).escalate:search(refs)) do + errors:collect(ref.deleted, path) end end errors:raise() -- cgit v1.2.3