tinybase 2.0.0 → 2.1.0-beta.0

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.
Files changed (123) hide show
  1. package/lib/checkpoints.js +1 -1
  2. package/lib/checkpoints.js.gz +0 -0
  3. package/lib/common.js +1 -1
  4. package/lib/common.js.gz +0 -0
  5. package/lib/debug/checkpoints.js +7 -1
  6. package/lib/debug/common.js +1 -4
  7. package/lib/debug/indexes.d.ts +36 -10
  8. package/lib/debug/indexes.js +57 -25
  9. package/lib/debug/metrics.d.ts +1 -1
  10. package/lib/debug/metrics.js +19 -2
  11. package/lib/debug/persisters.d.ts +5 -5
  12. package/lib/debug/queries.js +18 -2
  13. package/lib/debug/relationships.d.ts +3 -3
  14. package/lib/debug/relationships.js +19 -2
  15. package/lib/debug/store.js +8 -2
  16. package/lib/debug/tinybase.js +53 -27
  17. package/lib/debug/ui-react.d.ts +17 -17
  18. package/lib/debug/ui-react.js +2 -1
  19. package/lib/es6/checkpoints.d.ts +946 -0
  20. package/lib/es6/checkpoints.js +1 -0
  21. package/lib/es6/checkpoints.js.gz +0 -0
  22. package/lib/es6/common.d.ts +115 -0
  23. package/lib/es6/common.js +1 -0
  24. package/lib/es6/common.js.gz +0 -0
  25. package/lib/es6/indexes.d.ts +967 -0
  26. package/lib/es6/indexes.js +1 -0
  27. package/lib/es6/indexes.js.gz +0 -0
  28. package/lib/es6/metrics.d.ts +829 -0
  29. package/lib/es6/metrics.js +1 -0
  30. package/lib/es6/metrics.js.gz +0 -0
  31. package/lib/es6/persisters.d.ts +717 -0
  32. package/lib/es6/persisters.js +1 -0
  33. package/lib/es6/persisters.js.gz +0 -0
  34. package/lib/es6/queries.d.ts +3026 -0
  35. package/lib/es6/queries.js +1 -0
  36. package/lib/es6/queries.js.gz +0 -0
  37. package/lib/es6/relationships.d.ts +1203 -0
  38. package/lib/es6/relationships.js +1 -0
  39. package/lib/es6/relationships.js.gz +0 -0
  40. package/lib/es6/store.d.ts +3572 -0
  41. package/lib/es6/store.js +1 -0
  42. package/lib/es6/store.js.gz +0 -0
  43. package/lib/es6/tinybase.d.ts +14 -0
  44. package/lib/es6/tinybase.js +1 -0
  45. package/lib/es6/tinybase.js.gz +0 -0
  46. package/lib/es6/ui-react.d.ts +9777 -0
  47. package/lib/es6/ui-react.js +1 -0
  48. package/lib/es6/ui-react.js.gz +0 -0
  49. package/lib/indexes.d.ts +36 -10
  50. package/lib/indexes.js +1 -1
  51. package/lib/indexes.js.gz +0 -0
  52. package/lib/metrics.d.ts +1 -1
  53. package/lib/metrics.js +1 -1
  54. package/lib/metrics.js.gz +0 -0
  55. package/lib/persisters.d.ts +5 -5
  56. package/lib/queries.js +1 -1
  57. package/lib/queries.js.gz +0 -0
  58. package/lib/relationships.d.ts +3 -3
  59. package/lib/relationships.js +1 -1
  60. package/lib/relationships.js.gz +0 -0
  61. package/lib/store.js +1 -1
  62. package/lib/store.js.gz +0 -0
  63. package/lib/tinybase.js +1 -1
  64. package/lib/tinybase.js.gz +0 -0
  65. package/lib/ui-react.d.ts +17 -17
  66. package/lib/umd/checkpoints.d.ts +946 -0
  67. package/lib/umd/checkpoints.js +1 -1
  68. package/lib/umd/checkpoints.js.gz +0 -0
  69. package/lib/umd/common.d.ts +115 -0
  70. package/lib/umd/common.js +1 -1
  71. package/lib/umd/common.js.gz +0 -0
  72. package/lib/umd/indexes.d.ts +967 -0
  73. package/lib/umd/indexes.js +1 -1
  74. package/lib/umd/indexes.js.gz +0 -0
  75. package/lib/umd/metrics.d.ts +829 -0
  76. package/lib/umd/metrics.js +1 -1
  77. package/lib/umd/metrics.js.gz +0 -0
  78. package/lib/umd/persisters.d.ts +717 -0
  79. package/lib/umd/queries.d.ts +3026 -0
  80. package/lib/umd/queries.js +1 -1
  81. package/lib/umd/queries.js.gz +0 -0
  82. package/lib/umd/relationships.d.ts +1203 -0
  83. package/lib/umd/relationships.js +1 -1
  84. package/lib/umd/relationships.js.gz +0 -0
  85. package/lib/umd/store.d.ts +3572 -0
  86. package/lib/umd/store.js +1 -1
  87. package/lib/umd/store.js.gz +0 -0
  88. package/lib/umd/tinybase.d.ts +14 -0
  89. package/lib/umd/tinybase.js +1 -1
  90. package/lib/umd/tinybase.js.gz +0 -0
  91. package/lib/umd/ui-react.d.ts +9777 -0
  92. package/lib/umd-es6/checkpoints.d.ts +946 -0
  93. package/lib/umd-es6/checkpoints.js +1 -0
  94. package/lib/umd-es6/checkpoints.js.gz +0 -0
  95. package/lib/umd-es6/common.d.ts +115 -0
  96. package/lib/umd-es6/common.js +1 -0
  97. package/lib/umd-es6/common.js.gz +0 -0
  98. package/lib/umd-es6/indexes.d.ts +967 -0
  99. package/lib/umd-es6/indexes.js +1 -0
  100. package/lib/umd-es6/indexes.js.gz +0 -0
  101. package/lib/umd-es6/metrics.d.ts +829 -0
  102. package/lib/umd-es6/metrics.js +1 -0
  103. package/lib/umd-es6/metrics.js.gz +0 -0
  104. package/lib/umd-es6/persisters.d.ts +717 -0
  105. package/lib/umd-es6/persisters.js +1 -0
  106. package/lib/umd-es6/persisters.js.gz +0 -0
  107. package/lib/umd-es6/queries.d.ts +3026 -0
  108. package/lib/umd-es6/queries.js +1 -0
  109. package/lib/umd-es6/queries.js.gz +0 -0
  110. package/lib/umd-es6/relationships.d.ts +1203 -0
  111. package/lib/umd-es6/relationships.js +1 -0
  112. package/lib/umd-es6/relationships.js.gz +0 -0
  113. package/lib/umd-es6/store.d.ts +3572 -0
  114. package/lib/umd-es6/store.js +1 -0
  115. package/lib/umd-es6/store.js.gz +0 -0
  116. package/lib/umd-es6/tinybase.d.ts +14 -0
  117. package/lib/umd-es6/tinybase.js +1 -0
  118. package/lib/umd-es6/tinybase.js.gz +0 -0
  119. package/lib/umd-es6/ui-react.d.ts +9777 -0
  120. package/lib/umd-es6/ui-react.js +1 -0
  121. package/lib/umd-es6/ui-react.js.gz +0 -0
  122. package/package.json +2 -1
  123. package/readme.md +12 -12
