diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2019-09-29 14:59:00 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2019-09-29 14:59:00 +0000 |
| commit | 7cb951d05eb9f2408ee34f7c5f0b49907a03bbfc (patch) | |
| tree | 67a077382fd8984ff216824f713df0c38c5dc5a1 | |
| parent | initial sqlite support (diff) | |
| download | mmm-7cb951d05eb9f2408ee34f7c5f0b49907a03bbfc.tar.gz mmm-7cb951d05eb9f2408ee34f7c5f0b49907a03bbfc.zip | |
add busted spec for driver
| -rw-r--r-- | mmm/mmmfs/drivers/sql.moon | 72 | ||||
| -rw-r--r-- | spec/driver_spec.moon | 88 | ||||
| -rw-r--r-- | tests/test_backend.moon | 49 |
3 files changed, 138 insertions, 71 deletions
diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon index cfe60e6..a961e1e 100644 --- a/mmm/mmmfs/drivers/sql.moon +++ b/mmm/mmmfs/drivers/sql.moon @@ -2,24 +2,27 @@ sqlite = require 'sqlite3' class TreeStore new: (name='db.sqlite3') => - @db = sqlite.open name + @db = if name then sqlite.open name else sqlite.open_memory! assert @db\exec [[ PRAGMA foreign_keys = ON; + PRAGMA case_sensitive_like = ON; CREATE TABLE IF NOT EXISTS fileder ( id INTEGER NOT NULL PRIMARY KEY, path TEXT NOT NULL UNIQUE, - parent TEXT + parent TEXT REFERENCES fileder(path) + ON DELETE CASCADE + ON UPDATE CASCADE ); 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) + name TEXT NOT NULL, + type TEXT NOT NULL, + value BLOB NOT NULL, + PRIMARY KEY (fileder_id, name, type) ); CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id); CREATE INDEX IF NOT EXISTS facet_name ON facet(name); @@ -30,47 +33,60 @@ class TreeStore fetch: (q, ...) => stmt = assert @db\prepare q - stmt\bind ... + stmt\bind ... if 0 < select '#', ... stmt\irows! fetch_one: (q, ...) => stmt = assert @db\prepare q - stmt\bind ... + stmt\bind ... if 0 < select '#', ... stmt\first_irow! exec: (q, ...) => stmt = assert @db\prepare q - stmt\bind ... - assert stmt\exec! + stmt\bind ... if 0 < select '#', ... + res = assert stmt\exec! -- fileders - list_fileders: (path, recursive=false) => + list_fileders_in: (path) => coroutine.wrap -> for { path } in @fetch 'SELECT path - FROM fileder WHERE parent = ?', path + FROM fileder WHERE parent IS ?', path coroutine.yield path - if recursive - for p in @list_fileders path - coroutine.yield p + + list_all_fileders: (path) => + coroutine.wrap -> + for path in @list_fileders_in path + coroutine.yield path + for p in @list_all_fileders path + coroutine.yield p create_fileder: (parent, name) => @exec 'INSERT INTO fileder (path, parent) - VALUES (:path, :parent)', - { path: "#{parent}/#{name}", :parent } + VALUES (IFNULL(:parent, "") || "/" || :name, :parent)', + { :parent, :name } + + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "couldn't create fileder - parent missing?" remove_fileder: (path) => @exec 'DELETE FROM fileder - WHERE path = ?', path + WHERE path LIKE :path || "/%" + OR path = :path', path rename_fileder: (path, next_name) => + error 'not implemented' + @exec 'UPDATE fileder - SET path = CONCAT(parent, "/", :next_name) + SET path = IFNULL(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' + move_fileder: (path, new_parent) => + error 'not implemented' + + -- @TODO: remove all children, child-children... -- facets list_facets: (path) => @@ -89,7 +105,7 @@ class TreeStore AND facet.name = :name AND facet.type = :type', { :path, :name, :type } - v[1] + v and v[1] create_facet: (path, name, type, blob) => @exec 'INSERT INTO facet (fileder_id, name, type, value) @@ -98,6 +114,9 @@ class TreeStore WHERE fileder.path = :path', { :path, :name, :type, :blob } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "couldn't create facet - fileder missing?" + remove_facet: (path, name, type) => @exec 'DELETE FROM facet WHERE name = :name @@ -105,6 +124,9 @@ class TreeStore AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', { :path, :name, :type } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + rename_facet: (path, name, type, next_name) => @exec 'UPDATE facet SET name = :next_name @@ -113,6 +135,9 @@ class TreeStore AND fileder_id = (SELECT id FROM fileder WHERE path = :path)', { :path, :name, :next_name, :type } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + update_facet: (path, name, type, blob) => @exec 'UPDATE facet SET value = :blob @@ -121,6 +146,9 @@ class TreeStore AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)', { :path, :name, :type, :blob } + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + load_tree = (file='root.zip') -> archive = zip.open file diff --git a/spec/driver_spec.moon b/spec/driver_spec.moon new file mode 100644 index 0000000..60cd574 --- /dev/null +++ b/spec/driver_spec.moon @@ -0,0 +1,88 @@ +import TreeStore from require 'mmm.mmmfs.drivers.sql' + +sort2 = (a, b) -> + {ax, ay}, {bx, by} = a, b + "#{ax}//#{ay}" < "#{bx}//#{by}" +toseq = (iter) -> with v = [x for x in iter] + table.sort v +toseq2 = (iter) -> with v = [{x, y} for x, y in iter] + table.sort v, sort2 + +describe "sql driver", -> + randomize false + + ts = TreeStore! + + it "starts out empty", -> + assert.are.same {}, toseq ts\list_fileders_in! + assert.are.same {}, toseq ts\list_all_fileders! + + it "can't create fileders without missing parents", -> + assert.has_error -> + ts\create_fileder '/hello', 'world' + + it "can create root fileders", -> + ts\create_fileder nil, 'hello' + assert.are.same {'/hello'}, toseq ts\list_all_fileders! + + it "can create and list child fileders recursively", -> + ts\create_fileder '/hello', 'world' + ts\create_fileder '/hello/world', 'again' + + assert.are.same {'/hello', '/hello/world', '/hello/world/again'}, + toseq ts\list_all_fileders! + + it "can list immediate children", -> + assert.are.same {"/hello"}, toseq ts\list_fileders_in! + assert.are.same {"/hello/world"}, toseq ts\list_fileders_in "/hello" + assert.are.same {"/hello/world/again"}, toseq ts\list_fileders_in "/hello/world" + + describe "can create and list facets", -> + ts\create_facet '/hello', 'name', 'alpha', 'hello' + ts\create_facet '/hello/world', 'name', 'alpha', 'world' + ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' + + it "can't create facet for nonexistant fileders", -> + assert.has_error -> ts\create_facet '/hello/orldw', 'name', 'alpha', 'foo' + + it "can't create facet without value", -> + assert.has_error -> ts\create_facet '/hello/world', 'other', 'alpha', nil + + it "can't create facet for duplicate keys", -> + assert.has_error -> ts\create_facet '/hello/world', 'name', 'alpha', 'foo' + + assert.are.same {{'name', 'alpha'}}, toseq2 ts\list_facets '/hello' + assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + + it "can load facets", -> + assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha' + assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha' + assert.are.equal '# Helau World!', ts\load_facet '/hello/world', '', 'text/markdown' + assert.is_falsy ts\load_facet '/hello', 'nonexistant', 'facet' + + it "can rename facets", -> + ts\rename_facet '/hello/world', 'name', 'alpha', 'gnome' + assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + assert.are.equal 'world', ts\load_facet '/hello/world', 'gnome', 'alpha' + + it "can update facets", -> + ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' + assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + assert.are.equal '# Hello World!', ts\load_facet '/hello/world', '', 'text/markdown' + + it "can remove facets", -> + ts\remove_facet '/hello/world', 'gnome', 'alpha' + assert.are.same {{'', 'text/markdown'}}, toseq2 ts\list_facets '/hello/world' + + assert.has_error -> ts\remove_facet '/hello/world', 'gnome', 'alpha' + + it "can delete fileders", -> + ts\remove_fileder '/hello/world' + assert.is_falsy ts\load_facet '/hello/world', 'gnome', 'alpha' + assert.are.same {'/hello'}, toseq ts\list_all_fileders! + + ts\remove_fileder '/hello' + assert.are.same {}, toseq ts\list_all_fileders! diff --git a/tests/test_backend.moon b/tests/test_backend.moon deleted file mode 100644 index d217c47..0000000 --- a/tests/test_backend.moon +++ /dev/null @@ -1,49 +0,0 @@ -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 |
