tinybase 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.
@@ -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,l=(e,t,n)=>r(e)?n?.():t(e),c=(e,t)=>e?.has(t)??!1,i=e=>r(e)||0==(e=>e.size)(e),d=(e,t)=>e?.forEach(t),a=(e,t)=>e?.delete(t),p=e=>new Map(e),h=(e,t)=>e?.get(t),u=(e,t,n)=>r(n)?(a(e,t),e):e?.set(t,n),g=(e,t,n,s)=>(c(e,t)||(s?.(n),e.set(t,n)),h(e,t)),C=e=>new Set(e),k=(e,t,r)=>n(r)<2?((e,t)=>e?.add(t))(s(r)?e:g(e,r[0],C()),t):k(g(e,r[0],p()),t,o(r)),f=e=>{const n=(r,c,...i)=>l(r,(r=>s(i)?e(r,c):t([i[0],null],(e=>n(h(r,e),c,...o(i))))));return n},L=Object.freeze,w=(e=>{const t=new WeakMap;return n=>(t.has(n)||t.set(n,e(n)),t.get(n))})((o=>{let w,v,S,z=100,E=p(),I=1;const M=C(),b=p(),[j,x,y]=(e=>{let s,o=0;const c=[],i=p();return[(t,n,r=[])=>{s??=e();const l=c.pop()??""+o++;return u(i,l,[t,n,r]),k(n,l,r),l},(e,t=[],...n)=>f(d)(e,(e=>l(h(i,e),(([e])=>e(s,...t,...n)))),...t),e=>l(h(i,e),(([,t,s])=>(f(a)(t,e,...s),u(i,e),n(c)<1e3&&c.push(e),s)),(()=>[])),(e,o,c)=>l(h(i,e),(([e,,l])=>{const i=(...d)=>{const a=n(d);a==n(l)?e(s,...d,...c(d)):r(l[a])?t(o[a](...d),(e=>i(...d,e))):i(...d,l[a])};i()}))]})((()=>R)),B=p(),F=p(),O=[],T=[],W=(e,t)=>{I=0,o.transaction((()=>d(h(B,t),((t,n)=>d(t,((t,s)=>d(t,((t,l)=>r(t[e])?o.delCell(n,s,l,!0):o.setCell(n,s,l,t[e]))))))))),I=1},m=e=>{u(B,e),u(F,e),x(b,[e])},q=(e,s)=>t(((e,t)=>e.splice(0,t))(e,s??n(e)),m),A=()=>q(O,n(O)-z),D=o.addCellListener(null,null,null,((e,t,n,s,o,r)=>{if(I){l(w,(()=>{O.push(w),A(),q(T),w=void 0,S=1}));const e=g(E,t,p()),c=g(e,n,p()),d=g(c,s,[void 0,void 0],(e=>e[0]=r));d[1]=o,d[0]===d[1]&&i(u(c,s))&&i(u(e,n))&&i(u(E,t))&&(w=O.pop(),S=1),K()}})),G=(e="")=>(r(w)&&(w=""+v++,u(B,w,E),P(w,e),E=p(),S=1),w),H=()=>{s(O)||(T.unshift(G()),W(0,w),w=O.pop(),S=1)},J=()=>{s(T)||(O.push(w),w=T.shift(),W(1,w),S=1)},K=()=>{S&&(x(M),S=0)},N=e=>{const t=G(e);return K(),t},P=(e,t)=>(Q(e)&&h(F,e)!==t&&(u(F,e,t),x(b,[e])),R),Q=e=>c(B,e),R={setSize:e=>(z=e,A(),R),addCheckpoint:N,setCheckpoint:P,getStore:()=>o,getCheckpointIds:()=>[[...O],w,[...T]],hasCheckpoint:Q,getCheckpoint:e=>h(F,e),goBackward:()=>(H(),K(),R),goForward:()=>(J(),K(),R),goTo:t=>{const n=e(O,t)?H:e(T,t)?J:null;for(;!r(n)&&t!=w;)n();return K(),R},addCheckpointIdsListener:e=>j(e,M),addCheckpointListener:(e,t)=>j(t,b,[e]),delListener:e=>(y(e),R),clear:()=>(q(O),q(T),r(w)||m(w),w=void 0,v=0,N(),R),destroy:()=>{o.delListener(D)},getListenerStats:()=>({})};return L(R.clear())}));export{w as createCheckpoints};
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,c=(e,t,n)=>r(e)?n?.():t(e),l=(e,t)=>e?.has(t)??!1,i=e=>r(e)||0==(e=>e.size)(e),d=(e,t)=>e?.forEach(t),a=(e,t)=>e?.delete(t),p=e=>new Map(e),h=(e,t)=>e?.get(t),u=(e,t,n)=>r(n)?(a(e,t),e):e?.set(t,n),C=(e,t,n,s)=>(l(e,t)||(s?.(n),e.set(t,n)),h(e,t)),g=e=>new Set(e),k=(e,t,r)=>n(r)<2?((e,t)=>e?.add(t))(s(r)?e:C(e,r[0],g()),t):k(C(e,r[0],p()),t,o(r)),f=e=>{const n=(r,l,...i)=>c(r,(r=>s(i)?e(r,l):t([i[0],null],(e=>n(h(r,e),l,...o(i))))));return n},L=Object.freeze,v=(e=>{const t=new WeakMap;return n=>(t.has(n)||t.set(n,e(n)),t.get(n))})((o=>{let v,w,S,z=100,E=p(),I=1;const M=g(),b=p(),[j,x,y]=(e=>{let s,o=0;const l=[],i=p();return[(t,n,r=[])=>{s??=e();const c=l.pop()??""+o++;return u(i,c,[t,n,r]),k(n,c,r),c},(e,t=[],...n)=>f(d)(e,(e=>c(h(i,e),(([e])=>e(s,...t,...n)))),...t),e=>c(h(i,e),(([,t,s])=>(f(a)(t,e,...s),u(i,e),n(l)<1e3&&l.push(e),s)),(()=>[])),(e,o,l)=>c(h(i,e),(([e,,c])=>{const i=(...d)=>{const a=n(d);a==n(c)?e(s,...d,...l(d)):r(c[a])?t(o[a](...d),(e=>i(...d,e))):i(...d,c[a])};i()}))]})((()=>R)),B=p(),F=p(),O=[],T=[],W=(e,t)=>{I=0,o.transaction((()=>d(h(B,t),((t,n)=>d(t,((t,s)=>d(t,((t,c)=>r(t[e])?o.delCell(n,s,c,!0):o.setCell(n,s,c,t[e]))))))))),I=1},m=e=>{u(B,e),u(F,e),x(b,[e])},q=(e,s)=>t(((e,t)=>e.splice(0,t))(e,s??n(e)),m),A=()=>q(O,n(O)-z),D=o.addCellListener(null,null,null,((e,t,n,s,o,r)=>{if(I){c(v,(()=>{O.push(v),A(),q(T),v=void 0,S=1}));const e=C(E,t,p()),l=C(e,n,p()),d=C(l,s,[void 0,void 0],(e=>e[0]=r));d[1]=o,d[0]===d[1]&&i(u(l,s))&&i(u(e,n))&&i(u(E,t))&&(v=O.pop(),S=1),K()}})),G=(e="")=>(r(v)&&(v=""+w++,u(B,v,E),P(v,e),E=p(),S=1),v),H=()=>{s(O)||(T.unshift(G()),W(0,v),v=O.pop(),S=1)},J=()=>{s(T)||(O.push(v),v=T.shift(),W(1,v),S=1)},K=()=>{S&&(x(M),S=0)},N=e=>{const t=G(e);return K(),t},P=(e,t)=>(Q(e)&&h(F,e)!==t&&(u(F,e,t),x(b,[e])),R),Q=e=>l(B,e),R={setSize:e=>(z=e,A(),R),addCheckpoint:N,setCheckpoint:P,getStore:()=>o,getCheckpointIds:()=>[[...O],v,[...T]],forEachCheckpoint:e=>{return t=e,d(F,((e,n)=>t(n,e)));var t},hasCheckpoint:Q,getCheckpoint:e=>h(F,e),goBackward:()=>(H(),K(),R),goForward:()=>(J(),K(),R),goTo:t=>{const n=e(O,t)?H:e(T,t)?J:null;for(;!r(n)&&t!=v;)n();return K(),R},addCheckpointIdsListener:e=>j(e,M),addCheckpointListener:(e,t)=>j(t,b,[e]),delListener:e=>(y(e),R),clear:()=>(q(O),q(T),r(v)||m(v),v=void 0,w=0,N(),R),destroy:()=>{o.delListener(D)},getListenerStats:()=>({})};return L(R.clear())}));export{v as createCheckpoints};
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.
@@ -22,6 +22,8 @@ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
22
22
 
