tinybase 1.3.5 → 2.0.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 (53) hide show
  1. package/lib/checkpoints.js +1 -1
  2. package/lib/checkpoints.js.gz +0 -0
  3. package/lib/debug/checkpoints.js +67 -54
  4. package/lib/debug/indexes.js +104 -67
  5. package/lib/debug/metrics.js +185 -129
  6. package/lib/debug/persisters.js +2 -1
  7. package/lib/debug/queries.d.ts +3066 -0
  8. package/lib/debug/queries.js +883 -0
  9. package/lib/debug/relationships.d.ts +6 -5
  10. package/lib/debug/relationships.js +102 -66
  11. package/lib/debug/store.d.ts +128 -65
  12. package/lib/debug/store.js +215 -119
  13. package/lib/debug/tinybase.d.ts +1 -0
  14. package/lib/debug/tinybase.js +895 -175
  15. package/lib/debug/ui-react.d.ts +49 -2
  16. package/lib/debug/ui-react.js +85 -74
  17. package/lib/indexes.js +1 -1
  18. package/lib/indexes.js.gz +0 -0
  19. package/lib/metrics.js +1 -1
  20. package/lib/metrics.js.gz +0 -0
  21. package/lib/queries.d.ts +3066 -0
  22. package/lib/queries.js +1 -0
  23. package/lib/queries.js.gz +0 -0
  24. package/lib/relationships.d.ts +6 -5
  25. package/lib/relationships.js +1 -1
  26. package/lib/relationships.js.gz +0 -0
  27. package/lib/store.d.ts +128 -65
  28. package/lib/store.js +1 -1
  29. package/lib/store.js.gz +0 -0
  30. package/lib/tinybase.d.ts +1 -0
  31. package/lib/tinybase.js +1 -1
  32. package/lib/tinybase.js.gz +0 -0
  33. package/lib/ui-react.d.ts +49 -2
  34. package/lib/ui-react.js +1 -1
  35. package/lib/ui-react.js.gz +0 -0
  36. package/lib/umd/checkpoints.js +1 -1
  37. package/lib/umd/checkpoints.js.gz +0 -0
  38. package/lib/umd/indexes.js +1 -1
  39. package/lib/umd/indexes.js.gz +0 -0
  40. package/lib/umd/metrics.js +1 -1
  41. package/lib/umd/metrics.js.gz +0 -0
  42. package/lib/umd/queries.js +1 -0
  43. package/lib/umd/queries.js.gz +0 -0
  44. package/lib/umd/relationships.js +1 -1
  45. package/lib/umd/relationships.js.gz +0 -0
  46. package/lib/umd/store.js +1 -1
  47. package/lib/umd/store.js.gz +0 -0
  48. package/lib/umd/tinybase.js +1 -1
  49. package/lib/umd/tinybase.js.gz +0 -0
  50. package/lib/umd/ui-react.js +1 -1
  51. package/lib/umd/ui-react.js.gz +0 -0
  52. package/package.json +1 -1
  53. package/readme.md +2 -2
