git.s-ol.nu mmm / e2a4257
fileders load via get_index rather than list_facets/list_fileders s-ol 3 years ago
9 changed file(s) with 171 addition(s) and 74 deletion(s). Raw diff Collapse all Expand all
5959 local browser = require 'mmm.mmmfs.browser'
6060 local fileder = require 'mmm.mmmfs.fileder'
6161 local web = require 'mmm.mmmfs.stores.web'
62 local root = fileder.Fileder(web.WebStore({ verbose = true }), path)
62
63 local store = web.WebStore({ verbose = true })
64 local index = store:get_index(path, -1)
65 local root = fileder.Fileder(store, index)
6366
6467 BROWSER = browser.Browser(root, path, true)
6568 end)
6972 -- serve fileder index
7073 -- '?index': one level deep
7174 -- '?tree': recursively
72 index = fileder\get_index facet.name == '?tree'
75 depth = if facet.name == '?tree' then -1 else 1
76 index = @store\get_index path, depth
7377 convert 'table', facet.type, index, fileder, facet.name
7478 else
7579 -- fileder and facet given
3939 base = base\match '^(.*)%.%w+$'
4040
4141 (name, x) ->
42 name = base .. name if '.' == name\sub 1, 1
42 if name == '.'
43 name = base
44 else if '.' == name\sub 1, 1
45 name = base .. name
46
4347 _require name
4448
4549 if on_load
3434 base = base\match '^(.*)%.%w+$'
3535
3636 (name, x) ->
37 name = base .. name if '.' == name\sub 1, 1
37 if name == '.'
38 name = base
39 else if '.' == name\sub 1, 1
40 name = base .. name
41
3842 _require name
133133 @facet_keys[k] = v
134134 }
135135
136 load: =>
136 -- this fails with JS objects from JSON.parse
137 if 'table' == type @path
138 index = @path
139 @path = index.path
140 @load index
141
142 assert ('string' == type @path), "invalid path: '#{@path}'"
143
144 load: (index) =>
145 assert not @loaded, "already loaded!"
137146 @loaded = true
138147
139 for path in @store\list_fileders_in @path
140 table.insert @children, Fileder @store, path
141
142 for name, type in @store\list_facets @path
143 key = Key name, type
148 if not index
149 index = @store\get_index @path
150
151 for path_or_index in *index.children
152 table.insert @children, Fileder @store, path_or_index
153
154 for key in *index.facets
155 key = Key key
144156 @facet_keys[key] = key
145157
146158 _, name = dir_base @path
194206
195207 [name for name in pairs names]
196208
197 -- get an index table, listing path, facets and children
198 -- optionally get recursive index
199 get_index: (recursive=false) =>
200 {
201 path: @path
202 facets: [key for str, key in pairs @facet_keys]
203 children: if recursive
204 [child\get_index true for child in *@children]
205 else
206 [{ :path } for { :path } in *@children]
207 }
208
209209 -- check whether a facet is directly available
210210 has: (...) =>
211211 want = Key ...
0 require = relative ..., 1
01 lfs = require 'lfs'
2 import Store from require '.'
13
24 -- split filename into dirname + basename
35 dir_base = (path) ->
79
810 dir, base
911
10 class FSStore
12 class FSStore extends Store
1113 new: (opts = {}) =>
14 super opts
15
1216 opts.root or= 'root'
13 opts.verbose or= false
14
15 if not opts.verbose
16 @log = ->
1717
1818 -- ensure path doesnt end with a slash
1919 @root = opts.root\match '^(.-)/?$'
2020 @log "opening '#{opts.root}'..."
21
22 log: (...) =>
23 print "[DB]", ...
2421
2522 -- fileders
2623 list_fileders_in: (path='') =>
3027 entry_path = @root .. "#{path}/#{entry_name}"
3128 if 'directory' == lfs.attributes entry_path, 'mode'
3229 coroutine.yield "#{path}/#{entry_name}"
33
34 list_all_fileders: (path='') =>
35 coroutine.wrap ->
36 for path in @list_fileders_in path
37 coroutine.yield path
38 for p in @list_all_fileders path
39 coroutine.yield p
4030
4131 create_fileder: (parent, name) =>
4232 @log "creating fileder #{path}"
00 require = relative ..., 0
1
2 class Store
3 new: (opts) =>
4 opts.verbose or= false
5
6 if not opts.verbose
7 @log = ->
8
9 list_fileders_in: => error "not implemented"
10
11 list_all_fileders: (path='') =>
12 coroutine.wrap ->
13 for path in @list_fileders_in path
14 coroutine.yield path
15 for p in @list_all_fileders path
16 coroutine.yield p
17
18 get_index: (path='', depth=1) =>
19 if depth == 0
20 return path
21
22 {
23 :path
24 facets: [{:name, :type} for name, type in @list_facets path]
25 children: [@get_index child, depth - 1 for child in @list_fileders_in path]
26 }
27
28 close: =>
29
30 log: (...) =>
31 print "[#{@@__name}]", ...
132
233 -- instantiate a store from a CLI arg
334 -- e.g.: sql, fs:/path/to/root, sql:MEMORY, sql:db.sqlite3
2859 os.exit 1
2960
3061 {
62 :Store
3163 :get_store
3264 }
0 require = relative ..., 1
01 sqlite = require 'sqlite3'
1 root = os.tmpname!
2 import Store from require '.'
23
3 class SQLStore
4 class SQLStore extends Store
45 new: (opts = {}) =>
6 super opts
7
58 opts.file or= 'db.sqlite3'
6 opts.verbose or= false
79 opts.memory or= false
8
9 if not opts.verbose
10 @log = ->
1110
1211 if opts.memory
1312 @log "opening in-memory DB..."
4241 CREATE INDEX IF NOT EXISTS facet_name ON facet(name);
4342 ]]
4443
45 log: (...) =>
46 print "[DB]", ...
47
4844 close: =>
4945 @db\close!
5046
6965 for { path } in @fetch 'SELECT path
7066 FROM fileder WHERE parent IS ?', path
7167 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
7968
8069 create_fileder: (parent, name) =>
8170 path = "#{parent}/#{name}"
0 require = relative ..., 1
1 import Store from require '.'
2 { :location, :XMLHttpRequest, :JSON, :Object, :Array } = js.global
3
04 -- split filename into dirname + basename
15 dir_base = (path) ->
26 dir, base = path\match '(.-)([^/]-)$'
59
610 dir, base
711
8 { :location, :XMLHttpRequest, :JSON } = js.global
912 fetch = (url) ->
1013 request = js.new XMLHttpRequest
1114 request\open 'GET', url, false
1417 assert request.status == 200, "unexpected status code: #{request.status}"
1518 request.responseText
1619
17 class WebStore
20 parse_json = do
21 fix = (val) ->
22 switch type val
23 when 'userdata'
24 if Array\isArray val
25 [fix x for x in js.of val]
26 else
27 {(fix e[0]), (fix e[1]) for e in js.of Object\entries(val)}
28 else
29 val
30
31 (string) ->
32 print fix JSON\parse string
33 fix JSON\parse string
34
35 class WebStore extends Store
1836 new: (opts = {}) =>
37 super opts
38
1939 if MODE == 'CLIENT'
2040 origin = location.origin
2141 opts.host or= origin
22 opts.verbose or= false
23
24 if not opts.verbose
25 @log = ->
2642
2743 -- ensure host ends without a slash
2844 @host = opts.host\match '^(.-)/?$'
2945 @log "connecting to '#{@host}'..."
3046
31 log: (...) =>
32 print "[DB]", ...
47 get_index: (path='', depth=1) =>
48 pseudo = if depth > 1 or depth < 0 '?tree' else '?index'
49 json = fetch "#{@host .. path}/#{pseudo}: application/json"
50 parse_json json
3351
3452 -- fileders
3553 list_fileders_in: (path='') =>
3654 coroutine.wrap ->
3755 json = fetch "#{@host .. path}/?index: application/json"
38 index = JSON\parse json
56 index = parse_json json
3957 for child in js.of index.children
4058 coroutine.yield child.path
41
42 list_all_fileders: (path='') =>
43 coroutine.wrap ->
44 for path in @list_fileders_in path
45 coroutine.yield path
46 for p in @list_all_fileders path
47 coroutine.yield p
4859
4960 create_fileder: (parent, name) =>
5061 @log "creating fileder #{path}"
6980 index = JSON\parse json
7081 for facet in js.of index.facets
7182 coroutine.yield facet.name, facet.type
72 -- @TODO: this doesn't belong here!
73 if facet.type\match 'text/moonscript'
74 coroutine.yield facet.name, facet.type\gsub 'text/moonscript', 'text/lua'
7583
7684 load_facet: (path, name, type) =>
7785 fetch "#{@host .. path}/#{name}: #{type}"
0 -- relative imports
1 _G.relative = do
2 _require = require
3
4 (base, sub) ->
5 sub = sub or 0
6
7 for i=1, sub
8 base = base\match '^(.*)%.%w+$'
9
10 (name, x) ->
11 if name == '.'
12 name = base
13 else if '.' == name\sub 1, 1
14 name = base .. name
15
16 _require name
17
018 sort2 = (a, b) ->
119 {ax, ay}, {bx, by} = a, b
220 "#{ax}//#{ay}" < "#{bx}//#{by}"
5674 assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}},
5775 toseq2 ts\list_facets '/hello/world'
5876
77 describe "can get indexes", ->
78 hello_index = {
79 path: '/hello'
80 children: {
81 '/hello/world'
82 }
83 facets: {
84 { name: 'name', type: 'alpha' }
85 }
86 }
87
88 it "for a single level", ->
89 assert.are.same hello_index, ts\get_index '/hello'
90
91
92 root_index = {
93 path: ''
94 children: {
95 hello_index
96 }
97 facets: {}
98 }
99 it "for a limited number of levels", ->
100 assert.are.same root_index, ts\get_index '', 2
101
102 it "recursively", ->
103 hello_index.children[1] = {
104 path: '/hello/world'
105 children: {
106 {
107 path: '/hello/world/again'
108 children: {}
109 facets: {}
110 }
111 }
112 facets: {
113 { name: '', type: 'text/markdown' }
114 { name: 'name', type: 'alpha' }
115 }
116 }
117
118 assert.are.same root_index, ts\get_index '', -1
119
120 it "can get indexes recursively", ->
121
59122 it "can load facets", ->
60123 assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha'
61124 assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha'
88151 ts\remove_fileder '/hello'
89152 assert.are.same {}, toseq ts\list_all_fileders!
90153
91 describe "SQL spec", ->
154 it "can be closed", ->
155 ts\close!
156
157 describe "SQL store", ->
92158 import SQLStore from require 'mmm.mmmfs.stores.sql'
93159
94160 test_store SQLStore memory: true
104170 assert os.remove root
105171 assert lfs.mkdir root
106172
107 test_store LFSStore :root
173 test_store FSStore :root
108174
109175 teardown ->
110176 assert lfs.rmdir root