diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2019-09-28 14:42:49 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2019-09-28 14:42:49 +0000 |
| commit | 911ac978f7a70997637fcc5dcfe898eef4e11de9 (patch) | |
| tree | 108cdfc364636b557727603386d9ef4626a45a2b | |
| parent | wip zip (diff) | |
| download | mmm-911ac978f7a70997637fcc5dcfe898eef4e11de9.tar.gz mmm-911ac978f7a70997637fcc5dcfe898eef4e11de9.zip | |
initial sqlite support
| -rw-r--r-- | mmm/mmmfs/drivers/sql.moon | 157 | ||||
| -rw-r--r-- | mmm/mmmfs/fileder.moon | 2 | ||||
| -rw-r--r-- | tests/test_backend.moon | 49 | ||||
| -rw-r--r-- | tup.config | 2 |
4 files changed, 208 insertions, 2 deletions
diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon new file mode 100644 index 0000000..cfe60e6 --- /dev/null +++ b/mmm/mmmfs/drivers/sql.moon @@ -0,0 +1,157 @@ +sqlite = require 'sqlite3' + +class TreeStore + new: (name='db.sqlite3') => + @db = sqlite.open name + + assert @db\exec [[ + PRAGMA foreign_keys = ON; + CREATE TABLE IF NOT EXISTS fileder ( + id INTEGER NOT NULL PRIMARY KEY, + path TEXT NOT NULL UNIQUE, + parent TEXT + ); + CREATE TABLE IF NOT EXISTS facet ( + fileder_id INTEGER NOT NULL + REFERENCES fileder + ON UPDATE CASCADE + ON DELETE CASCADE, + name TEXT, + type TEXT, + value BLOB, + PRIMARY KEY (name, type) + ); + CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id); + CREATE INDEX IF NOT EXISTS facet_name ON facet(name); + ]] + + close: => + @db\close! + + fetch: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... + stmt\irows! + + fetch_one: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... + stmt\first_irow! + + exec: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... + assert stmt\exec! + + -- fileders + list_fileders: (path, recursive=false) => + coroutine.wrap -> + for { path } in @fetch 'SELECT path + FROM fileder WHERE parent = ?', path + coroutine.yield path + if recursive + for p in @list_fileders path + coroutine.yield p + + create_fileder: (parent, name) => + @exec 'INSERT INTO fileder (path, parent) + VALUES (:path, :parent)', + { path: "#{parent}/#{name}", :parent } + + remove_fileder: (path) => + @exec 'DELETE FROM fileder + WHERE path = ?', path + + rename_fileder: (path, next_name) => + @exec 'UPDATE fileder + SET path = CONCAT(parent, "/", :next_name) + WHERE path = :path', + { :path, :next_name } + -- @TODO: rename all children, child-children... + + move_fileder: (path, new_path) => + error '@TODO: implement move_fileder' + + -- facets + list_facets: (path) => + coroutine.wrap -> + for { name, type } in @fetch 'SELECT facet.name, facet.type + FROM facet + INNER JOIN fileder ON facet.fileder_id = fileder.id + WHERE fileder.path = ?', path + coroutine.yield name, type + + load_facet: (path, name, type) => + v = @fetch_one 'SELECT facet.value + FROM facet + INNER JOIN fileder ON facet.fileder_id = fileder.id + WHERE fileder.path = :path + AND facet.name = :name + AND facet.type = :type', + { :path, :name, :type } + v[1] + + create_facet: (path, name, type, blob) => + @exec 'INSERT INTO facet (fileder_id, name, type, value) + SELECT id, :name, :type, :blob + FROM fileder + WHERE fileder.path = :path', + { :path, :name, :type, :blob } + + remove_facet: (path, name, type) => + @exec 'DELETE FROM facet + WHERE name = :name + AND type = :type + AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', + { :path, :name, :type } + + rename_facet: (path, name, type, next_name) => + @exec 'UPDATE facet + SET name = :next_name + WHERE name = :name + AND type = :type + AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', + { :path, :name, :next_name, :type } + + update_facet: (path, name, type, blob) => + @exec 'UPDATE facet + SET value = :blob + WHERE facet.name = :name + AND facet.type = :type + AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)', + { :path, :name, :type, :blob } + +load_tree = (file='root.zip') -> + archive = zip.open file + + fileders = setmetatable {}, + __index: (path) => + with val = Fileder {} + .path = path + rawset @, path, val + + fileders['/root'].facets['name: alpha'] = -> 'root' + + for i = 1, #archive + { :name, :size } = archive\stat i + + path, facet = dir_base "/#{name}" + parent, name = dir_base path + + key = load_facet facet + + this = fileders[path] + this.facets['name: alpha'] = -> name + this.facets[key] = -> + file = archive\open i + with file\read size + file\close! + + table_add fileders[parent].children, this + + fileders['/root'] + +{ + :TreeStore, + load_tree, +} diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 16eef77..0400141 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -160,7 +160,7 @@ class Fileder key, conversions = @find want if key - value = apply_conversions conversions, @facets[key]!, @, key + value = apply_conversions conversions, @facets[key], @, key value, key -- like @get, throw if no value or conversion path diff --git a/tests/test_backend.moon b/tests/test_backend.moon new file mode 100644 index 0000000..d217c47 --- /dev/null +++ b/tests/test_backend.moon @@ -0,0 +1,49 @@ +import TreeStore from require 'mmm.mmmfs.drivers.sql' +ts = TreeStore! + +assert_seq1 = (expected, iter) -> + tbl + i = 0 + + for x in iter + i += 1 + assert expected[i] == x, "entry #{i}: '#{x}', expected '#{expected[i]}'!" + + assert i == #expected, "only #{i} entries found, expected #{#expected}" + +assert_seq2 = (expected, iter) -> + tbl + i = 0 + + for a, b in iter + i += 1 + assert expected[i][1] == a, "entry #{i} a: '#{a}', expected '#{expected[i][1]}'!" + assert expected[i][2] == b, "entry #{i} b: '#{b}', expected '#{expected[i][2]}'!" + + assert i == #expected, "only #{i} entries found, expected #{#expected}" + +assert_seq1 {}, ts\list_fileders '' +assert_seq1 {}, ts\list_fileders '', true + +ts\create_fileder '', 'hello' +ts\create_fileder '/hello', 'world' +assert_seq1 {'/hello', '/hello/world'}, ts\list_fileders '', true + +ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' +ts\create_facet '/hello/world', 'nome', 'alpha', 'world' + +assert_seq2 {}, ts\list_facets '/hello' +assert_seq2 { {'', 'text/markdown'}, {'nome', 'alpha'} }, ts\list_facets '/hello/world' + +ts\rename_facet '/hello/world', 'nome', 'alpha', 'name' +assert_seq2 { {'', 'text/markdown'}, {'name', 'alpha'} }, ts\list_facets '/hello/world' + +assert ('# Helau World!' == ts\load_facet '/hello/world', '', 'text/markdown') +ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' +assert ('# Hello World!' == ts\load_facet '/hello/world', '', 'text/markdown') + +ts\remove_fileder '/hello/world' +ts\remove_fileder '/hello' + +assert_seq2 {}, ts\list_facets '/hello/world' +assert_seq1 {}, ts\list_fileders '', true @@ -1,2 +1,2 @@ CONFIG_FENGARI_VERSION=v0.1.4 -CONFIG_SASS_ARGS=-m auto +CONFIG_SASS_ARGS=-mauto |
