localdb-ces6q 0.0.2 → 0.0.3

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": "localdb-ces6q",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "TypeScript ECMAScript Module Library Template",
5
5
  "type": "module",
6
6
  "module": "dist/index.js",
@@ -9,9 +9,9 @@
9
9
  "build:watch": "tsc -w",
10
10
  "format": "prettier --write {src,test}/**/*.{ts,tsx,js,jsx}",
11
11
  "pub": "node publish.js",
12
- "test": "jest -c ./jest.config.ts",
13
- "test:cov": "jest -c ./jest.config.ts --collect-coverage",
14
- "test:watch": "jest -c ./jest.config.ts --watch",
12
+ "test": "jest",
13
+ "test:cov": "jest --collect-coverage",
14
+ "test:watch": "jest --watch",
15
15
  "typecheck": "tsc --noEmit",
16
16
  "typecheck:watch": "tsc --noEmit -w"
17
17
  },
@@ -1 +0,0 @@
1
- export {};
@@ -1,1137 +0,0 @@
1
- import { arraysEqual, dedupKeys } from 'util-3gcvv/array.js';
2
- import { objectMap } from 'util-3gcvv/object.js';
3
- import { describe, expect, jest, test } from '@jest/globals';
4
- import { LocalDB } from '../src/LocalDB.js';
5
- jest.useFakeTimers();
6
- describe('LocalDB', () => {
7
- test('LocalDB', () => {
8
- const initData = {
9
- person: {
10
- p1: { id: 'p1', age: 10, name: 'john' },
11
- p2: { id: 'p2', age: 18, name: 'sean' },
12
- },
13
- city: {
14
- c1: { id: 'c1', name: 'Tokyo', location: [1, 2] },
15
- },
16
- };
17
- const db = new LocalDB({
18
- person: {
19
- fields: {
20
- id: { type: 'string' },
21
- age: { type: 'number' },
22
- name: { type: 'string' },
23
- },
24
- },
25
- city: {
26
- fields: {
27
- id: { type: 'string' },
28
- name: { type: 'string' },
29
- location: {
30
- type: 'array',
31
- normalize: (x) => x.sort(),
32
- equals: arraysEqual,
33
- },
34
- },
35
- },
36
- }, initData, { undoable: true });
37
- expect(db.toJSON()).toEqual(initData);
38
- expect(db.state.canUndo).toBe(false);
39
- expect(db.state.canRedo).toBe(false);
40
- expect(db.collection('person')).toEqual(initData.person);
41
- expect(db.collection('city')).toEqual(initData.city);
42
- expect(db.doc('person', 'p1')).toEqual(initData.person.p1);
43
- expect(db.doc('person', 'p2')).toEqual(initData.person.p2);
44
- expect(db.doc('city', 'c1')).toEqual(initData.city.c1);
45
- const dbChanges = [];
46
- const unsubDb = db.subToDB((next, prev, change) => {
47
- dbChanges.push([change, next, prev]);
48
- });
49
- const personChanges = [];
50
- const unsubPerson = db.subToCol('person', (next, prev, change) => {
51
- personChanges.push([change, next, prev]);
52
- });
53
- const p1Changes = [];
54
- const unsubP1 = db.subToDoc('person', 'p1', (next, prev, change) => {
55
- p1Changes.push([change, next, prev]);
56
- });
57
- const p2Changes = [];
58
- const unsubP2 = db.subToDoc('person', 'p2', (next, prev, change) => {
59
- p2Changes.push([change, next, prev]);
60
- });
61
- const p1AgeChanges = [];
62
- const unsubP1Age = db.subToField('person', 'p1', 'age', (next, prev, nextDoc, prevDoc) => {
63
- p1AgeChanges.push([next, prev, nextDoc, prevDoc]);
64
- });
65
- const p1NameChanges = [];
66
- const unsubP1Name = db.subToField('person', 'p1', 'name', (next, prev, nextDoc, prevDoc) => {
67
- p1NameChanges.push([next, prev, nextDoc, prevDoc]);
68
- });
69
- /// update
70
- db.updateDoc('person', 'p1', { age: 11 });
71
- expect(db.doc('person', 'p1')).toEqual({ id: 'p1', age: 11, name: 'john' });
72
- expect(dbChanges).toEqual([
73
- [
74
- { person: { p1: { age: 11 } } },
75
- {
76
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
77
- person: {
78
- p1: { age: 11, id: 'p1', name: 'john' },
79
- p2: { age: 18, id: 'p2', name: 'sean' },
80
- },
81
- },
82
- {
83
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
84
- person: {
85
- p1: { age: 10, id: 'p1', name: 'john' },
86
- p2: { age: 18, id: 'p2', name: 'sean' },
87
- },
88
- },
89
- ],
90
- ]);
91
- expect(personChanges).toEqual([
92
- [
93
- { p1: { age: 11 } },
94
- {
95
- p1: { age: 11, id: 'p1', name: 'john' },
96
- p2: { age: 18, id: 'p2', name: 'sean' },
97
- },
98
- {
99
- p1: { age: 10, id: 'p1', name: 'john' },
100
- p2: { age: 18, id: 'p2', name: 'sean' },
101
- },
102
- ],
103
- ]);
104
- expect(p1Changes).toEqual([
105
- [
106
- { age: 11 },
107
- { age: 11, id: 'p1', name: 'john' },
108
- { age: 10, id: 'p1', name: 'john' },
109
- ],
110
- ]);
111
- expect(p2Changes).toEqual([]);
112
- expect(p1AgeChanges).toEqual([
113
- [
114
- 11,
115
- 10,
116
- { age: 11, id: 'p1', name: 'john' },
117
- { age: 10, id: 'p1', name: 'john' },
118
- ],
119
- ]);
120
- expect(p1NameChanges).toEqual([]);
121
- expect(db.state.canUndo).toBe(true);
122
- expect(db.state.canRedo).toBe(false);
123
- dbChanges.length = 0;
124
- personChanges.length = 0;
125
- p1Changes.length = 0;
126
- p2Changes.length = 0;
127
- p1AgeChanges.length = 0;
128
- p1NameChanges.length = 0;
129
- /// update
130
- db.updateDoc('person', 'p1', { age: 12, name: 'jack' });
131
- expect(db.doc('person', 'p1')).toEqual({ id: 'p1', age: 12, name: 'jack' });
132
- expect(dbChanges).toEqual([
133
- [
134
- { person: { p1: { age: 12, name: 'jack' } } },
135
- {
136
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
137
- person: {
138
- p1: { age: 12, id: 'p1', name: 'jack' },
139
- p2: { age: 18, id: 'p2', name: 'sean' },
140
- },
141
- },
142
- {
143
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
144
- person: {
145
- p1: { age: 11, id: 'p1', name: 'john' },
146
- p2: { age: 18, id: 'p2', name: 'sean' },
147
- },
148
- },
149
- ],
150
- ]);
151
- expect(personChanges).toEqual([
152
- [
153
- { p1: { age: 12, name: 'jack' } },
154
- {
155
- p1: { age: 12, id: 'p1', name: 'jack' },
156
- p2: { age: 18, id: 'p2', name: 'sean' },
157
- },
158
- {
159
- p1: { age: 11, id: 'p1', name: 'john' },
160
- p2: { age: 18, id: 'p2', name: 'sean' },
161
- },
162
- ],
163
- ]);
164
- expect(p1Changes).toEqual([
165
- [
166
- { age: 12, name: 'jack' },
167
- { age: 12, id: 'p1', name: 'jack' },
168
- { age: 11, id: 'p1', name: 'john' },
169
- ],
170
- ]);
171
- expect(p2Changes).toEqual([]);
172
- expect(p1AgeChanges).toEqual([
173
- [
174
- 12,
175
- 11,
176
- { age: 12, id: 'p1', name: 'jack' },
177
- { age: 11, id: 'p1', name: 'john' },
178
- ],
179
- ]);
180
- expect(p1NameChanges).toEqual([
181
- [
182
- 'jack',
183
- 'john',
184
- { age: 12, id: 'p1', name: 'jack' },
185
- { age: 11, id: 'p1', name: 'john' },
186
- ],
187
- ]);
188
- expect(db.state.canUndo).toBe(true);
189
- expect(db.state.canRedo).toBe(false);
190
- dbChanges.length = 0;
191
- personChanges.length = 0;
192
- p1Changes.length = 0;
193
- p2Changes.length = 0;
194
- p1AgeChanges.length = 0;
195
- p1NameChanges.length = 0;
196
- // transaction
197
- db.tx(() => {
198
- db.updateDoc('person', 'p1', { age: 13, name: 'jackson' });
199
- db.updateDoc('person', 'p1', { age: 14, name: 'jackson' });
200
- db.updateDoc('person', 'p2', { age: 18, name: 'sean' });
201
- db.updateDoc('city', 'c1', { name: 'austin', location: [2, 1] });
202
- });
203
- expect(db.doc('person', 'p1')).toEqual({
204
- id: 'p1',
205
- age: 14,
206
- name: 'jackson',
207
- });
208
- expect(db.doc('person', 'p2')).toEqual({ id: 'p2', age: 18, name: 'sean' });
209
- expect(db.doc('city', 'c1')).toEqual({
210
- id: 'c1',
211
- location: [1, 2],
212
- name: 'austin',
213
- });
214
- expect(dbChanges).toEqual([
215
- [
216
- {
217
- city: { c1: { name: 'austin' } },
218
- person: { p1: { age: 14, name: 'jackson' } },
219
- },
220
- {
221
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
222
- person: {
223
- p1: { age: 14, id: 'p1', name: 'jackson' },
224
- p2: { age: 18, id: 'p2', name: 'sean' },
225
- },
226
- },
227
- {
228
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
229
- person: {
230
- p1: { age: 12, id: 'p1', name: 'jack' },
231
- p2: { age: 18, id: 'p2', name: 'sean' },
232
- },
233
- },
234
- ],
235
- ]);
236
- expect(personChanges).toEqual([
237
- [
238
- { p1: { age: 14, name: 'jackson' } },
239
- {
240
- p1: { age: 14, id: 'p1', name: 'jackson' },
241
- p2: { age: 18, id: 'p2', name: 'sean' },
242
- },
243
- {
244
- p1: { age: 12, id: 'p1', name: 'jack' },
245
- p2: { age: 18, id: 'p2', name: 'sean' },
246
- },
247
- ],
248
- ]);
249
- expect(p1Changes).toEqual([
250
- [
251
- { age: 14, name: 'jackson' },
252
- { age: 14, id: 'p1', name: 'jackson' },
253
- { age: 12, id: 'p1', name: 'jack' },
254
- ],
255
- ]);
256
- expect(p2Changes).toEqual([]);
257
- expect(p1AgeChanges).toEqual([
258
- [
259
- 14,
260
- 12,
261
- { age: 14, id: 'p1', name: 'jackson' },
262
- { age: 12, id: 'p1', name: 'jack' },
263
- ],
264
- ]);
265
- expect(p1NameChanges).toEqual([
266
- [
267
- 'jackson',
268
- 'jack',
269
- { age: 14, id: 'p1', name: 'jackson' },
270
- { age: 12, id: 'p1', name: 'jack' },
271
- ],
272
- ]);
273
- expect(db.state.canUndo).toBe(true);
274
- expect(db.state.canRedo).toBe(false);
275
- // getters
276
- expect(db.collection('person')).toEqual({
277
- p1: { age: 14, id: 'p1', name: 'jackson' },
278
- p2: { age: 18, id: 'p2', name: 'sean' },
279
- });
280
- expect(db.collection('city')).toEqual({
281
- c1: { id: 'c1', location: [1, 2], name: 'austin' },
282
- });
283
- expect(db.docs('person', ['p1', 'p2', 'p3'])).toEqual([
284
- { age: 14, id: 'p1', name: 'jackson' },
285
- { age: 18, id: 'p2', name: 'sean' },
286
- undefined,
287
- ]);
288
- expect(db.docs('city', ['c0', 'c1'])).toEqual([
289
- undefined,
290
- { id: 'c1', location: [1, 2], name: 'austin' },
291
- ]);
292
- // undo / redo
293
- expect(db.state.canUndo).toBe(true);
294
- expect(db.state.canRedo).toBe(false);
295
- db.undo();
296
- expect(db.state.canUndo).toBe(true);
297
- expect(db.state.canRedo).toBe(true);
298
- expect(db.toJSON()).toEqual({
299
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
300
- person: {
301
- p1: { age: 12, id: 'p1', name: 'jack' },
302
- p2: { age: 18, id: 'p2', name: 'sean' },
303
- },
304
- });
305
- db.redo();
306
- expect(db.state.canUndo).toBe(true);
307
- expect(db.state.canRedo).toBe(false);
308
- expect(db.toJSON()).toEqual({
309
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
310
- person: {
311
- p1: { age: 14, id: 'p1', name: 'jackson' },
312
- p2: { age: 18, id: 'p2', name: 'sean' },
313
- },
314
- });
315
- db.undo();
316
- expect(db.state.canUndo).toBe(true);
317
- expect(db.state.canRedo).toBe(true);
318
- expect(db.toJSON()).toEqual({
319
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
320
- person: {
321
- p1: { age: 12, id: 'p1', name: 'jack' },
322
- p2: { age: 18, id: 'p2', name: 'sean' },
323
- },
324
- });
325
- db.undo();
326
- expect(db.state.canUndo).toBe(true);
327
- expect(db.state.canRedo).toBe(true);
328
- expect(db.toJSON()).toEqual({
329
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
330
- person: {
331
- p1: { age: 11, id: 'p1', name: 'john' },
332
- p2: { age: 18, id: 'p2', name: 'sean' },
333
- },
334
- });
335
- db.undo();
336
- expect(db.state.canUndo).toBe(false);
337
- expect(db.state.canRedo).toBe(true);
338
- expect(db.toJSON()).toEqual({
339
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
340
- person: {
341
- p1: { age: 10, id: 'p1', name: 'john' },
342
- p2: { age: 18, id: 'p2', name: 'sean' },
343
- },
344
- });
345
- db.undo();
346
- expect(db.state.canUndo).toBe(false);
347
- expect(db.state.canRedo).toBe(true);
348
- expect(db.toJSON()).toEqual({
349
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
350
- person: {
351
- p1: { age: 10, id: 'p1', name: 'john' },
352
- p2: { age: 18, id: 'p2', name: 'sean' },
353
- },
354
- });
355
- db.redo();
356
- expect(db.state.canUndo).toBe(true);
357
- expect(db.state.canRedo).toBe(true);
358
- expect(db.toJSON()).toEqual({
359
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
360
- person: {
361
- p1: { age: 11, id: 'p1', name: 'john' },
362
- p2: { age: 18, id: 'p2', name: 'sean' },
363
- },
364
- });
365
- db.redo();
366
- expect(db.state.canUndo).toBe(true);
367
- expect(db.state.canRedo).toBe(true);
368
- expect(db.toJSON()).toEqual({
369
- city: { c1: { id: 'c1', location: [1, 2], name: 'Tokyo' } },
370
- person: {
371
- p1: { age: 12, id: 'p1', name: 'jack' },
372
- p2: { age: 18, id: 'p2', name: 'sean' },
373
- },
374
- });
375
- db.redo();
376
- expect(db.state.canUndo).toBe(true);
377
- expect(db.state.canRedo).toBe(false);
378
- expect(db.toJSON()).toEqual({
379
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
380
- person: {
381
- p1: { age: 14, id: 'p1', name: 'jackson' },
382
- p2: { age: 18, id: 'p2', name: 'sean' },
383
- },
384
- });
385
- // set doc new
386
- dbChanges.length = 0;
387
- personChanges.length = 0;
388
- p1Changes.length = 0;
389
- p2Changes.length = 0;
390
- p1AgeChanges.length = 0;
391
- p1NameChanges.length = 0;
392
- db.setDoc('person', { id: 'p3', age: 21, name: 'mike' });
393
- expect(dbChanges).toEqual([
394
- [
395
- { person: { p3: { age: 21, id: 'p3', name: 'mike' } } },
396
- {
397
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
398
- person: {
399
- p1: { age: 14, id: 'p1', name: 'jackson' },
400
- p2: { age: 18, id: 'p2', name: 'sean' },
401
- p3: { age: 21, id: 'p3', name: 'mike' },
402
- },
403
- },
404
- {
405
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
406
- person: {
407
- p1: { age: 14, id: 'p1', name: 'jackson' },
408
- p2: { age: 18, id: 'p2', name: 'sean' },
409
- },
410
- },
411
- ],
412
- ]);
413
- expect(personChanges).toEqual([
414
- [
415
- { p3: { age: 21, id: 'p3', name: 'mike' } },
416
- {
417
- p1: { age: 14, id: 'p1', name: 'jackson' },
418
- p2: { age: 18, id: 'p2', name: 'sean' },
419
- p3: { age: 21, id: 'p3', name: 'mike' },
420
- },
421
- {
422
- p1: { age: 14, id: 'p1', name: 'jackson' },
423
- p2: { age: 18, id: 'p2', name: 'sean' },
424
- },
425
- ],
426
- ]);
427
- expect(p1Changes).toEqual([]);
428
- expect(p2Changes).toEqual([]);
429
- expect(p1AgeChanges).toEqual([]);
430
- expect(p1NameChanges).toEqual([]);
431
- // set doc overwrite
432
- dbChanges.length = 0;
433
- personChanges.length = 0;
434
- p1Changes.length = 0;
435
- p2Changes.length = 0;
436
- p1AgeChanges.length = 0;
437
- p1NameChanges.length = 0;
438
- db.setDoc('person', { id: 'p2', age: 25, name: 'tom' });
439
- expect(dbChanges).toEqual([
440
- [
441
- { person: { p2: { age: 25, name: 'tom' } } },
442
- {
443
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
444
- person: {
445
- p1: { age: 14, id: 'p1', name: 'jackson' },
446
- p2: { age: 25, id: 'p2', name: 'tom' },
447
- p3: { age: 21, id: 'p3', name: 'mike' },
448
- },
449
- },
450
- {
451
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
452
- person: {
453
- p1: { age: 14, id: 'p1', name: 'jackson' },
454
- p2: { age: 18, id: 'p2', name: 'sean' },
455
- p3: { age: 21, id: 'p3', name: 'mike' },
456
- },
457
- },
458
- ],
459
- ]);
460
- expect(personChanges).toEqual([
461
- [
462
- { p2: { age: 25, name: 'tom' } },
463
- {
464
- p1: { age: 14, id: 'p1', name: 'jackson' },
465
- p2: { age: 25, id: 'p2', name: 'tom' },
466
- p3: { age: 21, id: 'p3', name: 'mike' },
467
- },
468
- {
469
- p1: { age: 14, id: 'p1', name: 'jackson' },
470
- p2: { age: 18, id: 'p2', name: 'sean' },
471
- p3: { age: 21, id: 'p3', name: 'mike' },
472
- },
473
- ],
474
- ]);
475
- expect(p1Changes).toEqual([]);
476
- expect(p2Changes).toEqual([
477
- [
478
- { age: 25, name: 'tom' },
479
- { age: 25, id: 'p2', name: 'tom' },
480
- { age: 18, id: 'p2', name: 'sean' },
481
- ],
482
- ]);
483
- expect(p1AgeChanges).toEqual([]);
484
- expect(p1NameChanges).toEqual([]);
485
- // delete doc
486
- dbChanges.length = 0;
487
- personChanges.length = 0;
488
- p1Changes.length = 0;
489
- p2Changes.length = 0;
490
- p1AgeChanges.length = 0;
491
- p1NameChanges.length = 0;
492
- db.deleteDoc('person', 'p2');
493
- expect(dbChanges).toEqual([
494
- [
495
- { person: { p2: null } },
496
- {
497
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
498
- person: {
499
- p1: { age: 14, id: 'p1', name: 'jackson' },
500
- p3: { age: 21, id: 'p3', name: 'mike' },
501
- },
502
- },
503
- {
504
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
505
- person: {
506
- p1: { age: 14, id: 'p1', name: 'jackson' },
507
- p2: { age: 25, id: 'p2', name: 'tom' },
508
- p3: { age: 21, id: 'p3', name: 'mike' },
509
- },
510
- },
511
- ],
512
- ]);
513
- expect(personChanges).toEqual([
514
- [
515
- { p2: null },
516
- {
517
- p1: { age: 14, id: 'p1', name: 'jackson' },
518
- p3: { age: 21, id: 'p3', name: 'mike' },
519
- },
520
- {
521
- p1: { age: 14, id: 'p1', name: 'jackson' },
522
- p2: { age: 25, id: 'p2', name: 'tom' },
523
- p3: { age: 21, id: 'p3', name: 'mike' },
524
- },
525
- ],
526
- ]);
527
- expect(p1Changes).toEqual([]);
528
- expect(p2Changes).toEqual([
529
- [null, undefined, { age: 25, id: 'p2', name: 'tom' }],
530
- ]);
531
- expect(p1AgeChanges).toEqual([]);
532
- expect(p1NameChanges).toEqual([]);
533
- // test rollback
534
- dbChanges.length = 0;
535
- personChanges.length = 0;
536
- p1Changes.length = 0;
537
- p2Changes.length = 0;
538
- p1AgeChanges.length = 0;
539
- p1NameChanges.length = 0;
540
- expect(() => db.tx(() => {
541
- db.updateDoc('person', 'p1', { age: 15 });
542
- db.updateDoc('person', 'p1', { age: 16 });
543
- throw 1;
544
- db.updateDoc('person', 'p1', { age: 17 });
545
- db.updateDoc('person', 'p1', { age: 18 });
546
- })).toThrowError();
547
- expect(dbChanges).toEqual([]);
548
- expect(personChanges).toEqual([]);
549
- expect(p1Changes).toEqual([]);
550
- expect(p2Changes).toEqual([]);
551
- expect(p1AgeChanges).toEqual([]);
552
- expect(p1NameChanges).toEqual([]);
553
- expect(db.toJSON()).toEqual({
554
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
555
- person: {
556
- p1: { age: 14, id: 'p1', name: 'jackson' },
557
- p3: { age: 21, id: 'p3', name: 'mike' },
558
- },
559
- });
560
- // test tx
561
- dbChanges.length = 0;
562
- personChanges.length = 0;
563
- p1Changes.length = 0;
564
- p2Changes.length = 0;
565
- p1AgeChanges.length = 0;
566
- p1NameChanges.length = 0;
567
- db.tx(() => {
568
- db.updateDoc('person', 'p1', { age: 15 });
569
- db.updateDoc('person', 'p1', { age: 16 });
570
- });
571
- expect(dbChanges).toEqual([
572
- [
573
- { person: { p1: { age: 16 } } },
574
- {
575
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
576
- person: {
577
- p1: { age: 16, id: 'p1', name: 'jackson' },
578
- p3: { age: 21, id: 'p3', name: 'mike' },
579
- },
580
- },
581
- {
582
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
583
- person: {
584
- p1: { age: 14, id: 'p1', name: 'jackson' },
585
- p3: { age: 21, id: 'p3', name: 'mike' },
586
- },
587
- },
588
- ],
589
- ]);
590
- expect(personChanges).toEqual([
591
- [
592
- { p1: { age: 16 } },
593
- {
594
- p1: { age: 16, id: 'p1', name: 'jackson' },
595
- p3: { age: 21, id: 'p3', name: 'mike' },
596
- },
597
- {
598
- p1: { age: 14, id: 'p1', name: 'jackson' },
599
- p3: { age: 21, id: 'p3', name: 'mike' },
600
- },
601
- ],
602
- ]);
603
- expect(p1Changes).toEqual([
604
- [
605
- { age: 16 },
606
- { age: 16, id: 'p1', name: 'jackson' },
607
- { age: 14, id: 'p1', name: 'jackson' },
608
- ],
609
- ]);
610
- expect(p2Changes).toEqual([]);
611
- expect(p1AgeChanges).toEqual([
612
- [
613
- 16,
614
- 14,
615
- { age: 16, id: 'p1', name: 'jackson' },
616
- { age: 14, id: 'p1', name: 'jackson' },
617
- ],
618
- ]);
619
- expect(p1NameChanges).toEqual([]);
620
- expect(db.toJSON()).toEqual({
621
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
622
- person: {
623
- p1: { age: 16, id: 'p1', name: 'jackson' },
624
- p3: { age: 21, id: 'p3', name: 'mike' },
625
- },
626
- });
627
- // delete docs
628
- dbChanges.length = 0;
629
- personChanges.length = 0;
630
- p1Changes.length = 0;
631
- p2Changes.length = 0;
632
- p1AgeChanges.length = 0;
633
- p1NameChanges.length = 0;
634
- db.deleteDocs('person', []);
635
- expect(dbChanges).toEqual([]);
636
- db.deleteDocs('person', ['p1']);
637
- expect(dbChanges).toEqual([
638
- [
639
- { person: { p1: null } },
640
- {
641
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
642
- person: { p3: { age: 21, id: 'p3', name: 'mike' } },
643
- },
644
- {
645
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
646
- person: {
647
- p1: { age: 16, id: 'p1', name: 'jackson' },
648
- p3: { age: 21, id: 'p3', name: 'mike' },
649
- },
650
- },
651
- ],
652
- ]);
653
- expect(Object.keys(db.collection('person'))).toEqual(['p3']);
654
- db.undo();
655
- dbChanges.length = 0;
656
- personChanges.length = 0;
657
- p1Changes.length = 0;
658
- p2Changes.length = 0;
659
- p1AgeChanges.length = 0;
660
- p1NameChanges.length = 0;
661
- expect(Object.keys(db.collection('person'))).toEqual(['p3', 'p1']);
662
- expect(() => db.deleteDocs('person', ['p1', 'p2'])).toThrowError();
663
- expect(Object.keys(db.collection('person'))).toEqual(['p3', 'p1']);
664
- db.deleteDocs('person', ['p1', 'p3']);
665
- expect(Object.keys(db.collection('person'))).toEqual([]);
666
- expect(dbChanges).toEqual([
667
- [
668
- { person: { p1: null, p3: null } },
669
- {
670
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
671
- person: {},
672
- },
673
- {
674
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
675
- person: {
676
- p1: { age: 16, id: 'p1', name: 'jackson' },
677
- p3: { age: 21, id: 'p3', name: 'mike' },
678
- },
679
- },
680
- ],
681
- ]);
682
- db.undo();
683
- // update docs
684
- dbChanges.length = 0;
685
- personChanges.length = 0;
686
- p1Changes.length = 0;
687
- p2Changes.length = 0;
688
- p1AgeChanges.length = 0;
689
- p1NameChanges.length = 0;
690
- db.updateDocs('person', { p1: { age: 17 } });
691
- expect(db.toJSON()).toEqual({
692
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
693
- person: {
694
- p1: { age: 17, id: 'p1', name: 'jackson' },
695
- p3: { age: 21, id: 'p3', name: 'mike' },
696
- },
697
- });
698
- expect(dbChanges).toEqual([
699
- [
700
- { person: { p1: { age: 17 } } },
701
- {
702
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
703
- person: {
704
- p1: { age: 17, id: 'p1', name: 'jackson' },
705
- p3: { age: 21, id: 'p3', name: 'mike' },
706
- },
707
- },
708
- {
709
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
710
- person: {
711
- p1: { age: 16, id: 'p1', name: 'jackson' },
712
- p3: { age: 21, id: 'p3', name: 'mike' },
713
- },
714
- },
715
- ],
716
- ]);
717
- dbChanges.length = 0;
718
- personChanges.length = 0;
719
- p1Changes.length = 0;
720
- p2Changes.length = 0;
721
- p1AgeChanges.length = 0;
722
- p1NameChanges.length = 0;
723
- expect(() => db.updateDocs('person', { p1: { age: 18 }, p2: { age: 13 } })).toThrowError();
724
- expect(db.toJSON()).toEqual({
725
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
726
- person: {
727
- p1: { age: 17, id: 'p1', name: 'jackson' },
728
- p3: { age: 21, id: 'p3', name: 'mike' },
729
- },
730
- });
731
- expect(dbChanges).toEqual([]);
732
- db.updateDocs('person', (persons) => objectMap(persons, (x) => {
733
- return { age: x.age + 1 };
734
- }));
735
- expect(db.toJSON()).toEqual({
736
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
737
- person: {
738
- p1: { age: 18, id: 'p1', name: 'jackson' },
739
- p3: { age: 22, id: 'p3', name: 'mike' },
740
- },
741
- });
742
- expect(dbChanges).toEqual([
743
- [
744
- { person: { p1: { age: 18 }, p3: { age: 22 } } },
745
- {
746
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
747
- person: {
748
- p1: { age: 18, id: 'p1', name: 'jackson' },
749
- p3: { age: 22, id: 'p3', name: 'mike' },
750
- },
751
- },
752
- {
753
- city: { c1: { id: 'c1', location: [1, 2], name: 'austin' } },
754
- person: {
755
- p1: { age: 17, id: 'p1', name: 'jackson' },
756
- p3: { age: 21, id: 'p3', name: 'mike' },
757
- },
758
- },
759
- ],
760
- ]);
761
- dbChanges.length = 0;
762
- personChanges.length = 0;
763
- p1Changes.length = 0;
764
- p2Changes.length = 0;
765
- p1AgeChanges.length = 0;
766
- p1NameChanges.length = 0;
767
- //
768
- // define new collection
769
- //
770
- expect(db.collectionNames).toEqual(['person', 'city']);
771
- expect(db.collection('color')).toEqual(undefined);
772
- db.defineCollection('color', {
773
- fields: {
774
- id: { type: 'string' },
775
- name: { type: 'string', index: 'asc' },
776
- code: { type: 'number', index: 'desc' },
777
- },
778
- });
779
- expect(db.collectionNames).toEqual(['person', 'city', 'color']);
780
- const newDb = db;
781
- const colorChanges = [];
782
- newDb.subToCol('color', (next, prev, change, fields) => {
783
- colorChanges.push([next, prev, change, fields]);
784
- });
785
- expect(newDb.collection('color')).toEqual({});
786
- expect(() => newDb.docsOrderBy('color', 'id')).toThrow();
787
- expect(newDb.docsOrderBy('color', 'name')).toEqual([]);
788
- expect(newDb.docsOrderBy('color', 'code')).toEqual([]);
789
- const red = { id: 'red', name: 'Red', code: 0xff0000 };
790
- newDb.setDoc('color', red);
791
- expect(newDb.docsOrderBy('color', 'name')).toEqual([red]);
792
- expect(newDb.docsOrderBy('color', 'code')).toEqual([red]);
793
- expect(newDb.collection('color')).toEqual({ red });
794
- expect(colorChanges).toEqual([
795
- [
796
- { red: { code: 16711680, id: 'red', name: 'Red' } },
797
- {},
798
- { red: { code: 16711680, id: 'red', name: 'Red' } },
799
- { code: true, id: true, name: true },
800
- ],
801
- ]);
802
- colorChanges.length = 0;
803
- newDb.updateDoc('color', 'red', { code: 0xf00000 });
804
- expect(newDb.docsOrderBy('color', 'name')).toEqual([
805
- { ...red, code: 0xf00000 },
806
- ]);
807
- expect(newDb.docsOrderBy('color', 'code')).toEqual([
808
- { ...red, code: 0xf00000 },
809
- ]);
810
- expect(newDb.collection('color')).toEqual({
811
- red: { code: 0xf00000, id: 'red', name: 'Red' },
812
- });
813
- expect(colorChanges).toEqual([
814
- [
815
- { red: { code: 15728640, id: 'red', name: 'Red' } },
816
- { red: { code: 16711680, id: 'red', name: 'Red' } },
817
- { red: { code: 15728640 } },
818
- { code: true },
819
- ],
820
- ]);
821
- newDb.setDocs('color', [
822
- { id: 'blue', name: 'Blue', code: 0x0000ff },
823
- { id: 'yellow', name: 'Yellow', code: 0xffff00 },
824
- { id: 'green', name: 'Green', code: 0x00ff00 },
825
- ]);
826
- expect(newDb.docsOrderBy('color', 'code').map((x) => x.code)).toEqual([
827
- 16776960, 15728640, 65280, 255,
828
- ]);
829
- expect(newDb.docsOrderBy('color', 'name').map((x) => x.name)).toEqual([
830
- 'Blue',
831
- 'Green',
832
- 'Red',
833
- 'Yellow',
834
- ]);
835
- newDb.updateDoc('color', 'blue', { name: 'XXX', code: 0xffffff });
836
- expect(newDb.docsOrderBy('color', 'code').map((x) => x.code)).toEqual([
837
- 16777215, 16776960, 15728640, 65280,
838
- ]);
839
- expect(newDb.docsOrderBy('color', 'name').map((x) => x.name)).toEqual([
840
- 'Green',
841
- 'Red',
842
- 'XXX',
843
- 'Yellow',
844
- ]);
845
- newDb.deleteCollection('color');
846
- expect(db.collectionNames).toEqual(['person', 'city']);
847
- expect(newDb.collection('color')).toEqual(undefined);
848
- expect(() => {
849
- newDb.setDoc('color', { id: 'red', name: 'Red', code: 0xff0000 });
850
- }).toThrow();
851
- });
852
- test('LocalDB computes', () => {
853
- const initData = {
854
- person: {
855
- p1: { id: 'p1', age: 10, age2: 20, name: 'john', name_age: 'john_10' },
856
- p2: { id: 'p2', age: 18, age2: 36, name: 'sean', name_age: 'sean_18' },
857
- },
858
- };
859
- const db = new LocalDB({
860
- person: {
861
- fields: {
862
- id: { type: 'string' },
863
- age: { type: 'number' },
864
- age2: { type: 'number' },
865
- name: { type: 'string' },
866
- name_age: { type: 'string' },
867
- },
868
- computes: [
869
- {
870
- deps: ['age', 'name'],
871
- mutates: ['name_age'],
872
- compute(doc) {
873
- return {
874
- name_age: `${doc.name}_${doc.age}`,
875
- };
876
- },
877
- },
878
- {
879
- deps: ['name_age'],
880
- mutates: ['age', 'name'],
881
- compute(doc) {
882
- const i = doc.name_age.lastIndexOf('_');
883
- const name = doc.name_age.substring(0, i);
884
- const age = parseInt(doc.name_age.substring(i + 1), 10);
885
- return { name, age };
886
- },
887
- },
888
- {
889
- deps: ['age'],
890
- mutates: ['age2'],
891
- compute(doc) {
892
- return {
893
- age2: doc.age * 2,
894
- };
895
- },
896
- },
897
- {
898
- deps: ['age2'],
899
- mutates: ['age'],
900
- compute(doc) {
901
- return {
902
- age: doc.age2 / 2,
903
- };
904
- },
905
- },
906
- ],
907
- },
908
- }, initData, { undoable: true });
909
- expect(db.toJSON()).toEqual(initData);
910
- db.updateDoc('person', 'p1', { age: 12 });
911
- expect(db.doc('person', 'p1')).toEqual({
912
- age: 12,
913
- age2: 24,
914
- id: 'p1',
915
- name: 'john',
916
- name_age: 'john_12',
917
- });
918
- db.updateDoc('person', 'p1', { age: 20 });
919
- expect(db.doc('person', 'p1')).toEqual({
920
- age: 20,
921
- age2: 40,
922
- id: 'p1',
923
- name: 'john',
924
- name_age: 'john_20',
925
- });
926
- db.updateDoc('person', 'p1', { name: 'jack' });
927
- expect(db.doc('person', 'p1')).toEqual({
928
- age: 20,
929
- age2: 40,
930
- id: 'p1',
931
- name: 'jack',
932
- name_age: 'jack_20',
933
- });
934
- db.updateDoc('person', 'p1', { age: 11, name: 'sean' });
935
- expect(db.doc('person', 'p1')).toEqual({
936
- age: 11,
937
- age2: 22,
938
- id: 'p1',
939
- name: 'sean',
940
- name_age: 'sean_11',
941
- });
942
- db.updateDoc('person', 'p1', { name_age: 'john_12' });
943
- expect(db.doc('person', 'p1')).toEqual({
944
- age: 12,
945
- age2: 24,
946
- id: 'p1',
947
- name: 'john',
948
- name_age: 'john_12',
949
- });
950
- db.updateDoc('person', 'p1', { age2: 34 });
951
- expect(db.doc('person', 'p1')).toEqual({
952
- age: 17,
953
- age2: 34,
954
- id: 'p1',
955
- name: 'john',
956
- name_age: 'john_17',
957
- });
958
- expect(db.collection('person')).toEqual({
959
- p1: { age: 17, age2: 34, id: 'p1', name: 'john', name_age: 'john_17' },
960
- p2: { age: 18, age2: 36, id: 'p2', name: 'sean', name_age: 'sean_18' },
961
- });
962
- db.updateDocs('person', {
963
- p1: { name_age: 'jack_19' },
964
- p2: { name_age: 'tom_21' },
965
- }, { undoable: true });
966
- expect(db.collection('person')).toEqual({
967
- p1: { age: 19, age2: 38, id: 'p1', name: 'jack', name_age: 'jack_19' },
968
- p2: { age: 21, age2: 42, id: 'p2', name: 'tom', name_age: 'tom_21' },
969
- });
970
- db.undo();
971
- expect(db.collection('person')).toEqual({
972
- p1: { age: 17, age2: 34, id: 'p1', name: 'john', name_age: 'john_17' },
973
- p2: { age: 18, age2: 36, id: 'p2', name: 'sean', name_age: 'sean_18' },
974
- });
975
- db.redo();
976
- expect(db.collection('person')).toEqual({
977
- p1: { age: 19, age2: 38, id: 'p1', name: 'jack', name_age: 'jack_19' },
978
- p2: { age: 21, age2: 42, id: 'p2', name: 'tom', name_age: 'tom_21' },
979
- });
980
- db.undo();
981
- expect(db.collection('person')).toEqual({
982
- p1: { age: 17, age2: 34, id: 'p1', name: 'john', name_age: 'john_17' },
983
- p2: { age: 18, age2: 36, id: 'p2', name: 'sean', name_age: 'sean_18' },
984
- });
985
- db.redo();
986
- expect(db.collection('person')).toEqual({
987
- p1: { age: 19, age2: 38, id: 'p1', name: 'jack', name_age: 'jack_19' },
988
- p2: { age: 21, age2: 42, id: 'p2', name: 'tom', name_age: 'tom_21' },
989
- });
990
- db.updateDocs('person', {
991
- p1: { name_age: 'mike_23' },
992
- p2: { name_age: 'paul_27' },
993
- }, { undoable: true });
994
- expect(db.collection('person')).toEqual({
995
- p1: { age: 23, age2: 46, id: 'p1', name: 'mike', name_age: 'mike_23' },
996
- p2: { age: 27, age2: 54, id: 'p2', name: 'paul', name_age: 'paul_27' },
997
- });
998
- db.undo();
999
- expect(db.collection('person')).toEqual({
1000
- p1: { age: 19, age2: 38, id: 'p1', name: 'jack', name_age: 'jack_19' },
1001
- p2: { age: 21, age2: 42, id: 'p2', name: 'tom', name_age: 'tom_21' },
1002
- });
1003
- });
1004
- test('LocalDB foreignComputes', () => {
1005
- const initData = {
1006
- person: {
1007
- p1: { id: 'p1', name: 'jack', cars: [] },
1008
- },
1009
- car: {
1010
- c1: { id: 'c1', owner: null, name: 'bmw' },
1011
- },
1012
- };
1013
- const db = new LocalDB({
1014
- person: {
1015
- fields: {
1016
- id: { type: 'string' },
1017
- name: { type: 'string' },
1018
- cars: {
1019
- type: 'string[]',
1020
- normalize(list) {
1021
- return dedupKeys(list).sort((a, b) => a.localeCompare(b));
1022
- },
1023
- equals: arraysEqual,
1024
- },
1025
- },
1026
- foreignComputes: [
1027
- {
1028
- mutates: ['car'],
1029
- compute(db, updates) {
1030
- const carUpdates = {};
1031
- updates.map(({ next, prev }) => {
1032
- if (next?.cars !== prev?.cars) {
1033
- prev?.cars.forEach((carId) => {
1034
- carUpdates[carId] = { owner: null };
1035
- });
1036
- next?.cars.forEach((carId) => {
1037
- carUpdates[carId] = { owner: next.id };
1038
- });
1039
- }
1040
- });
1041
- db.updateDocs('car', carUpdates);
1042
- },
1043
- },
1044
- ],
1045
- },
1046
- car: {
1047
- fields: {
1048
- id: { type: 'string' },
1049
- name: { type: 'string', nullable: true },
1050
- owner: { type: 'string' },
1051
- },
1052
- foreignComputes: [
1053
- {
1054
- mutates: ['person'],
1055
- compute(db, updates) {
1056
- updates.map(({ next, prev }) => {
1057
- if (next?.owner !== prev?.owner) {
1058
- db.updateDocs('person', (persons) => {
1059
- const personUpdates = {};
1060
- if (prev?.owner) {
1061
- const p = persons[prev.owner];
1062
- if (p) {
1063
- personUpdates[p.id] = {
1064
- cars: p.cars.filter((x) => x !== prev.id),
1065
- };
1066
- }
1067
- }
1068
- if (next?.owner) {
1069
- const p = persons[next.owner];
1070
- if (p) {
1071
- personUpdates[p.id] = {
1072
- cars: [...p.cars, next.id],
1073
- };
1074
- }
1075
- }
1076
- return personUpdates;
1077
- });
1078
- }
1079
- });
1080
- },
1081
- },
1082
- ],
1083
- },
1084
- }, initData, { undoable: true });
1085
- expect(db.toJSON()).toEqual(initData);
1086
- db.updateDoc('person', 'p1', { cars: ['c1', 'c1'] }, { undoable: true });
1087
- expect(db.toJSON()).toEqual({
1088
- car: { c1: { id: 'c1', name: 'bmw', owner: 'p1' } },
1089
- person: { p1: { cars: ['c1'], id: 'p1', name: 'jack' } },
1090
- });
1091
- db.undo();
1092
- expect(db.toJSON()).toEqual({
1093
- car: { c1: { id: 'c1', name: 'bmw', owner: null } },
1094
- person: { p1: { cars: [], id: 'p1', name: 'jack' } },
1095
- });
1096
- db.redo();
1097
- expect(db.toJSON()).toEqual({
1098
- car: { c1: { id: 'c1', name: 'bmw', owner: 'p1' } },
1099
- person: { p1: { cars: ['c1'], id: 'p1', name: 'jack' } },
1100
- });
1101
- db.updateDoc('person', 'p1', { cars: [] }, { undoable: true });
1102
- expect(db.toJSON()).toEqual({
1103
- car: { c1: { id: 'c1', name: 'bmw', owner: null } },
1104
- person: { p1: { cars: [], id: 'p1', name: 'jack' } },
1105
- });
1106
- db.updateDoc('person', 'p1', { cars: [] }, { undoable: true });
1107
- expect(db.toJSON()).toEqual({
1108
- car: { c1: { id: 'c1', name: 'bmw', owner: null } },
1109
- person: { p1: { cars: [], id: 'p1', name: 'jack' } },
1110
- });
1111
- db.updateDoc('car', 'c1', { owner: 'p1' }, { undoable: true });
1112
- expect(db.toJSON()).toEqual({
1113
- car: { c1: { id: 'c1', name: 'bmw', owner: 'p1' } },
1114
- person: { p1: { cars: ['c1'], id: 'p1', name: 'jack' } },
1115
- });
1116
- db.undo();
1117
- expect(db.toJSON()).toEqual({
1118
- car: { c1: { id: 'c1', name: 'bmw', owner: null } },
1119
- person: { p1: { cars: [], id: 'p1', name: 'jack' } },
1120
- });
1121
- db.redo();
1122
- expect(db.toJSON()).toEqual({
1123
- car: { c1: { id: 'c1', name: 'bmw', owner: 'p1' } },
1124
- person: { p1: { cars: ['c1'], id: 'p1', name: 'jack' } },
1125
- });
1126
- db.updateDoc('car', 'c1', { owner: null }, { undoable: true });
1127
- expect(db.toJSON()).toEqual({
1128
- car: { c1: { id: 'c1', name: 'bmw', owner: null } },
1129
- person: { p1: { cars: [], id: 'p1', name: 'jack' } },
1130
- });
1131
- db.undo();
1132
- expect(db.toJSON()).toEqual({
1133
- car: { c1: { id: 'c1', name: 'bmw', owner: 'p1' } },
1134
- person: { p1: { cars: ['c1'], id: 'p1', name: 'jack' } },
1135
- });
1136
- });
1137
- });
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes