aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2019-09-28 14:42:49 +0000
committers-ol <s-ol@users.noreply.github.com>2019-09-28 14:42:49 +0000
commit911ac978f7a70997637fcc5dcfe898eef4e11de9 (patch)
tree108cdfc364636b557727603386d9ef4626a45a2b
parentwip zip (diff)
downloadmmm-911ac978f7a70997637fcc5dcfe898eef4e11de9.tar.gz
mmm-911ac978f7a70997637fcc5dcfe898eef4e11de9.zip
initial sqlite support
-rw-r--r--mmm/mmmfs/drivers/sql.moon157
-rw-r--r--mmm/mmmfs/fileder.moon2
-rw-r--r--tests/test_backend.moon49
-rw-r--r--tup.config2
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
diff --git a/tup.config b/tup.config
index 7010858..54e707c 100644
--- a/tup.config
+++ b/tup.config
@@ -1,2 +1,2 @@
CONFIG_FENGARI_VERSION=v0.1.4
-CONFIG_SASS_ARGS=-m auto
+CONFIG_SASS_ARGS=-mauto