@@ -1 +1 @@
1
- const e=(e,t)=>e.includes(t),t=(e,t)=>e.forEach(t),n=e=>e.length,r=e=>0==n(e),o=(e,...t)=>e.push(...t),s=e=>e.pop(),l=e=>e.shift(),c=e=>null==e,i=(e,t,n)=>c(e)?n?.():t(e),d=(e,t)=>e?.has(t)??!1,a=e=>c(e)||0==(e=>e.size)(e),u=(e,t)=>e?.forEach(t),h=(e,t)=>e?.delete(t),p=e=>new Map(e),C=(e,t)=>e?.get(t),g=(e,t,n)=>c(n)?(h(e,t),e):e?.set(t,n),k=(e,t,n)=>(d(e,t)||g(e,t,n()),C(e,t)),f=(e,t,r,o,s=0)=>i((r?k:C)(e,t[s],s>n(t)-2?r:p),(l=>{if(s>n(t)-2)return o?.(l)&&g(e,t[s]),l;const c=f(l,t,r,o,s+1);return a(l)&&g(e,t[s]),c})),v=e=>new Set(e),L=/^\d+$/,w=e=>{let r;const[s,d]=(()=>{const e=[];let t=0;return[()=>l(e)??""+t++,t=>{L.test(t)&&n(e)<1e3&&o(e,t)}]})(),k=p();return[(t,n,o)=>{r??=e();const l=s();var c,i;return g(k,l,[t,n,o]),c=f(n,o??[""],v),i=l,c?.add(i),l},(e,s,...l)=>t(((e,r=[""])=>{const s=[],l=(e,c)=>c==n(r)?o(s,e):null===r[c]?u(e,(e=>l(e,c+1))):t([r[c],null],(t=>l(C(e,t),c+1)));return l(e,0),s})(e,s),(e=>u(e,(e=>C(k,e)[0](r,...s??[],...l))))),e=>i(C(k,e),(([,t,n])=>(f(t,n??[""],void 0,(t=>(h(t,e),a(t)?1:0))),g(k,e),d(e),n))),(e,o,s)=>i(C(k,e),(([e,,l=[]])=>{const i=(...d)=>{const a=n(d);a==n(l)?e(r,...d,...s(d)):c(l[a])?t(o[a](...d),(e=>i(...d,e))):i(...d,l[a])};i()}))]},S=Object.freeze,z=(e=>{const t=new WeakMap;return n=>(t.has(n)||t.set(n,e(n)),t.get(n))})((h=>{let f,v,L,z=100,E=p(),I=1;const M=p(),b=p(),[j,x,y]=w((()=>Q)),B=p(),F=p(),O=[],T=[],W=(e,t)=>{I=0,h.transaction((()=>u(C(B,t),((t,n)=>u(t,((t,r)=>u(t,((t,o)=>((e,t,n,r,o)=>c(o)?e.delCell(t,n,r,!0):e.setCell(t,n,r,o))(h,n,r,o,t[e]))))))))),I=1},$=e=>{g(B,e),g(F,e),x(b,[e])},m=(e,r)=>t(((e,t)=>e.splice(0,t))(e,r??n(e)),$),q=()=>m(O,n(O)-z),A=h.addCellListener(null,null,null,((e,t,n,r,l,c)=>{if(I){i(f,(()=>{o(O,f),q(),m(T),f=void 0,L=1}));const e=k(E,t,p),d=k(e,n,p),u=k(d,r,(()=>[c,void 0]));u[1]=l,u[0]===l&&a(g(d,r))&&a(g(e,n))&&a(g(E,t))&&(f=s(O),L=1),J()}})),D=(e="")=>(c(f)&&(f=""+v++,g(B,f,E),N(f,e),E=p(),L=1),f),G=()=>{r(O)||(T.unshift(D()),W(0,f),f=s(O),L=1)},H=()=>{r(T)||(o(O,f),f=l(T),W(1,f),L=1)},J=()=>{L&&(x(M),L=0)},K=e=>{const t=D(e);return J(),t},N=(e,t)=>(P(e)&&C(F,e)!==t&&(g(F,e,t),x(b,[e])),Q),P=e=>d(B,e),Q={setSize:e=>(z=e,q(),Q),addCheckpoint:K,setCheckpoint:N,getStore:()=>h,getCheckpointIds:()=>[[...O],f,[...T]],forEachCheckpoint:e=>{return t=e,u(F,((e,n)=>t(n,e)));var t},hasCheckpoint:P,getCheckpoint:e=>C(F,e),goBackward:()=>(G(),J(),Q),goForward:()=>(H(),J(),Q),goTo:t=>{const n=e(O,t)?G:e(T,t)?H:null;for(;!c(n)&&t!=f;)n();return J(),Q},addCheckpointIdsListener:e=>j(e,M),addCheckpointListener:(e,t)=>j(t,b,[e]),delListener:e=>(y(e),Q),clear:()=>(m(O),m(T),c(f)||$(f),f=void 0,v=0,K(),Q),destroy:()=>{h.delListener(A)},getListenerStats:()=>({})};return S(Q.clear())}));export{z as createCheckpoints};
1
+ const e=(e,t)=>e.includes(t),t=(e,t)=>e.forEach(t),n=e=>e.length,r=e=>0==n(e),s=(e,...t)=>e.push(...t),o=e=>e.pop(),l=e=>e.shift(),c=e=>null==e,i=(e,t,n)=>c(e)?n?.():t(e),a=(e,t)=>e?.has(t)??!1,d=e=>c(e)||0==(e=>e.size)(e),u=(e,t)=>e?.forEach(t),h=(e,t)=>e?.delete(t),p=e=>new Map(e),C=(e,t)=>e?.get(t),g=(e,t,n)=>c(n)?(h(e,t),e):e?.set(t,n),k=(e,t,n)=>(a(e,t)||g(e,t,n()),C(e,t)),f=(e,t,r,s,o=0)=>i((r?k:C)(e,t[o],o>n(t)-2?r:p),(l=>{if(o>n(t)-2)return s?.(l)&&g(e,t[o]),l;const c=f(l,t,r,s,o+1);return d(l)&&g(e,t[o]),c})),v=e=>new Set(Array.isArray(e)||c(e)?e:[e]),L=/^\d+$/,w=e=>{let r;const[o,a]=(()=>{const e=[];let t=0;return[()=>l(e)??""+t++,t=>{L.test(t)&&n(e)<1e3&&s(e,t)}]})(),k=p();return[(t,n,s)=>{r??=e();const l=o();var c,i;return g(k,l,[t,n,s]),c=f(n,s??[""],v),i=l,c?.add(i),l},(e,o,...l)=>t(((e,r=[""])=>{const o=[],l=(e,c)=>c==n(r)?s(o,e):null===r[c]?u(e,(e=>l(e,c+1))):t([r[c],null],(t=>l(C(e,t),c+1)));return l(e,0),o})(e,o),(e=>u(e,(e=>C(k,e)[0](r,...o??[],...l))))),e=>i(C(k,e),(([,t,n])=>(f(t,n??[""],void 0,(t=>(h(t,e),d(t)?1:0))),g(k,e),a(e),n))),(e,s,o)=>i(C(k,e),(([e,,l=[]])=>{const i=(...a)=>{const d=n(a);d==n(l)?e(r,...a,...o(a)):c(l[d])?t(s[d](...a),(e=>i(...a,e))):i(...a,l[d])};i()}))]},S=Object.freeze,y=(e=>{const t=new WeakMap;return n=>(t.has(n)||t.set(n,e(n)),t.get(n))})((h=>{let f,v,L,y=100,z=p(),E=1;const A=p(),I=p(),[M,b,j]=w((()=>Q)),x=p(),B=p(),F=[],O=[],T=(e,t)=>{E=0,h.transaction((()=>u(C(x,t),((t,n)=>u(t,((t,r)=>u(t,((t,s)=>((e,t,n,r,s)=>c(s)?e.delCell(t,n,r,!0):e.setCell(t,n,r,s))(h,n,r,s,t[e]))))))))),E=1},W=e=>{g(x,e),g(B,e),b(I,[e])},$=(e,r)=>t(((e,t)=>e.splice(0,t))(e,r??n(e)),W),m=()=>$(F,n(F)-y),q=h.addCellListener(null,null,null,((e,t,n,r,l,c)=>{if(E){i(f,(()=>{s(F,f),m(),$(O),f=void 0,L=1}));const e=k(z,t,p),a=k(e,n,p),u=k(a,r,(()=>[c,void 0]));u[1]=l,u[0]===l&&d(g(a,r))&&d(g(e,n))&&d(g(z,t))&&(f=o(F),L=1),J()}})),D=(e="")=>(c(f)&&(f=""+v++,g(x,f,z),N(f,e),z=p(),L=1),f),G=()=>{r(F)||(O.unshift(D()),T(0,f),f=o(F),L=1)},H=()=>{r(O)||(s(F,f),f=l(O),T(1,f),L=1)},J=()=>{L&&(b(A),L=0)},K=e=>{const t=D(e);return J(),t},N=(e,t)=>(P(e)&&C(B,e)!==t&&(g(B,e,t),b(I,[e])),Q),P=e=>a(x,e),Q={setSize:e=>(y=e,m(),Q),addCheckpoint:K,setCheckpoint:N,getStore:()=>h,getCheckpointIds:()=>[[...F],f,[...O]],forEachCheckpoint:e=>{return t=e,u(B,((e,n)=>t(n,e)));var t},hasCheckpoint:P,getCheckpoint:e=>C(B,e),goBackward:()=>(G(),J(),Q),goForward:()=>(H(),J(),Q),goTo:t=>{const n=e(F,t)?G:e(O,t)?H:null;for(;!c(n)&&t!=f;)n();return J(),Q},addCheckpointIdsListener:e=>M(e,A),addCheckpointListener:(e,t)=>M(t,I,[e]),delListener:e=>(j(e),Q),clear:()=>($(F),$(O),c(f)||W(f),f=void 0,v=0,K(),Q),destroy:()=>{h.delListener(q)},getListenerStats:()=>({})};return S(Q.clear())}));export{y as createCheckpoints};
Binary file
package/lib/common.js CHANGED
@@ -1 +1 @@
1
- const o=(o,t)=>o<t?-1:1,t=o=>""+o;export{o as defaultSorter,t as id};
1
+ const o=(o,t)=>o<t?-1:1;export{o as defaultSorter};
package/lib/common.js.gz CHANGED
Binary file
@@ -13,6 +13,7 @@ const arrayShift = (array) => array.shift();
13
13
  const isUndefined = (thing) => thing == void 0;