23
23
  const mapNew = (entries) => new Map(entries);
24
24
  const mapGet = (map, key) => map?.get(key);
25
+ const mapForEach = (map, cb) =>
26
+ collForEach(map, (value, key) => cb(key, value));
25
27
  const mapSet = (map, key, value) =>
26
28
  isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
27
29
  const mapEnsure = (map, key, defaultValue, onWillAdd) => {
@@ -251,6 +253,8 @@ const createCheckpoints = getCreateFunction((store) => {
251
253
  };
252
254
  const getStore = () => store;
253
255
  const getCheckpointIds = () => [[...backwardIds], currentId, [...forwardIds]];
256
+ const forEachCheckpoint = (checkpointCallback) =>
257
+ mapForEach(labels, checkpointCallback);
254
258
  const hasCheckpoint = (checkpointId) => collHas(deltas, checkpointId);
255
259
  const getCheckpoint = (checkpointId) => mapGet(labels, checkpointId);
256
260
  const goBackward = () => {
@@ -307,6 +311,7 @@ const createCheckpoints = getCreateFunction((store) => {
307
311
  setCheckpoint,
308
312
  getStore,
309
313
  getCheckpointIds,
314
+ forEachCheckpoint,
310
315
  hasCheckpoint,
311
316
  getCheckpoint,
312
317
  goBackward,
@@ -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.
@@ -57,6 +57,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
57
57
  const storeListenerIds = mapNew();
58
58
  const getStore = () => store;
59
59
  const getThingIds = () => mapKeys(tableIds);
60
+ const forEachThing = (cb) => mapForEach(things, cb);
60
61
  const hasThing = (id) => collHas(things, id);
61
62
  const getTableId = (id) => mapGet(tableIds, id);
62
63
  const getThing = (id) => mapGet(things, id);
@@ -147,6 +148,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
147
148
  return [
148
149
  getStore,
149
150
  getThingIds,
151
+ forEachThing,
150
152
  hasThing,
151
153
  getTableId,
152
154
  getThing,
@@ -254,6 +256,7 @@ const createIndexes = getCreateFunction((store) => {
254
256
  const [
255
257
  getStore,
256
258
  getIndexIds,
259
+ forEachIndexImpl,
257
260
  hasIndex,
258
261
  getTableId,
259
262
  getIndex,
@@ -363,6 +366,26 @@ const createIndexes = getCreateFunction((store) => {
363
366
  );
364
367
  return indexes;
365
368
  };
369
+ const forEachIndex = (indexCallback) =>
370
+ forEachIndexImpl((indexId, slices) =>
371
+ indexCallback(indexId, (sliceCallback) =>
372
+ forEachSliceImpl(indexId, sliceCallback, slices),
373
+ ),
374
+ );
375
+ const forEachSlice = (indexId, sliceCallback) =>
376
+ forEachSliceImpl(indexId, sliceCallback, getIndex(indexId));
377
+ const forEachSliceImpl = (indexId, sliceCallback, slices) => {
378
+ const tableId = getTableId(indexId);
379
+ collForEach(slices, (rowIds, sliceId) =>
380
+ sliceCallback(sliceId, (rowCallback) =>
381
+ collForEach(rowIds, (rowId) =>
382
+ rowCallback(rowId, (cellCallback) =>
383
+ store.forEachCell(tableId, rowId, cellCallback),
384
+ ),
385
+ ),
386
+ ),
387
+ );
388
+ };
366
389
  const delIndexDefinition = (indexId) => {
367
390
  delDefinition(indexId);
368
391
  return indexes;
@@ -387,6 +410,8 @@ const createIndexes = getCreateFunction((store) => {
387
410
  delIndexDefinition,
388
411
  getStore,
389
412
  getIndexIds,
413
+ forEachIndex,
414
+ forEachSlice,
390
415
  hasIndex,
391
416
  hasSlice,
392
417
  getTableId,
@@ -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.
@@ -62,6 +62,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
62
62
  const storeListenerIds = mapNew();
63
63
  const getStore = () => store;
64
64
  const getThingIds = () => mapKeys(tableIds);
65
+ const forEachThing = (cb) => mapForEach(things, cb);
65
66
  const hasThing = (id) => collHas(things, id);
66
67
  const getTableId = (id) => mapGet(tableIds, id);
67
68
  const getThing = (id) => mapGet(things, id);
@@ -152,6 +153,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
152
153
  return [
153
154
  getStore,
154
155
  getThingIds,
156
+ forEachThing,
155
157
  hasThing,
156
158
  getTableId,
157
159
  getThing,
@@ -296,6 +298,7 @@ const createMetrics = getCreateFunction((store) => {
296
298
  const [
297
299
  getStore,
298
300
  getMetricIds,
301
+ forEachMetric,
299
302
  hasMetric,
300
303
  getTableId,
301
304
  getMetric,
@@ -381,6 +384,7 @@ const createMetrics = getCreateFunction((store) => {
381
384
  delMetricDefinition,
382
385
  getStore,
383
386
  getMetricIds,
387
+ forEachMetric,
384
388
  hasMetric,
385
389
  getTableId,
386
390
  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.
@@ -52,6 +52,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
52
52
  const storeListenerIds = mapNew();
53
53
  const getStore = () => store;
54
54
  const getThingIds = () => mapKeys(tableIds);
55
+ const forEachThing = (cb) => mapForEach(things, cb);
55
56
  const hasThing = (id) => collHas(things, id);
56
57
  const getTableId = (id) => mapGet(tableIds, id);
57
58
  const getThing = (id) => mapGet(things, id);
@@ -142,6 +143,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
142
143
  return [
143
144
  getStore,
144
145
  getThingIds,
146
+ forEachThing,
145
147
  hasThing,
146
148
  getTableId,
147
149
  getThing,
@@ -249,6 +251,7 @@ const createRelationships = getCreateFunction((store) => {
249
251
  const [
250
252
  getStore,
251
253
  getRelationshipIds,
254
+ forEachRelationshipImpl,
252
255
  hasRelationship,
253
256
  getLocalTableId,
254
257
  getRelationship,
@@ -363,6 +366,12 @@ const createRelationships = getCreateFunction((store) => {
363
366
  );
364
367
  return relationships;
365
368
  };
369
+ const forEachRelationship = (relationshipCallback) =>
370
+ forEachRelationshipImpl((relationshipId) =>
371
+ relationshipCallback(relationshipId, (rowCallback) =>
372
+ store.forEachRow(getLocalTableId(relationshipId), rowCallback),
373
+ ),
374
+ );
366
375
  const delRelationshipDefinition = (relationshipId) => {
367
376
  mapSet(remoteTableIds, relationshipId);
368
377
  delDefinition(relationshipId);
@@ -403,6 +412,7 @@ const createRelationships = getCreateFunction((store) => {
403
412
  delRelationshipDefinition,
404
413
  getStore,
405
414
  getRelationshipIds,
415
+ forEachRelationship,
406
416
  hasRelationship,
407
417
  getLocalTableId,
408
418
  getRemoteTableId,
@@ -89,7 +89,7 @@ export type Row = {[cellId: Id]: Cell};
89
89
  export type Cell = string | number | boolean;
90
90
 
91
91
  /**
92
- * The TableCallback type describes a function that takes a Tables's Id and a
92
+ * The TableCallback type describes a function that takes a Table's Id and a
93
93
  * callback to loop over each Row within it.
94
94
  *
95
95
  * A TableCallback is provided when using the forEachTable method, so that you
@@ -1631,7 +1631,7 @@ export interface Store {
1631
1631
  *
1632
1632
  * This method is useful for iterating over the Table structure of the Store
1633
1633
  * in a functional style. The `tableCallback` parameter is a TableCallback
1634
- * function that will called with the Id of each Table, and with a function
1634
+ * function that will be called with the Id of each Table, and with a function
1635
1635
  * that can then be used to iterate over each Row of the Table, should you
1636
1636
  * wish.
1637
1637
  *
@@ -1664,9 +1664,10 @@ export interface Store {
1664
1664
  *
1665
1665
  * This method is useful for iterating over the Row structure of the Table in
1666
1666
  * a functional style. The `rowCallback` parameter is a RowCallback function
1667
- * that will called with the Id of each Row, and with a function that can then
1668
- * be used to iterate over each Cell of the Row, should you wish.
1667
+ * that will be called with the Id of each Row, and with a function that can
1668
+ * then be used to iterate over each Cell of the Row, should you wish.
1669
1669
  *
1670
+ * @param tableId The Id of the Table to iterate over.
1670
1671
  * @param rowCallback The function that should be called for every Row.
1671
1672
  * @example
1672
1673
  * This example iterates over each Row in a Table, and lists each Cell Id
@@ -1698,8 +1699,10 @@ export interface Store {
1698
1699
  *
1699
1700
  * This method is useful for iterating over the Cell structure of the Row in a
1700
1701
  * functional style. The `cellCallback` parameter is a CellCallback function
1701
- * that will called with the Id and value of each Cell.
1702
+ * that will be called with the Id and value of each Cell.
1702
1703
  *
1704
+ * @param tableId The Id of the Table containing the Row to iterate over.
1705
+ * @param rowId The Id of the Row to iterate over.
1703
1706
  * @param cellCallback The function that should be called for every Cell.
1704
1707
  * @example
1705
1708
  * This example iterates over each Cell in a Row, and lists its value.