@mblaney/holster 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/holster.js +3 -3
- package/build/holster.js.map +3 -3
- package/package.json +1 -1
- package/src/radisk.js +35 -60
- package/test/radisk.test.js +147 -8
- package/test/split.test.js +317 -0
- package/test/store.test.js +3 -3
package/package.json
CHANGED
package/src/radisk.js
CHANGED
|
@@ -119,7 +119,6 @@ const Radisk = opt => {
|
|
|
119
119
|
// 4. Read the previous file into memory
|
|
120
120
|
// 5. Scan through in memory radix for all values lexically less than limit
|
|
121
121
|
// 6. Merge and write all of those to the in-memory file and back to disk
|
|
122
|
-
// 7. If file is to large then split. More details needed here
|
|
123
122
|
radisk.save = (rad, cb) => {
|
|
124
123
|
const save = {
|
|
125
124
|
find: (tree, key) => {
|
|
@@ -135,11 +134,12 @@ const Radisk = opt => {
|
|
|
135
134
|
save.end = file
|
|
136
135
|
// ! is used as the first file name as it's the first printable
|
|
137
136
|
// character, so always matches as lexically less than any node.
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
// Also save.start can be set to undefined by a previous call to
|
|
138
|
+
// save.mix, so don't continue in this case.
|
|
139
|
+
if (save.start) save.mix(save.file || "!", save.start, save.end)
|
|
140
|
+
} else {
|
|
141
|
+
save.file = file
|
|
140
142
|
}
|
|
141
|
-
|
|
142
|
-
save.file = file
|
|
143
143
|
},
|
|
144
144
|
mix: (file, start, end) => {
|
|
145
145
|
save.start = save.end = save.file = u
|
|
@@ -151,7 +151,7 @@ const Radisk = opt => {
|
|
|
151
151
|
|
|
152
152
|
if (end && end < key) {
|
|
153
153
|
save.start = key
|
|
154
|
-
return
|
|
154
|
+
return
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
disk(key, value)
|
|
@@ -175,69 +175,47 @@ const Radisk = opt => {
|
|
|
175
175
|
cache = null
|
|
176
176
|
const write = {
|
|
177
177
|
text: "",
|
|
178
|
+
limit: "",
|
|
179
|
+
done: false,
|
|
178
180
|
count: 0,
|
|
179
|
-
file: file,
|
|
180
181
|
each: (value, key, k, pre) => {
|
|
182
|
+
// each is called for all keys, but stop adding to write.text when
|
|
183
|
+
// write.slice is called, then the current contents of write.text
|
|
184
|
+
// will be written to file.
|
|
185
|
+
if (write.done) return
|
|
186
|
+
|
|
181
187
|
write.count++
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
"#" +
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
write.text
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
write.
|
|
188
|
+
value = typeof value === "undefined" ? "" : "=" + Radisk.encode(value)
|
|
189
|
+
const enc =
|
|
190
|
+
Radisk.encode(pre.length) + "#" + Radisk.encode(k) + value + "\n"
|
|
191
|
+
// Cannot split the file if only have one entry to write. Also don't
|
|
192
|
+
// start a split if in the middle of writing a node (pre > 0).
|
|
193
|
+
if (
|
|
194
|
+
write.count > 1 &&
|
|
195
|
+
pre.length === 0 &&
|
|
196
|
+
write.text.length + enc.length > opt.size
|
|
197
|
+
) {
|
|
198
|
+
const end = k.indexOf(enq)
|
|
199
|
+
write.limit = end === -1 ? k : k.substring(0, end)
|
|
200
|
+
write.done = true
|
|
194
201
|
write.sub = Radix()
|
|
195
202
|
Radix.map(rad, write.slice)
|
|
196
|
-
|
|
203
|
+
radisk.write(write.limit, write.sub, cb)
|
|
204
|
+
return
|
|
197
205
|
}
|
|
198
206
|
|
|
199
207
|
write.text += enc
|
|
200
208
|
},
|
|
201
|
-
put: () => {
|
|
202
|
-
opt.store.put(file, write.text, cb)
|
|
203
|
-
},
|
|
204
209
|
slice: (value, key) => {
|
|
205
|
-
if (key < write.
|
|
206
|
-
|
|
207
|
-
if (++write.count > write.limit) {
|
|
208
|
-
var name = write.file
|
|
209
|
-
// Use only the soul of the key as the filename so that all
|
|
210
|
-
// properties of a soul are written to the same file.
|
|
211
|
-
let end = key.indexOf(enq)
|
|
212
|
-
if (end === -1) {
|
|
213
|
-
write.file = key
|
|
214
|
-
} else {
|
|
215
|
-
write.file = key.substring(0, end)
|
|
216
|
-
}
|
|
217
|
-
// write.limit can be reached after already writing properties of
|
|
218
|
-
// the current node, so remove it from write.sub before writing to
|
|
219
|
-
// disk so that it's not duplicated across files.
|
|
220
|
-
write.sub(write.file, null)
|
|
221
|
-
write.count = 0
|
|
222
|
-
radisk.write(name, write.sub, write.next)
|
|
223
|
-
return true
|
|
224
|
-
}
|
|
210
|
+
if (key < write.limit) return
|
|
225
211
|
|
|
226
212
|
write.sub(key, value)
|
|
227
213
|
},
|
|
228
|
-
next: err => {
|
|
229
|
-
if (err) return cb(err)
|
|
230
|
-
|
|
231
|
-
write.sub = Radix()
|
|
232
|
-
if (!Radix.map(rad, write.slice)) {
|
|
233
|
-
radisk.write(write.file, write.sub, cb)
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
214
|
}
|
|
237
|
-
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
|
|
215
|
+
Radix.map(rad, write.each, true)
|
|
216
|
+
// There is always accumulated write.text to store once write.each has
|
|
217
|
+
// finished.
|
|
218
|
+
opt.store.put(file, write.text, cb)
|
|
241
219
|
}
|
|
242
220
|
|
|
243
221
|
radisk.read = (key, cb) => {
|
|
@@ -246,11 +224,8 @@ const Radisk = opt => {
|
|
|
246
224
|
if (typeof value !== "undefined") return cb(u, value)
|
|
247
225
|
}
|
|
248
226
|
// Only the soul of the key is compared to filenames (see radisk.write).
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (end !== -1) {
|
|
252
|
-
soul = key.substring(0, end)
|
|
253
|
-
}
|
|
227
|
+
const end = key.indexOf(enq)
|
|
228
|
+
const soul = end === -1 ? key : key.substring(0, end)
|
|
254
229
|
|
|
255
230
|
const read = {
|
|
256
231
|
lex: file => {
|
package/test/radisk.test.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import {describe, test} from "node:test"
|
|
2
2
|
import assert from "node:assert/strict"
|
|
3
3
|
import Radisk from "../src/radisk.js"
|
|
4
|
-
import Names from "./names.js"
|
|
5
|
-
const names = Names()
|
|
6
4
|
|
|
7
5
|
describe("radisk", () => {
|
|
8
6
|
const puts = {}
|
|
@@ -25,6 +23,8 @@ describe("radisk", () => {
|
|
|
25
23
|
},
|
|
26
24
|
}
|
|
27
25
|
const radisk = Radisk(opt)
|
|
26
|
+
const big =
|
|
27
|
+
"file size is only 100 bytes so writing this value requires calling slice"
|
|
28
28
|
|
|
29
29
|
test("write and read from memory", (t, done) => {
|
|
30
30
|
radisk("key", "value", () => {
|
|
@@ -164,8 +164,6 @@ describe("radisk", () => {
|
|
|
164
164
|
})
|
|
165
165
|
|
|
166
166
|
test("write and read value bigger than file size", (t, done) => {
|
|
167
|
-
const big =
|
|
168
|
-
"file size is only 100 bytes so writing this value requires calling slice"
|
|
169
167
|
radisk("newFile", big)
|
|
170
168
|
radisk("newFile", (err, value) => {
|
|
171
169
|
assert.equal(value, big)
|
|
@@ -176,10 +174,7 @@ describe("radisk", () => {
|
|
|
176
174
|
'\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
|
|
177
175
|
'\x1F+1\x1F#\x1F"A\x1F=\x1F"valueA\x1F\n' +
|
|
178
176
|
'\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
|
|
179
|
-
'\x1F+1\x1F#\x1F"C\x1F=\x1F
|
|
180
|
-
keyC:
|
|
181
|
-
'\x1F+0\x1F#\x1F"keyC\x1F=\x1F"valueC\x1F\n' +
|
|
182
|
-
'\x1F+0\x1F#\x1F"newFile\x1F=\x1F \x1F\n',
|
|
177
|
+
'\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
|
|
183
178
|
newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"' + big + "\x1F\n",
|
|
184
179
|
})
|
|
185
180
|
radisk("newFile", (err, value) => {
|
|
@@ -188,4 +183,148 @@ describe("radisk", () => {
|
|
|
188
183
|
})
|
|
189
184
|
}, 10)
|
|
190
185
|
})
|
|
186
|
+
|
|
187
|
+
// This tests trying to add to a file that is already too long, so needs to
|
|
188
|
+
// split again. Previously wasn't able to do this and would loop.
|
|
189
|
+
test("write and read a small value after split", (t, done) => {
|
|
190
|
+
radisk("small", "small value")
|
|
191
|
+
radisk("small", (err, value) => {
|
|
192
|
+
assert.equal(value, "small value")
|
|
193
|
+
})
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
assert.deepEqual(puts, {
|
|
196
|
+
"!":
|
|
197
|
+
'\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
|
|
198
|
+
'\x1F+1\x1F#\x1F"A\x1F=\x1F"valueA\x1F\n' +
|
|
199
|
+
'\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
|
|
200
|
+
'\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
|
|
201
|
+
newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"' + big + "\x1F\n",
|
|
202
|
+
small: '\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n',
|
|
203
|
+
})
|
|
204
|
+
done()
|
|
205
|
+
}, 10)
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
// This tests how existing files are handled when they are made smaller than
|
|
209
|
+
// the maximum file size. (They should be kept as they are created so that
|
|
210
|
+
// we don't have to deal with removing files.)
|
|
211
|
+
test("write small value to newFile", (t, done) => {
|
|
212
|
+
radisk("newFile", "removed...")
|
|
213
|
+
radisk("newFile", (err, value) => {
|
|
214
|
+
assert.equal(value, "removed...")
|
|
215
|
+
})
|
|
216
|
+
setTimeout(() => {
|
|
217
|
+
assert.deepEqual(puts, {
|
|
218
|
+
"!":
|
|
219
|
+
'\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
|
|
220
|
+
'\x1F+1\x1F#\x1F"A\x1F=\x1F"valueA\x1F\n' +
|
|
221
|
+
'\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
|
|
222
|
+
'\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
|
|
223
|
+
newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
|
|
224
|
+
small: '\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n',
|
|
225
|
+
})
|
|
226
|
+
done()
|
|
227
|
+
}, 10)
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
// This tests ignoring the maximum file size when writing sub-keys. Since
|
|
231
|
+
// radisk.write has already been called for a key it would previously get
|
|
232
|
+
// duplicated when trying to split due to reaching the max length.
|
|
233
|
+
test("write big value to first file", (t, done) => {
|
|
234
|
+
radisk("keyA", big)
|
|
235
|
+
radisk("keyA", (err, value) => {
|
|
236
|
+
assert.equal(value, big)
|
|
237
|
+
})
|
|
238
|
+
setTimeout(() => {
|
|
239
|
+
assert.deepEqual(puts, {
|
|
240
|
+
"!":
|
|
241
|
+
'\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
|
|
242
|
+
'\x1F+1\x1F#\x1F"A\x1F=\x1F"' +
|
|
243
|
+
big +
|
|
244
|
+
"\x1F\n" +
|
|
245
|
+
'\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
|
|
246
|
+
'\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
|
|
247
|
+
newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
|
|
248
|
+
small: '\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n',
|
|
249
|
+
})
|
|
250
|
+
done()
|
|
251
|
+
}, 10)
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test("add to last file", (t, done) => {
|
|
255
|
+
radisk("smallContinued", "continued value")
|
|
256
|
+
radisk("smallContinued", (err, value) => {
|
|
257
|
+
assert.equal(value, "continued value")
|
|
258
|
+
})
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
assert.deepEqual(puts, {
|
|
261
|
+
"!":
|
|
262
|
+
'\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
|
|
263
|
+
'\x1F+1\x1F#\x1F"A\x1F=\x1F"' +
|
|
264
|
+
big +
|
|
265
|
+
"\x1F\n" +
|
|
266
|
+
'\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
|
|
267
|
+
'\x1F+1\x1F#\x1F"C\x1F=\x1F"valueC\x1F\n',
|
|
268
|
+
newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
|
|
269
|
+
small:
|
|
270
|
+
'\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n' +
|
|
271
|
+
'\x1F+1\x1F#\x1F"Continued\x1F=\x1F"continued value\x1F\n',
|
|
272
|
+
})
|
|
273
|
+
done()
|
|
274
|
+
}, 10)
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
test("set a key to null and add a value to that file", (t, done) => {
|
|
278
|
+
radisk("keyC", null)
|
|
279
|
+
radisk("keyC", (err, value) => {
|
|
280
|
+
assert.equal(value, null)
|
|
281
|
+
})
|
|
282
|
+
radisk("keyD", "valueD")
|
|
283
|
+
radisk("keyD", (err, value) => {
|
|
284
|
+
assert.equal(value, "valueD")
|
|
285
|
+
})
|
|
286
|
+
setTimeout(() => {
|
|
287
|
+
assert.deepEqual(puts, {
|
|
288
|
+
"!":
|
|
289
|
+
'\x1F+0\x1F#\x1F"key\x1F=\x1F"value\ncontinued\x0312345\x1F\n' +
|
|
290
|
+
'\x1F+1\x1F#\x1F"A\x1F=\x1F"' +
|
|
291
|
+
big +
|
|
292
|
+
"\x1F\n" +
|
|
293
|
+
'\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
|
|
294
|
+
'\x1F+1\x1F#\x1F"C\x1F=\x1F \x1F\n' +
|
|
295
|
+
'\x1F+1\x1F#\x1F"D\x1F=\x1F"valueD\x1F\n',
|
|
296
|
+
newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
|
|
297
|
+
small:
|
|
298
|
+
'\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n' +
|
|
299
|
+
'\x1F+1\x1F#\x1F"Continued\x1F=\x1F"continued value\x1F\n',
|
|
300
|
+
})
|
|
301
|
+
done()
|
|
302
|
+
}, 10)
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
test("set first keys to null", (t, done) => {
|
|
306
|
+
radisk("key", null)
|
|
307
|
+
radisk("key", (err, value) => {
|
|
308
|
+
assert.equal(value, null)
|
|
309
|
+
})
|
|
310
|
+
radisk("keyA", null)
|
|
311
|
+
radisk("keyA", (err, value) => {
|
|
312
|
+
assert.equal(value, null)
|
|
313
|
+
})
|
|
314
|
+
setTimeout(() => {
|
|
315
|
+
assert.deepEqual(puts, {
|
|
316
|
+
"!":
|
|
317
|
+
'\x1F+0\x1F#\x1F"key\x1F=\x1F \x1F\n' +
|
|
318
|
+
'\x1F+1\x1F#\x1F"A\x1F=\x1F \x1F\n' +
|
|
319
|
+
'\x1F+1\x1F#\x1F"B\x1F=\x1F"valueB\x1F\n' +
|
|
320
|
+
'\x1F+1\x1F#\x1F"C\x1F=\x1F \x1F\n' +
|
|
321
|
+
'\x1F+1\x1F#\x1F"D\x1F=\x1F"valueD\x1F\n',
|
|
322
|
+
newFile: '\x1F+0\x1F#\x1F"newFile\x1F=\x1F"removed...\x1F\n',
|
|
323
|
+
small:
|
|
324
|
+
'\x1F+0\x1F#\x1F"small\x1F=\x1F"small value\x1F\n' +
|
|
325
|
+
'\x1F+1\x1F#\x1F"Continued\x1F=\x1F"continued value\x1F\n',
|
|
326
|
+
})
|
|
327
|
+
done()
|
|
328
|
+
}, 10)
|
|
329
|
+
})
|
|
191
330
|
})
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import {describe, test} from "node:test"
|
|
2
|
+
import assert from "node:assert/strict"
|
|
3
|
+
import Radisk from "../src/radisk.js"
|
|
4
|
+
|
|
5
|
+
// ASCII character for enquiry.
|
|
6
|
+
const enq = String.fromCharCode(5)
|
|
7
|
+
|
|
8
|
+
describe("split", () => {
|
|
9
|
+
const puts = {}
|
|
10
|
+
const opt = {
|
|
11
|
+
size: 100,
|
|
12
|
+
store: {
|
|
13
|
+
get: (file, cb) => {
|
|
14
|
+
cb(null, puts[file])
|
|
15
|
+
},
|
|
16
|
+
put: (file, data, cb) => {
|
|
17
|
+
puts[file] = data
|
|
18
|
+
cb(null)
|
|
19
|
+
},
|
|
20
|
+
list: cb => {
|
|
21
|
+
Object.keys(puts).sort().forEach(cb)
|
|
22
|
+
cb(null)
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
const radisk = Radisk(opt)
|
|
27
|
+
const now = Date.now()
|
|
28
|
+
const lorem =
|
|
29
|
+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
|
30
|
+
const parent = () => {
|
|
31
|
+
return (
|
|
32
|
+
'\x1F+0\x1F#\x1F"parent\x05\x1F\n' +
|
|
33
|
+
'\x1F+1\x1F#\x1F"boolean\x1F=\x1F+\x03' +
|
|
34
|
+
now +
|
|
35
|
+
"\x1F\n" +
|
|
36
|
+
'\x1F+1\x1F#\x1F"number\x1F=\x1F+42\x03' +
|
|
37
|
+
now +
|
|
38
|
+
"\x1F\n" +
|
|
39
|
+
'\x1F+1\x1F#\x1F"rel\x1F=\x1F#child\x03' +
|
|
40
|
+
now +
|
|
41
|
+
"\x1F\n" +
|
|
42
|
+
'\x1F+1\x1F#\x1F"string\x1F=\x1F"parent value\x03' +
|
|
43
|
+
now +
|
|
44
|
+
"\x1F\n"
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
const child = () => {
|
|
48
|
+
return (
|
|
49
|
+
'\x1F+0\x1F#\x1F"child\x05\x1F\n' +
|
|
50
|
+
'\x1F+1\x1F#\x1F"boolean\x1F=\x1F+\x03' +
|
|
51
|
+
now +
|
|
52
|
+
"\x1F\n" +
|
|
53
|
+
'\x1F+1\x1F#\x1F"number\x1F=\x1F+43\x03' +
|
|
54
|
+
now +
|
|
55
|
+
"\x1F\n" +
|
|
56
|
+
'\x1F+1\x1F#\x1F"rel\x1F=\x1F#grandchild\x03' +
|
|
57
|
+
now +
|
|
58
|
+
"\x1F\n" +
|
|
59
|
+
'\x1F+1\x1F#\x1F"string\x1F=\x1F"child value\x03' +
|
|
60
|
+
now +
|
|
61
|
+
"\x1F\n"
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
const grandchild = () => {
|
|
65
|
+
return (
|
|
66
|
+
'\x1F+0\x1F#\x1F"grandchild\x05\x1F\n' +
|
|
67
|
+
'\x1F+1\x1F#\x1F"boolean\x1F=\x1F-\x03' +
|
|
68
|
+
now +
|
|
69
|
+
"\x1F\n" +
|
|
70
|
+
'\x1F+1\x1F#\x1F"number\x1F=\x1F+44\x03' +
|
|
71
|
+
now +
|
|
72
|
+
"\x1F\n" +
|
|
73
|
+
'\x1F+1\x1F#\x1F"rel\x1F=\x1F#toys\x03' +
|
|
74
|
+
now +
|
|
75
|
+
"\x1F\n" +
|
|
76
|
+
'\x1F+1\x1F#\x1F"string\x1F=\x1F"grandchild value\x03' +
|
|
77
|
+
now +
|
|
78
|
+
"\x1F\n"
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
const toys = () => {
|
|
82
|
+
return (
|
|
83
|
+
'\x1F+0\x1F#\x1F"toys\x05\x1F\n' +
|
|
84
|
+
'\x1F+1\x1F#\x1F"b\x1F\n' +
|
|
85
|
+
'\x1F+2\x1F#\x1F"all\x1F=\x1F"green\x03' +
|
|
86
|
+
now +
|
|
87
|
+
"\x1F\n" +
|
|
88
|
+
'\x1F+2\x1F#\x1F"ook\x1F=\x1F"' +
|
|
89
|
+
lorem +
|
|
90
|
+
"\x03" +
|
|
91
|
+
now +
|
|
92
|
+
"\x1F\n" +
|
|
93
|
+
'\x1F+1\x1F#\x1F"car\x1F=\x1F"red\x03' +
|
|
94
|
+
now +
|
|
95
|
+
"\x1F\n"
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
const alpha = () => {
|
|
99
|
+
return (
|
|
100
|
+
'\x1F+0\x1F#\x1F"alpha\x05\x1F\n' +
|
|
101
|
+
'\x1F+1\x1F#\x1F"boolean\x1F=\x1F+\x03' +
|
|
102
|
+
now +
|
|
103
|
+
"\x1F\n" +
|
|
104
|
+
'\x1F+1\x1F#\x1F"number\x1F=\x1F+1\x03' +
|
|
105
|
+
now +
|
|
106
|
+
"\x1F\n" +
|
|
107
|
+
'\x1F+1\x1F#\x1F"rel\x1F=\x1F#beta\x03' +
|
|
108
|
+
now +
|
|
109
|
+
"\x1F\n" +
|
|
110
|
+
'\x1F+1\x1F#\x1F"string\x1F=\x1F"alpha value\x03' +
|
|
111
|
+
now +
|
|
112
|
+
"\x1F\n"
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
test("write a parent node", (t, done) => {
|
|
117
|
+
radisk("parent" + enq + "string", ["parent value", now])
|
|
118
|
+
radisk("parent" + enq + "number", [42, now])
|
|
119
|
+
radisk("parent" + enq + "boolean", [true, now])
|
|
120
|
+
radisk("parent" + enq + "rel", [{"#": "child"}, now])
|
|
121
|
+
|
|
122
|
+
setTimeout(() => {
|
|
123
|
+
assert.deepEqual(puts, {
|
|
124
|
+
"!": parent(),
|
|
125
|
+
})
|
|
126
|
+
done()
|
|
127
|
+
}, 10)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test("write a child node", (t, done) => {
|
|
131
|
+
radisk("child" + enq + "string", ["child value", now])
|
|
132
|
+
radisk("child" + enq + "number", [43, now])
|
|
133
|
+
radisk("child" + enq + "boolean", [true, now])
|
|
134
|
+
radisk("child" + enq + "rel", [{"#": "grandchild"}, now])
|
|
135
|
+
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
assert.deepEqual(puts, {
|
|
138
|
+
"!": child(),
|
|
139
|
+
parent: parent(),
|
|
140
|
+
})
|
|
141
|
+
done()
|
|
142
|
+
}, 10)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
test("write a grandchild node", (t, done) => {
|
|
146
|
+
radisk("grandchild" + enq + "string", ["grandchild value", now])
|
|
147
|
+
radisk("grandchild" + enq + "number", [44, now])
|
|
148
|
+
radisk("grandchild" + enq + "boolean", [false, now])
|
|
149
|
+
radisk("grandchild" + enq + "rel", [{"#": "toys"}, now])
|
|
150
|
+
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
assert.deepEqual(puts, {
|
|
153
|
+
"!": child(),
|
|
154
|
+
parent: parent(),
|
|
155
|
+
grandchild: grandchild(),
|
|
156
|
+
})
|
|
157
|
+
done()
|
|
158
|
+
}, 10)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test("write grandchild toys", (t, done) => {
|
|
162
|
+
radisk("toys" + enq + "car", ["red", now])
|
|
163
|
+
radisk("toys" + enq + "ball", ["green", now])
|
|
164
|
+
radisk("toys" + enq + "book", [lorem, now])
|
|
165
|
+
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
assert.deepEqual(puts, {
|
|
168
|
+
"!": child(),
|
|
169
|
+
parent: parent(),
|
|
170
|
+
grandchild: grandchild(),
|
|
171
|
+
toys: toys(),
|
|
172
|
+
})
|
|
173
|
+
done()
|
|
174
|
+
}, 10)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
test("write new first node", (t, done) => {
|
|
178
|
+
radisk("alpha" + enq + "string", ["alpha value", now])
|
|
179
|
+
radisk("alpha" + enq + "number", [1, now])
|
|
180
|
+
radisk("alpha" + enq + "boolean", [true, now])
|
|
181
|
+
radisk("alpha" + enq + "rel", [{"#": "beta"}, now])
|
|
182
|
+
radisk("beta" + enq + "string", ["beta value", now])
|
|
183
|
+
|
|
184
|
+
setTimeout(() => {
|
|
185
|
+
assert.deepEqual(puts, {
|
|
186
|
+
"!": alpha(),
|
|
187
|
+
beta:
|
|
188
|
+
'\x1F+0\x1F#\x1F"beta\x05string\x1F=\x1F"beta value\x03' +
|
|
189
|
+
now +
|
|
190
|
+
"\x1F\n" +
|
|
191
|
+
child(),
|
|
192
|
+
parent: parent(),
|
|
193
|
+
grandchild: grandchild(),
|
|
194
|
+
toys: toys(),
|
|
195
|
+
})
|
|
196
|
+
done()
|
|
197
|
+
}, 10)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// Note that "beta" remains a separate file here (nodes aren't combined).
|
|
201
|
+
test("write new second node", (t, done) => {
|
|
202
|
+
radisk("be" + enq + "string", ["be value", now])
|
|
203
|
+
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
assert.deepEqual(puts, {
|
|
206
|
+
"!": alpha(),
|
|
207
|
+
be:
|
|
208
|
+
'\x1F+0\x1F#\x1F"be\x05string\x1F=\x1F"be value\x03' + now + "\x1F\n",
|
|
209
|
+
beta:
|
|
210
|
+
'\x1F+0\x1F#\x1F"beta\x05string\x1F=\x1F"beta value\x03' +
|
|
211
|
+
now +
|
|
212
|
+
"\x1F\n" +
|
|
213
|
+
child(),
|
|
214
|
+
parent: parent(),
|
|
215
|
+
grandchild: grandchild(),
|
|
216
|
+
toys: toys(),
|
|
217
|
+
})
|
|
218
|
+
done()
|
|
219
|
+
}, 10)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
test("add a parent item", (t, done) => {
|
|
223
|
+
radisk("parent" + enq + "after", ["this was added after", now])
|
|
224
|
+
|
|
225
|
+
setTimeout(() => {
|
|
226
|
+
assert.deepEqual(puts, {
|
|
227
|
+
"!": alpha(),
|
|
228
|
+
be:
|
|
229
|
+
'\x1F+0\x1F#\x1F"be\x05string\x1F=\x1F"be value\x03' + now + "\x1F\n",
|
|
230
|
+
beta:
|
|
231
|
+
'\x1F+0\x1F#\x1F"beta\x05string\x1F=\x1F"beta value\x03' +
|
|
232
|
+
now +
|
|
233
|
+
"\x1F\n" +
|
|
234
|
+
child(),
|
|
235
|
+
grandchild: grandchild(),
|
|
236
|
+
parent:
|
|
237
|
+
'\x1F+0\x1F#\x1F"parent\x05\x1F\n' +
|
|
238
|
+
'\x1F+1\x1F#\x1F"after\x1F=\x1F"this was added after\x03' +
|
|
239
|
+
now +
|
|
240
|
+
"\x1F\n" +
|
|
241
|
+
'\x1F+1\x1F#\x1F"boolean\x1F=\x1F+\x03' +
|
|
242
|
+
now +
|
|
243
|
+
"\x1F\n" +
|
|
244
|
+
'\x1F+1\x1F#\x1F"number\x1F=\x1F+42\x03' +
|
|
245
|
+
now +
|
|
246
|
+
"\x1F\n" +
|
|
247
|
+
'\x1F+1\x1F#\x1F"rel\x1F=\x1F#child\x03' +
|
|
248
|
+
now +
|
|
249
|
+
"\x1F\n" +
|
|
250
|
+
'\x1F+1\x1F#\x1F"string\x1F=\x1F"parent value\x03' +
|
|
251
|
+
now +
|
|
252
|
+
"\x1F\n",
|
|
253
|
+
toys: toys(),
|
|
254
|
+
})
|
|
255
|
+
done()
|
|
256
|
+
}, 10)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
test("add two child items", (t, done) => {
|
|
260
|
+
radisk("child" + enq + "book", [lorem, now])
|
|
261
|
+
radisk("child" + enq + "pi", [3.14159, now])
|
|
262
|
+
|
|
263
|
+
setTimeout(() => {
|
|
264
|
+
assert.deepEqual(puts, {
|
|
265
|
+
"!": alpha(),
|
|
266
|
+
be:
|
|
267
|
+
'\x1F+0\x1F#\x1F"be\x05string\x1F=\x1F"be value\x03' + now + "\x1F\n",
|
|
268
|
+
beta:
|
|
269
|
+
'\x1F+0\x1F#\x1F"beta\x05string\x1F=\x1F"beta value\x03' +
|
|
270
|
+
now +
|
|
271
|
+
"\x1F\n" +
|
|
272
|
+
'\x1F+0\x1F#\x1F"child\x05\x1F\n' +
|
|
273
|
+
'\x1F+1\x1F#\x1F"boo\x1F\n' +
|
|
274
|
+
'\x1F+2\x1F#\x1F"k\x1F=\x1F"' +
|
|
275
|
+
lorem +
|
|
276
|
+
"\x03" +
|
|
277
|
+
now +
|
|
278
|
+
"\x1F\n" +
|
|
279
|
+
'\x1F+2\x1F#\x1F"lean\x1F=\x1F+\x03' +
|
|
280
|
+
now +
|
|
281
|
+
"\x1F\n" +
|
|
282
|
+
'\x1F+1\x1F#\x1F"number\x1F=\x1F+43\x03' +
|
|
283
|
+
now +
|
|
284
|
+
"\x1F\n" +
|
|
285
|
+
'\x1F+1\x1F#\x1F"pi\x1F=\x1F+3.14159\x03' +
|
|
286
|
+
now +
|
|
287
|
+
"\x1F\n" +
|
|
288
|
+
'\x1F+1\x1F#\x1F"rel\x1F=\x1F#grandchild\x03' +
|
|
289
|
+
now +
|
|
290
|
+
"\x1F\n" +
|
|
291
|
+
'\x1F+1\x1F#\x1F"string\x1F=\x1F"child value\x03' +
|
|
292
|
+
now +
|
|
293
|
+
"\x1F\n",
|
|
294
|
+
grandchild: grandchild(),
|
|
295
|
+
parent:
|
|
296
|
+
'\x1F+0\x1F#\x1F"parent\x05\x1F\n' +
|
|
297
|
+
'\x1F+1\x1F#\x1F"after\x1F=\x1F"this was added after\x03' +
|
|
298
|
+
now +
|
|
299
|
+
"\x1F\n" +
|
|
300
|
+
'\x1F+1\x1F#\x1F"boolean\x1F=\x1F+\x03' +
|
|
301
|
+
now +
|
|
302
|
+
"\x1F\n" +
|
|
303
|
+
'\x1F+1\x1F#\x1F"number\x1F=\x1F+42\x03' +
|
|
304
|
+
now +
|
|
305
|
+
"\x1F\n" +
|
|
306
|
+
'\x1F+1\x1F#\x1F"rel\x1F=\x1F#child\x03' +
|
|
307
|
+
now +
|
|
308
|
+
"\x1F\n" +
|
|
309
|
+
'\x1F+1\x1F#\x1F"string\x1F=\x1F"parent value\x03' +
|
|
310
|
+
now +
|
|
311
|
+
"\x1F\n",
|
|
312
|
+
toys: toys(),
|
|
313
|
+
})
|
|
314
|
+
done()
|
|
315
|
+
}, 10)
|
|
316
|
+
})
|
|
317
|
+
})
|
package/test/store.test.js
CHANGED
|
@@ -75,7 +75,7 @@ describe("store", () => {
|
|
|
75
75
|
},
|
|
76
76
|
err => {
|
|
77
77
|
assert.equal(err, null)
|
|
78
|
-
fs.access("test/multiple
|
|
78
|
+
fs.access("test/multiple/!", err => {
|
|
79
79
|
assert.equal(err, null)
|
|
80
80
|
fs.access("test/multiple/newFile", err => {
|
|
81
81
|
assert.equal(err, null)
|
|
@@ -103,7 +103,7 @@ describe("store", () => {
|
|
|
103
103
|
})
|
|
104
104
|
})
|
|
105
105
|
|
|
106
|
-
test("get
|
|
106
|
+
test("get another key from first file", (t, done) => {
|
|
107
107
|
multiple.get({"#": "keyC"}, (err, value) => {
|
|
108
108
|
assert.deepEqual(value, {
|
|
109
109
|
keyC: {
|
|
@@ -135,7 +135,7 @@ describe("store", () => {
|
|
|
135
135
|
})
|
|
136
136
|
})
|
|
137
137
|
|
|
138
|
-
test("get key from
|
|
138
|
+
test("get key from second file", (t, done) => {
|
|
139
139
|
multiple.get({"#": "newFile"}, (err, value) => {
|
|
140
140
|
assert.deepEqual(value, {
|
|
141
141
|
newFile: {
|