@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblaney/holster",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Holster is a service that allows synchronising data between devices using Node, Deno, Bun or the browser.",
5
5
  "type": "module",
6
6
  "main": "index.js",
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
- save.mix(save.file || "!", save.start, save.end)
139
- return true
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 save.start
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
- var enc =
183
- Radisk.encode(pre.length) +
184
- "#" +
185
- Radisk.encode(k) +
186
- (typeof value === "undefined" ? "" : "=" + Radisk.encode(value)) +
187
- "\n"
188
- // Cannot split the file if only have one entry to write.
189
- if (write.count > 1 && write.text.length + enc.length > opt.size) {
190
- write.text = ""
191
- // Otherwise split the entries in half.
192
- write.limit = Math.ceil(write.count / 2)
193
- write.count = 0
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
- return true
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.file) return
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
- // If Radix.map doesn't return true when called with write.each as a
238
- // callback then didn't need to split the data. The accumulated write.text
239
- // can then be stored with write.put().
240
- if (!Radix.map(rad, write.each, true)) write.put()
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
- let soul = key
250
- let end = key.indexOf(enq)
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 => {
@@ -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 \x1F\n',
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
+ })
@@ -75,7 +75,7 @@ describe("store", () => {
75
75
  },
76
76
  err => {
77
77
  assert.equal(err, null)
78
- fs.access("test/multiple/keyC", err => {
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 keys from second file", (t, done) => {
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 third file", (t, done) => {
138
+ test("get key from second file", (t, done) => {
139
139
  multiple.get({"#": "newFile"}, (err, value) => {
140
140
  assert.deepEqual(value, {
141
141
  newFile: {