tinybase 1.2.1 → 1.3.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.
@@ -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,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};
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};
Binary file
@@ -28,10 +28,9 @@ const mapForEach = (map, cb) =>
28
28
  collForEach(map, (value, key) => cb(key, value));
29
29
  const mapSet = (map, key, value) =>
30
30
  isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
31
- const mapEnsure = (map, key, defaultValue, onWillAdd) => {
31
+ const mapEnsure = (map, key, getDefaultValue) => {
32
32
  if (!collHas(map, key)) {
33
- onWillAdd?.(defaultValue);
34
- map.set(key, defaultValue);
33
+ map.set(key, getDefaultValue());
35
34
  }
36
35
  return mapGet(map, key);
37
36
  };
@@ -52,11 +51,11 @@ const getCreateFunction = (getFunction) => {
52
51
  const addDeepSet = (deepSet, value, ids) =>
53
52
  arrayLength(ids) < 2
54
53
  ? setAdd(
55
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew()),
54
+ arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
56
55
  value,
57
56
  )
58
57
  : addDeepSet(
59
- mapEnsure(deepSet, ids[0], mapNew()),
58
+ mapEnsure(deepSet, ids[0], mapNew),
60
59
  value,
61
60
  arrayFromSecond(ids),
62
61
  );
@@ -181,16 +180,11 @@ const createCheckpoints = getCreateFunction((store) => {
181
180
  currentId = void 0;
182
181
  checkpointsChanged = 1;
183
182
  });
184
- const table = mapEnsure(delta, tableId, mapNew());
185
- const row = mapEnsure(table, rowId, mapNew());
186
- const oldNew = mapEnsure(
187
- row,
188
- cellId,
189
- [void 0, void 0],
190
- (addOldNew) => (addOldNew[0] = oldCell),
191
- );
183
+ const table = mapEnsure(delta, tableId, mapNew);
184
+ const row = mapEnsure(table, rowId, mapNew);
185
+ const oldNew = mapEnsure(row, cellId, () => [oldCell, void 0]);
192
186
  oldNew[1] = newCell;
193
- if (oldNew[0] === oldNew[1]) {
187
+ if (oldNew[0] === newCell) {
194
188
  if (collIsEmpty(mapSet(row, cellId))) {
195
189
  if (collIsEmpty(mapSet(table, rowId))) {
196
190
  if (collIsEmpty(mapSet(delta, tableId))) {
@@ -39,10 +39,9 @@ const mapForEach = (map, cb) =>
39
39
  collForEach(map, (value, key) => cb(key, value));
40
40
  const mapSet = (map, key, value) =>
41
41
  isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
42
- const mapEnsure = (map, key, defaultValue, onWillAdd) => {
42
+ const mapEnsure = (map, key, getDefaultValue) => {
43
43
  if (!collHas(map, key)) {
44
- onWillAdd?.(defaultValue);
45
- map.set(key, defaultValue);
44
+ map.set(key, getDefaultValue());
46
45
  }
47
46
  return mapGet(map, key);
48
47
  };
@@ -179,11 +178,11 @@ const defaultSorter = (sortKey1, sortKey2) => (sortKey1 < sortKey2 ? -1 : 1);
179
178
  const addDeepSet = (deepSet, value, ids) =>
180
179
  arrayLength(ids) < 2
181
180
  ? setAdd(
182
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew()),
181
+ arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
183
182
  value,
184
183
  )
185
184
  : addDeepSet(
186
- mapEnsure(deepSet, ids[0], mapNew()),
185
+ mapEnsure(deepSet, ids[0], mapNew),
187
186
  value,
188
187
  arrayFromSecond(ids),
189
188
  );
@@ -44,10 +44,9 @@ const mapForEach = (map, cb) =>
44
44
  collForEach(map, (value, key) => cb(key, value));
45
45
  const mapSet = (map, key, value) =>
46
46
  isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
47
- const mapEnsure = (map, key, defaultValue, onWillAdd) => {
47
+ const mapEnsure = (map, key, getDefaultValue) => {
48
48
  if (!collHas(map, key)) {
49
- onWillAdd?.(defaultValue);
50
- map.set(key, defaultValue);
49
+ map.set(key, getDefaultValue());
51
50
  }
52
51
  return mapGet(map, key);
53
52
  };
@@ -182,11 +181,11 @@ const getCreateFunction = (getFunction) => {
182
181
  const addDeepSet = (deepSet, value, ids) =>
183
182
  arrayLength(ids) < 2
184
183
  ? setAdd(
185
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew()),
184
+ arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
186
185
  value,
187
186
  )
188
187
  : addDeepSet(
189
- mapEnsure(deepSet, ids[0], mapNew()),
188
+ mapEnsure(deepSet, ids[0], mapNew),
190
189
  value,
191
190
  arrayFromSecond(ids),
192
191
  );
@@ -34,10 +34,9 @@ const mapForEach = (map, cb) =>
34
34
  collForEach(map, (value, key) => cb(key, value));
35
35
  const mapSet = (map, key, value) =>
36
36
  isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
37
- const mapEnsure = (map, key, defaultValue, onWillAdd) => {
37
+ const mapEnsure = (map, key, getDefaultValue) => {
38
38
  if (!collHas(map, key)) {
39
- onWillAdd?.(defaultValue);
40
- map.set(key, defaultValue);
39
+ map.set(key, getDefaultValue());
41
40
  }
42
41
  return mapGet(map, key);
43
42
  };
@@ -172,11 +171,11 @@ const getCreateFunction = (getFunction) => {
172
171
  const addDeepSet = (deepSet, value, ids) =>
173
172
  arrayLength(ids) < 2
174
173
  ? setAdd(
175
- arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew()),
174
+ arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew),
176
175
  value,
177
176
  )
178
177
  : addDeepSet(
179
- mapEnsure(deepSet, ids[0], mapNew()),
178
+ mapEnsure(deepSet, ids[0], mapNew),
180
179
  value,
181
180
  arrayFromSecond(ids),
182
181
  );
@@ -176,6 +176,32 @@ export type MapCell = (cell: CellOrUndefined) => Cell;
176
176
  */
177
177
  export type GetCell = (cellId: Id) => CellOrUndefined;
178
178
 
179
+ /**
180
+ * The TransactionListener type describes a function that is used to listen to
181
+ * the completion of a transaction for the Store.
182
+ *
183
+ * A TransactionListener is provided when using the
184
+ * addWillFinishTransactionListener and addDidFinishTransactionListener methods.
185
+ * See those methods for specific examples.
186
+ *
187
+ * When called, a TransactionListener is simply given a reference to the Store
188
+ * and a boolean to indicate whether Cell values have been touched during the
189
+ * transaction. The latter flag is intended as a hint about whether non-mutating
190
+ * listeners might be being called at the end of the transaction.
191
+ *
192
+ * Here, 'touched' means that Cell values have either been changed, or changed
193
+ * and then changed back to its original value during the transaction. The
194
+ * exception is a transaction that has been rolled back, for which the value of
195
+ * `cellsTouched` in the listener will be `false` because all changes have been
196
+ * reverted.
197
+ *
198
+ * @param store A reference to the Store that is completing a transaction.
199
+ * @param cellsTouched Whether Cell values have been touched during the
200
+ * transaction.
201
+ * @category Listener
202
+ */
203
+ export type TransactionListener = (store: Store, cellsTouched: boolean) => void;
204
+
179
205
  /**
180
206
  * The TablesListener type describes a function that is used to listen to
181
207
  * changes to the whole Store.
@@ -566,6 +592,10 @@ export type StoreListenerStats = {
566
592
  * The number of CellListeners registered with the Store.
567
593
  */
568
594
  cell?: number;
595
+ /**
596
+ * The number of InvalidCellListeners registered with the Store.
597
+ */
598
+ invalidCell?: number;
569
599
  };
570
600
 
571
601
  /**
@@ -1648,7 +1678,7 @@ export interface Store {
1648
1678
 
1649
1679
  /**
1650
1680
  * The transaction method takes a function that makes multiple mutations to
1651
- * the store, buffering all calls to the relevant listeners until it
1681
+ * the Store, buffering all calls to the relevant listeners until it
1652
1682
  * completes.
1653
1683
  *
1654
1684
  * This method is useful for making bulk changes to the data in a Store, and
@@ -1767,6 +1797,135 @@ export interface Store {
1767
1797
  ) => boolean,
1768
1798
  ): Return;
1769
1799
 
1800
+ /**
1801
+ * The startTransaction allows you to explicitly start a transaction that will
1802
+ * make multiple mutations to the Store, buffering all calls to the relevant
1803
+ * listeners until it completes when you call the finishTransaction method.
1804
+ *
1805
+ * Transactions are useful for making bulk changes to the data in a Store, and
1806
+ * when you don't want listeners to be called as you make each change. Changes
1807
+ * are made silently during the transaction, and listeners relevant to the
1808
+ * changes you have made will instead only be called when the whole
1809
+ * transaction is complete.
1810
+ *
1811
+ * Generally it is preferable to use the transaction method to wrap a block of
1812
+ * code as a transaction. It simply calls both the startTransaction and
1813
+ * finishTransaction methods for you. See that method for several transaction
1814
+ * examples.
1815
+ *
1816
+ * Use this startTransaction method when you have a more 'open-ended'
1817
+ * transaction, such as one containing mutations triggered from other events
1818
+ * that are asynchronous or not occurring inline to your code. You must
1819
+ * remember to also call the finishTransaction method explicitly when it is
1820
+ * done, of course.
1821
+ *
1822
+ * @returns A reference to the Store.
1823
+ * @example
1824
+ * This example makes changes to two Cells, first outside, and secondly
1825
+ * within, a transaction that is explicitly started and finished. In the
1826
+ * second case, the Row listener is only called once.
1827
+ *
1828
+ * ```js
1829
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
1830
+ * store.addRowListener('pets', 'fido', () => console.log('Fido changed'));
1831
+ *
1832
+ * store.setCell('pets', 'fido', 'color', 'brown');
1833
+ * store.setCell('pets', 'fido', 'sold', false);
1834
+ * // -> 'Fido changed'
1835
+ * // -> 'Fido changed'
1836
+ *
1837
+ * store.startTransaction();
1838
+ * store.setCell('pets', 'fido', 'color', 'walnut');
1839
+ * store.setCell('pets', 'fido', 'sold', true);
1840
+ * store.finishTransaction();
1841
+ * // -> 'Fido changed'
1842
+ * ```
1843
+ * @category Transaction
1844
+ */
1845
+ startTransaction(): Store;
1846
+
1847
+ /**
1848
+ * The finishTransaction allows you to explicitly finish a transaction that
1849
+ * has made multiple mutations to the Store, triggering all calls to the
1850
+ * relevant listeners.
1851
+ *
1852
+ * Transactions are useful for making bulk changes to the data in a Store, and
1853
+ * when you don't want listeners to be called as you make each change. Changes
1854
+ * are made silently during the transaction, and listeners relevant to the
1855
+ * changes you have made will instead only be called when the whole
1856
+ * transaction is complete.
1857
+ *
1858
+ * Generally it is preferable to use the transaction method to wrap a block of
1859
+ * code as a transaction. It simply calls both the startTransaction and
1860
+ * finishTransaction methods for you. See that method for several transaction
1861
+ * examples.
1862
+ *
1863
+ * Use this finishTransaction method when you have a more 'open-ended'
1864
+ * transaction, such as one containing mutations triggered from other events
1865
+ * that are asynchronous or not occurring inline to your code. There must have
1866
+ * been a corresponding startTransaction method that this completes, of
1867
+ * course, otherwise this function has no effect.
1868
+ *
1869
+ * @param doRollback An optional callback that should return `true` if you
1870
+ * want to rollback the transaction at the end.
1871
+ * @returns A reference to the Store.
1872
+ * @example
1873
+ * This example makes changes to two Cells, first outside, and secondly
1874
+ * within, a transaction that is explicitly started and finished. In the
1875
+ * second case, the Row listener is only called once.
1876
+ *
1877
+ * ```js
1878
+ * const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
1879
+ * store.addRowListener('pets', 'fido', () => console.log('Fido changed'));
1880
+ *
1881
+ * store.setCell('pets', 'fido', 'color', 'brown');
1882
+ * store.setCell('pets', 'fido', 'sold', false);
1883
+ * // -> 'Fido changed'
1884
+ * // -> 'Fido changed'
1885
+ *
1886
+ * store.startTransaction();
1887
+ * store.setCell('pets', 'fido', 'color', 'walnut');
1888
+ * store.setCell('pets', 'fido', 'sold', true);
1889
+ * store.finishTransaction();
1890
+ * // -> 'Fido changed'
1891
+ * ```
1892
+ * @example
1893
+ * This example makes multiple changes to the Store, including some attempts
1894
+ * to update a Cell with invalid values. The `doRollback` callback receives
1895
+ * information about the changes and invalid attempts, and then judges that
1896
+ * the transaction should be rolled back to its original state.
1897
+ *
1898
+ * ```js
1899
+ * const store = createStore().setTables({
1900
+ * pets: {fido: {species: 'dog', color: 'brown'}},
1901
+ * });
1902
+ *
1903
+ * store.startTransaction();
1904
+ * store.setCell('pets', 'fido', 'color', 'black');
1905
+ * store.setCell('pets', 'fido', 'eyes', ['left', 'right']);
1906
+ * store.setCell('pets', 'fido', 'info', {sold: null});
1907
+ * store.finishTransaction((changedCells, invalidCells) => {
1908
+ * console.log(store.getTables());
1909
+ * // -> {pets: {fido: {species: 'dog', color: 'black'}}}
1910
+ * console.log(changedCells);
1911
+ * // -> {pets: {fido: {color: ['brown', 'black']}}}
1912
+ * console.log(invalidCells);
1913
+ * // -> {pets: {fido: {eyes: [['left', 'right']], info: [{sold: null}]}}}
1914
+ * return invalidCells['pets'] != null;
1915
+ * });
1916
+ *
1917
+ * console.log(store.getTables());
1918
+ * // -> {pets: {fido: {species: 'dog', color: 'brown'}}}
1919
+ * ```
1920
+ * @category Transaction
1921
+ */
1922
+ finishTransaction(
1923
+ doRollback?: (
1924
+ changedCells: ChangedCells,
1925
+ invalidCells: InvalidCells,
1926
+ ) => boolean,
1927
+ ): Store;
1928
+
1770
1929
  /**
1771
1930
  * The forEachTable method takes a function that it will then call for each
1772
1931
  * Table in the Store.
@@ -2742,6 +2901,143 @@ export interface Store {
2742
2901
  mutator?: boolean,
2743
2902
  ): Id;
2744
2903
 
2904
+ /**
2905
+ * The addWillFinishTransactionListener method registers a listener function
2906
+ * with the Store that will be called just before other non-mutating listeners
2907
+ * are called at the end of the transaction.
2908
+ *
2909
+ * This is useful if you need to know that a set of listeners are about to be
2910
+ * called at the end of a transaction, perhaps to batch _their_ consequences
2911
+ * together.
2912
+ *
2913
+ * The provided TransactionListener will receive a reference to the Store and
2914
+ * a boolean to indicate whether Cell values have been touched during the
2915
+ * transaction. The latter flag is intended as a hint about whether
2916
+ * non-mutating listeners might be being called at the end of the transaction.
2917
+ *
2918
+ * Here, 'touched' means that Cell values have either been changed, or changed
2919
+ * and then changed back to its original value during the transaction. The
2920
+ * exception is a transaction that has been rolled back, for which the value
2921
+ * of `cellsTouched` in the listener will be `false` because all changes have
2922
+ * been reverted.
2923
+ *
2924
+ * @returns A unique Id for the listener that can later be used to remove it.
2925
+ * @example
2926
+ * This example registers a listener that is called at the end of the
2927
+ * transaction, just before its listeners will be called. The transactions
2928
+ * shown here variously change, touch, and rollback cells, demonstrating how
2929
+ * the `cellsTouched` parameter in the listener works.
2930
+ *
2931
+ * ```js
2932
+ * const store = createStore().setTables({
2933
+ * pets: {fido: {species: 'dog', color: 'brown'}},
2934
+ * });
2935
+ * const listenerId = store.addWillFinishTransactionListener(
2936
+ * (store, cellsTouched) => console.log(`Cells touched: ${cellsTouched}`),
2937
+ * );
2938
+ * const listenerId2 = store.addTablesListener(() =>
2939
+ * console.log('Tables changed'),
2940
+ * );
2941
+ *
2942
+ * store.transaction(() => store.setCell('pets', 'fido', 'color', 'brown'));
2943
+ * // -> 'Cells touched: false'
2944
+ *
2945
+ * store.transaction(() => store.setCell('pets', 'fido', 'color', 'walnut'));
2946
+ * // -> 'Cells touched: true'
2947
+ * // -> 'Tables changed'
2948
+ *
2949
+ * store.transaction(() => {
2950
+ * store.setRow('pets', 'felix', {species: 'cat'});
2951
+ * store.delRow('pets', 'felix');
2952
+ * });
2953
+ * // -> 'Cells touched: true'
2954
+ *
2955
+ * store.transaction(
2956
+ * () => store.setRow('pets', 'fido', {species: 'dog'}),
2957
+ * () => true,
2958
+ * );
2959
+ * // -> 'Cells touched: false'
2960
+ * // Transaction was rolled back.
2961
+ *
2962
+ * store.callListener(listenerId);
2963
+ * // -> 'Cells touched: undefined'
2964
+ * // It is meaningless to call this listener directly.
2965
+ *
2966
+ * store.delListener(listenerId).delListener(listenerId2);
2967
+ * ```
2968
+ * @category Listener
2969
+ */
2970
+ addWillFinishTransactionListener(listener: TransactionListener): Id;
2971
+
2972
+ /**
2973
+ * The addDidFinishTransactionListener method registers a listener function
2974
+ * with the Store that will be called just after other non-mutating listeners
2975
+ * are called at the end of the transaction.
2976
+ *
2977
+ * This is useful if you need to know that a set of listeners have just been
2978
+ * called at the end of a transaction, perhaps to batch _their_ consequences
2979
+ * together.
2980
+ *
2981
+ * The provided TransactionListener will receive a reference to the Store and
2982
+ * a boolean to indicate whether Cell values have been touched during the
2983
+ * transaction. The latter flag is intended as a hint about whether
2984
+ * non-mutating listeners might have been called at the end of the
2985
+ * transaction.
2986
+ *
2987
+ * Here, 'touched' means that Cell values have either been changed, or changed
2988
+ * and then changed back to its original value during the transaction. The
2989
+ * exception is a transaction that has been rolled back, for which the value
2990
+ * of `cellsTouched` in the listener will be `false` because all changes have
2991
+ * been reverted.
2992
+ *
2993
+ * @returns A unique Id for the listener that can later be used to remove it.
2994
+ * @example
2995
+ * This example registers a listener that is called at the end of the
2996
+ * transaction, just after its listeners have been called. The transactions
2997
+ * shown here variously change, touch, and rollback cells, demonstrating how
2998
+ * the `cellsTouched` parameter in the listener works.
2999
+ *
3000
+ * ```js
3001
+ * const store = createStore().setTables({
3002
+ * pets: {fido: {species: 'dog', color: 'brown'}},
3003
+ * });
3004
+ * const listenerId = store.addDidFinishTransactionListener(
3005
+ * (store, cellsTouched) => console.log(`Cells touched: ${cellsTouched}`),
3006
+ * );
3007
+ * const listenerId2 = store.addTablesListener(() =>
3008
+ * console.log('Tables changed'),
3009
+ * );
3010
+ *
3011
+ * store.transaction(() => store.setCell('pets', 'fido', 'color', 'brown'));
3012
+ * // -> 'Cells touched: false'
3013
+ *
3014
+ * store.transaction(() => store.setCell('pets', 'fido', 'color', 'walnut'));
3015
+ * // -> 'Tables changed'
3016
+ * // -> 'Cells touched: true'
3017
+ *
3018
+ * store.transaction(() => {
3019
+ * store.setRow('pets', 'felix', {species: 'cat'});
3020
+ * store.delRow('pets', 'felix');
3021
+ * });
3022
+ * // -> 'Cells touched: true'
3023
+ *
3024
+ * store.transaction(
3025
+ * () => store.setRow('pets', 'fido', {species: 'dog'}),
3026
+ * () => true,
3027
+ * );
3028
+ * // -> 'Cells touched: false'
3029
+ * // Transaction was rolled back.
3030
+ *
3031
+ * store.callListener(listenerId);
3032
+ * // -> 'Cells touched: undefined'
3033
+ * // It is meaningless to call this listener directly.
3034
+ *
3035
+ * store.delListener(listenerId).delListener(listenerId2);
3036
+ * ```
3037
+ * @category Listener
3038
+ */
3039
+ addDidFinishTransactionListener(listener: TransactionListener): Id;
3040
+
2745
3041
  /**
2746
3042
  * The callListener method provides a way for you to manually provoke a
2747
3043
  * listener to be called, even if the underlying data hasn't changed.