From 342db785a82417c58ec54bd9779a8a7fca61bfaf Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 9 Oct 2019 13:47:39 +0200 Subject: rename drivers to stores, make server, render_all store-agnostic --- build/import.moon | 2 +- build/render_all.moon | 9 ++- build/server.moon | 9 ++- mmm/init.server.moon | 4 +- mmm/mmmfs/drivers/lfs.moon | 157 -------------------------------------- mmm/mmmfs/drivers/sql.moon | 183 --------------------------------------------- mmm/mmmfs/fileder.moon | 2 +- mmm/mmmfs/stores/init.moon | 33 ++++++++ mmm/mmmfs/stores/lfs.moon | 157 ++++++++++++++++++++++++++++++++++++++ mmm/mmmfs/stores/sql.moon | 183 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 387 insertions(+), 352 deletions(-) delete mode 100644 mmm/mmmfs/drivers/lfs.moon delete mode 100644 mmm/mmmfs/drivers/sql.moon create mode 100644 mmm/mmmfs/stores/init.moon create mode 100644 mmm/mmmfs/stores/lfs.moon create mode 100644 mmm/mmmfs/stores/sql.moon diff --git a/build/import.moon b/build/import.moon index ceb56ad..1e4df31 100644 --- a/build/import.moon +++ b/build/import.moon @@ -14,7 +14,7 @@ import SQLStore from require 'mmm.mmmfs.drivers.sql' -- usage: -- moon import.moon [output.sqlite3] -{ root, file } = arg +{ root, store } = arg assert root, "please specify the root directory" diff --git a/build/render_all.moon b/build/render_all.moon index 2a16a5f..02da12c 100644 --- a/build/render_all.moon +++ b/build/render_all.moon @@ -9,17 +9,18 @@ add '?/init.server' require 'mmm' import load_tree from require 'mmm.mmmfs.fileder' +import get_store from require 'mmm.mmmfs.stores' import render from require 'mmm.mmmfs.layout' -import SQLStore from require 'mmm.mmmfs.drivers.sql' -- usage: --- moon render_all.moon [db.sqlite3] [startpath] -{ file, startpath } = arg +-- moon render_all.moon [STORE] [startpath] +{ store, startpath } = arg export STATIC STATIC = true -tree = load_tree SQLStore :file +store = get_store store +tree = load_tree store tree = tree\walk startpath if startpath for fileder in coroutine.wrap tree\iterate diff --git a/build/server.moon b/build/server.moon index b28073e..2906d9b 100644 --- a/build/server.moon +++ b/build/server.moon @@ -10,7 +10,7 @@ add '?/init.server' require 'mmm' import Key, dir_base, load_tree from require 'mmm.mmmfs.fileder' -import SQLStore from require 'mmm.mmmfs.drivers.sql' +import get_store from require 'mmm.mmmfs.stores' import decodeURI from require 'http.util' lfs = require 'lfs' @@ -164,9 +164,10 @@ class Server print msg -- usage: --- moon server.moon [db.sqlite3] [host] [port] -{ file, host, port } = arg +-- moon server.moon [STORE] [host] [port] +{ store, host, port } = arg -tree = load_tree SQLStore :file +store = get_store store +tree = load_tree store server = Server tree, :host, port: port and tonumber port server\listen! diff --git a/mmm/init.server.moon b/mmm/init.server.moon index 2c83ab5..8fc6a0e 100644 --- a/mmm/init.server.moon +++ b/mmm/init.server.moon @@ -1,4 +1,4 @@ -export MODE, print, warn, relative, on_client +export MODE, print, warn, relative MODE = 'SERVER' deep_tostring = (tbl, space='') -> @@ -29,7 +29,7 @@ relative = do _require = require (base, sub) -> - sub = 0 unless 'number' == type sub + sub = sub or 0 for i=1, sub base = base\match '^(.*)%.%w+$' diff --git a/mmm/mmmfs/drivers/lfs.moon b/mmm/mmmfs/drivers/lfs.moon deleted file mode 100644 index a90b55a..0000000 --- a/mmm/mmmfs/drivers/lfs.moon +++ /dev/null @@ -1,157 +0,0 @@ -lfs = require 'lfs' - --- split filename into dirname + basename -dir_base = (path) -> - dir, base = path\match '(.-)([^/]-)$' - if dir and #dir > 0 - dir = dir\sub 1, #dir - 1 - - dir, base - - -class LFSStore - new: (opts = {}) => - opts.root or= 'root' - opts.verbose or= false - - if not opts.verbose - @log = -> - - -- ensure path doesnt end with a slash - @root = opts.root\match '^(.-)/?$' - @log "opening '#{opts.root}'..." - - log: (...) => - print "[DB]", ... - - -- fileders - list_fileders_in: (path='') => - coroutine.wrap -> - for entry_name in lfs.dir @root .. path - continue if '.' == entry_name\sub 1, 1 - entry_path = @root .. "#{path}/#{entry_name}" - if 'directory' == lfs.attributes entry_path, 'mode' - coroutine.yield "#{path}/#{entry_name}" - - 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) => - @log "creating fileder #{path}" - path = "#{parent}/#{name}" - assert lfs.mkdir @root .. path - path - - remove_fileder: (path) => - @log "removing fileder #{path}" - - rmdir = (path) -> - for file in lfs.dir path - continue if '.' == file\sub 1, 1 - - file_path = "#{path}/#{file}" - switch lfs.attributes file_path, 'mode' - when 'file' - assert os.remove file_path - when 'directory' - assert rmdir file_path - - lfs.rmdir path - - rmdir @root .. path - - rename_fileder: (path, next_name) => - @log "renaming fileder #{path} -> '#{next_name}'" - parent, name = dir_base path - assert os.rename path, @root .. "#{parent}/#{next_name}" - - move_fileder: (path, next_parent) => - @log "moving fileder #{path} -> #{next_parent}/" - parent, name = dir_base path - assert os.rename @root .. path, @root .. "#{next_parent}/#{name}" - - -- facets - list_facets: (path) => - coroutine.wrap -> - for entry_name in lfs.dir @root .. path - entry_path = "#{@root .. path}/#{entry_name}" - if 'file' == lfs.attributes entry_path, 'mode' - entry_name = (entry_name\match '(.*)%.%w+') or entry_name - entry_name = entry_name\gsub '%$', '/' - name, type = entry_name\match '(%w+): *(.+)' - if not name - name = '' - type = entry_name - - coroutine.yield name, type - - tofp: (path, name, type) => - type = "#{name}: #{type}" if #name > 0 - type = type\gsub '%/', '$' - @root .. "#{path}/#{type}" - - locate: (path, name, type) => - return unless lfs.attributes @root .. path, 'mode' - - type = type\gsub '%/', '$' - name = "#{name}: " if #name > 0 - name = name .. type - name = name\gsub '([^%w])', '%%%1' - - local file_name - for entry_name in lfs.dir @root .. path - if (entry_name\match "^#{name}$") or entry_name\match "^#{name}%.%w+$" - if file_name - error "two files match #{name}: #{file_name} and #{entry_name}!" - file_name = entry_name - - - file_name and @root .. "#{path}/#{file_name}" - - load_facet: (path, name, type) => - filepath = @locate path, name, type - return unless filepath - file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filepath}'" - with file\read '*all' - file\close! - - create_facet: (path, name, type, blob) => - @log "creating facet #{path} | #{name}: #{type}" - assert blob, "cant create facet without value!" - - filepath = @tofp path, name, type - if lfs.attributes filepath, 'mode' - error "facet file already exists!" - - file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" - file\write blob - file\close! - - remove_facet: (path, name, type) => - @log "removing facet #{path} | #{name}: #{type}" - - filepath = @locate path, name, type - assert filepath, "couldn't locate facet!" - assert os.remove filepath - - rename_facet: (path, name, type, next_name) => - @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" - filepath = @locate path, name, type - assert filepath, "couldn't locate facet!" - assert os.rename filepath, @tofp path, next_name, type - - update_facet: (path, name, type, blob) => - @log "updating facet #{path} | #{name}: #{type}" - filepath = @locate path, name, type - assert filepath, "couldn't locate facet!" - file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" - file\write blob - file\close! - -{ - :LFSStore -} diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon deleted file mode 100644 index 490eade..0000000 --- a/mmm/mmmfs/drivers/sql.moon +++ /dev/null @@ -1,183 +0,0 @@ -sqlite = require 'sqlite3' -root = os.tmpname! - -class SQLStore - new: (opts = {}) => - opts.file or= 'db.sqlite3' - opts.verbose or= false - opts.memory or= false - - if not opts.verbose - @log = -> - - if opts.memory - @log "opening in-memory DB..." - @db = sqlite.open_memory! - else - @log "opening '#{opts.file}'..." - @db = sqlite.open opts.file - - 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 REFERENCES fileder(path) - ON DELETE CASCADE - ON UPDATE CASCADE - ); - INSERT OR IGNORE INTO fileder (path, parent) VALUES ("", NULL); - - CREATE TABLE IF NOT EXISTS facet ( - fileder_id INTEGER NOT NULL - REFERENCES fileder - ON UPDATE CASCADE - ON DELETE CASCADE, - 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); - ]] - - log: (...) => - print "[DB]", ... - - close: => - @db\close! - - fetch: (q, ...) => - stmt = assert @db\prepare q - stmt\bind ... if 0 < select '#', ... - stmt\irows! - - fetch_one: (q, ...) => - stmt = assert @db\prepare q - stmt\bind ... if 0 < select '#', ... - stmt\first_irow! - - exec: (q, ...) => - stmt = assert @db\prepare q - stmt\bind ... if 0 < select '#', ... - res = assert stmt\exec! - - -- fileders - list_fileders_in: (path='') => - coroutine.wrap -> - for { path } in @fetch 'SELECT path - FROM fileder WHERE parent IS ?', path - coroutine.yield path - - 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) => - path = "#{parent}/#{name}" - - @log "creating fileder #{path}" - @exec 'INSERT INTO fileder (path, parent) - VALUES (:path, :parent)', - { :path, :parent } - - changes = @fetch_one 'SELECT changes()' - assert changes[1] == 1, "couldn't create fileder - parent missing?" - path - - remove_fileder: (path) => - @log "removing fileder #{path}" - @exec 'DELETE FROM fileder - WHERE path LIKE :path || "/%" - OR path = :path', path - - rename_fileder: (path, next_name) => - @log "renaming fileder #{path} -> '#{next_name}'" - error 'not implemented' - - @exec 'UPDATE fileder - SET path = parent || "/" || :next_name - WHERE path = :path', - { :path, :next_name } - - -- @TODO: rename all children, child-children... - - move_fileder: (path, next_parent) => - @log "moving fileder #{path} -> #{next_parent}/" - error 'not implemented' - - -- @TODO: remove all children, child-children... - - -- 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 and v[1] - - create_facet: (path, name, type, blob) => - @log "creating facet #{path} | #{name}: #{type}" - @exec 'INSERT INTO facet (fileder_id, name, type, value) - SELECT id, :name, :type, :blob - FROM fileder - 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) => - @log "removing 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 } - - changes = @fetch_one 'SELECT changes()' - assert changes[1] == 1, "no such facet" - - rename_facet: (path, name, type, next_name) => - @log "renaming 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 } - - changes = @fetch_one 'SELECT changes()' - assert changes[1] == 1, "no such facet" - - update_facet: (path, name, type, blob) => - @log "updating facet #{path} | #{name}: #{type}" - @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 } - - changes = @fetch_one 'SELECT changes()' - assert changes[1] == 1, "no such facet" - -{ - :SQLStore -} diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 2472933..939d32f 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -190,7 +190,7 @@ dir_base = (path) -> dir, base --- load tree from a driver instance +-- load tree from a store instance -- optionally load subtree starting at 'root' path load_tree = (store, root='') -> fileders = setmetatable {}, diff --git a/mmm/mmmfs/stores/init.moon b/mmm/mmmfs/stores/init.moon new file mode 100644 index 0000000..17595fe --- /dev/null +++ b/mmm/mmmfs/stores/init.moon @@ -0,0 +1,33 @@ +require = relative ..., 0 + +-- instantiate a store from a CLI arg +-- e.g.: sql, lfs:/path/to/root, sql:MEMORY, sql:db.sqlite3 +get_store = (args='sql', opts={verbose: true}) -> + type, arg = args\match '(%w+):(.*)' + type = arg unless type + + switch type\lower! + when 'sql' + import SQLStore from require '.sql' + + if arg == 'MEMORY' + opts.memory = true + else + opts.name = arg + + SQLStore opts + + when 'lfs' + import LFSStore from require '.lfs' + + opts.root = arg + + LFSStore opts + + else + warn "unknown or missing value for STORE: valid types values are sql, lfs" + os.exit 1 + +{ + :get_store +} diff --git a/mmm/mmmfs/stores/lfs.moon b/mmm/mmmfs/stores/lfs.moon new file mode 100644 index 0000000..a90b55a --- /dev/null +++ b/mmm/mmmfs/stores/lfs.moon @@ -0,0 +1,157 @@ +lfs = require 'lfs' + +-- split filename into dirname + basename +dir_base = (path) -> + dir, base = path\match '(.-)([^/]-)$' + if dir and #dir > 0 + dir = dir\sub 1, #dir - 1 + + dir, base + + +class LFSStore + new: (opts = {}) => + opts.root or= 'root' + opts.verbose or= false + + if not opts.verbose + @log = -> + + -- ensure path doesnt end with a slash + @root = opts.root\match '^(.-)/?$' + @log "opening '#{opts.root}'..." + + log: (...) => + print "[DB]", ... + + -- fileders + list_fileders_in: (path='') => + coroutine.wrap -> + for entry_name in lfs.dir @root .. path + continue if '.' == entry_name\sub 1, 1 + entry_path = @root .. "#{path}/#{entry_name}" + if 'directory' == lfs.attributes entry_path, 'mode' + coroutine.yield "#{path}/#{entry_name}" + + 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) => + @log "creating fileder #{path}" + path = "#{parent}/#{name}" + assert lfs.mkdir @root .. path + path + + remove_fileder: (path) => + @log "removing fileder #{path}" + + rmdir = (path) -> + for file in lfs.dir path + continue if '.' == file\sub 1, 1 + + file_path = "#{path}/#{file}" + switch lfs.attributes file_path, 'mode' + when 'file' + assert os.remove file_path + when 'directory' + assert rmdir file_path + + lfs.rmdir path + + rmdir @root .. path + + rename_fileder: (path, next_name) => + @log "renaming fileder #{path} -> '#{next_name}'" + parent, name = dir_base path + assert os.rename path, @root .. "#{parent}/#{next_name}" + + move_fileder: (path, next_parent) => + @log "moving fileder #{path} -> #{next_parent}/" + parent, name = dir_base path + assert os.rename @root .. path, @root .. "#{next_parent}/#{name}" + + -- facets + list_facets: (path) => + coroutine.wrap -> + for entry_name in lfs.dir @root .. path + entry_path = "#{@root .. path}/#{entry_name}" + if 'file' == lfs.attributes entry_path, 'mode' + entry_name = (entry_name\match '(.*)%.%w+') or entry_name + entry_name = entry_name\gsub '%$', '/' + name, type = entry_name\match '(%w+): *(.+)' + if not name + name = '' + type = entry_name + + coroutine.yield name, type + + tofp: (path, name, type) => + type = "#{name}: #{type}" if #name > 0 + type = type\gsub '%/', '$' + @root .. "#{path}/#{type}" + + locate: (path, name, type) => + return unless lfs.attributes @root .. path, 'mode' + + type = type\gsub '%/', '$' + name = "#{name}: " if #name > 0 + name = name .. type + name = name\gsub '([^%w])', '%%%1' + + local file_name + for entry_name in lfs.dir @root .. path + if (entry_name\match "^#{name}$") or entry_name\match "^#{name}%.%w+$" + if file_name + error "two files match #{name}: #{file_name} and #{entry_name}!" + file_name = entry_name + + + file_name and @root .. "#{path}/#{file_name}" + + load_facet: (path, name, type) => + filepath = @locate path, name, type + return unless filepath + file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filepath}'" + with file\read '*all' + file\close! + + create_facet: (path, name, type, blob) => + @log "creating facet #{path} | #{name}: #{type}" + assert blob, "cant create facet without value!" + + filepath = @tofp path, name, type + if lfs.attributes filepath, 'mode' + error "facet file already exists!" + + file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" + file\write blob + file\close! + + remove_facet: (path, name, type) => + @log "removing facet #{path} | #{name}: #{type}" + + filepath = @locate path, name, type + assert filepath, "couldn't locate facet!" + assert os.remove filepath + + rename_facet: (path, name, type, next_name) => + @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" + filepath = @locate path, name, type + assert filepath, "couldn't locate facet!" + assert os.rename filepath, @tofp path, next_name, type + + update_facet: (path, name, type, blob) => + @log "updating facet #{path} | #{name}: #{type}" + filepath = @locate path, name, type + assert filepath, "couldn't locate facet!" + file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" + file\write blob + file\close! + +{ + :LFSStore +} diff --git a/mmm/mmmfs/stores/sql.moon b/mmm/mmmfs/stores/sql.moon new file mode 100644 index 0000000..490eade --- /dev/null +++ b/mmm/mmmfs/stores/sql.moon @@ -0,0 +1,183 @@ +sqlite = require 'sqlite3' +root = os.tmpname! + +class SQLStore + new: (opts = {}) => + opts.file or= 'db.sqlite3' + opts.verbose or= false + opts.memory or= false + + if not opts.verbose + @log = -> + + if opts.memory + @log "opening in-memory DB..." + @db = sqlite.open_memory! + else + @log "opening '#{opts.file}'..." + @db = sqlite.open opts.file + + 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 REFERENCES fileder(path) + ON DELETE CASCADE + ON UPDATE CASCADE + ); + INSERT OR IGNORE INTO fileder (path, parent) VALUES ("", NULL); + + CREATE TABLE IF NOT EXISTS facet ( + fileder_id INTEGER NOT NULL + REFERENCES fileder + ON UPDATE CASCADE + ON DELETE CASCADE, + 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); + ]] + + log: (...) => + print "[DB]", ... + + close: => + @db\close! + + fetch: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... if 0 < select '#', ... + stmt\irows! + + fetch_one: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... if 0 < select '#', ... + stmt\first_irow! + + exec: (q, ...) => + stmt = assert @db\prepare q + stmt\bind ... if 0 < select '#', ... + res = assert stmt\exec! + + -- fileders + list_fileders_in: (path='') => + coroutine.wrap -> + for { path } in @fetch 'SELECT path + FROM fileder WHERE parent IS ?', path + coroutine.yield path + + 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) => + path = "#{parent}/#{name}" + + @log "creating fileder #{path}" + @exec 'INSERT INTO fileder (path, parent) + VALUES (:path, :parent)', + { :path, :parent } + + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "couldn't create fileder - parent missing?" + path + + remove_fileder: (path) => + @log "removing fileder #{path}" + @exec 'DELETE FROM fileder + WHERE path LIKE :path || "/%" + OR path = :path', path + + rename_fileder: (path, next_name) => + @log "renaming fileder #{path} -> '#{next_name}'" + error 'not implemented' + + @exec 'UPDATE fileder + SET path = parent || "/" || :next_name + WHERE path = :path', + { :path, :next_name } + + -- @TODO: rename all children, child-children... + + move_fileder: (path, next_parent) => + @log "moving fileder #{path} -> #{next_parent}/" + error 'not implemented' + + -- @TODO: remove all children, child-children... + + -- 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 and v[1] + + create_facet: (path, name, type, blob) => + @log "creating facet #{path} | #{name}: #{type}" + @exec 'INSERT INTO facet (fileder_id, name, type, value) + SELECT id, :name, :type, :blob + FROM fileder + 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) => + @log "removing 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 } + + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + + rename_facet: (path, name, type, next_name) => + @log "renaming 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 } + + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + + update_facet: (path, name, type, blob) => + @log "updating facet #{path} | #{name}: #{type}" + @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 } + + changes = @fetch_one 'SELECT changes()' + assert changes[1] == 1, "no such facet" + +{ + :SQLStore +} -- cgit v1.2.3