tinybase 1.0.4 → 1.1.0-beta.2
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/lib/checkpoints.d.ts +44 -0
- package/lib/checkpoints.js +1 -1
- package/lib/checkpoints.js.gz +0 -0
- package/lib/debug/checkpoints.d.ts +44 -0
- package/lib/debug/checkpoints.js +13 -6
- package/lib/debug/indexes.d.ts +114 -1
- package/lib/debug/indexes.js +29 -2
- package/lib/debug/metrics.d.ts +46 -0
- package/lib/debug/metrics.js +8 -2
- package/lib/debug/relationships.d.ts +63 -1
- package/lib/debug/relationships.js +14 -2
- package/lib/debug/store.d.ts +269 -5
- package/lib/debug/store.js +243 -185
- package/lib/debug/tinybase.js +285 -189
- package/lib/indexes.d.ts +114 -1
- package/lib/indexes.js +1 -1
- package/lib/indexes.js.gz +0 -0
- package/lib/metrics.d.ts +46 -0
- package/lib/metrics.js +1 -1
- package/lib/metrics.js.gz +0 -0
- package/lib/relationships.d.ts +63 -1
- package/lib/relationships.js +1 -1
- package/lib/relationships.js.gz +0 -0
- package/lib/store.d.ts +269 -5
- package/lib/store.js +1 -1
- package/lib/store.js.gz +0 -0
- package/lib/tinybase.js +1 -1
- package/lib/tinybase.js.gz +0 -0
- package/lib/umd/checkpoints.js +1 -1
- package/lib/umd/checkpoints.js.gz +0 -0
- package/lib/umd/indexes.js +1 -1
- package/lib/umd/indexes.js.gz +0 -0
- package/lib/umd/metrics.js +1 -1
- package/lib/umd/metrics.js.gz +0 -0
- package/lib/umd/relationships.js +1 -1
- package/lib/umd/relationships.js.gz +0 -0
- package/lib/umd/store.js +1 -1
- package/lib/umd/store.js.gz +0 -0
- package/lib/umd/tinybase.js +1 -1
- package/lib/umd/tinybase.js.gz +0 -0
- package/package.json +20 -19
- package/readme.md +2 -2
package/lib/checkpoints.d.ts
CHANGED
|
@@ -33,6 +33,20 @@ import {Store} from './store.d';
|
|
|
33
33
|
*/
|
|
34
34
|
export type CheckpointIds = [Ids, Id | undefined, Ids];
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* The CheckpointCallback type describes a function that takes a Checkpoint's
|
|
38
|
+
* Id.
|
|
39
|
+
*
|
|
40
|
+
* A CheckpointCallback is provided when using the forEachCheckpoint method,
|
|
41
|
+
* so that you can do something based on every Checkpoint in the Checkpoints
|
|
42
|
+
* object. See that method for specific examples.
|
|
43
|
+
*
|
|
44
|
+
* @param checkpointId The Id of the Checkpoint that the callback can operate
|
|
45
|
+
* on.
|
|
46
|
+
* @category Callback
|
|
47
|
+
*/
|
|
48
|
+
export type CheckpointCallback = (checkpointId: Id, label?: string) => void;
|
|
49
|
+
|
|
36
50
|
/**
|
|
37
51
|
* The CheckpointIdsListener type describes a function that is used to listen to
|
|
38
52
|
* changes to the checkpoint Ids in a Checkpoints object.
|
|
@@ -353,6 +367,36 @@ export interface Checkpoints {
|
|
|
353
367
|
*/
|
|
354
368
|
getCheckpointIds(): CheckpointIds;
|
|
355
369
|
|
|
370
|
+
/**
|
|
371
|
+
* The forEachCheckpoint method takes a function that it will then call for
|
|
372
|
+
* each Checkpoint in a specified Checkpoints object.
|
|
373
|
+
*
|
|
374
|
+
* This method is useful for iterating over the structure of the Checkpoints
|
|
375
|
+
* object in a functional style. The `checkpointCallback` parameter is a
|
|
376
|
+
* CheckpointCallback function that will be called with the Id of each
|
|
377
|
+
* Checkpoint.
|
|
378
|
+
*
|
|
379
|
+
* @param checkpointCallback The function that should be called for every
|
|
380
|
+
* Checkpoint.
|
|
381
|
+
* @example
|
|
382
|
+
* This example iterates over each Checkpoint in a Checkpoints object.
|
|
383
|
+
*
|
|
384
|
+
* ```js
|
|
385
|
+
* const store = createStore().setTables({pets: {fido: {sold: false}}});
|
|
386
|
+
* const checkpoints = createCheckpoints(store);
|
|
387
|
+
* store.setCell('pets', 'fido', 'sold', true);
|
|
388
|
+
* checkpoints.addCheckpoint('sale');
|
|
389
|
+
*
|
|
390
|
+
* checkpoints.forEachCheckpoint((checkpointId, label) => {
|
|
391
|
+
* console.log(`${checkpointId}:${label}`);
|
|
392
|
+
* });
|
|
393
|
+
* // -> '0:'
|
|
394
|
+
* // -> '1:sale'
|
|
395
|
+
* ```
|
|
396
|
+
* @category Iterator
|
|
397
|
+
*/
|
|
398
|
+
forEachCheckpoint(checkpointCallback: CheckpointCallback): void;
|
|
399
|
+
|
|
356
400
|
/**
|
|
357
401
|
* The hasCheckpoint method returns a boolean indicating whether a given
|
|
358
402
|
* Checkpoint exists in the Checkpoints object.
|
package/lib/checkpoints.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=(e,t)=>e.includes(t),t=(e,t)=>e.forEach(t),n=e=>e.length,s=e=>0==n(e),o=e=>e.slice(1),r=e=>null==e,
|
|
1
|
+
const e=(e,t)=>e.includes(t),t=(e,t)=>e.forEach(t),n=e=>e.length,s=e=>0==n(e),o=e=>e.slice(1),r=(e,t)=>e.push(t),c=e=>e.pop(),l=e=>null==e,i=(e,t,n)=>l(e)?n?.():t(e),d=(e,t)=>e?.has(t)??!1,a=e=>l(e)||0==(e=>e.size)(e),h=(e,t)=>e?.forEach(t),u=(e,t)=>e?.delete(t),p=e=>new Map(e),C=(e,t)=>e?.get(t),g=(e,t,n)=>l(n)?(u(e,t),e):e?.set(t,n),k=(e,t,n,s)=>(d(e,t)||(s?.(n),e.set(t,n)),C(e,t)),f=e=>new Set(e),L=(e,t,r)=>n(r)<2?((e,t)=>e?.add(t))(s(r)?e:k(e,r[0],f()),t):L(k(e,r[0],p()),t,o(r)),v=e=>{const n=(r,c,...l)=>i(r,(r=>s(l)?e(r,c):t([l[0],null],(e=>n(C(r,e),c,...o(l))))));return n},w=Object.freeze,S=(e=>{const t=new WeakMap;return n=>(t.has(n)||t.set(n,e(n)),t.get(n))})((o=>{let S,z,E,I=100,M=p(),b=1;const j=f(),x=p(),[y,B,F]=(e=>{let s,o=0;const d=[],a=p();return[(t,n,r=[])=>{s??=e();const l=c(d)??""+o++;return g(a,l,[t,n,r]),L(n,l,r),l},(e,t=[],...n)=>v(h)(e,(e=>i(C(a,e),(([e])=>e(s,...t,...n)))),...t),e=>i(C(a,e),(([,t,s])=>(v(u)(t,e,...s),g(a,e),n(d)<1e3&&r(d,e),s)),(()=>[])),(e,o,r)=>i(C(a,e),(([e,,c])=>{const i=(...d)=>{const a=n(d);a==n(c)?e(s,...d,...r(d)):l(c[a])?t(o[a](...d),(e=>i(...d,e))):i(...d,c[a])};i()}))]})((()=>V)),O=p(),T=p(),W=[],m=[],q=(e,t)=>{b=0,o.transaction((()=>h(C(O,t),((t,n)=>h(t,((t,s)=>h(t,((t,r)=>l(t[e])?o.delCell(n,s,r,!0):o.setCell(n,s,r,t[e]))))))))),b=1},A=e=>{g(O,e),g(T,e),B(x,[e])},D=(e,s)=>t(((e,t)=>e.splice(0,t))(e,s??n(e)),A),G=()=>D(W,n(W)-I),H=o.addCellListener(null,null,null,((e,t,n,s,o,l)=>{if(b){i(S,(()=>{r(W,S),G(),D(m),S=void 0,E=1}));const e=k(M,t,p()),d=k(e,n,p()),h=k(d,s,[void 0,void 0],(e=>e[0]=l));h[1]=o,h[0]===h[1]&&a(g(d,s))&&a(g(e,n))&&a(g(M,t))&&(S=c(W),E=1),P()}})),J=(e="")=>(l(S)&&(S=""+z++,g(O,S,M),R(S,e),M=p(),E=1),S),K=()=>{s(W)||(m.unshift(J()),q(0,S),S=c(W),E=1)},N=()=>{s(m)||(r(W,S),S=m.shift(),q(1,S),E=1)},P=()=>{E&&(B(j),E=0)},Q=e=>{const t=J(e);return P(),t},R=(e,t)=>(U(e)&&C(T,e)!==t&&(g(T,e,t),B(x,[e])),V),U=e=>d(O,e),V={setSize:e=>(I=e,G(),V),addCheckpoint:Q,setCheckpoint:R,getStore:()=>o,getCheckpointIds:()=>[[...W],S,[...m]],forEachCheckpoint:e=>{return t=e,h(T,((e,n)=>t(n,e)));var t},hasCheckpoint:U,getCheckpoint:e=>C(T,e),goBackward:()=>(K(),P(),V),goForward:()=>(N(),P(),V),goTo:t=>{const n=e(W,t)?K:e(m,t)?N:null;for(;!l(n)&&t!=S;)n();return P(),V},addCheckpointIdsListener:e=>y(e,j),addCheckpointListener:(e,t)=>y(t,x,[e]),delListener:e=>(F(e),V),clear:()=>(D(W),D(m),l(S)||A(S),S=void 0,z=0,Q(),V),destroy:()=>{o.delListener(H)},getListenerStats:()=>({})};return w(V.clear())}));export{S as createCheckpoints};
|
package/lib/checkpoints.js.gz
CHANGED
|
Binary file
|
|
@@ -33,6 +33,20 @@ import {Store} from './store.d';
|
|
|
33
33
|
*/
|
|
34
34
|
export type CheckpointIds = [Ids, Id | undefined, Ids];
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* The CheckpointCallback type describes a function that takes a Checkpoint's
|
|
38
|
+
* Id.
|
|
39
|
+
*
|
|
40
|
+
* A CheckpointCallback is provided when using the forEachCheckpoint method,
|
|
41
|
+
* so that you can do something based on every Checkpoint in the Checkpoints
|
|
42
|
+
* object. See that method for specific examples.
|
|
43
|
+
*
|
|
44
|
+
* @param checkpointId The Id of the Checkpoint that the callback can operate
|
|
45
|
+
* on.
|
|
46
|
+
* @category Callback
|
|
47
|
+
*/
|
|
48
|
+
export type CheckpointCallback = (checkpointId: Id, label?: string) => void;
|
|
49
|
+
|
|
36
50
|
/**
|
|
37
51
|
* The CheckpointIdsListener type describes a function that is used to listen to
|
|
38
52
|
* changes to the checkpoint Ids in a Checkpoints object.
|
|
@@ -353,6 +367,36 @@ export interface Checkpoints {
|
|
|
353
367
|
*/
|
|
354
368
|
getCheckpointIds(): CheckpointIds;
|
|
355
369
|
|
|
370
|
+
/**
|
|
371
|
+
* The forEachCheckpoint method takes a function that it will then call for
|
|
372
|
+
* each Checkpoint in a specified Checkpoints object.
|
|
373
|
+
*
|
|
374
|
+
* This method is useful for iterating over the structure of the Checkpoints
|
|
375
|
+
* object in a functional style. The `checkpointCallback` parameter is a
|
|
376
|
+
* CheckpointCallback function that will be called with the Id of each
|
|
377
|
+
* Checkpoint.
|
|
378
|
+
*
|
|
379
|
+
* @param checkpointCallback The function that should be called for every
|
|
380
|
+
* Checkpoint.
|
|
381
|
+
* @example
|
|
382
|
+
* This example iterates over each Checkpoint in a Checkpoints object.
|
|
383
|
+
*
|
|
384
|
+
* ```js
|
|
385
|
+
* const store = createStore().setTables({pets: {fido: {sold: false}}});
|
|
386
|
+
* const checkpoints = createCheckpoints(store);
|
|
387
|
+
* store.setCell('pets', 'fido', 'sold', true);
|
|
388
|
+
* checkpoints.addCheckpoint('sale');
|
|
389
|
+
*
|
|
390
|
+
* checkpoints.forEachCheckpoint((checkpointId, label) => {
|
|
391
|
+
* console.log(`${checkpointId}:${label}`);
|
|
392
|
+
* });
|
|
393
|
+
* // -> '0:'
|
|
394
|
+
* // -> '1:sale'
|
|
395
|
+
* ```
|
|
396
|
+
* @category Iterator
|
|
397
|
+
*/
|
|
398
|
+
forEachCheckpoint(checkpointCallback: CheckpointCallback): void;
|
|
399
|
+
|
|
356
400
|
/**
|
|
357
401
|
* The hasCheckpoint method returns a boolean indicating whether a given
|
|
358
402
|
* Checkpoint exists in the Checkpoints object.
|
package/lib/debug/checkpoints.js
CHANGED
|
@@ -5,6 +5,8 @@ const arrayIsEmpty = (array) => arrayLength(array) == 0;
|
|
|
5
5
|
const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
|
|
6
6
|
const arrayFromSecond = (ids) => ids.slice(1);
|
|
7
7
|
const arrayClear = (array, to) => array.splice(0, to);
|
|
8
|
+
const arrayPush = (array, value) => array.push(value);
|
|
9
|
+
const arrayPop = (array) => array.pop();
|
|
8
10
|
|
|
9
11
|
const isUndefined = (thing) => thing == void 0;
|
|
10
12
|
const ifNotUndefined = (value, then, otherwise) =>
|
|
@@ -22,6 +24,8 @@ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
|
|
|
22
24
|
|
|
23
25
|
const mapNew = (entries) => new Map(entries);
|
|
24
26
|
const mapGet = (map, key) => map?.get(key);
|
|
27
|
+
const mapForEach = (map, cb) =>
|
|
28
|
+
collForEach(map, (value, key) => cb(key, value));
|
|
25
29
|
const mapSet = (map, key, value) =>
|
|
26
30
|
isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
|
|
27
31
|
const mapEnsure = (map, key, defaultValue, onWillAdd) => {
|
|
@@ -74,7 +78,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
74
78
|
const allListeners = mapNew();
|
|
75
79
|
const addListener = (listener, deepSet, idOrNulls = []) => {
|
|
76
80
|
thing ??= getThing();
|
|
77
|
-
const id = listenerPool
|
|
81
|
+
const id = arrayPop(listenerPool) ?? '' + nextId++;
|
|
78
82
|
mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
|
|
79
83
|
addDeepSet(deepSet, id, idOrNulls);
|
|
80
84
|
return id;
|
|
@@ -95,7 +99,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
95
99
|
forDeepSet(collDel)(deepSet, id, ...idOrNulls);
|
|
96
100
|
mapSet(allListeners, id);
|
|
97
101
|
if (arrayLength(listenerPool) < 1e3) {
|
|
98
|
-
listenerPool
|
|
102
|
+
arrayPush(listenerPool, id);
|
|
99
103
|
}
|
|
100
104
|
return idOrNulls;
|
|
101
105
|
},
|
|
@@ -171,7 +175,7 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
171
175
|
(_store, tableId, rowId, cellId, newCell, oldCell) => {
|
|
172
176
|
if (listening) {
|
|
173
177
|
ifNotUndefined(currentId, () => {
|
|
174
|
-
backwardIds
|
|
178
|
+
arrayPush(backwardIds, currentId);
|
|
175
179
|
trimBackwardsIds();
|
|
176
180
|
clearCheckpointIds(forwardIds);
|
|
177
181
|
currentId = void 0;
|
|
@@ -190,7 +194,7 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
190
194
|
if (collIsEmpty(mapSet(row, cellId))) {
|
|
191
195
|
if (collIsEmpty(mapSet(table, rowId))) {
|
|
192
196
|
if (collIsEmpty(mapSet(delta, tableId))) {
|
|
193
|
-
currentId = backwardIds
|
|
197
|
+
currentId = arrayPop(backwardIds);
|
|
194
198
|
checkpointsChanged = 1;
|
|
195
199
|
}
|
|
196
200
|
}
|
|
@@ -214,13 +218,13 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
214
218
|
if (!arrayIsEmpty(backwardIds)) {
|
|
215
219
|
forwardIds.unshift(addCheckpointImpl());
|
|
216
220
|
updateStore(0, currentId);
|
|
217
|
-
currentId = backwardIds
|
|
221
|
+
currentId = arrayPop(backwardIds);
|
|
218
222
|
checkpointsChanged = 1;
|
|
219
223
|
}
|
|
220
224
|
};
|
|
221
225
|
const goForwardImpl = () => {
|
|
222
226
|
if (!arrayIsEmpty(forwardIds)) {
|
|
223
|
-
backwardIds
|
|
227
|
+
arrayPush(backwardIds, currentId);
|
|
224
228
|
currentId = forwardIds.shift();
|
|
225
229
|
updateStore(1, currentId);
|
|
226
230
|
checkpointsChanged = 1;
|
|
@@ -251,6 +255,8 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
251
255
|
};
|
|
252
256
|
const getStore = () => store;
|
|
253
257
|
const getCheckpointIds = () => [[...backwardIds], currentId, [...forwardIds]];
|
|
258
|
+
const forEachCheckpoint = (checkpointCallback) =>
|
|
259
|
+
mapForEach(labels, checkpointCallback);
|
|
254
260
|
const hasCheckpoint = (checkpointId) => collHas(deltas, checkpointId);
|
|
255
261
|
const getCheckpoint = (checkpointId) => mapGet(labels, checkpointId);
|
|
256
262
|
const goBackward = () => {
|
|
@@ -307,6 +313,7 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
307
313
|
setCheckpoint,
|
|
308
314
|
getStore,
|
|
309
315
|
getCheckpointIds,
|
|
316
|
+
forEachCheckpoint,
|
|
310
317
|
hasCheckpoint,
|
|
311
318
|
getCheckpoint,
|
|
312
319
|
goBackward,
|
package/lib/debug/indexes.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @module indexes
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {GetCell, Store} from './store.d';
|
|
14
|
+
import {GetCell, RowCallback, Store} from './store.d';
|
|
15
15
|
import {Id, IdOrNull, Ids, SortKey} from './common.d';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -43,6 +43,42 @@ export type Index = {[sliceId: Id]: Slice};
|
|
|
43
43
|
*/
|
|
44
44
|
export type Slice = Ids;
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* The IndexCallback type describes a function that takes an Index's Id and a
|
|
48
|
+
* callback to loop over each Slice within it.
|
|
49
|
+
*
|
|
50
|
+
* A IndexCallback is provided when using the forEachIndex method, so that you
|
|
51
|
+
* can do something based on every Index in the Indexes object. See that method
|
|
52
|
+
* for specific examples.
|
|
53
|
+
*
|
|
54
|
+
* @param indexId The Id of the Index that the callback can operate on.
|
|
55
|
+
* @param forEachRow A function that will let you iterate over the Slice objects
|
|
56
|
+
* in this Index.
|
|
57
|
+
* @category Callback
|
|
58
|
+
*/
|
|
59
|
+
export type IndexCallback = (
|
|
60
|
+
indexId: Id,
|
|
61
|
+
forEachSlice: (sliceCallback: SliceCallback) => void,
|
|
62
|
+
) => void;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The SliceCallback type describes a function that takes a Slice's Id and a
|
|
66
|
+
* callback to loop over each Row within it.
|
|
67
|
+
*
|
|
68
|
+
* A SliceCallback is provided when using the forEachSlice method, so that you
|
|
69
|
+
* can do something based on every Slice in an Index. See that method for
|
|
70
|
+
* specific examples.
|
|
71
|
+
*
|
|
72
|
+
* @param sliceId The Id of the Slice that the callback can operate on.
|
|
73
|
+
* @param forEachRow A function that will let you iterate over the Row objects
|
|
74
|
+
* in this Slice.
|
|
75
|
+
* @category Callback
|
|
76
|
+
*/
|
|
77
|
+
export type SliceCallback = (
|
|
78
|
+
sliceId: Id,
|
|
79
|
+
forEachRow: (rowCallback: RowCallback) => void,
|
|
80
|
+
) => void;
|
|
81
|
+
|
|
46
82
|
/**
|
|
47
83
|
* The SliceIdsListener type describes a function that is used to listen to
|
|
48
84
|
* changes to the Slice Ids in an Index.
|
|
@@ -362,6 +398,83 @@ export interface Indexes {
|
|
|
362
398
|
*/
|
|
363
399
|
getIndexIds(): Ids;
|
|
364
400
|
|
|
401
|
+
/**
|
|
402
|
+
* The forEachIndex method takes a function that it will then call for each
|
|
403
|
+
* Index in a specified Indexes object.
|
|
404
|
+
*
|
|
405
|
+
* This method is useful for iterating over the structure of the Indexes
|
|
406
|
+
* object in a functional style. The `indexCallback` parameter is a
|
|
407
|
+
* IndexCallback function that will be called with the Id of each Index, and
|
|
408
|
+
* with a function that can then be used to iterate over each Slice of the
|
|
409
|
+
* Index, should you wish.
|
|
410
|
+
*
|
|
411
|
+
* @param indexCallback The function that should be called for every Index.
|
|
412
|
+
* @example
|
|
413
|
+
* This example iterates over each Index in an Indexes object, and lists each
|
|
414
|
+
* Slice Id within them.
|
|
415
|
+
*
|
|
416
|
+
* ```js
|
|
417
|
+
* const store = createStore().setTable('pets', {
|
|
418
|
+
* fido: {species: 'dog', color: 'brown'},
|
|
419
|
+
* felix: {species: 'cat', color: 'black'},
|
|
420
|
+
* cujo: {species: 'dog', color: 'black'},
|
|
421
|
+
* });
|
|
422
|
+
* const indexes = createIndexes(store)
|
|
423
|
+
* .setIndexDefinition('bySpecies', 'pets', 'species')
|
|
424
|
+
* .setIndexDefinition('byColor', 'pets', 'color');
|
|
425
|
+
*
|
|
426
|
+
* indexes.forEachIndex((indexId, forEachSlice) => {
|
|
427
|
+
* console.log(indexId);
|
|
428
|
+
* forEachSlice((sliceId) => console.log(`- ${sliceId}`));
|
|
429
|
+
* });
|
|
430
|
+
* // -> 'bySpecies'
|
|
431
|
+
* // -> '- dog'
|
|
432
|
+
* // -> '- cat'
|
|
433
|
+
* // -> 'byColor'
|
|
434
|
+
* // -> '- brown'
|
|
435
|
+
* // -> '- black'
|
|
436
|
+
* ```
|
|
437
|
+
* @category Iterator
|
|
438
|
+
*/
|
|
439
|
+
forEachIndex(indexCallback: IndexCallback): void;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* The forEachSlice method takes a function that it will then call for each
|
|
443
|
+
* Slice in a specified Index.
|
|
444
|
+
*
|
|
445
|
+
* This method is useful for iterating over the Slice structure of the Index
|
|
446
|
+
* in a functional style. The `rowCallback` parameter is a RowCallback
|
|
447
|
+
* function that will be called with the Id and value of each Row in the
|
|
448
|
+
* Slice.
|
|
449
|
+
*
|
|
450
|
+
* @param indexId The Id of the Index to iterate over.
|
|
451
|
+
* @param sliceCallback The function that should be called for every Slice.
|
|
452
|
+
* @example
|
|
453
|
+
* This example iterates over each Row in a Slice, and lists its Id.
|
|
454
|
+
*
|
|
455
|
+
* ```js
|
|
456
|
+
* const store = createStore().setTable('pets', {
|
|
457
|
+
* fido: {species: 'dog'},
|
|
458
|
+
* felix: {species: 'cat'},
|
|
459
|
+
* cujo: {species: 'dog'},
|
|
460
|
+
* });
|
|
461
|
+
* const indexes = createIndexes(store);
|
|
462
|
+
* indexes.setIndexDefinition('bySpecies', 'pets', 'species');
|
|
463
|
+
*
|
|
464
|
+
* indexes.forEachSlice('bySpecies', (sliceId, forEachRow) => {
|
|
465
|
+
* console.log(sliceId);
|
|
466
|
+
* forEachRow((rowId) => console.log(`- ${rowId}`));
|
|
467
|
+
* });
|
|
468
|
+
* // -> 'dog'
|
|
469
|
+
* // -> '- fido'
|
|
470
|
+
* // -> '- cujo'
|
|
471
|
+
* // -> 'cat'
|
|
472
|
+
* // -> '- felix'
|
|
473
|
+
* ```
|
|
474
|
+
* @category Iterator
|
|
475
|
+
*/
|
|
476
|
+
forEachSlice(indexId: Id, sliceCallback: SliceCallback): void;
|
|
477
|
+
|
|
365
478
|
/**
|
|
366
479
|
* The hasIndex method returns a boolean indicating whether a given Index
|
|
367
480
|
* exists in the Indexes object.
|
package/lib/debug/indexes.js
CHANGED
|
@@ -12,6 +12,8 @@ const arrayLength = (array) => array.length;
|
|
|
12
12
|
const arrayIsEmpty = (array) => arrayLength(array) == 0;
|
|
13
13
|
const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
|
|
14
14
|
const arrayFromSecond = (ids) => ids.slice(1);
|
|
15
|
+
const arrayPush = (array, value) => array.push(value);
|
|
16
|
+
const arrayPop = (array) => array.pop();
|
|
15
17
|
|
|
16
18
|
const isUndefined = (thing) => thing == void 0;
|
|
17
19
|
const ifNotUndefined = (value, then, otherwise) =>
|
|
@@ -57,6 +59,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
|
|
|
57
59
|
const storeListenerIds = mapNew();
|
|
58
60
|
const getStore = () => store;
|
|
59
61
|
const getThingIds = () => mapKeys(tableIds);
|
|
62
|
+
const forEachThing = (cb) => mapForEach(things, cb);
|
|
60
63
|
const hasThing = (id) => collHas(things, id);
|
|
61
64
|
const getTableId = (id) => mapGet(tableIds, id);
|
|
62
65
|
const getThing = (id) => mapGet(things, id);
|
|
@@ -147,6 +150,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
|
|
|
147
150
|
return [
|
|
148
151
|
getStore,
|
|
149
152
|
getThingIds,
|
|
153
|
+
forEachThing,
|
|
150
154
|
hasThing,
|
|
151
155
|
getTableId,
|
|
152
156
|
getThing,
|
|
@@ -201,7 +205,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
201
205
|
const allListeners = mapNew();
|
|
202
206
|
const addListener = (listener, deepSet, idOrNulls = []) => {
|
|
203
207
|
thing ??= getThing();
|
|
204
|
-
const id = listenerPool
|
|
208
|
+
const id = arrayPop(listenerPool) ?? '' + nextId++;
|
|
205
209
|
mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
|
|
206
210
|
addDeepSet(deepSet, id, idOrNulls);
|
|
207
211
|
return id;
|
|
@@ -222,7 +226,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
222
226
|
forDeepSet(collDel)(deepSet, id, ...idOrNulls);
|
|
223
227
|
mapSet(allListeners, id);
|
|
224
228
|
if (arrayLength(listenerPool) < 1e3) {
|
|
225
|
-
listenerPool
|
|
229
|
+
arrayPush(listenerPool, id);
|
|
226
230
|
}
|
|
227
231
|
return idOrNulls;
|
|
228
232
|
},
|
|
@@ -254,6 +258,7 @@ const createIndexes = getCreateFunction((store) => {
|
|
|
254
258
|
const [
|
|
255
259
|
getStore,
|
|
256
260
|
getIndexIds,
|
|
261
|
+
forEachIndexImpl,
|
|
257
262
|
hasIndex,
|
|
258
263
|
getTableId,
|
|
259
264
|
getIndex,
|
|
@@ -363,6 +368,26 @@ const createIndexes = getCreateFunction((store) => {
|
|
|
363
368
|
);
|
|
364
369
|
return indexes;
|
|
365
370
|
};
|
|
371
|
+
const forEachIndex = (indexCallback) =>
|
|
372
|
+
forEachIndexImpl((indexId, slices) =>
|
|
373
|
+
indexCallback(indexId, (sliceCallback) =>
|
|
374
|
+
forEachSliceImpl(indexId, sliceCallback, slices),
|
|
375
|
+
),
|
|
376
|
+
);
|
|
377
|
+
const forEachSlice = (indexId, sliceCallback) =>
|
|
378
|
+
forEachSliceImpl(indexId, sliceCallback, getIndex(indexId));
|
|
379
|
+
const forEachSliceImpl = (indexId, sliceCallback, slices) => {
|
|
380
|
+
const tableId = getTableId(indexId);
|
|
381
|
+
collForEach(slices, (rowIds, sliceId) =>
|
|
382
|
+
sliceCallback(sliceId, (rowCallback) =>
|
|
383
|
+
collForEach(rowIds, (rowId) =>
|
|
384
|
+
rowCallback(rowId, (cellCallback) =>
|
|
385
|
+
store.forEachCell(tableId, rowId, cellCallback),
|
|
386
|
+
),
|
|
387
|
+
),
|
|
388
|
+
),
|
|
389
|
+
);
|
|
390
|
+
};
|
|
366
391
|
const delIndexDefinition = (indexId) => {
|
|
367
392
|
delDefinition(indexId);
|
|
368
393
|
return indexes;
|
|
@@ -387,6 +412,8 @@ const createIndexes = getCreateFunction((store) => {
|
|
|
387
412
|
delIndexDefinition,
|
|
388
413
|
getStore,
|
|
389
414
|
getIndexIds,
|
|
415
|
+
forEachIndex,
|
|
416
|
+
forEachSlice,
|
|
390
417
|
hasIndex,
|
|
391
418
|
hasSlice,
|
|
392
419
|
getTableId,
|
package/lib/debug/metrics.d.ts
CHANGED
|
@@ -22,6 +22,20 @@ import {Id, IdOrNull, Ids} from './common.d';
|
|
|
22
22
|
*/
|
|
23
23
|
export type Metric = number;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* The MetricCallback type describes a function that takes a Metric's Id and a
|
|
27
|
+
* callback to loop over each Row within it.
|
|
28
|
+
*
|
|
29
|
+
* A MetricCallback is provided when using the forEachMetric method, so that you
|
|
30
|
+
* can do something based on every Metric in the Metrics object. See that method
|
|
31
|
+
* for specific examples.
|
|
32
|
+
*
|
|
33
|
+
* @param metricId The Id of the Metric that the callback can operate on.
|
|
34
|
+
* @param metric The value of the Metric.
|
|
35
|
+
* @category Callback
|
|
36
|
+
*/
|
|
37
|
+
export type MetricCallback = (metricId: Id, metric?: Metric) => void;
|
|
38
|
+
|
|
25
39
|
/**
|
|
26
40
|
* The Aggregate type describes a custom function that takes an array or numbers
|
|
27
41
|
* and returns an aggregate that is used as a Metric.
|
|
@@ -478,6 +492,38 @@ export interface Metrics {
|
|
|
478
492
|
*/
|
|
479
493
|
getMetricIds(): Ids;
|
|
480
494
|
|
|
495
|
+
/**
|
|
496
|
+
* The forEachMetric method takes a function that it will then call for each
|
|
497
|
+
* Metric in the Metrics object.
|
|
498
|
+
*
|
|
499
|
+
* This method is useful for iterating over all the Metrics in a functional
|
|
500
|
+
* style. The `metricCallback` parameter is a MetricCallback function that
|
|
501
|
+
* will be called with the Id of each Metric and its value.
|
|
502
|
+
*
|
|
503
|
+
* @param metricCallback The function that should be called for every Metric.
|
|
504
|
+
* @example
|
|
505
|
+
* This example iterates over each Metric in a Metrics object.
|
|
506
|
+
*
|
|
507
|
+
* ```js
|
|
508
|
+
* const store = createStore().setTable('species', {
|
|
509
|
+
* dog: {price: 5},
|
|
510
|
+
* cat: {price: 4},
|
|
511
|
+
* worm: {price: 1},
|
|
512
|
+
* });
|
|
513
|
+
* const metrics = createMetrics(store)
|
|
514
|
+
* .setMetricDefinition('highestPrice', 'species', 'max', 'price')
|
|
515
|
+
* .setMetricDefinition('lowestPrice', 'species', 'min', 'price');
|
|
516
|
+
*
|
|
517
|
+
* metrics.forEachMetric((metricId, metric) => {
|
|
518
|
+
* console.log([metricId, metric]);
|
|
519
|
+
* });
|
|
520
|
+
* // -> ['highestPrice', 5]
|
|
521
|
+
* // -> ['lowestPrice', 1]
|
|
522
|
+
* ```
|
|
523
|
+
* @category Iterator
|
|
524
|
+
*/
|
|
525
|
+
forEachMetric(metricCallback: MetricCallback): void;
|
|
526
|
+
|
|
481
527
|
/**
|
|
482
528
|
* The hasMetric method returns a boolean indicating whether a given Metric
|
|
483
529
|
* exists in the Metrics object, and has a value.
|
package/lib/debug/metrics.js
CHANGED
|
@@ -13,6 +13,8 @@ const arrayLength = (array) => array.length;
|
|
|
13
13
|
const arrayIsEmpty = (array) => arrayLength(array) == 0;
|
|
14
14
|
const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
|
|
15
15
|
const arrayFromSecond = (ids) => ids.slice(1);
|
|
16
|
+
const arrayPush = (array, value) => array.push(value);
|
|
17
|
+
const arrayPop = (array) => array.pop();
|
|
16
18
|
|
|
17
19
|
const mathMax = Math.max;
|
|
18
20
|
const mathMin = Math.min;
|
|
@@ -62,6 +64,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
|
|
|
62
64
|
const storeListenerIds = mapNew();
|
|
63
65
|
const getStore = () => store;
|
|
64
66
|
const getThingIds = () => mapKeys(tableIds);
|
|
67
|
+
const forEachThing = (cb) => mapForEach(things, cb);
|
|
65
68
|
const hasThing = (id) => collHas(things, id);
|
|
66
69
|
const getTableId = (id) => mapGet(tableIds, id);
|
|
67
70
|
const getThing = (id) => mapGet(things, id);
|
|
@@ -152,6 +155,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
|
|
|
152
155
|
return [
|
|
153
156
|
getStore,
|
|
154
157
|
getThingIds,
|
|
158
|
+
forEachThing,
|
|
155
159
|
hasThing,
|
|
156
160
|
getTableId,
|
|
157
161
|
getThing,
|
|
@@ -204,7 +208,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
204
208
|
const allListeners = mapNew();
|
|
205
209
|
const addListener = (listener, deepSet, idOrNulls = []) => {
|
|
206
210
|
thing ??= getThing();
|
|
207
|
-
const id = listenerPool
|
|
211
|
+
const id = arrayPop(listenerPool) ?? '' + nextId++;
|
|
208
212
|
mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
|
|
209
213
|
addDeepSet(deepSet, id, idOrNulls);
|
|
210
214
|
return id;
|
|
@@ -225,7 +229,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
225
229
|
forDeepSet(collDel)(deepSet, id, ...idOrNulls);
|
|
226
230
|
mapSet(allListeners, id);
|
|
227
231
|
if (arrayLength(listenerPool) < 1e3) {
|
|
228
|
-
listenerPool
|
|
232
|
+
arrayPush(listenerPool, id);
|
|
229
233
|
}
|
|
230
234
|
return idOrNulls;
|
|
231
235
|
},
|
|
@@ -296,6 +300,7 @@ const createMetrics = getCreateFunction((store) => {
|
|
|
296
300
|
const [
|
|
297
301
|
getStore,
|
|
298
302
|
getMetricIds,
|
|
303
|
+
forEachMetric,
|
|
299
304
|
hasMetric,
|
|
300
305
|
getTableId,
|
|
301
306
|
getMetric,
|
|
@@ -381,6 +386,7 @@ const createMetrics = getCreateFunction((store) => {
|
|
|
381
386
|
delMetricDefinition,
|
|
382
387
|
getStore,
|
|
383
388
|
getMetricIds,
|
|
389
|
+
forEachMetric,
|
|
384
390
|
hasMetric,
|
|
385
391
|
getTableId,
|
|
386
392
|
getMetric,
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @module relationships
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {GetCell, Store} from './store.d';
|
|
14
|
+
import {GetCell, RowCallback, Store} from './store.d';
|
|
15
15
|
import {Id, IdOrNull, Ids} from './common.d';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -39,6 +39,25 @@ export type Relationship = {
|
|
|
39
39
|
linkedRowIds: {[firstRowId: Id]: Ids};
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The RelationshipCallback type describes a function that takes a
|
|
44
|
+
* Relationship's Id and a callback to loop over each local Row within it.
|
|
45
|
+
*
|
|
46
|
+
* A RelationshipCallback is provided when using the forEachRelationship method,
|
|
47
|
+
* so that you can do something based on every Relationship in the Relationships
|
|
48
|
+
* object. See that method for specific examples.
|
|
49
|
+
*
|
|
50
|
+
* @param relationshipId The Id of the Relationship that the callback can
|
|
51
|
+
* operate on.
|
|
52
|
+
* @param forEachRow A function that will let you iterate over the local Row
|
|
53
|
+
* objects in this Relationship.
|
|
54
|
+
* @category Callback
|
|
55
|
+
*/
|
|
56
|
+
export type RelationshipCallback = (
|
|
57
|
+
relationshipId: Id,
|
|
58
|
+
forEachRow: (rowCallback: RowCallback) => void,
|
|
59
|
+
) => void;
|
|
60
|
+
|
|
42
61
|
/**
|
|
43
62
|
* The RemoteRowIdListener type describes a function that is used to listen to
|
|
44
63
|
* changes to the remote Row Id end of a Relationship.
|
|
@@ -405,6 +424,49 @@ export interface Relationships {
|
|
|
405
424
|
*/
|
|
406
425
|
getRelationshipIds(): Ids;
|
|
407
426
|
|
|
427
|
+
/**
|
|
428
|
+
* The forEachRelationship method takes a function that it will then call for
|
|
429
|
+
* each Relationship in a specified Relationships object.
|
|
430
|
+
*
|
|
431
|
+
* This method is useful for iterating over the structure of the Relationships
|
|
432
|
+
* object in a functional style. The `relationshipCallback` parameter is a
|
|
433
|
+
* RelationshipCallback function that will be called with the Id of each
|
|
434
|
+
* Relationship, and with a function that can then be used to iterate over
|
|
435
|
+
* each local Row involved in the Relationship.
|
|
436
|
+
*
|
|
437
|
+
* @param relationshipCallback The function that should be called for every
|
|
438
|
+
* Relationship.
|
|
439
|
+
* @example
|
|
440
|
+
* This example iterates over each Relationship in a Relationships object, and
|
|
441
|
+
* lists each Row Id within them.
|
|
442
|
+
*
|
|
443
|
+
* ```js
|
|
444
|
+
* const store = createStore().setTable('pets', {
|
|
445
|
+
* fido: {species: 'dog', next: 'felix'},
|
|
446
|
+
* felix: {species: 'cat', next: 'cujo'},
|
|
447
|
+
* cujo: {species: 'dog'},
|
|
448
|
+
* });
|
|
449
|
+
* const relationships = createRelationships(store)
|
|
450
|
+
* .setRelationshipDefinition('petSpecies', 'pets', 'species', 'species')
|
|
451
|
+
* .setRelationshipDefinition('petSequence', 'pets', 'pets', 'next');
|
|
452
|
+
*
|
|
453
|
+
* relationships.forEachRelationship((relationshipId, forEachRow) => {
|
|
454
|
+
* console.log(relationshipId);
|
|
455
|
+
* forEachRow((rowId) => console.log(`- ${rowId}`));
|
|
456
|
+
* });
|
|
457
|
+
* // -> 'petSpecies'
|
|
458
|
+
* // -> '- fido'
|
|
459
|
+
* // -> '- felix'
|
|
460
|
+
* // -> '- cujo'
|
|
461
|
+
* // -> 'petSequence'
|
|
462
|
+
* // -> '- fido'
|
|
463
|
+
* // -> '- felix'
|
|
464
|
+
* // -> '- cujo'
|
|
465
|
+
* ```
|
|
466
|
+
* @category Iterator
|
|
467
|
+
*/
|
|
468
|
+
forEachRelationship(relationshipCallback: RelationshipCallback): void;
|
|
469
|
+
|
|
408
470
|
/**
|
|
409
471
|
* The hasRelationship method returns a boolean indicating whether a given
|
|
410
472
|
* Relationship exists in the Relationships object.
|