diff options
author | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2012-12-16 19:10:38 +0200 |
---|---|---|
committer | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2012-12-16 19:10:38 +0200 |
commit | e4361842fcdec369fbd4466f2528b2815f504ff9 (patch) | |
tree | 4694ca56f9e9a4869763d8fe1f31a81f6f62ac0b /acf/persistence/backends/json.lua | |
download | acf2-e4361842fcdec369fbd4466f2528b2815f504ff9.tar.bz2 acf2-e4361842fcdec369fbd4466f2528b2815f504ff9.tar.xz |
initial version
Diffstat (limited to 'acf/persistence/backends/json.lua')
-rw-r--r-- | acf/persistence/backends/json.lua | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/acf/persistence/backends/json.lua b/acf/persistence/backends/json.lua new file mode 100644 index 0000000..7300ce9 --- /dev/null +++ b/acf/persistence/backends/json.lua @@ -0,0 +1,110 @@ +--[[ +Copyright (c) 2012 Kaarle Ritvanen +See LICENSE file for license details +--]] + +module(..., package.seeall) + +local pth = require('acf.path') +local util = require('acf.persistence.util') +local copy = require('acf.util').copy + +require 'json' +require 'lfs' + + +local function keys(tbl) + local res = {} + for k, v in pairs(tbl) do table.insert(res, k) end + return res +end + + +backend = require('acf.object').class() + +function backend:init() + -- TODO cache expiration + self.cache = {} + self.dirty = {} +end + +function backend:split_path(path) + local fpath = copy(path) + local jpath = {} + local res + + while #fpath > 0 do + local fp = pth.join('/', unpack(fpath)) + if self.cache[fp] then return fp, jpath end + table.insert(jpath, 1, fpath[#fpath]) + table.remove(fpath) + end + + fpath = '/' + + while true do + fpath = pth.join(fpath, jpath[1]) + table.remove(jpath, 1) + + local attrs = lfs.attributes(fpath) + if not attrs or not ({directory=true, file=true})[attrs.mode] then + error('File or directory does not exist: '..fpath) + end + + if attrs.mode == 'file' then return fpath, jpath end + + assert(#jpath > 0) + end +end + +function backend:_get(path) + local fpath, jpath = self:split_path(path) + + if not self.cache[fpath] then + self.cache[fpath] = json.decode(util.read_file(fpath)) + end + + local res = self.cache[fpath] + + while #jpath > 0 do + if res == nil then return end + assert(type(res) == 'table') + local next = jpath[1] + res = res[tonumber(next) or next] + table.remove(jpath, 1) + end + + return res +end + +function backend:get(path) + local res = self:_get(path) + return type(res) == 'table' and keys(res) or res +end + +function backend:set(mods) + local dirty = {} + + for _, mod in ipairs(mods) do + local p, t, value = unpack(mod) + local fpath, jpath = self:split_path(p) + if t == 'table' then value = {} end + + if #jpath == 0 then self.cache[fpath] = value + + else + local comps = copy(p) + local name = comps[#comps] + table.remove(comps) + self:_get(comps)[tonumber(name) or name] = value + end + + dirty[fpath] = true + end + + for path, _ in pairs(dirty) do + local file = util.open_file(path, 'w') + file:write(json.encode(self.cache[path])) + file:close() + end +end |