git.s-ol.nu mmm / 342db78
rename drivers to stores, make server, render_all store-agnostic s-ol 3 years ago
10 changed file(s) with 387 addition(s) and 352 deletion(s). Raw diff Collapse all Expand all
1313
1414 -- usage:
1515 -- moon import.moon <root> [output.sqlite3]
16 { root, file } = arg
16 { root, store } = arg
1717
1818 assert root, "please specify the root directory"
1919
88
99 require 'mmm'
1010 import load_tree from require 'mmm.mmmfs.fileder'
11 import get_store from require 'mmm.mmmfs.stores'
1112 import render from require 'mmm.mmmfs.layout'
12 import SQLStore from require 'mmm.mmmfs.drivers.sql'
1313
1414 -- usage:
15 -- moon render_all.moon [db.sqlite3] [startpath]
16 { file, startpath } = arg
15 -- moon render_all.moon [STORE] [startpath]
16 { store, startpath } = arg
1717
1818 export STATIC
1919 STATIC = true
2020
21 tree = load_tree SQLStore :file
21 store = get_store store
22 tree = load_tree store
2223 tree = tree\walk startpath if startpath
2324
2425 for fileder in coroutine.wrap tree\iterate
99 require 'mmm'
1010
1111 import Key, dir_base, load_tree from require 'mmm.mmmfs.fileder'
12 import SQLStore from require 'mmm.mmmfs.drivers.sql'
12 import get_store from require 'mmm.mmmfs.stores'
1313 import decodeURI from require 'http.util'
1414
1515 lfs = require 'lfs'
163163 print msg
164164
165165 -- usage:
166 -- moon server.moon [db.sqlite3] [host] [port]
167 { file, host, port } = arg
166 -- moon server.moon [STORE] [host] [port]
167 { store, host, port } = arg
168168
169 tree = load_tree SQLStore :file
169 store = get_store store
170 tree = load_tree store
170171 server = Server tree, :host, port: port and tonumber port
171172 server\listen!
0 export MODE, print, warn, relative, on_client
0 export MODE, print, warn, relative
11 MODE = 'SERVER'
22
33 deep_tostring = (tbl, space='') ->
2828 _require = require
2929
3030 (base, sub) ->
31 sub = 0 unless 'number' == type sub
31 sub = sub or 0
3232
3333 for i=1, sub
3434 base = base\match '^(.*)%.%w+$'
+0
-157
mmm/mmmfs/drivers/lfs.moon less more
0 lfs = require 'lfs'
1
2 -- split filename into dirname + basename
3 dir_base = (path) ->
4 dir, base = path\match '(.-)([^/]-)$'
5 if dir and #dir > 0
6 dir = dir\sub 1, #dir - 1
7
8 dir, base
9
10
11 class LFSStore
12 new: (opts = {}) =>
13 opts.root or= 'root'
14 opts.verbose or= false
15
16 if not opts.verbose
17 @log = ->
18
19 -- ensure path doesnt end with a slash
20 @root = opts.root\match '^(.-)/?$'
21 @log "opening '#{opts.root}'..."
22
23 log: (...) =>
24 print "[DB]", ...
25
26 -- fileders
27 list_fileders_in: (path='') =>
28 coroutine.wrap ->
29 for entry_name in lfs.dir @root .. path
30 continue if '.' == entry_name\sub 1, 1
31 entry_path = @root .. "#{path}/#{entry_name}"
32 if 'directory' == lfs.attributes entry_path, 'mode'
33 coroutine.yield "#{path}/#{entry_name}"
34
35 list_all_fileders: (path='') =>
36 coroutine.wrap ->
37 for path in @list_fileders_in path
38 coroutine.yield path
39 for p in @list_all_fileders path
40 coroutine.yield p
41
42 create_fileder: (parent, name) =>
43 @log "creating fileder #{path}"
44 path = "#{parent}/#{name}"
45 assert lfs.mkdir @root .. path
46 path
47
48 remove_fileder: (path) =>
49 @log "removing fileder #{path}"
50
51 rmdir = (path) ->
52 for file in lfs.dir path
53 continue if '.' == file\sub 1, 1
54
55 file_path = "#{path}/#{file}"
56 switch lfs.attributes file_path, 'mode'
57 when 'file'
58 assert os.remove file_path
59 when 'directory'
60 assert rmdir file_path
61
62 lfs.rmdir path
63
64 rmdir @root .. path
65
66 rename_fileder: (path, next_name) =>
67 @log "renaming fileder #{path} -> '#{next_name}'"
68 parent, name = dir_base path
69 assert os.rename path, @root .. "#{parent}/#{next_name}"
70
71 move_fileder: (path, next_parent) =>
72 @log "moving fileder #{path} -> #{next_parent}/"
73 parent, name = dir_base path
74 assert os.rename @root .. path, @root .. "#{next_parent}/#{name}"
75
76 -- facets
77 list_facets: (path) =>
78 coroutine.wrap ->
79 for entry_name in lfs.dir @root .. path
80 entry_path = "#{@root .. path}/#{entry_name}"
81 if 'file' == lfs.attributes entry_path, 'mode'
82 entry_name = (entry_name\match '(.*)%.%w+') or entry_name
83 entry_name = entry_name\gsub '%$', '/'
84 name, type = entry_name\match '(%w+): *(.+)'
85 if not name
86 name = ''
87 type = entry_name
88
89 coroutine.yield name, type
90
91 tofp: (path, name, type) =>
92 type = "#{name}: #{type}" if #name > 0
93 type = type\gsub '%/', '$'
94 @root .. "#{path}/#{type}"
95
96 locate: (path, name, type) =>
97 return unless lfs.attributes @root .. path, 'mode'
98
99 type = type\gsub '%/', '$'
100 name = "#{name}: " if #name > 0
101 name = name .. type
102 name = name\gsub '([^%w])', '%%%1'
103
104 local file_name
105 for entry_name in lfs.dir @root .. path
106 if (entry_name\match "^#{name}$") or entry_name\match "^#{name}%.%w+$"
107 if file_name
108 error "two files match #{name}: #{file_name} and #{entry_name}!"
109 file_name = entry_name
110
111
112 file_name and @root .. "#{path}/#{file_name}"
113
114 load_facet: (path, name, type) =>
115 filepath = @locate path, name, type
116 return unless filepath
117 file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filepath}'"
118 with file\read '*all'
119 file\close!
120
121 create_facet: (path, name, type, blob) =>
122 @log "creating facet #{path} | #{name}: #{type}"
123 assert blob, "cant create facet without value!"
124
125 filepath = @tofp path, name, type
126 if lfs.attributes filepath, 'mode'
127 error "facet file already exists!"
128
129 file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'"
130 file\write blob
131 file\close!
132
133 remove_facet: (path, name, type) =>
134 @log "removing facet #{path} | #{name}: #{type}"
135
136 filepath = @locate path, name, type
137 assert filepath, "couldn't locate facet!"
138 assert os.remove filepath
139
140 rename_facet: (path, name, type, next_name) =>
141 @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}"
142 filepath = @locate path, name, type
143 assert filepath, "couldn't locate facet!"
144 assert os.rename filepath, @tofp path, next_name, type
145
146 update_facet: (path, name, type, blob) =>
147 @log "updating facet #{path} | #{name}: #{type}"
148 filepath = @locate path, name, type
149 assert filepath, "couldn't locate facet!"
150 file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'"
151 file\write blob
152 file\close!
153
154 {
155 :LFSStore
156 }
+0
-183
mmm/mmmfs/drivers/sql.moon less more
0 sqlite = require 'sqlite3'
1 root = os.tmpname!
2
3 class SQLStore
4 new: (opts = {}) =>
5 opts.file or= 'db.sqlite3'
6 opts.verbose or= false
7 opts.memory or= false
8
9 if not opts.verbose
10 @log = ->
11
12 if opts.memory
13 @log "opening in-memory DB..."
14 @db = sqlite.open_memory!
15 else
16 @log "opening '#{opts.file}'..."
17 @db = sqlite.open opts.file
18
19 assert @db\exec [[
20 PRAGMA foreign_keys = ON;
21 PRAGMA case_sensitive_like = ON;
22 CREATE TABLE IF NOT EXISTS fileder (
23 id INTEGER NOT NULL PRIMARY KEY,
24 path TEXT NOT NULL UNIQUE,
25 parent TEXT REFERENCES fileder(path)
26 ON DELETE CASCADE
27 ON UPDATE CASCADE
28 );
29 INSERT OR IGNORE INTO fileder (path, parent) VALUES ("", NULL);
30
31 CREATE TABLE IF NOT EXISTS facet (
32 fileder_id INTEGER NOT NULL
33 REFERENCES fileder
34 ON UPDATE CASCADE
35 ON DELETE CASCADE,
36 name TEXT NOT NULL,
37 type TEXT NOT NULL,
38 value BLOB NOT NULL,
39 PRIMARY KEY (fileder_id, name, type)
40 );
41 CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id);
42 CREATE INDEX IF NOT EXISTS facet_name ON facet(name);
43 ]]
44
45 log: (...) =>
46 print "[DB]", ...
47
48 close: =>
49 @db\close!
50
51 fetch: (q, ...) =>
52 stmt = assert @db\prepare q
53 stmt\bind ... if 0 < select '#', ...
54 stmt\irows!
55
56 fetch_one: (q, ...) =>
57 stmt = assert @db\prepare q
58 stmt\bind ... if 0 < select '#', ...
59 stmt\first_irow!
60
61 exec: (q, ...) =>
62 stmt = assert @db\prepare q
63 stmt\bind ... if 0 < select '#', ...
64 res = assert stmt\exec!
65
66 -- fileders
67 list_fileders_in: (path='') =>
68 coroutine.wrap ->
69 for { path } in @fetch 'SELECT path
70 FROM fileder WHERE parent IS ?', path
71 coroutine.yield path
72
73 list_all_fileders: (path='') =>
74 coroutine.wrap ->
75 for path in @list_fileders_in path
76 coroutine.yield path
77 for p in @list_all_fileders path
78 coroutine.yield p
79
80 create_fileder: (parent, name) =>
81 path = "#{parent}/#{name}"
82
83 @log "creating fileder #{path}"
84 @exec 'INSERT INTO fileder (path, parent)
85 VALUES (:path, :parent)',
86 { :path, :parent }
87
88 changes = @fetch_one 'SELECT changes()'
89 assert changes[1] == 1, "couldn't create fileder - parent missing?"
90 path
91
92 remove_fileder: (path) =>
93 @log "removing fileder #{path}"
94 @exec 'DELETE FROM fileder
95 WHERE path LIKE :path || "/%"
96 OR path = :path', path
97
98 rename_fileder: (path, next_name) =>
99 @log "renaming fileder #{path} -> '#{next_name}'"
100 error 'not implemented'
101
102 @exec 'UPDATE fileder
103 SET path = parent || "/" || :next_name
104 WHERE path = :path',
105 { :path, :next_name }
106
107 -- @TODO: rename all children, child-children...
108
109 move_fileder: (path, next_parent) =>
110 @log "moving fileder #{path} -> #{next_parent}/"
111 error 'not implemented'
112
113 -- @TODO: remove all children, child-children...
114
115 -- facets
116 list_facets: (path) =>
117 coroutine.wrap ->
118 for { name, type } in @fetch 'SELECT facet.name, facet.type
119 FROM facet
120 INNER JOIN fileder ON facet.fileder_id = fileder.id
121 WHERE fileder.path = ?', path
122 coroutine.yield name, type
123
124 load_facet: (path, name, type) =>
125 v = @fetch_one 'SELECT facet.value
126 FROM facet
127 INNER JOIN fileder ON facet.fileder_id = fileder.id
128 WHERE fileder.path = :path
129 AND facet.name = :name
130 AND facet.type = :type',
131 { :path, :name, :type }
132 v and v[1]
133
134 create_facet: (path, name, type, blob) =>
135 @log "creating facet #{path} | #{name}: #{type}"
136 @exec 'INSERT INTO facet (fileder_id, name, type, value)
137 SELECT id, :name, :type, :blob
138 FROM fileder
139 WHERE fileder.path = :path',
140 { :path, :name, :type, :blob }
141
142 changes = @fetch_one 'SELECT changes()'
143 assert changes[1] == 1, "couldn't create facet - fileder missing?"
144
145 remove_facet: (path, name, type) =>
146 @log "removing facet #{path} | #{name}: #{type}"
147 @exec 'DELETE FROM facet
148 WHERE name = :name
149 AND type = :type
150 AND fileder_id = (SELECT id FROM fileder WHERE path = :path)',
151 { :path, :name, :type }
152
153 changes = @fetch_one 'SELECT changes()'
154 assert changes[1] == 1, "no such facet"
155
156 rename_facet: (path, name, type, next_name) =>
157 @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}"
158 @exec 'UPDATE facet
159 SET name = :next_name
160 WHERE name = :name
161 AND type = :type
162 AND fileder_id = (SELECT id FROM fileder WHERE path = :path)',
163 { :path, :name, :next_name, :type }
164
165 changes = @fetch_one 'SELECT changes()'
166 assert changes[1] == 1, "no such facet"
167
168 update_facet: (path, name, type, blob) =>
169 @log "updating facet #{path} | #{name}: #{type}"
170 @exec 'UPDATE facet
171 SET value = :blob
172 WHERE facet.name = :name
173 AND facet.type = :type
174 AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)',
175 { :path, :name, :type, :blob }
176
177 changes = @fetch_one 'SELECT changes()'
178 assert changes[1] == 1, "no such facet"
179
180 {
181 :SQLStore
182 }
189189
190190 dir, base
191191
192 -- load tree from a driver instance
192 -- load tree from a store instance
193193 -- optionally load subtree starting at 'root' path
194194 load_tree = (store, root='') ->
195195 fileders = setmetatable {},
0 require = relative ..., 0
1
2 -- instantiate a store from a CLI arg
3 -- e.g.: sql, lfs:/path/to/root, sql:MEMORY, sql:db.sqlite3
4 get_store = (args='sql', opts={verbose: true}) ->
5 type, arg = args\match '(%w+):(.*)'
6 type = arg unless type
7
8 switch type\lower!
9 when 'sql'
10 import SQLStore from require '.sql'
11
12 if arg == 'MEMORY'
13 opts.memory = true
14 else
15 opts.name = arg
16
17 SQLStore opts
18
19 when 'lfs'
20 import LFSStore from require '.lfs'
21
22 opts.root = arg
23
24 LFSStore opts
25
26 else
27 warn "unknown or missing value for STORE: valid types values are sql, lfs"
28 os.exit 1
29
30 {
31 :get_store
32 }
0 lfs = require 'lfs'
1
2 -- split filename into dirname + basename
3 dir_base = (path) ->
4 dir, base = path\match '(.-)([^/]-)$'
5 if dir and #dir > 0
6 dir = dir\sub 1, #dir - 1
7
8 dir, base
9
10
11 class LFSStore
12 new: (opts = {}) =>
13 opts.root or= 'root'
14 opts.verbose or= false
15
16 if not opts.verbose
17 @log = ->
18
19 -- ensure path doesnt end with a slash
20 @root = opts.root\match '^(.-)/?$'
21 @log "opening '#{opts.root}'..."
22
23 log: (...) =>
24 print "[DB]", ...
25
26 -- fileders
27 list_fileders_in: (path='') =>
28 coroutine.wrap ->
29 for entry_name in lfs.dir @root .. path
30 continue if '.' == entry_name\sub 1, 1
31 entry_path = @root .. "#{path}/#{entry_name}"
32 if 'directory' == lfs.attributes entry_path, 'mode'
33 coroutine.yield "#{path}/#{entry_name}"
34
35 list_all_fileders: (path='') =>
36 coroutine.wrap ->
37 for path in @list_fileders_in path
38 coroutine.yield path
39 for p in @list_all_fileders path
40 coroutine.yield p
41
42 create_fileder: (parent, name) =>
43 @log "creating fileder #{path}"
44 path = "#{parent}/#{name}"
45 assert lfs.mkdir @root .. path
46 path
47
48 remove_fileder: (path) =>
49 @log "removing fileder #{path}"
50
51 rmdir = (path) ->
52 for file in lfs.dir path
53 continue if '.' == file\sub 1, 1
54
55 file_path = "#{path}/#{file}"
56 switch lfs.attributes file_path, 'mode'
57 when 'file'
58 assert os.remove file_path
59 when 'directory'
60 assert rmdir file_path
61
62 lfs.rmdir path
63
64 rmdir @root .. path
65
66 rename_fileder: (path, next_name) =>
67 @log "renaming fileder #{path} -> '#{next_name}'"
68 parent, name = dir_base path
69 assert os.rename path, @root .. "#{parent}/#{next_name}"
70
71 move_fileder: (path, next_parent) =>
72 @log "moving fileder #{path} -> #{next_parent}/"
73 parent, name = dir_base path
74 assert os.rename @root .. path, @root .. "#{next_parent}/#{name}"
75
76 -- facets
77 list_facets: (path) =>
78 coroutine.wrap ->
79 for entry_name in lfs.dir @root .. path
80 entry_path = "#{@root .. path}/#{entry_name}"
81 if 'file' == lfs.attributes entry_path, 'mode'
82 entry_name = (entry_name\match '(.*)%.%w+') or entry_name
83 entry_name = entry_name\gsub '%$', '/'
84 name, type = entry_name\match '(%w+): *(.+)'
85 if not name
86 name = ''
87 type = entry_name
88
89 coroutine.yield name, type
90
91 tofp: (path, name, type) =>
92 type = "#{name}: #{type}" if #name > 0
93 type = type\gsub '%/', '$'
94 @root .. "#{path}/#{type}"
95
96 locate: (path, name, type) =>
97 return unless lfs.attributes @root .. path, 'mode'
98
99 type = type\gsub '%/', '$'
100 name = "#{name}: " if #name > 0
101 name = name .. type
102 name = name\gsub '([^%w])', '%%%1'
103
104 local file_name
105 for entry_name in lfs.dir @root .. path
106 if (entry_name\match "^#{name}$") or entry_name\match "^#{name}%.%w+$"
107 if file_name
108 error "two files match #{name}: #{file_name} and #{entry_name}!"
109 file_name = entry_name
110
111
112 file_name and @root .. "#{path}/#{file_name}"
113
114 load_facet: (path, name, type) =>
115 filepath = @locate path, name, type
116 return unless filepath
117 file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filepath}'"
118 with file\read '*all'
119 file\close!
120
121 create_facet: (path, name, type, blob) =>
122 @log "creating facet #{path} | #{name}: #{type}"
123 assert blob, "cant create facet without value!"
124
125 filepath = @tofp path, name, type
126 if lfs.attributes filepath, 'mode'
127 error "facet file already exists!"
128
129 file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'"
130 file\write blob
131 file\close!
132
133 remove_facet: (path, name, type) =>
134 @log "removing facet #{path} | #{name}: #{type}"
135
136 filepath = @locate path, name, type
137 assert filepath, "couldn't locate facet!"
138 assert os.remove filepath
139
140 rename_facet: (path, name, type, next_name) =>
141 @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}"
142 filepath = @locate path, name, type
143 assert filepath, "couldn't locate facet!"
144 assert os.rename filepath, @tofp path, next_name, type
145
146 update_facet: (path, name, type, blob) =>
147 @log "updating facet #{path} | #{name}: #{type}"
148 filepath = @locate path, name, type
149 assert filepath, "couldn't locate facet!"
150 file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'"
151 file\write blob
152 file\close!
153
154 {
155 :LFSStore
156 }
0 sqlite = require 'sqlite3'
1 root = os.tmpname!
2
3 class SQLStore
4 new: (opts = {}) =>
5 opts.file or= 'db.sqlite3'
6 opts.verbose or= false
7 opts.memory or= false
8
9 if not opts.verbose
10 @log = ->
11
12 if opts.memory
13 @log "opening in-memory DB..."
14 @db = sqlite.open_memory!
15 else
16 @log "opening '#{opts.file}'..."
17 @db = sqlite.open opts.file
18
19 assert @db\exec [[
20 PRAGMA foreign_keys = ON;
21 PRAGMA case_sensitive_like = ON;
22 CREATE TABLE IF NOT EXISTS fileder (
23 id INTEGER NOT NULL PRIMARY KEY,
24 path TEXT NOT NULL UNIQUE,
25 parent TEXT REFERENCES fileder(path)
26 ON DELETE CASCADE
27 ON UPDATE CASCADE
28 );
29 INSERT OR IGNORE INTO fileder (path, parent) VALUES ("", NULL);
30
31 CREATE TABLE IF NOT EXISTS facet (
32 fileder_id INTEGER NOT NULL
33 REFERENCES fileder
34 ON UPDATE CASCADE
35 ON DELETE CASCADE,
36 name TEXT NOT NULL,
37 type TEXT NOT NULL,
38 value BLOB NOT NULL,
39 PRIMARY KEY (fileder_id, name, type)
40 );
41 CREATE INDEX IF NOT EXISTS facet_fileder_id ON facet(fileder_id);
42 CREATE INDEX IF NOT EXISTS facet_name ON facet(name);
43 ]]
44
45 log: (...) =>
46 print "[DB]", ...
47
48 close: =>
49 @db\close!
50
51 fetch: (q, ...) =>
52 stmt = assert @db\prepare q
53 stmt\bind ... if 0 < select '#', ...
54 stmt\irows!
55
56 fetch_one: (q, ...) =>
57 stmt = assert @db\prepare q
58 stmt\bind ... if 0 < select '#', ...
59 stmt\first_irow!
60
61 exec: (q, ...) =>
62 stmt = assert @db\prepare q
63 stmt\bind ... if 0 < select '#', ...
64 res = assert stmt\exec!
65
66 -- fileders
67 list_fileders_in: (path='') =>
68 coroutine.wrap ->
69 for { path } in @fetch 'SELECT path
70 FROM fileder WHERE parent IS ?', path
71 coroutine.yield path
72
73 list_all_fileders: (path='') =>
74 coroutine.wrap ->
75 for path in @list_fileders_in path
76 coroutine.yield path
77 for p in @list_all_fileders path
78 coroutine.yield p
79
80 create_fileder: (parent, name) =>
81 path = "#{parent}/#{name}"
82
83 @log "creating fileder #{path}"
84 @exec 'INSERT INTO fileder (path, parent)
85 VALUES (:path, :parent)',
86 { :path, :parent }
87
88 changes = @fetch_one 'SELECT changes()'
89 assert changes[1] == 1, "couldn't create fileder - parent missing?"
90 path
91
92 remove_fileder: (path) =>
93 @log "removing fileder #{path}"
94 @exec 'DELETE FROM fileder
95 WHERE path LIKE :path || "/%"
96 OR path = :path', path
97
98 rename_fileder: (path, next_name) =>
99 @log "renaming fileder #{path} -> '#{next_name}'"
100 error 'not implemented'
101
102 @exec 'UPDATE fileder
103 SET path = parent || "/" || :next_name
104 WHERE path = :path',
105 { :path, :next_name }
106
107 -- @TODO: rename all children, child-children...
108
109 move_fileder: (path, next_parent) =>
110 @log "moving fileder #{path} -> #{next_parent}/"
111 error 'not implemented'
112
113 -- @TODO: remove all children, child-children...
114
115 -- facets
116 list_facets: (path) =>
117 coroutine.wrap ->
118 for { name, type } in @fetch 'SELECT facet.name, facet.type
119 FROM facet
120 INNER JOIN fileder ON facet.fileder_id = fileder.id
121 WHERE fileder.path = ?', path
122 coroutine.yield name, type
123
124 load_facet: (path, name, type) =>
125 v = @fetch_one 'SELECT facet.value
126 FROM facet
127 INNER JOIN fileder ON facet.fileder_id = fileder.id
128 WHERE fileder.path = :path
129 AND facet.name = :name
130 AND facet.type = :type',
131 { :path, :name, :type }
132 v and v[1]
133
134 create_facet: (path, name, type, blob) =>
135 @log "creating facet #{path} | #{name}: #{type}"
136 @exec 'INSERT INTO facet (fileder_id, name, type, value)
137 SELECT id, :name, :type, :blob
138 FROM fileder
139 WHERE fileder.path = :path',
140 { :path, :name, :type, :blob }
141
142 changes = @fetch_one 'SELECT changes()'
143 assert changes[1] == 1, "couldn't create facet - fileder missing?"
144
145 remove_facet: (path, name, type) =>
146 @log "removing facet #{path} | #{name}: #{type}"
147 @exec 'DELETE FROM facet
148 WHERE name = :name
149 AND type = :type
150 AND fileder_id = (SELECT id FROM fileder WHERE path = :path)',
151 { :path, :name, :type }
152
153 changes = @fetch_one 'SELECT changes()'
154 assert changes[1] == 1, "no such facet"
155
156 rename_facet: (path, name, type, next_name) =>
157 @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}"
158 @exec 'UPDATE facet
159 SET name = :next_name
160 WHERE name = :name
161 AND type = :type
162 AND fileder_id = (SELECT id FROM fileder WHERE path = :path)',
163 { :path, :name, :next_name, :type }
164
165 changes = @fetch_one 'SELECT changes()'
166 assert changes[1] == 1, "no such facet"
167
168 update_facet: (path, name, type, blob) =>
169 @log "updating facet #{path} | #{name}: #{type}"
170 @exec 'UPDATE facet
171 SET value = :blob
172 WHERE facet.name = :name
173 AND facet.type = :type
174 AND facet.fileder_id = (SELECT id FROM fileder WHERE path = :path)',
175 { :path, :name, :type, :blob }
176
177 changes = @fetch_one 'SELECT changes()'
178 assert changes[1] == 1, "no such facet"
179
180 {
181 :SQLStore
182 }