14
14
  const ifNotUndefined = (value, then, otherwise) =>
15
15
  isUndefined(value) ? otherwise?.() : then(value);
16
+ const isArray = (thing) => Array.isArray(thing);
16
17
 
17
18
  const collSizeN = (collSizer) => (coll) =>
18
19
  arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
@@ -58,7 +59,12 @@ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
58
59
  },
59
60
  );
60
61
 
61
- const setNew = (entries) => new Set(entries);
62
+ const setNew = (entryOrEntries) =>
63
+ new Set(
64
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
65
+ ? entryOrEntries
66
+ : [entryOrEntries],
67
+ );
62
68
  const setAdd = (set, value) => set?.add(value);
63
69
 
64
70
  const getCreateFunction = (getFunction) => {
@@ -1,6 +1,3 @@
1
- const EMPTY_STRING = '';
2
-
3
1
  const defaultSorter = (sortKey1, sortKey2) => (sortKey1 < sortKey2 ? -1 : 1);
4
- const id = (key) => EMPTY_STRING + key;
5
2
 
6
- export {defaultSorter, id};
3
+ export {defaultSorter};
@@ -1,6 +1,6 @@
1
1
  /**
2
- * The indexes module of the TinyBase project provides the ability to create
3
- * and track indexes of the data in Store objects.
2
+ * The indexes module of the TinyBase project provides the ability to create and
3
+ * track indexes of the data in Store objects.
4
4
  *
5
5
  * The main entry point to this module is the createIndexes function, which
6
6
  * returns a new Indexes object. From there, you can create new Index
@@ -209,11 +209,12 @@ export interface Indexes {
209
209
  * derived string value in common, as described by this method. Those values
210
210
  * are used as the key for each Slice in the overall Index object.
211
211
  *
212
- * Without the third `getSliceId` parameter, the Index will simply have a
212
+ * Without the third `getSliceIdOrIds` parameter, the Index will simply have a
213
213
  * single Slice, keyed by an empty string. But more often you will specify a
214
214
  * Cell value containing the Slice Id that the Row should belong to.
215
215
  * Alternatively, a custom function can be provided that produces your own
216
- * Slice Id from the local Row as a whole.
216
+ * Slice Id from the local Row as a whole. Since v2.1, the custom function can
217
+ * return an array of Slice Ids, each of which the Row will then belong to.
217
218
  *
218
219
  * The fourth `getSortKey` parameter specifies a Cell Id to get a value (or a
219
220
  * function that processes a whole Row to get a value) that is used to sort
@@ -241,11 +242,13 @@ export interface Indexes {
241
242
  *
242
243
  * @param indexId The Id of the Index to define.
243
244
  * @param tableId The Id of the Table the Index will be generated from.
244
- * @param getSliceId Either the Id of the Cell containing, or a function that
245
- * produces, the Id that is used to indicate which Slice in the Index the Row
246
- * Id should be in. Defaults to a function that returns `''` (meaning that if
247
- * this `getSliceId` parameter is omitted, the Index will simply contain a
248
- * single Slice containing all the Row Ids in the Table).
245
+ * @param getSliceIdOrIds Either the Id of the Cell containing, or a function
246
+ * that produces, the Id that is used to indicate which Slice in the Index the
247
+ * Row Id should be in. Defaults to a function that returns `''` (meaning that
248
+ * if this `getSliceIdOrIds` parameter is omitted, the Index will simply
249
+ * contain a single Slice containing all the Row Ids in the Table). Since
250
+ * v2.1, this can return an array of Slice Ids, each of which the Row will
251
+ * then belong to.
249
252
  * @param getSortKey Either the Id of the Cell containing, or a function that
250
253
  * produces, the value that is used to sort the Row Ids in each Slice.
251
254
  * @param sliceIdSorter A function that takes two Slice Id values and returns
@@ -294,6 +297,29 @@ export interface Indexes {
294
297
  * ```
295
298
  * @example
296
299
  * This example creates a Store, creates an Indexes object, and defines an
300
+ * Index based on each of the letters present in the pets' names.
301
+ *
302
+ * ```js
303
+ * const store = createStore().setTable('pets', {
304
+ * fido: {species: 'dog'},
305
+ * felix: {species: 'cat'},
306
+ * rex: {species: 'dog'},
307
+ * });
308
+ *
309
+ * const indexes = createIndexes(store);
310
+ * indexes.setIndexDefinition('containsLetter', 'pets', (_, rowId) =>
311
+ * rowId.split(''),
312
+ * );
313
+ *
314
+ * console.log(indexes.getSliceIds('containsLetter'));
315
+ * // -> ['f', 'i', 'd', 'o', 'e', 'l', 'x', 'r']
316
+ * console.log(indexes.getSliceRowIds('containsLetter', 'i'));
317
+ * // -> ['fido', 'felix']
318
+ * console.log(indexes.getSliceRowIds('containsLetter', 'x'));
319
+ * // -> ['felix', 'rex']
320
+ * ```
321
+ * @example
322
+ * This example creates a Store, creates an Indexes object, and defines an
297
323
  * Index based on the first letter of the pets' names. The Slice Ids (and Row
298
324
  * Ids within them) are alphabetically sorted.
299
325
  *
@@ -324,7 +350,7 @@ export interface Indexes {
324
350
  setIndexDefinition(
325
351
  indexId: Id,
326
352
  tableId: Id,
327
- getSliceId?: Id | ((getCell: GetCell, rowId: Id) => Id),
353
+ getSliceIdOrIds?: Id | ((getCell: GetCell, rowId: Id) => Id | Ids),
328
354
  getSortKey?: Id | ((getCell: GetCell, rowId: Id) => SortKey),
329
355
  sliceIdSorter?: (sliceId1: Id, sliceId2: Id) => number,
330
356
  rowIdSorter?: (sortKey1: SortKey, sortKey2: SortKey, sliceId: Id) => number,
@@ -1,8 +1,12 @@
1
1
  const getTypeOf = (thing) => typeof thing;
2
2
  const EMPTY_STRING = '';
3
3
  const STRING = getTypeOf(EMPTY_STRING);
4
+ const id = (key) => EMPTY_STRING + key;
4
5
 
5
6
  const arrayEvery = (array, cb) => array.every(cb);
7
+ const arrayIsEqual = (array1, array2) =>
8
+ arrayLength(array1) === arrayLength(array2) &&
9
+ arrayEvery(array1, (value1, index) => array2[index] === value1);
6
10
  const arrayIsSorted = (array, sorter) =>
7
11
  arrayEvery(
8
12
  array,
@@ -10,6 +14,7 @@ const arrayIsSorted = (array, sorter) =>
10
14
  );
11
15
  const arraySort = (array, sorter) => array.sort(sorter);
12
16
  const arrayForEach = (array, cb) => array.forEach(cb);
17
+ const arrayMap = (array, cb) => array.map(cb);
13
18
  const arrayLength = (array) => array.length;
14
19
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
15
20
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
@@ -20,6 +25,7 @@ const isUndefined = (thing) => thing == void 0;
20
25
  const ifNotUndefined = (value, then, otherwise) =>
21
26
  isUndefined(value) ? otherwise?.() : then(value);
22
27
  const isString = (thing) => getTypeOf(thing) == STRING;
28
+ const isArray = (thing) => Array.isArray(thing);
23
29
 
24
30
  const collSizeN = (collSizer) => (coll) =>
25
31
  arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
@@ -68,7 +74,12 @@ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
68
74
  },
69
75
  );
70
76
 
71
- const setNew = (entries) => new Set(entries);
77
+ const setNew = (entryOrEntries) =>
78
+ new Set(
79
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
80
+ ? entryOrEntries
81
+ : [entryOrEntries],
82
+ );
72
83
  const setAdd = (set, value) => set?.add(value);
73
84
 
74
85
  const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
@@ -133,7 +144,14 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
133
144
  const newRowValue = hasRow(tableId, rowId)
134
145
  ? validateRowValue(getRowValue(getCell, rowId))
135
146
  : void 0;
136
- if (oldRowValue != newRowValue) {
147
+ if (
148
+ !(
149
+ oldRowValue === newRowValue ||
150
+ (isArray(oldRowValue) &&
151
+ isArray(newRowValue) &&
152
+ arrayIsEqual(oldRowValue, newRowValue))
153
+ )
154
+ ) {
137
155
  mapSet(changedRowValues, rowId, [oldRowValue, newRowValue]);
138
156
  }
139
157
  if (!isUndefined(getSortKey)) {
@@ -312,7 +330,11 @@ const createIndexes = getCreateFunction((store) => {
312
330
  delDefinition,
313
331
  destroy,
314
332
  ] = getDefinableFunctions(store, mapNew, (value) =>
315
- isUndefined(value) ? EMPTY_STRING : value + EMPTY_STRING,
333
+ isUndefined(value)
334
+ ? EMPTY_STRING
335
+ : isArray(value)
336
+ ? arrayMap(value, id)
337
+ : id(value),
316
338
  );
317
339
  const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
318
340
  () => indexes,
@@ -321,7 +343,7 @@ const createIndexes = getCreateFunction((store) => {
321
343
  const setIndexDefinition = (
322
344
  indexId,
323
345
  tableId,
324
- getSliceId,
346
+ getSliceIdOrIds,
325
347
  getSortKey,
326
348
  sliceIdSorter,
327
349
  rowIdSorter = defaultSorter,
@@ -337,29 +359,39 @@ const createIndexes = getCreateFunction((store) => {
337
359
  const changedSlices = setNew();
338
360
  const unsortedSlices = setNew();
339
361
  const index = getIndex(indexId);
340
- collForEach(changedSliceIds, ([oldSliceId, newSliceId], rowId) => {
341
- if (!isUndefined(oldSliceId)) {
342
- setAdd(changedSlices, oldSliceId);
343
- ifNotUndefined(mapGet(index, oldSliceId), (oldSlice) => {
344
- collDel(oldSlice, rowId);
345
- if (collIsEmpty(oldSlice)) {
346
- mapSet(index, oldSliceId);
362
+ collForEach(
363
+ changedSliceIds,
364
+ ([oldSliceIdOrIds, newSliceIdOrIds], rowId) => {
365
+ const oldSliceIds = setNew(oldSliceIdOrIds);
366
+ const newSliceIds = setNew(newSliceIdOrIds);
367
+ collForEach(oldSliceIds, (oldSliceId) =>
368
+ collDel(newSliceIds, oldSliceId)
369
+ ? collDel(oldSliceIds, oldSliceId)
370
+ : 0,
371
+ );
372
+ collForEach(oldSliceIds, (oldSliceId) => {
373
+ setAdd(changedSlices, oldSliceId);
374
+ ifNotUndefined(mapGet(index, oldSliceId), (oldSlice) => {
375
+ collDel(oldSlice, rowId);
376
+ if (collIsEmpty(oldSlice)) {
377
+ mapSet(index, oldSliceId);
378
+ sliceIdsChanged = 1;
379
+ }
380
+ });
381
+ });
382
+ collForEach(newSliceIds, (newSliceId) => {
383
+ setAdd(changedSlices, newSliceId);
384
+ if (!collHas(index, newSliceId)) {
385
+ mapSet(index, newSliceId, setNew());
347
386
  sliceIdsChanged = 1;
348
387
  }
388
+ setAdd(mapGet(index, newSliceId), rowId);
389
+ if (!isUndefined(getSortKey)) {
390
+ setAdd(unsortedSlices, newSliceId);
391
+ }
349
392
  });
350
- }
351
- if (!isUndefined(newSliceId)) {
352
- setAdd(changedSlices, newSliceId);
353
- if (!collHas(index, newSliceId)) {
354
- mapSet(index, newSliceId, setNew());
355
- sliceIdsChanged = 1;
356
- }
357
- setAdd(mapGet(index, newSliceId), rowId);
358
- if (!isUndefined(getSortKey)) {
359
- setAdd(unsortedSlices, newSliceId);
360
- }
361
- }
362
- });
393
+ },
394
+ );
363
395
  change();
364
396
  if (!collIsEmpty(sortKeys)) {
365
397
  if (force) {
@@ -408,7 +440,7 @@ const createIndexes = getCreateFunction((store) => {
408
440
  callListeners(sliceRowIdsListeners, [indexId, sliceId]),
409
441
  );
410
442
  },
411
- getRowCellFunction(getSliceId),
443
+ getRowCellFunction(getSliceIdOrIds),
412
444
  ifNotUndefined(getSortKey, getRowCellFunction),
413
445
  );
414
446
  return indexes;
@@ -210,7 +210,7 @@ export type MetricsListenerStats = {
210
210
  *
211
211
  * @example
212
212
  * This example shows a very simple lifecycle of a Metrics object: from
213
- * creation, to adding a definition, getting an Metric, and then registering and
213
+ * creation, to adding a definition, getting a Metric, and then registering and
214
214
  * removing a listener for it.
215
215
  *
216
216
  * ```js
@@ -7,6 +7,10 @@ const AVG = 'avg';
7
7
  const MIN = 'min';
8
8
  const MAX = 'max';
9
9
 
10
+ const arrayEvery = (array, cb) => array.every(cb);
11
+ const arrayIsEqual = (array1, array2) =>
12
+ arrayLength(array1) === arrayLength(array2) &&
13
+ arrayEvery(array1, (value1, index) => array2[index] === value1);
10
14
  const arrayForEach = (array, cb) => array.forEach(cb);
11
15
  const arraySum = (array) => arrayReduce(array, (i, j) => i + j, 0);
12
16
  const arrayLength = (array) => array.length;
@@ -23,6 +27,7 @@ const ifNotUndefined = (value, then, otherwise) =>
23
27
  isUndefined(value) ? otherwise?.() : then(value);
24
28
  const isString = (thing) => getTypeOf(thing) == STRING;
25
29
  const isFunction = (thing) => getTypeOf(thing) == FUNCTION;
30
+ const isArray = (thing) => Array.isArray(thing);
26
31
  const getUndefined = () => void 0;
27
32
 
28
33
  const collSizeN = (collSizer) => (coll) =>
@@ -140,7 +145,12 @@ const getAggregateValue = (
140
145
  : aggregateValue;
141
146
  };
142
147
 
143
- const setNew = (entries) => new Set(entries);
148
+ const setNew = (entryOrEntries) =>
149
+ new Set(
150
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
151
+ ? entryOrEntries
152
+ : [entryOrEntries],
153
+ );
144
154
  const setAdd = (set, value) => set?.add(value);
145
155
 
146
156
  const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
@@ -205,7 +215,14 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
205
215
  const newRowValue = hasRow(tableId, rowId)
206
216
  ? validateRowValue(getRowValue(getCell, rowId))
207
217
  : void 0;
208
- if (oldRowValue != newRowValue) {
218
+ if (
219
+ !(
220
+ oldRowValue === newRowValue ||
221
+ (isArray(oldRowValue) &&
222
+ isArray(newRowValue) &&
223
+ arrayIsEqual(oldRowValue, newRowValue))
224
+ )
225
+ ) {
209
226
  mapSet(changedRowValues, rowId, [oldRowValue, newRowValue]);
210
227
  }
211
228
  if (!isUndefined(getSortKey)) {
@@ -509,7 +509,7 @@ export interface Persister {
509
509
  }
510
510
 
511
511
  /**
512
- * The createSessionPersister function creates an Persister object that can
512
+ * The createSessionPersister function creates a Persister object that can
513
513
  * persist the Store to the browser's session storage.
514
514
  *
515
515
  * As well as providing a reference to the Store to persist, you must provide a
@@ -542,7 +542,7 @@ export function createSessionPersister(
542
542
  ): Persister;
543
543
 
544
544
  /**
545
- * The createLocalPersister function creates an Persister object that can
545
+ * The createLocalPersister function creates a Persister object that can
546
546
  * persist the Store to the browser's local storage.
547
547
  *
548
548
  * As well as providing a reference to the Store to persist, you must provide a
@@ -575,7 +575,7 @@ export function createLocalPersister(
575
575
  ): Persister;
576
576
 
577
577
  /**
578
- * The createRemotePersister function creates an Persister object that can
578
+ * The createRemotePersister function creates a Persister object that can
579
579
  * persist the Store to a remote server.
580
580
  *
581
581
  * As well as providing a reference to the Store to persist, you must provide
@@ -624,7 +624,7 @@ export function createRemotePersister(
624
624
  ): Persister;
625
625
 
626
626
  /**
627
- * The createFilePersister function creates an Persister object that can persist
627
+ * The createFilePersister function creates a Persister object that can persist
628
628
  * the Store to a local file (in an appropriate environment).
629
629
  *
630
630
  * As well as providing a reference to the Store to persist, you must provide
@@ -654,7 +654,7 @@ export function createRemotePersister(
654
654
  export function createFilePersister(store: Store, filePath: string): Persister;
655
655
 
656
656
  /**
657
- * The createCustomPersister function creates an Persister object that you can
657
+ * The createCustomPersister function creates a Persister object that you can
658
658
  * configure to persist the Store in any way you wish.
659
659
  *
660
660
  * As well as providing a reference to the Store to persist, you must provide
@@ -20,6 +20,9 @@ const CELL_IDS = 'CellIds';
20
20
  const CELL = 'Cell';
21
21
 
22
22
  const arrayEvery = (array, cb) => array.every(cb);
23
+ const arrayIsEqual = (array1, array2) =>
24
+ arrayLength(array1) === arrayLength(array2) &&
25
+ arrayEvery(array1, (value1, index) => array2[index] === value1);
23
26
  const arrayForEach = (array, cb) => array.forEach(cb);
24
27
  const arraySum = (array) => arrayReduce(array, (i, j) => i + j, 0);
25
28
  const arrayLength = (array) => array.length;
@@ -36,6 +39,7 @@ const ifNotUndefined = (value, then, otherwise) =>
36
39
  isUndefined(value) ? otherwise?.() : then(value);
37
40
  const isTypeStringOrBoolean = (type) => type == STRING || type == BOOLEAN;
38
41
  const isFunction = (thing) => getTypeOf(thing) == FUNCTION;
42
+ const isArray = (thing) => Array.isArray(thing);
39
43
  const getUndefined = () => void 0;
40
44
 
41
45
  const collSize = (coll) => coll.size;
@@ -81,7 +85,12 @@ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
81
85
  },
82
86
  );
83
87
 
84
- const setNew = (entries) => new Set(entries);
88
+ const setNew = (entryOrEntries) =>
89
+ new Set(
90
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
91
+ ? entryOrEntries
92
+ : [entryOrEntries],
93
+ );
85
94
  const setAdd = (set, value) => set?.add(value);
86
95
 
87
96
  const numericAggregators = mapNew([
@@ -226,7 +235,14 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
226
235
  const newRowValue = hasRow(tableId, rowId)
227
236
  ? validateRowValue(getRowValue(getCell, rowId))
228
237
  : void 0;
229
- if (oldRowValue != newRowValue) {
238
+ if (
239
+ !(
240
+ oldRowValue === newRowValue ||
241
+ (isArray(oldRowValue) &&
242
+ isArray(newRowValue) &&
243
+ arrayIsEqual(oldRowValue, newRowValue))
244
+ )
245
+ ) {
230
246
  mapSet(changedRowValues, rowId, [oldRowValue, newRowValue]);
231
247
  }
232
248
  if (!isUndefined(getSortKey)) {
@@ -1091,7 +1091,7 @@ export interface Relationships {
1091
1091
  * the underlying Store are removed and it can be correctly garbage collected.
1092
1092
  *
1093
1093
  * @example
1094
- * This example creates a Store, adds an Relationships object with a
1094
+ * This example creates a Store, adds a Relationships object with a
1095
1095
  * definition (that registers a RowListener with the underlying Store),
1096
1096
  * and then destroys it again, removing the listener.
1097
1097
  *
@@ -1167,7 +1167,7 @@ export interface Relationships {
1167
1167
  }
1168
1168
 
1169
1169
  /**
1170
- * The createRelationships function creates an Relationships object, and is the
1170
+ * The createRelationships function creates a Relationships object, and is the
1171
1171
  * main entry point into the relationships module.
1172
1172
  *
1173
1173
  * It is trivially simple.
@@ -1179,7 +1179,7 @@ export interface Relationships {
1179
1179
  * @param store The Store for which to register Relationships.
1180
1180
  * @returns A reference to the new Relationships object.
1181
1181
  * @example
1182
- * This example creates an Relationships object.
1182
+ * This example creates a Relationships object.
1183
1183
  *
1184
1184
  * ```js
1185
1185
  * const store = createStore();
@@ -2,6 +2,10 @@ const getTypeOf = (thing) => typeof thing;
2
2
  const EMPTY_STRING = '';
3
3
  const STRING = getTypeOf(EMPTY_STRING);
4
4
 
5
+ const arrayEvery = (array, cb) => array.every(cb);
6
+ const arrayIsEqual = (array1, array2) =>
7
+ arrayLength(array1) === arrayLength(array2) &&
8
+ arrayEvery(array1, (value1, index) => array2[index] === value1);
5
9
  const arrayForEach = (array, cb) => array.forEach(cb);
6
10
  const arrayLength = (array) => array.length;
7
11
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
@@ -13,6 +17,7 @@ const isUndefined = (thing) => thing == void 0;
13
17
  const ifNotUndefined = (value, then, otherwise) =>
14
18
  isUndefined(value) ? otherwise?.() : then(value);
15
19
  const isString = (thing) => getTypeOf(thing) == STRING;
20
+ const isArray = (thing) => Array.isArray(thing);
16
21
 
17
22
  const collSizeN = (collSizer) => (coll) =>
18
23
  arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
@@ -61,7 +66,12 @@ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
61
66
  },
62
67
  );
63
68
 
64
- const setNew = (entries) => new Set(entries);
69
+ const setNew = (entryOrEntries) =>
70
+ new Set(
71
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
72
+ ? entryOrEntries
73
+ : [entryOrEntries],
74
+ );
65
75
  const setAdd = (set, value) => set?.add(value);
66
76
 
67
77
  const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
@@ -126,7 +136,14 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
126
136
  const newRowValue = hasRow(tableId, rowId)
127
137
  ? validateRowValue(getRowValue(getCell, rowId))
128
138
  : void 0;
129
- if (oldRowValue != newRowValue) {
139
+ if (
140
+ !(
141
+ oldRowValue === newRowValue ||
142
+ (isArray(oldRowValue) &&
143
+ isArray(newRowValue) &&
144
+ arrayIsEqual(oldRowValue, newRowValue))
145
+ )
146
+ ) {
130
147
  mapSet(changedRowValues, rowId, [oldRowValue, newRowValue]);
131
148
  }
132
149
  if (!isUndefined(getSortKey)) {
@@ -16,6 +16,7 @@ const ROW_IDS = 'RowIds';
16
16
  const ROW = 'Row';
17
17
  const CELL_IDS = 'CellIds';
18
18
  const CELL = 'Cell';
19
+ const id = (key) => EMPTY_STRING + key;
19
20
 
20
21
  const arrayHas = (array, value) => array.includes(value);
21
22
  const arrayEvery = (array, cb) => array.every(cb);
@@ -54,6 +55,7 @@ const ifNotUndefined = (value, then, otherwise) =>
54
55
  isUndefined(value) ? otherwise?.() : then(value);
55
56
  const isTypeStringOrBoolean = (type) => type == STRING || type == BOOLEAN;
56
57
  const isFunction = (thing) => getTypeOf(thing) == FUNCTION;
58
+ const isArray = (thing) => Array.isArray(thing);
57
59
 
58
60
  const collSizeN = (collSizer) => (coll) =>
59
61
  arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
@@ -133,7 +135,12 @@ const objForEach = (obj, cb) =>
133
135
  arrayForEach(object.entries(obj), ([id, value]) => cb(value, id));
134
136
  const objIsEmpty = (obj) => arrayIsEmpty(objIds(obj));
135
137
 
136
- const setNew = (entries) => new Set(entries);
138
+ const setNew = (entryOrEntries) =>
139
+ new Set(
140
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
141
+ ? entryOrEntries
142
+ : [entryOrEntries],
143
+ );
137
144
  const setAdd = (set, value) => set?.add(value);
138
145
 
139
146
  const INTEGER = /^\d+$/;
@@ -221,7 +228,6 @@ const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
221
228
  : store.setCell(tableId, rowId, cellId, cell);
222
229
 
223
230
  const defaultSorter = (sortKey1, sortKey2) => (sortKey1 < sortKey2 ? -1 : 1);
224
- const id = (key) => EMPTY_STRING + key;
225
231
 
226
232
  const transformMap = (map, toBeLikeObject, setId, delId = mapSet) => {
227
233
  const idsToDelete = arrayFilter(