@@ -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),r=e=>e.slice(1),o=(e,t)=>e.push(t),c=e=>e.pop(),l=e=>null==e,i=(e,t,n)=>l(e)?n?.():t(e),a=(e,t)=>e?.has(t)??!1,d=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)=>(a(e,t)||e.set(t,n()),C(e,t)),f=e=>new Set(e),L=(e,t,o)=>n(o)<2?((e,t)=>e?.add(t))(s(o)?e:k(e,o[0],f),t):L(k(e,o[0],p),t,r(o)),w=e=>{const n=(o,c,...l)=>i(o,(o=>s(l)?e(o,c):t([l[0],null],(e=>n(C(o,e),c,...r(l))))));return n},v=Object.freeze,S=(e=>{const t=new WeakMap;return n=>(t.has(n)||t.set(n,e(n)),t.get(n))})((r=>{let S,z,E,I=100,M=p(),b=1;const j=f(),x=p(),[y,B,F]=(e=>{let s,r=0;const a=[],d=p();return[(t,n,o=[])=>{s??=e();const l=c(a)??""+r++;return g(d,l,[t,n,o]),L(n,l,o),l},(e,t=[],...n)=>w(h)(e,(e=>i(C(d,e),(([e])=>e(s,...t,...n)))),...t),e=>i(C(d,e),(([,t,s])=>(w(u)(t,e,...s),g(d,e),n(a)<1e3&&o(a,e),s)),(()=>[])),(e,r,o)=>i(C(d,e),(([e,,c])=>{const i=(...a)=>{const d=n(a);d==n(c)?e(s,...a,...o(a)):l(c[d])?t(r[d](...a),(e=>i(...a,e))):i(...a,c[d])};i()}))]})((()=>V)),O=p(),T=p(),W=[],m=[],q=(e,t)=>{b=0,r.transaction((()=>h(C(O,t),((t,n)=>h(t,((t,s)=>h(t,((t,o)=>l(t[e])?r.delCell(n,s,o,!0):r.setCell(n,s,o,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=r.addCellListener(null,null,null,((e,t,n,s,r,l)=>{if(b){i(S,(()=>{o(W,S),G(),D(m),S=void 0,E=1}));const e=k(M,t,p),a=k(e,n,p),h=k(a,s,(()=>[l,void 0]));h[1]=r,h[0]===r&&d(g(a,s))&&d(g(e,n))&&d(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)||(o(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=>a(O,e),V={setSize:e=>(I=e,G(),V),addCheckpoint:Q,setCheckpoint:R,getStore:()=>r,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:()=>{r.delListener(H)},getListenerStats:()=>({})};return v(V.clear())}));export{S 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),o=(e,...t)=>e.push(...t),s=e=>e.pop(),c=e=>null==e,l=(e,t,n)=>c(e)?n?.():t(e),i=(e,t)=>e?.has(t)??!1,a=e=>c(e)||0==(e=>e.size)(e),d=(e,t)=>e?.forEach(t),u=(e,t)=>e?.delete(t),h=e=>new Map(e),p=(e,t)=>e?.get(t),C=(e,t,n)=>c(n)?(u(e,t),e):e?.set(t,n),g=(e,t,n)=>(i(e,t)||e.set(t,n()),p(e,t)),k=(e,t,r,o,s=0)=>l((r?g:p)(e,t[s],s>n(t)-2?r:h),(c=>{if(s>n(t)-2)return o?.(c)&&C(e,t[s]),c;const l=k(c,t,r,o,s+1);return a(c)&&C(e,t[s]),l})),f=e=>new Set(e),v=(e,r=[""])=>{const s=[],c=(e,l)=>l==n(r)?o(s,e):t([r[l],null],(t=>c(p(e,t),l+1)));return c(e,0),s},L=Object.freeze,w=(e=>{const t=new WeakMap;return n=>(t.has(n)||t.set(n,e(n)),t.get(n))})((w=>{let S,z,E,y=100,I=h(),M=1;const b=h(),j=h(),[x,B,F]=(e=>{let r,i=0;const g=[],L=h();return[(t,n,o)=>{r??=e();const c=s(g)??""+i++;var l;return C(L,c,[t,n,o]),l=c,k(n,o??[""],f)?.add(l),c},(e,n,...o)=>t(v(e,n),(e=>d(e,(e=>l(p(L,e),(([e])=>e(r,...n??[],...o))))))),e=>l(p(L,e),(([,t,r])=>(k(t,r??[""],void 0,(t=>(u(t,e),a(t)?1:0))),C(L,e),n(g)<1e3&&o(g,e),r))),(e,t)=>{return n=v(e,t),r=c,!n.every(r);var n,r},(e,o,s)=>l(p(L,e),(([e,,l=[]])=>{const i=(...a)=>{const d=n(a);d==n(l)?e(r,...a,...s(a)):c(l[d])?t(o[d](...a),(e=>i(...a,e))):i(...a,l[d])};i()}))]})((()=>V)),O=h(),T=h(),W=[],m=[],q=(e,t)=>{M=0,w.transaction((()=>d(p(O,t),((t,n)=>d(t,((t,r)=>d(t,((t,o)=>((e,t,n,r,o)=>c(o)?e.delCell(t,n,r,!0):e.setCell(t,n,r,o))(w,n,r,o,t[e]))))))))),M=1},A=e=>{C(O,e),C(T,e),B(j,[e])},D=(e,r)=>t(((e,t)=>e.splice(0,t))(e,r??n(e)),A),G=()=>D(W,n(W)-y),H=w.addCellListener(null,null,null,((e,t,n,r,c,i)=>{if(M){l(S,(()=>{o(W,S),G(),D(m),S=void 0,E=1}));const e=g(I,t,h),d=g(e,n,h),u=g(d,r,(()=>[i,void 0]));u[1]=c,u[0]===c&&a(C(d,r))&&a(C(e,n))&&a(C(I,t))&&(S=s(W),E=1),P()}})),J=(e="")=>(c(S)&&(S=""+z++,C(O,S,I),R(S,e),I=h(),E=1),S),K=()=>{r(W)||(m.unshift(J()),q(0,S),S=s(W),E=1)},N=()=>{r(m)||(o(W,S),S=m.shift(),q(1,S),E=1)},P=()=>{E&&(B(b),E=0)},Q=e=>{const t=J(e);return P(),t},R=(e,t)=>(U(e)&&p(T,e)!==t&&(C(T,e,t),B(j,[e])),V),U=e=>i(O,e),V={setSize:e=>(y=e,G(),V),addCheckpoint:Q,setCheckpoint:R,getStore:()=>w,getCheckpointIds:()=>[[...W],S,[...m]],forEachCheckpoint:e=>{return t=e,d(T,((e,n)=>t(n,e)));var t},hasCheckpoint:U,getCheckpoint:e=>p(T,e),goBackward:()=>(K(),P(),V),goForward:()=>(N(),P(),V),goTo:t=>{const n=e(W,t)?K:e(m,t)?N:null;for(;!c(n)&&t!=S;)n();return P(),V},addCheckpointIdsListener:e=>x(e,b),addCheckpointListener:(e,t)=>x(t,j,[e]),delListener:e=>(F(e),V),clear:()=>(D(W),D(m),c(S)||A(S),S=void 0,z=0,Q(),V),destroy:()=>{w.delListener(H)},getListenerStats:()=>({})};return L(V.clear())}));export{w as createCheckpoints};
Binary file
@@ -1,11 +1,13 @@
1
+ const EMPTY_STRING = '';
2
+
1
3
  const arrayHas = (array, value) => array.includes(value);
4
+ const arrayEvery = (array, cb) => array.every(cb);
2
5
  const arrayForEach = (array, cb) => array.forEach(cb);
3
6
  const arrayLength = (array) => array.length;
4
7
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
5
8
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
6
- const arrayFromSecond = (ids) => ids.slice(1);
7
9
  const arrayClear = (array, to) => array.splice(0, to);
8
- const arrayPush = (array, value) => array.push(value);
10
+ const arrayPush = (array, ...values) => array.push(...values);
9
11
  const arrayPop = (array) => array.pop();
10
12
 
11
13
  const isUndefined = (thing) => thing == void 0;
@@ -34,6 +36,27 @@ const mapEnsure = (map, key, getDefaultValue) => {
34
36
  }
35
37
  return mapGet(map, key);
36
38
  };
39
+ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
40
+ ifNotUndefined(
41
+ (ensureLeaf ? mapEnsure : mapGet)(
42
+ node,
43
+ path[p],
44
+ p > arrayLength(path) - 2 ? ensureLeaf : mapNew,
45
+ ),
46
+ (nodeOrLeaf) => {
47
+ if (p > arrayLength(path) - 2) {
48
+ if (pruneLeaf?.(nodeOrLeaf)) {
49
+ mapSet(node, path[p]);
50
+ }
51
+ return nodeOrLeaf;
52
+ }
53
+ const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
54
+ if (collIsEmpty(nodeOrLeaf)) {
55
+ mapSet(node, path[p]);
56
+ }
57
+ return leaf;
58
+ },
59
+ );
37
60
 
38
61
  const setNew = (entries) => new Set(entries);
39
62
  const setAdd = (set, value) => set?.add(value);
@@ -48,64 +71,51 @@ const getCreateFunction = (getFunction) => {
48
71
  };
49
72
  };
50
73
 
51
- const addDeepSet = (deepSet, value, ids) =>
52
- arrayLength(ids) < 2
53
- ? setAdd(
54
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
55
- value,
56
- )
57
- : addDeepSet(
58
- mapEnsure(deepSet, ids[0], mapNew),
59
- value,
60
- arrayFromSecond(ids),
61
- );
62
- const forDeepSet = (valueDo) => {
63
- const deep = (deepIdSet, arg, ...ids) =>
64
- ifNotUndefined(deepIdSet, (deepIdSet2) =>
65
- arrayIsEmpty(ids)
66
- ? valueDo(deepIdSet2, arg)
67
- : arrayForEach([ids[0], null], (id) =>
68
- deep(mapGet(deepIdSet2, id), arg, ...arrayFromSecond(ids)),
69
- ),
70
- );
71
- return deep;
74
+ const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
75
+ const sets = [];
76
+ const deep = (set, p) =>
77
+ p == arrayLength(path)
78
+ ? arrayPush(sets, set)
79
+ : arrayForEach([path[p], null], (id) => deep(mapGet(set, id), p + 1));
80
+ deep(deepIdSet, 0);
81
+ return sets;
72
82
  };
73
83
  const getListenerFunctions = (getThing) => {
74
84
  let thing;
75
85
  let nextId = 0;
76
86
  const listenerPool = [];
77
87
  const allListeners = mapNew();
78
- const addListener = (listener, deepSet, idOrNulls = []) => {
88
+ const addListener = (listener, idSetNode, idOrNulls) => {
79
89
  thing ??= getThing();
80
- const id = arrayPop(listenerPool) ?? '' + nextId++;
81
- mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
82
- addDeepSet(deepSet, id, idOrNulls);
90
+ const id = arrayPop(listenerPool) ?? EMPTY_STRING + nextId++;
91
+ mapSet(allListeners, id, [listener, idSetNode, idOrNulls]);
92
+ setAdd(visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], setNew), id);
83
93
  return id;
84
94
  };
85
- const callListeners = (deepSet, ids = [], ...extraArgs) =>
86
- forDeepSet(collForEach)(
87
- deepSet,
88
- (id) =>
95
+ const callListeners = (idSetNode, ids, ...extraArgs) =>
96
+ arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
97
+ collForEach(set, (id) =>
89
98
  ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
90
- listener(thing, ...ids, ...extraArgs),
99
+ listener(thing, ...(ids ?? []), ...extraArgs),
91
100
  ),
92
- ...ids,
101
+ ),
93
102
  );
94
103
  const delListener = (id) =>
95
- ifNotUndefined(
96
- mapGet(allListeners, id),
97
- ([, deepSet, idOrNulls]) => {
98
- forDeepSet(collDel)(deepSet, id, ...idOrNulls);
99
- mapSet(allListeners, id);
100
- if (arrayLength(listenerPool) < 1e3) {
101
- arrayPush(listenerPool, id);
102
- }
103
- return idOrNulls;
104
- },
105
- () => [],
106
- );
104
+ ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
105
+ visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
106
+ collDel(idSet, id);
107
+ return collIsEmpty(idSet) ? 1 : 0;
108
+ });
109
+ mapSet(allListeners, id);
110
+ if (arrayLength(listenerPool) < 1e3) {
111
+ arrayPush(listenerPool, id);
112
+ }
113
+ return idOrNulls;
114
+ });
115
+ const hasListeners = (idSetNode, ids) =>
116
+ !arrayEvery(getWildcardedLeaves(idSetNode, ids), isUndefined);
107
117
  const callListener = (id, idNullGetters, extraArgsGetter) =>
108
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls]) => {
118
+ ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
109
119
  const callWithIds = (...ids) => {
110
120
  const index = arrayLength(ids);
111
121
  index == arrayLength(idOrNulls)
@@ -118,12 +128,17 @@ const getListenerFunctions = (getThing) => {
118
128
  };
119
129
  callWithIds();
120
130
  });
121
- return [addListener, callListeners, delListener, callListener];
131
+ return [addListener, callListeners, delListener, hasListeners, callListener];
122
132
  };
123
133
 
124
134
  const object = Object;
125
135
  const objFreeze = object.freeze;
126
136
 
137
+ const setOrDelCell = (store, tableId, rowId, cellId, cell) =>
138
+ isUndefined(cell)
139
+ ? store.delCell(tableId, rowId, cellId, true)
140
+ : store.setCell(tableId, rowId, cellId, cell);
141
+
127
142
  const createCheckpoints = getCreateFunction((store) => {
128
143
  let backwardIdsSize = 100;
129
144
  let currentId;
@@ -131,7 +146,7 @@ const createCheckpoints = getCreateFunction((store) => {
131
146
  let listening = 1;
132
147
  let nextCheckpointId;
133
148
  let checkpointsChanged;
134
- const checkpointIdsListeners = setNew();
149
+ const checkpointIdsListeners = mapNew();
135
150
  const checkpointListeners = mapNew();
136
151
  const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
137
152
  () => checkpoints,
@@ -146,9 +161,7 @@ const createCheckpoints = getCreateFunction((store) => {
146
161
  collForEach(mapGet(deltas, checkpointId), (table, tableId) =>
147
162
  collForEach(table, (row, rowId) =>
148
163
  collForEach(row, (oldNew, cellId) =>
149
- isUndefined(oldNew[oldOrNew])
150
- ? store.delCell(tableId, rowId, cellId, true)
151
- : store.setCell(tableId, rowId, cellId, oldNew[oldOrNew]),
164
+ setOrDelCell(store, tableId, rowId, cellId, oldNew[oldOrNew]),
152
165
  ),
153
166
  ),
154
167
  ),
@@ -198,9 +211,9 @@ const createCheckpoints = getCreateFunction((store) => {
198
211
  }
199
212
  },
200
213
  );
201
- const addCheckpointImpl = (label = '') => {
214
+ const addCheckpointImpl = (label = EMPTY_STRING) => {
202
215
  if (isUndefined(currentId)) {
203
- currentId = '' + nextCheckpointId++;
216
+ currentId = EMPTY_STRING + nextCheckpointId++;
204
217
  mapSet(deltas, currentId, delta);
205
218
  setCheckpoint(currentId, label);
206
219
  delta = mapNew();
@@ -298,7 +311,7 @@ const createCheckpoints = getCreateFunction((store) => {
298
311
  store.delListener(listenerId);
299
312
  };
300
313
  const getListenerStats = () => ({
301
- checkpointIds: collSize(checkpointIdsListeners),
314
+ checkpointIds: collSize2(checkpointIdsListeners),
302
315
  checkpoint: collSize2(checkpointListeners),
303
316
  });
304
317
  const checkpoints = {
@@ -2,8 +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);
5
6
  const arrayIsSorted = (array, sorter) =>
6
- array.every(
7
+ arrayEvery(
8
+ array,
7
9
  (value, index) => index == 0 || sorter(array[index - 1], value) <= 0,
8
10
  );
9
11
  const arraySort = (array, sorter) => array.sort(sorter);
@@ -11,8 +13,7 @@ const arrayForEach = (array, cb) => array.forEach(cb);
11
13
  const arrayLength = (array) => array.length;
12
14
  const arrayIsEmpty = (array) => arrayLength(array) == 0;
13
15
  const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
14
- const arrayFromSecond = (ids) => ids.slice(1);
15
- const arrayPush = (array, value) => array.push(value);
16
+ const arrayPush = (array, ...values) => array.push(...values);
16
17
  const arrayPop = (array) => array.pop();
17
18
 
18
19
  const isUndefined = (thing) => thing == void 0;
@@ -45,6 +46,27 @@ const mapEnsure = (map, key, getDefaultValue) => {
45
46
  }
46
47
  return mapGet(map, key);
47
48
  };
49
+ const visitTree = (node, path, ensureLeaf, pruneLeaf, p = 0) =>
50
+ ifNotUndefined(
51
+ (ensureLeaf ? mapEnsure : mapGet)(
52
+ node,
53
+ path[p],
54
+ p > arrayLength(path) - 2 ? ensureLeaf : mapNew,
55
+ ),
56
+ (nodeOrLeaf) => {
57
+ if (p > arrayLength(path) - 2) {
58
+ if (pruneLeaf?.(nodeOrLeaf)) {
59
+ mapSet(node, path[p]);
60
+ }
61
+ return nodeOrLeaf;
62
+ }
63
+ const leaf = visitTree(nodeOrLeaf, path, ensureLeaf, pruneLeaf, p + 1);
64
+ if (collIsEmpty(nodeOrLeaf)) {
65
+ mapSet(node, path[p]);
66
+ }
67
+ return leaf;
68
+ },
69
+ );
48
70
 
49
71
  const setNew = (entries) => new Set(entries);
50
72
  const setAdd = (set, value) => set?.add(value);
@@ -63,20 +85,46 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
63
85
  const getTableId = (id) => mapGet(tableIds, id);
64
86
  const getThing = (id) => mapGet(things, id);
65
87
  const setThing = (id, thing) => mapSet(things, id, thing);
66
- const removeStoreListeners = (id) =>
67
- ifNotUndefined(mapGet(storeListenerIds, id), (listenerIds) => {
68
- collForEach(listenerIds, store.delListener);
69
- mapSet(storeListenerIds, id);
88
+ const addStoreListeners = (id, andCall, ...listenerIds) => {
89
+ const set = mapEnsure(storeListenerIds, id, setNew);
90
+ arrayForEach(
91
+ listenerIds,
92
+ (listenerId) =>
93
+ setAdd(set, listenerId) && andCall && store.callListener(listenerId),
94
+ );
95
+ return listenerIds;
96
+ };
97
+ const delStoreListeners = (id, ...listenerIds) =>
98
+ ifNotUndefined(mapGet(storeListenerIds, id), (allListenerIds) => {
99
+ arrayForEach(
100
+ arrayIsEmpty(listenerIds) ? collValues(allListenerIds) : listenerIds,
101
+ (listenerId) => {
102
+ store.delListener(listenerId);
103
+ collDel(allListenerIds, listenerId);
104
+ },
105
+ );
106
+ if (collIsEmpty(allListenerIds)) {
107
+ mapSet(storeListenerIds, id);
108
+ }
70
109
  });
71
- const setDefinition = (id, tableId, onChanged, getRowValue, getSortKey) => {
72
- const changedRowValues = mapNew();
73
- const changedSortKeys = mapNew();
110
+ const setDefinition = (id, tableId) => {
74
111
  mapSet(tableIds, id, tableId);
75
112
  if (!collHas(things, id)) {
76
113
  mapSet(things, id, getDefaultThing());
77
114
  mapSet(allRowValues, id, mapNew());
78
115
  mapSet(allSortKeys, id, mapNew());
79
116
  }
117
+ };
118
+ const setDefinitionAndListen = (
119
+ id,
120
+ tableId,
121
+ onChanged,
122
+ getRowValue,
123
+ getSortKey,
124
+ ) => {
125
+ setDefinition(id, tableId);
126
+ const changedRowValues = mapNew();
127
+ const changedSortKeys = mapNew();
80
128
  const rowValues = mapGet(allRowValues, id);
81
129
  const sortKeys = mapGet(allSortKeys, id);
82
130
  const processRow = (rowId) => {
@@ -126,16 +174,14 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
126
174
  });
127
175
  }
128
176
  processTable(true);
129
- removeStoreListeners(id);
130
- mapSet(
131
- storeListenerIds,
177
+ delStoreListeners(id);
178
+ addStoreListeners(
132
179
  id,
133
- setNew([
134
- store.addRowListener(tableId, null, (_store, _tableId, rowId) =>
135
- processRow(rowId),
136
- ),
137
- store.addTableListener(tableId, () => processTable()),
138
- ]),
180
+ 0,
181
+ store.addRowListener(tableId, null, (_store, _tableId, rowId) =>
182
+ processRow(rowId),
183
+ ),
184
+ store.addTableListener(tableId, () => processTable()),
139
185
  );
140
186
  };
141
187
  const delDefinition = (id) => {
@@ -143,7 +189,7 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
143
189
  mapSet(things, id);
144
190
  mapSet(allRowValues, id);
145
191
  mapSet(allSortKeys, id);
146
- removeStoreListeners(id);
192
+ delStoreListeners(id);
147
193
  };
148
194
  const destroy = () => mapForEach(storeListenerIds, delDefinition);
149
195
  return [
@@ -155,8 +201,11 @@ const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
155
201
  getThing,
156
202
  setThing,
157
203
  setDefinition,
204
+ setDefinitionAndListen,
158
205
  delDefinition,
159
206
  destroy,
207
+ addStoreListeners,
208
+ delStoreListeners,
160
209
  ];
161
210
  };
162
211
  const getRowCellFunction = (getRowCell, defaultCellValue) =>
@@ -175,64 +224,51 @@ const getCreateFunction = (getFunction) => {
175
224
 
176
225
  const defaultSorter = (sortKey1, sortKey2) => (sortKey1 < sortKey2 ? -1 : 1);
177
226
 
178
- const addDeepSet = (deepSet, value, ids) =>
179
- arrayLength(ids) < 2
180
- ? setAdd(
181
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
182
- value,
183
- )
184
- : addDeepSet(
185
- mapEnsure(deepSet, ids[0], mapNew),
186
- value,
187
- arrayFromSecond(ids),
188
- );
189
- const forDeepSet = (valueDo) => {
190
- const deep = (deepIdSet, arg, ...ids) =>
191
- ifNotUndefined(deepIdSet, (deepIdSet2) =>
192
- arrayIsEmpty(ids)
193
- ? valueDo(deepIdSet2, arg)
194
- : arrayForEach([ids[0], null], (id) =>
195
- deep(mapGet(deepIdSet2, id), arg, ...arrayFromSecond(ids)),
196
- ),
197
- );
198
- return deep;
227
+ const getWildcardedLeaves = (deepIdSet, path = [EMPTY_STRING]) => {
228
+ const sets = [];
229
+ const deep = (set, p) =>
230
+ p == arrayLength(path)
231
+ ? arrayPush(sets, set)
232
+ : arrayForEach([path[p], null], (id) => deep(mapGet(set, id), p + 1));
233
+ deep(deepIdSet, 0);
234
+ return sets;
199
235
  };
200
236
  const getListenerFunctions = (getThing) => {
201
237
  let thing;
202
238
  let nextId = 0;
203
239
  const listenerPool = [];
204
240
  const allListeners = mapNew();
205
- const addListener = (listener, deepSet, idOrNulls = []) => {
241
+ const addListener = (listener, idSetNode, idOrNulls) => {
206
242
  thing ??= getThing();
207
- const id = arrayPop(listenerPool) ?? '' + nextId++;
208
- mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
209
- addDeepSet(deepSet, id, idOrNulls);
243
+ const id = arrayPop(listenerPool) ?? EMPTY_STRING + nextId++;
244
+ mapSet(allListeners, id, [listener, idSetNode, idOrNulls]);
245
+ setAdd(visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], setNew), id);
210
246
  return id;
211
247
  };
212
- const callListeners = (deepSet, ids = [], ...extraArgs) =>
213
- forDeepSet(collForEach)(
214
- deepSet,
215
- (id) =>
248
+ const callListeners = (idSetNode, ids, ...extraArgs) =>
249
+ arrayForEach(getWildcardedLeaves(idSetNode, ids), (set) =>
250
+ collForEach(set, (id) =>
216
251
  ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
217
- listener(thing, ...ids, ...extraArgs),
252
+ listener(thing, ...(ids ?? []), ...extraArgs),
218
253
  ),
219
- ...ids,
254
+ ),
220
255
  );
221
256
  const delListener = (id) =>
222
- ifNotUndefined(
223
- mapGet(allListeners, id),
224
- ([, deepSet, idOrNulls]) => {
225
- forDeepSet(collDel)(deepSet, id, ...idOrNulls);
226
- mapSet(allListeners, id);
227
- if (arrayLength(listenerPool) < 1e3) {
228
- arrayPush(listenerPool, id);
229
- }
230
- return idOrNulls;
231
- },
232
- () => [],
233
- );
257
+ ifNotUndefined(mapGet(allListeners, id), ([, idSetNode, idOrNulls]) => {
258
+ visitTree(idSetNode, idOrNulls ?? [EMPTY_STRING], void 0, (idSet) => {
259
+ collDel(idSet, id);
260
+ return collIsEmpty(idSet) ? 1 : 0;
261
+ });
262
+ mapSet(allListeners, id);
263
+ if (arrayLength(listenerPool) < 1e3) {
264
+ arrayPush(listenerPool, id);
265
+ }
266
+ return idOrNulls;
267
+ });
268
+ const hasListeners = (idSetNode, ids) =>
269
+ !arrayEvery(getWildcardedLeaves(idSetNode, ids), isUndefined);
234
270
  const callListener = (id, idNullGetters, extraArgsGetter) =>
235
- ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls]) => {
271
+ ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls = []]) => {
236
272
  const callWithIds = (...ids) => {
237
273
  const index = arrayLength(ids);
238
274
  index == arrayLength(idOrNulls)
@@ -245,7 +281,7 @@ const getListenerFunctions = (getThing) => {
245
281
  };
246
282
  callWithIds();
247
283
  });
248
- return [addListener, callListeners, delListener, callListener];
284
+ return [addListener, callListeners, delListener, hasListeners, callListener];
249
285
  };
250
286
 
251
287
  const object = Object;
@@ -262,7 +298,8 @@ const createIndexes = getCreateFunction((store) => {
262
298
  getTableId,
263
299
  getIndex,
264
300
  setIndex,
265
- setDefinition,
301
+ ,
302
+ setDefinitionAndListen,
266
303
  delDefinition,
267
304
  destroy,
268
305
  ] = getDefinableFunctions(store, mapNew, (value) =>
@@ -283,7 +320,7 @@ const createIndexes = getCreateFunction((store) => {
283
320
  const sliceIdArraySorter = isUndefined(sliceIdSorter)
284
321
  ? void 0
285
322
  : ([id1], [id2]) => sliceIdSorter(id1, id2);
286
- setDefinition(
323
+ setDefinitionAndListen(
287
324
  indexId,
288
325
  tableId,
289
326
  (change, changedSliceIds, changedSortKeys, sliceIds, sortKeys, force) => {