summaryrefslogtreecommitdiffstats
path: root/acf
diff options
context:
space:
mode:
authorKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-06-27 15:10:29 +0300
committerKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2013-06-28 13:24:36 +0300
commite6ed4efcbd9b87641e471d0879ab8ff70867f544 (patch)
treef9161d7d33940d2a8334a1bb788e5136912aa024 /acf
parenta68e8d3ed61c991b5b5af1de3a19d74c3ed21d74 (diff)
downloadaconf-e6ed4efcbd9b87641e471d0879ab8ff70867f544.tar.bz2
aconf-e6ed4efcbd9b87641e471d0879ab8ff70867f544.tar.xz
collect topological information on models
Diffstat (limited to 'acf')
-rw-r--r--acf/model/field.lua14
-rw-r--r--acf/model/init.lua2
-rw-r--r--acf/model/model.lua28
-rw-r--r--acf/model/node.lua10
-rw-r--r--acf/model/root.lua39
-rw-r--r--acf/util.lua5
6 files changed, 85 insertions, 13 deletions
diff --git a/acf/model/field.lua b/acf/model/field.lua
index 1c903b0..beb6b28 100644
--- a/acf/model/field.lua
+++ b/acf/model/field.lua
@@ -14,7 +14,7 @@ local object = require('acf.object')
local class = object.class
local super = object.super
-local map = require('acf.util').map
+local util = require('acf.util')
local function contains(list, value)
@@ -52,7 +52,7 @@ function Field:init(params)
super(self, Field):init(params)
if self.choice and not self['ui-choice'] then
- self['ui-choice'] = map(
+ self['ui-choice'] = util.map(
function(name) return self:auto_ui_name(name) end,
self.choice
)
@@ -79,6 +79,10 @@ end
function Field:btype(context) return self.dtype end
+function Field:topology(context)
+ return {{path=context.path, addr=context.addr}}
+end
+
function Field:load(context)
local value = context.txn:get(context.addr, self:btype(context))
if value == nil then return self.default end
@@ -172,6 +176,12 @@ end
TreeNode = class(Field)
+function TreeNode:topology(context)
+ local res = super(self, TreeNode):topology(context)
+ util.extend(res, node.topology(self:load(context, true)))
+ return res
+end
+
function TreeNode:load(context, create)
if not (
create or self.create or context.txn:get(context.addr, 'table')
diff --git a/acf/model/init.lua b/acf/model/init.lua
index 19cb848..ba3eae5 100644
--- a/acf/model/init.lua
+++ b/acf/model/init.lua
@@ -168,6 +168,8 @@ function Mixed:init(params)
self.pfield = Field()
end
+function Mixed:topology(context) return {} end
+
function Mixed:load(context)
local value = self.pfield:load(context)
if type(value) == 'table' then return super(self, Mixed):load(context) end
diff --git a/acf/model/model.lua b/acf/model/model.lua
index 11e7fed..e4cffa4 100644
--- a/acf/model/model.lua
+++ b/acf/model/model.lua
@@ -120,8 +120,26 @@ function Model:init(context)
return BoundMember(self, m)
end
+ local function _members(tpe)
+ local res = {}
+ for _, name in ipairs(self.members) do
+ local m = member(name, false, tpe)
+ if m then table.insert(res, m) end
+ end
+ return res
+ end
+
+ function mt.topology()
+ local res = {}
+ for _, f in ipairs(_members(Field)) do util.extend(res, f:topology()) end
+ return res
+ end
+
function mt.valid_member(name) return member(name) end
+ if not mt.txn then return end
+
+
function mt.mmeta(name) return member(name, true):meta() end
function mt.load(k, create)
@@ -157,12 +175,7 @@ function Model:init(context)
function mt.save(k, v) return member(k, true, Field):save(v) end
local function tmeta(tpe)
- local res = {}
- for _, name in ipairs(self.members) do
- local m = member(name, false, tpe)
- if m then table.insert(res, m:meta()) end
- end
- return res
+ return util.map(function(m) return m:meta() end, _members(tpe))
end
mt.meta.type = 'model'
@@ -174,8 +187,7 @@ function Model:init(context)
end
function mt.validate()
- for _, name in ipairs(mt.members()) do
- local f = member(name, false, Field)
+ for _, f in ipairs(_members(Field)) do
if not f.compute then f:validate_saved() end
end
end
diff --git a/acf/model/node.lua b/acf/model/node.lua
index 380f809..eb06b2d 100644
--- a/acf/model/node.lua
+++ b/acf/model/node.lua
@@ -56,6 +56,9 @@ function TreeNode:init(context)
util.update(mt, context)
mt.meta = {}
+
+ if not mt.txn then return end
+
if mt.parent then
mt.meta['ui-name'] = getmetatable(mt.parent).mmeta(
pth.name(mt.path)
@@ -118,6 +121,10 @@ function Collection:init(context, params)
local field = BoundMember(self, params.field)
local mt = getmetatable(self)
+ function mt.topology() return field:topology(pth.wildcard) end
+ function mt.valid_member(name) return true end
+
+ if not mt.txn then return end
mt.meta.type = 'collection'
mt.meta.members = field:meta(pth.wildcard)
@@ -125,8 +132,6 @@ function Collection:init(context, params)
mt.meta['ui-name'], 's$', ''
)
- function mt.valid_member(name) return true end
-
function mt.mmeta(name)
local res = util.copy(mt.meta.members)
res['ui-name'] = mt.meta['ui-member']..' '..name
@@ -210,6 +215,7 @@ meta = meta_func('meta')
mmeta = meta_func('mmeta')
parent = meta_func('parent')
path = meta_func('path')
+topology = meta_func('topology')
validate = meta_func('validate')
diff --git a/acf/model/root.lua b/acf/model/root.lua
index f0f21c1..f273c4a 100644
--- a/acf/model/root.lua
+++ b/acf/model/root.lua
@@ -5,11 +5,14 @@ See LICENSE file for license details
module(..., package.seeall)
-local node = require('acf.model.node')
local model = require('acf.model.model')
+local node = require('acf.model.node')
local object = require('acf.object')
local pth = require('acf.path')
+local util = require('acf.util')
+local setdefault = util.setdefault
+
RootModel = model.new()
@@ -27,7 +30,41 @@ function RootModel:meta(path)
return node.mmeta(self:search(pth.parent(path), true), pth.name(path))
end
+
+local _topology = {}
+
+function topology(addr, create)
+ local top = _topology
+ if type(addr) == 'table' then addr = util.copy(addr)
+ else addr = pth.split(addr) end
+
+ local function defaults(top)
+ return util.setdefaults(top, {members={}, paths={}})
+ end
+
+ while #addr > 0 do
+ if create then
+ top = setdefault(defaults(top).members, addr[1], {})
+ else
+ top = top.members[addr[1]] or top.members[pth.wildcard]
+ if not top then return end
+ end
+ table.remove(addr, 1)
+ end
+
+ return defaults(top)
+end
+
function register(name, field, params)
params.create = true
RootModel[name] = model.to_field(field, params)
+
+ _topology = {}
+
+ -- TODO optimize: do not traverse already registered models
+ for i, record in ipairs(node.topology(RootModel())) do
+ local top = topology(record.addr, true)
+ setdefault(top, 'order', i)
+ table.insert(top.paths, record.path)
+ end
end
diff --git a/acf/util.lua b/acf/util.lua
index cc44fc2..63276ec 100644
--- a/acf/util.lua
+++ b/acf/util.lua
@@ -23,6 +23,11 @@ function copy(var)
return type(var) == 'table' and setdefaults({}, var) or var
end
+function extend(dst, src)
+ for _, v in ipairs(src) do table.insert(dst, v) end
+ return dst
+end
+
function keys(tbl)
local res = {}
for k, v in pairs(tbl) do table.insert(res, k) end