diff options
Diffstat (limited to 'acf/model/node.lua')
-rw-r--r-- | acf/model/node.lua | 275 |
1 files changed, 0 insertions, 275 deletions
diff --git a/acf/model/node.lua b/acf/model/node.lua deleted file mode 100644 index 56d3416..0000000 --- a/acf/model/node.lua +++ /dev/null @@ -1,275 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local M = {} - -local raise = require('acf.error').raise - -local object = require('acf.object') -local class = object.class -local isinstance = object.isinstance -local super = object.super - -local pth = require('acf.path') -local util = require('acf.util') - - -M.BoundMember = class() - -function M.BoundMember:init(parent, name, field) - local pmt = getmetatable(parent) - local mt = {} - - function mt.__index(t, k) - local member = field[k] - if type(member) ~= 'function' then return member end - return function(self, ...) - return member( - field, - { - txn=pmt.txn, - parent=parent, - path=pth.join(pmt.path, name), - addr=pth.to_absolute( - field.addr or pth.escape(name), pmt.addr - ) - }, - ... - ) - end - end - - setmetatable(self, mt) -end - - -M.TreeNode = class() - -function M.TreeNode:init(context) - local mt = getmetatable(self) - util.update(mt, context) - - mt.dereference = true - mt.meta = {} - function mt.get(k, create) return mt.load(k, {create=create}) end - - if not mt.txn then return end - - if mt.parent then - mt.meta['ui-name'] = getmetatable(mt.parent).mmeta( - pth.name(mt.path) - )['ui-name'] - end - - function mt.save(k, v) rawset(self, k, v) end - function mt.__index(t, k) return mt.get(k) end - function mt.__newindex(t, k, v) mt.save(k, v) end - - function mt.has_permission(user, permission) - local p = permission..mt.path - if mt.txn:fetch('/auth/permissions')[p] then - return user:check_permission(p) - end - - if ({create=true, delete=true})[permission] then - permission = 'modify' - end - return M.has_permission(mt.parent, user, permission) - end - - mt.txn.validable[mt.path] = mt.addr -end - -function M.TreeNode:fetch(path, create) - if type(path) == 'string' then path = pth.split(path) end - - if #path == 0 then return self end - - local mt = getmetatable(self) - local name = path[1] - if not mt.member(name) then - raise(mt.path, 'Member does not exist: '..name) - end - - local next = mt.get(name, create) - if next == nil and (not create or #path > 1) then - raise(mt.path, 'Subordinate does not exist: '..name) - end - - table.remove(path, 1) - if #path > 0 and type(next) ~= 'table' then - raise(pth.join(mt.path, name), 'Is a primitive value') - end - - return M.TreeNode.fetch(next, path, create) -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(self) - local name = path[1] - table.remove(path, 1) - - local function collect(name) - local next = mt.load(name) - 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) - -function M.Collection:init(context, params) - super(self, M.Collection):init(context) - - self.init = nil - self.fetch = nil - self.search_refs = nil - - local mt = getmetatable(self) - local field = M.BoundMember(self, pth.wildcard, params.field) - - function mt.topology() return field:topology() end - - function mt.member(name) - return M.BoundMember(self, name, params.field) - end - - function mt.load(k, options) return mt.member(k):load(options) end - - if not mt.txn then return end - - mt.meta.type = 'collection' - mt.meta.members = field:meta() - mt.meta['ui-member'] = params.ui_member or mt.meta['ui-name']:gsub('s$', '') - mt.meta.widget = params.layout - - function mt.mmeta(name) - local res = util.copy(mt.meta.members) - if name ~= pth.wildcard then - res['ui-name'] = mt.meta['ui-member']..' '..name - end - return res - end - - function mt.members() return mt.txn:get(mt.addr) or {} end - - function mt.validate() - if #mt.members() > 0 then return end - if params.required then raise(mt.path, 'Collection cannot be empty') end - if params.destroy then - mt.txn:set(mt.addr) - validate(mt.parent) - end - end - - function mt.save(k, v) mt.member(k):save(v) end -end - - -M.List = class(M.Collection) - -function M.List:init(context, params) - super(self, M.List):init(context, params) - - local mt = getmetatable(self) - mt.meta.type = 'list' - - local save = mt.save - function mt.save(k, v) - assert(type(k) == 'number') - if v == nil then - local len = #mt.members() - while k < len do - mt.save(k, mt.load(k + 1, {dereference=false})) - k = k + 1 - end - end - save(k, v) - end - - function mt.insert(v, i) - local len = #mt.members() - if not i then i = len + 1 end - for j = len,i,-1 do mt.save(j + 1, mt.load(j, {dereference=false})) end - mt.save(i, v) - end -end - - --- experimental -M.Mixed = class(M.Collection) - -function M.Mixed:init(context, params) - super(self, M.Mixed):init(context, params) - - -- TODO dynamic meta: list non-leaf children - local mt = getmetatable(self) - mt.meta = {type='mixed', ['ui-name']=mt.path} - function mt.mmeta(name) - return {type='mixed', ['ui-name']=pth.join(mt.path, name)} - end -end - - -local function meta_func(attr) - return function(node, ...) - local res = getmetatable(node)[attr] - if type(res) == 'function' then return res(...) end - return res - end -end - -for _, mf in ipairs{ - 'addr', 'has_permission', 'insert', 'meta', 'mmeta', 'path', 'topology' -} do M[mf] = meta_func(mf) end - - -function M.pairs(tbl, dereference) - if not isinstance(tbl, M.TreeNode) then return pairs(tbl) end - - local mt = getmetatable(tbl) - if dereference == nil then dereference = mt.dereference end - - local res = {} - for _, member in ipairs(mt.members()) do - res[member] = mt.load(member, {dereference=dereference}) - end - return pairs(res) -end - -local function _ipairs(mt, i) - i = i + 1 - local v = mt.load(i) - if v == nil then return end - return i, v -end -function M.ipairs(tbl) - if not isinstance(tbl, M.TreeNode) then return ipairs(tbl) end - return _ipairs, getmetatable(tbl), 0 -end - - -return M |