diff options
Diffstat (limited to 'acf/model/field.lua')
-rw-r--r-- | acf/model/field.lua | 241 |
1 files changed, 0 insertions, 241 deletions
diff --git a/acf/model/field.lua b/acf/model/field.lua deleted file mode 100644 index 4d539e8..0000000 --- a/acf/model/field.lua +++ /dev/null @@ -1,241 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local M = {} - -local err = require('acf.error') -local raise = err.raise - -local node = require('acf.model.node') - -local object = require('acf.object') -local class = object.class -local super = object.super - -local util = require('acf.util') - - -local function contains(list, value) - for k, v in ipairs(list) do if v == value then return true end end - return false -end - -M.Member = class() - -function M.Member:init(params) - for k, v in pairs(params or {}) do - if self[k] == nil then self[k] = v end - end -end - -function M.Member:auto_ui_name(name) - if not name then return end - return (name:sub(1, 1):upper()..name:sub(2)):gsub('-', ' ') -end - -function M.Member:meta(context) - return { - name=self.name, - description=self.description, - ['ui-name']=self.ui_name or self:auto_ui_name(self.name) - } -end - - -M.Field = class(M.Member) - -function M.Field:init(params) - super(self, M.Field):init(params) - - if self.choice and not self['ui-choice'] then - self['ui-choice'] = util.map( - function(name) return self:auto_ui_name(name) end, - self.choice - ) - end - - if not self.widget then - self.widget = self.choice and 'combobox' or 'field' - end -end - -function M.Field:meta(context) - assert(self.dtype) - local res = super(self, M.Field):meta(context) - - res.type = self.dtype - res.required = self.required - res.default = self.default - res.choice = self.choice - res.widget = self.widget - res['ui-choice'] = self['ui-choice'] - - return res -end - -function M.Field:topology(context) - return { - {path=context.path, addr=context.addr, type=self.dtype} - } -end - -function M.Field:load(context) - if not context.txn then return setmetatable({}, context) end - local value = context.txn:get(context.addr) - if value == nil then return self.default end - return value -end - -function M.Field:_validate(context, value) - if self.required and value == nil then - raise(context.path, 'Required value not set') - end - if self.choice and value ~= nil and not contains(self.choice, value) then - raise(context.path, 'Invalid value') - end - if value ~= nil then self:validate(context, value) end - return value -end - -function M.Field:validate(context, value) end - -function M.Field:save(context, value) - context.txn:set(context.addr, self:_validate(context, value)) -end - -function M.Field:validate_saved(context) - self:save(context, self:load(context)) -end - - -local Primitive = class(M.Field) - -function Primitive:validate(context, value) - local t = self.dtype - if type(value) ~= t then raise(context.path, 'Not a '..t) end -end - - -M.String = class(Primitive) - -function M.String:init(params) - super(self, M.String):init(params) - self.dtype = 'string' -end - -function M.String:validate(context, value) - super(self, M.String):validate(context, value) - if self['max-length'] and value:len() > self['max-length'] then - raise(context.path, 'Maximum length exceeded') - end - if self.pattern and not value:match('^'..self.pattern..'$') then - raise(context.path, 'Invalid value') - end -end - -function M.String:meta(context) - local res = super(self, M.String):meta(context) - res['max-length'] = self['max-length'] - return res -end - - -M.Number = class(Primitive) - -function M.Number:init(params) - super(self, M.Number):init(params) - self.dtype = 'number' -end - -function M.Number:_validate(context, value) - return super(self, M.Number):_validate( - context, - value and tonumber(value) or value - ) -end - - -M.Integer = class(M.Number) - -function M.Integer:validate(context, value) - super(self, M.Integer):validate(context, value) - if math.floor(value) ~= value then raise(context.path, 'Not an integer') end -end - - -M.Boolean = class(Primitive) - -function M.Boolean:init(params) - super(self, M.Boolean):init(params) - self.dtype = 'boolean' - self.widget = self.dtype -end - - -M.TreeNode = class(M.Field) - -function M.TreeNode:init(params) - if not params.widget then params.widget = 'link' end - super(self, M.TreeNode):init(params) -end - -function M.TreeNode:topology(context) - local res = super(self, M.TreeNode):topology(context) - res[1].type = 'table' - util.extend(res, node.topology(self:load(context, {create=true}))) - return res -end - -function M.TreeNode:load(context, options) - if context.txn and not ( - ( - options and options.create - ) or self.create or context.txn:get(context.addr) - ) then return end - return self.itype(context, self.iparams) -end - -function M.TreeNode:save(context, value) - local path = context.path - - if value == path then return end - if type(value) == 'string' then value = context.txn:fetch(value) end - if object.isinstance(value, node.TreeNode) and node.path(value) == path then - return - end - - context.txn:set(context.addr) - - if value then - if type(value) ~= 'table' then - raise(path, 'Cannot assign primitive value') - end - - context.txn:set(context.addr, {}) - local new = self:load(context, {create=true}) - - local errors = err.ErrorDict() - for k, v in node.pairs(value) do - errors:collect(self.save_member, new, k, v) - end - errors:raise() - end -end - -function M.TreeNode.save_member(node, k, v) node[k] = v end - - -M.Model = class(M.TreeNode) - -function M.Model:init(params) - super(self, M.Model):init(params) - - assert(self.model) - self.itype = self.model - self.dtype = 'model' -end - - -return M |