tinybase 1.0.3 → 1.1.0-beta.1
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 +66 -0
- package/lib/checkpoints.js +1 -1
- package/lib/checkpoints.js.gz +0 -0
- package/lib/debug/checkpoints.d.ts +66 -0
- package/lib/debug/checkpoints.js +16 -10
- package/lib/debug/indexes.d.ts +167 -6
- package/lib/debug/indexes.js +35 -2
- package/lib/debug/metrics.d.ts +72 -0
- package/lib/debug/metrics.js +12 -2
- package/lib/debug/relationships.d.ts +86 -1
- package/lib/debug/relationships.js +18 -2
- package/lib/debug/store.d.ts +187 -5
- package/lib/debug/store.js +217 -164
- package/lib/debug/tinybase.js +272 -172
- package/lib/indexes.d.ts +167 -6
- package/lib/indexes.js +1 -1
- package/lib/indexes.js.gz +0 -0
- package/lib/metrics.d.ts +72 -0
- package/lib/metrics.js +1 -1
- package/lib/metrics.js.gz +0 -0
- package/lib/relationships.d.ts +86 -1
- package/lib/relationships.js +1 -1
- package/lib/relationships.js.gz +0 -0
- package/lib/store.d.ts +187 -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 +14 -14
- 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,58 @@ 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
|
+
|
|
400
|
+
/**
|
|
401
|
+
* The hasCheckpoint method returns a boolean indicating whether a given
|
|
402
|
+
* Checkpoint exists in the Checkpoints object.
|
|
403
|
+
*
|
|
404
|
+
* @param checkpointId The Id of a possible Checkpoint in the Checkpoints
|
|
405
|
+
* object.
|
|
406
|
+
* @returns Whether a Checkpoint with that Id exists.
|
|
407
|
+
* @example
|
|
408
|
+
* This example shows two simple Checkpoint existence checks.
|
|
409
|
+
*
|
|
410
|
+
* ```js
|
|
411
|
+
* const store = createStore().setTables({pets: {fido: {sold: false}}});
|
|
412
|
+
* const checkpoints = createCheckpoints(store);
|
|
413
|
+
* console.log(checkpoints.hasCheckpoint('0'));
|
|
414
|
+
* // -> true
|
|
415
|
+
* console.log(checkpoints.hasCheckpoint('1'));
|
|
416
|
+
* // -> false
|
|
417
|
+
* ```
|
|
418
|
+
* @category Getter
|
|
419
|
+
*/
|
|
420
|
+
hasCheckpoint(checkpointId: Id): boolean;
|
|
421
|
+
|
|
356
422
|
/**
|
|
357
423
|
* The getCheckpoint method fetches the label for a checkpoint, if it had been
|
|
358
424
|
* provided at the time of the addCheckpoint method or set subsequently with
|
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,58 @@ 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
|
+
|
|
400
|
+
/**
|
|
401
|
+
* The hasCheckpoint method returns a boolean indicating whether a given
|
|
402
|
+
* Checkpoint exists in the Checkpoints object.
|
|
403
|
+
*
|
|
404
|
+
* @param checkpointId The Id of a possible Checkpoint in the Checkpoints
|
|
405
|
+
* object.
|
|
406
|
+
* @returns Whether a Checkpoint with that Id exists.
|
|
407
|
+
* @example
|
|
408
|
+
* This example shows two simple Checkpoint existence checks.
|
|
409
|
+
*
|
|
410
|
+
* ```js
|
|
411
|
+
* const store = createStore().setTables({pets: {fido: {sold: false}}});
|
|
412
|
+
* const checkpoints = createCheckpoints(store);
|
|
413
|
+
* console.log(checkpoints.hasCheckpoint('0'));
|
|
414
|
+
* // -> true
|
|
415
|
+
* console.log(checkpoints.hasCheckpoint('1'));
|
|
416
|
+
* // -> false
|
|
417
|
+
* ```
|
|
418
|
+
* @category Getter
|
|
419
|
+
*/
|
|
420
|
+
hasCheckpoint(checkpointId: Id): boolean;
|
|
421
|
+
|
|
356
422
|
/**
|
|
357
423
|
* The getCheckpoint method fetches the label for a checkpoint, if it had been
|
|
358
424
|
* provided at the time of the addCheckpoint method or set subsequently with
|
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;
|
|
@@ -243,10 +247,7 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
243
247
|
return id;
|
|
244
248
|
};
|
|
245
249
|
const setCheckpoint = (checkpointId, label) => {
|
|
246
|
-
if (
|
|
247
|
-
collHas(deltas, checkpointId) &&
|
|
248
|
-
mapGet(labels, checkpointId) !== label
|
|
249
|
-
) {
|
|
250
|
+
if (hasCheckpoint(checkpointId) && mapGet(labels, checkpointId) !== label) {
|
|
250
251
|
mapSet(labels, checkpointId, label);
|
|
251
252
|
callListeners(checkpointListeners, [checkpointId]);
|
|
252
253
|
}
|
|
@@ -254,6 +255,9 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
254
255
|
};
|
|
255
256
|
const getStore = () => store;
|
|
256
257
|
const getCheckpointIds = () => [[...backwardIds], currentId, [...forwardIds]];
|
|
258
|
+
const forEachCheckpoint = (checkpointCallback) =>
|
|
259
|
+
mapForEach(labels, checkpointCallback);
|
|
260
|
+
const hasCheckpoint = (checkpointId) => collHas(deltas, checkpointId);
|
|
257
261
|
const getCheckpoint = (checkpointId) => mapGet(labels, checkpointId);
|
|
258
262
|
const goBackward = () => {
|
|
259
263
|
goBackwardImpl();
|
|
@@ -309,6 +313,8 @@ const createCheckpoints = getCreateFunction((store) => {
|
|
|
309
313
|
setCheckpoint,
|
|
310
314
|
getStore,
|
|
311
315
|
getCheckpointIds,
|
|
316
|
+
forEachCheckpoint,
|
|
317
|
+
hasCheckpoint,
|
|
312
318
|
getCheckpoint,
|
|
313
319
|
goBackward,
|
|
314
320
|
goForward,
|
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,131 @@ 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
|
+
|
|
478
|
+
/**
|
|
479
|
+
* The hasIndex method returns a boolean indicating whether a given Index
|
|
480
|
+
* exists in the Indexes object.
|
|
481
|
+
*
|
|
482
|
+
* @param indexId The Id of a possible Index in the Indexes object.
|
|
483
|
+
* @returns Whether an Index with that Id exists.
|
|
484
|
+
* @example
|
|
485
|
+
* This example shows two simple Index existence checks.
|
|
486
|
+
*
|
|
487
|
+
* ```js
|
|
488
|
+
* const indexes = createIndexes(createStore());
|
|
489
|
+
* indexes.setIndexDefinition('bySpecies', 'pets', 'species');
|
|
490
|
+
* console.log(indexes.hasIndex('bySpecies'));
|
|
491
|
+
* // -> true
|
|
492
|
+
* console.log(indexes.hasIndex('byColor'));
|
|
493
|
+
* // -> false
|
|
494
|
+
* ```
|
|
495
|
+
* @category Getter
|
|
496
|
+
*/
|
|
497
|
+
hasIndex(indexId: Id): boolean;
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* The hasSlice method returns a boolean indicating whether a given Slice
|
|
501
|
+
* exists in the Indexes object.
|
|
502
|
+
*
|
|
503
|
+
* @param indexId The Id of a possible Index in the Indexes object.
|
|
504
|
+
* @param sliceId The Id of a possible Slice in the Index.
|
|
505
|
+
* @returns Whether a Slice with that Id exists.
|
|
506
|
+
* @example
|
|
507
|
+
* This example shows two simple Index existence checks.
|
|
508
|
+
*
|
|
509
|
+
* ```js
|
|
510
|
+
* const store = createStore().setTable('pets', {
|
|
511
|
+
* fido: {species: 'dog'},
|
|
512
|
+
* felix: {species: 'cat'},
|
|
513
|
+
* cujo: {species: 'dog'},
|
|
514
|
+
* });
|
|
515
|
+
* const indexes = createIndexes(store);
|
|
516
|
+
* indexes.setIndexDefinition('bySpecies', 'pets', 'species');
|
|
517
|
+
* console.log(indexes.hasSlice('bySpecies', 'dog'));
|
|
518
|
+
* // -> true
|
|
519
|
+
* console.log(indexes.hasSlice('bySpecies', 'worm'));
|
|
520
|
+
* // -> false
|
|
521
|
+
* ```
|
|
522
|
+
* @category Getter
|
|
523
|
+
*/
|
|
524
|
+
hasSlice(indexId: Id, sliceId: Id): boolean;
|
|
525
|
+
|
|
365
526
|
/**
|
|
366
527
|
* The getTableId method returns the Id of the underlying Table that is
|
|
367
528
|
* backing an Index.
|
|
@@ -473,7 +634,7 @@ export interface Indexes {
|
|
|
473
634
|
* the Index change.
|
|
474
635
|
* @returns A unique Id for the listener that can later be used to remove it.
|
|
475
636
|
* @example
|
|
476
|
-
* This example creates a Store,
|
|
637
|
+
* This example creates a Store, an Indexes object, and then registers a
|
|
477
638
|
* listener that responds to any changes to a specific Index.
|
|
478
639
|
*
|
|
479
640
|
* ```js
|
|
@@ -501,7 +662,7 @@ export interface Indexes {
|
|
|
501
662
|
* indexes.delListener(listenerId);
|
|
502
663
|
* ```
|
|
503
664
|
* @example
|
|
504
|
-
* This example creates a Store,
|
|
665
|
+
* This example creates a Store, an Indexes object, and then registers a
|
|
505
666
|
* listener that responds to any changes to any Index.
|
|
506
667
|
*
|
|
507
668
|
* ```js
|
|
@@ -558,7 +719,7 @@ export interface Indexes {
|
|
|
558
719
|
* the Slice change.
|
|
559
720
|
* @returns A unique Id for the listener that can later be used to remove it.
|
|
560
721
|
* @example
|
|
561
|
-
* This example creates a Store,
|
|
722
|
+
* This example creates a Store, an Indexes object, and then registers a
|
|
562
723
|
* listener that responds to any changes to a specific Slice.
|
|
563
724
|
*
|
|
564
725
|
* ```js
|
|
@@ -587,7 +748,7 @@ export interface Indexes {
|
|
|
587
748
|
* indexes.delListener(listenerId);
|
|
588
749
|
* ```
|
|
589
750
|
* @example
|
|
590
|
-
* This example creates a Store,
|
|
751
|
+
* This example creates a Store, an Indexes object, and then registers a
|
|
591
752
|
* listener that responds to any changes to any Slice.
|
|
592
753
|
*
|
|
593
754
|
* ```js
|
|
@@ -639,7 +800,7 @@ export interface Indexes {
|
|
|
639
800
|
* @param listenerId The Id of the listener to remove.
|
|
640
801
|
* @returns A reference to the Indexes object.
|
|
641
802
|
* @example
|
|
642
|
-
* This example creates a Store,
|
|
803
|
+
* This example creates a Store, an Indexes object, registers a listener, and
|
|
643
804
|
* then removes it.
|
|
644
805
|
*
|
|
645
806
|
* ```js
|
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,8 @@ 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);
|
|
63
|
+
const hasThing = (id) => collHas(things, id);
|
|
60
64
|
const getTableId = (id) => mapGet(tableIds, id);
|
|
61
65
|
const getThing = (id) => mapGet(things, id);
|
|
62
66
|
const setThing = (id, thing) => mapSet(things, id, thing);
|
|
@@ -146,6 +150,8 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
|
|
|
146
150
|
return [
|
|
147
151
|
getStore,
|
|
148
152
|
getThingIds,
|
|
153
|
+
forEachThing,
|
|
154
|
+
hasThing,
|
|
149
155
|
getTableId,
|
|
150
156
|
getThing,
|
|
151
157
|
setThing,
|
|
@@ -199,7 +205,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
199
205
|
const allListeners = mapNew();
|
|
200
206
|
const addListener = (listener, deepSet, idOrNulls = []) => {
|
|
201
207
|
thing ??= getThing();
|
|
202
|
-
const id = listenerPool
|
|
208
|
+
const id = arrayPop(listenerPool) ?? '' + nextId++;
|
|
203
209
|
mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
|
|
204
210
|
addDeepSet(deepSet, id, idOrNulls);
|
|
205
211
|
return id;
|
|
@@ -220,7 +226,7 @@ const getListenerFunctions = (getThing) => {
|
|
|
220
226
|
forDeepSet(collDel)(deepSet, id, ...idOrNulls);
|
|
221
227
|
mapSet(allListeners, id);
|
|
222
228
|
if (arrayLength(listenerPool) < 1e3) {
|
|
223
|
-
listenerPool
|
|
229
|
+
arrayPush(listenerPool, id);
|
|
224
230
|
}
|
|
225
231
|
return idOrNulls;
|
|
226
232
|
},
|
|
@@ -252,6 +258,8 @@ const createIndexes = getCreateFunction((store) => {
|
|
|
252
258
|
const [
|
|
253
259
|
getStore,
|
|
254
260
|
getIndexIds,
|
|
261
|
+
forEachIndexImpl,
|
|
262
|
+
hasIndex,
|
|
255
263
|
getTableId,
|
|
256
264
|
getIndex,
|
|
257
265
|
setIndex,
|
|
@@ -264,6 +272,7 @@ const createIndexes = getCreateFunction((store) => {
|
|
|
264
272
|
const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
|
|
265
273
|
() => indexes,
|
|
266
274
|
);
|
|
275
|
+
const hasSlice = (indexId, sliceId) => collHas(getIndex(indexId), sliceId);
|
|
267
276
|
const setIndexDefinition = (
|
|
268
277
|
indexId,
|
|
269
278
|
tableId,
|
|
@@ -359,6 +368,26 @@ const createIndexes = getCreateFunction((store) => {
|
|
|
359
368
|
);
|
|
360
369
|
return indexes;
|
|
361
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
|
+
};
|
|
362
391
|
const delIndexDefinition = (indexId) => {
|
|
363
392
|
delDefinition(indexId);
|
|
364
393
|
return indexes;
|
|
@@ -383,6 +412,10 @@ const createIndexes = getCreateFunction((store) => {
|
|
|
383
412
|
delIndexDefinition,
|
|
384
413
|
getStore,
|
|
385
414
|
getIndexIds,
|
|
415
|
+
forEachIndex,
|
|
416
|
+
forEachSlice,
|
|
417
|
+
hasIndex,
|
|
418
|
+
hasSlice,
|
|
386
419
|
getTableId,
|
|
387
420
|
getSliceIds,
|
|
388
421
|
getSliceRowIds,
|