@tanstack/db 0.0.14 → 0.0.15

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 (198) hide show
  1. package/dist/cjs/collection.cjs +117 -104
  2. package/dist/cjs/collection.cjs.map +1 -1
  3. package/dist/cjs/collection.d.cts +18 -21
  4. package/dist/cjs/index.cjs +35 -13
  5. package/dist/cjs/index.cjs.map +1 -1
  6. package/dist/cjs/index.d.cts +0 -1
  7. package/dist/cjs/query/builder/functions.cjs +107 -0
  8. package/dist/cjs/query/builder/functions.cjs.map +1 -0
  9. package/dist/cjs/query/builder/functions.d.cts +38 -0
  10. package/dist/cjs/query/builder/index.cjs +499 -0
  11. package/dist/cjs/query/builder/index.cjs.map +1 -0
  12. package/dist/cjs/query/builder/index.d.cts +324 -0
  13. package/dist/cjs/query/builder/ref-proxy.cjs +96 -0
  14. package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -0
  15. package/dist/cjs/query/builder/ref-proxy.d.cts +28 -0
  16. package/dist/cjs/query/builder/types.d.cts +80 -0
  17. package/dist/cjs/query/compiler/evaluators.cjs +261 -0
  18. package/dist/cjs/query/compiler/evaluators.cjs.map +1 -0
  19. package/dist/cjs/query/compiler/evaluators.d.cts +11 -0
  20. package/dist/cjs/query/compiler/group-by.cjs +271 -0
  21. package/dist/cjs/query/compiler/group-by.cjs.map +1 -0
  22. package/dist/cjs/query/compiler/group-by.d.cts +7 -0
  23. package/dist/cjs/query/compiler/index.cjs +181 -0
  24. package/dist/cjs/query/compiler/index.cjs.map +1 -0
  25. package/dist/cjs/query/compiler/index.d.cts +15 -0
  26. package/dist/cjs/query/compiler/joins.cjs +116 -0
  27. package/dist/cjs/query/compiler/joins.cjs.map +1 -0
  28. package/dist/cjs/query/compiler/joins.d.cts +11 -0
  29. package/dist/cjs/query/compiler/order-by.cjs +89 -0
  30. package/dist/cjs/query/compiler/order-by.cjs.map +1 -0
  31. package/dist/cjs/query/compiler/order-by.d.cts +9 -0
  32. package/dist/cjs/query/compiler/select.cjs +57 -0
  33. package/dist/cjs/query/compiler/select.cjs.map +1 -0
  34. package/dist/cjs/query/compiler/select.d.cts +15 -0
  35. package/dist/cjs/query/index.d.cts +6 -5
  36. package/dist/cjs/query/ir.cjs +57 -0
  37. package/dist/cjs/query/ir.cjs.map +1 -0
  38. package/dist/cjs/query/ir.d.cts +81 -0
  39. package/dist/cjs/query/live-query-collection.cjs +224 -0
  40. package/dist/cjs/query/live-query-collection.cjs.map +1 -0
  41. package/dist/cjs/query/live-query-collection.d.cts +124 -0
  42. package/dist/cjs/transactions.cjs +20 -13
  43. package/dist/cjs/transactions.cjs.map +1 -1
  44. package/dist/cjs/transactions.d.cts +10 -1
  45. package/dist/cjs/types.d.cts +13 -0
  46. package/dist/esm/collection.d.ts +18 -21
  47. package/dist/esm/collection.js +118 -105
  48. package/dist/esm/collection.js.map +1 -1
  49. package/dist/esm/index.d.ts +0 -1
  50. package/dist/esm/index.js +34 -12
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/query/builder/functions.d.ts +38 -0
  53. package/dist/esm/query/builder/functions.js +107 -0
  54. package/dist/esm/query/builder/functions.js.map +1 -0
  55. package/dist/esm/query/builder/index.d.ts +324 -0
  56. package/dist/esm/query/builder/index.js +499 -0
  57. package/dist/esm/query/builder/index.js.map +1 -0
  58. package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
  59. package/dist/esm/query/builder/ref-proxy.js +96 -0
  60. package/dist/esm/query/builder/ref-proxy.js.map +1 -0
  61. package/dist/esm/query/builder/types.d.ts +80 -0
  62. package/dist/esm/query/compiler/evaluators.d.ts +11 -0
  63. package/dist/esm/query/compiler/evaluators.js +261 -0
  64. package/dist/esm/query/compiler/evaluators.js.map +1 -0
  65. package/dist/esm/query/compiler/group-by.d.ts +7 -0
  66. package/dist/esm/query/compiler/group-by.js +271 -0
  67. package/dist/esm/query/compiler/group-by.js.map +1 -0
  68. package/dist/esm/query/compiler/index.d.ts +15 -0
  69. package/dist/esm/query/compiler/index.js +181 -0
  70. package/dist/esm/query/compiler/index.js.map +1 -0
  71. package/dist/esm/query/compiler/joins.d.ts +11 -0
  72. package/dist/esm/query/compiler/joins.js +116 -0
  73. package/dist/esm/query/compiler/joins.js.map +1 -0
  74. package/dist/esm/query/compiler/order-by.d.ts +9 -0
  75. package/dist/esm/query/compiler/order-by.js +89 -0
  76. package/dist/esm/query/compiler/order-by.js.map +1 -0
  77. package/dist/esm/query/compiler/select.d.ts +15 -0
  78. package/dist/esm/query/compiler/select.js +57 -0
  79. package/dist/esm/query/compiler/select.js.map +1 -0
  80. package/dist/esm/query/index.d.ts +6 -5
  81. package/dist/esm/query/ir.d.ts +81 -0
  82. package/dist/esm/query/ir.js +57 -0
  83. package/dist/esm/query/ir.js.map +1 -0
  84. package/dist/esm/query/live-query-collection.d.ts +124 -0
  85. package/dist/esm/query/live-query-collection.js +224 -0
  86. package/dist/esm/query/live-query-collection.js.map +1 -0
  87. package/dist/esm/transactions.d.ts +10 -1
  88. package/dist/esm/transactions.js +20 -13
  89. package/dist/esm/transactions.js.map +1 -1
  90. package/dist/esm/types.d.ts +13 -0
  91. package/package.json +3 -4
  92. package/src/collection.ts +152 -129
  93. package/src/index.ts +0 -1
  94. package/src/query/builder/functions.ts +267 -0
  95. package/src/query/builder/index.ts +648 -0
  96. package/src/query/builder/ref-proxy.ts +156 -0
  97. package/src/query/builder/types.ts +278 -0
  98. package/src/query/compiler/evaluators.ts +315 -0
  99. package/src/query/compiler/group-by.ts +428 -0
  100. package/src/query/compiler/index.ts +276 -0
  101. package/src/query/compiler/joins.ts +228 -0
  102. package/src/query/compiler/order-by.ts +139 -0
  103. package/src/query/compiler/select.ts +173 -0
  104. package/src/query/index.ts +64 -5
  105. package/src/query/ir.ts +128 -0
  106. package/src/query/live-query-collection.ts +509 -0
  107. package/src/transactions.ts +27 -16
  108. package/src/types.ts +15 -0
  109. package/dist/cjs/query/compiled-query.cjs +0 -160
  110. package/dist/cjs/query/compiled-query.cjs.map +0 -1
  111. package/dist/cjs/query/compiled-query.d.cts +0 -20
  112. package/dist/cjs/query/evaluators.cjs +0 -161
  113. package/dist/cjs/query/evaluators.cjs.map +0 -1
  114. package/dist/cjs/query/evaluators.d.cts +0 -14
  115. package/dist/cjs/query/extractors.cjs +0 -122
  116. package/dist/cjs/query/extractors.cjs.map +0 -1
  117. package/dist/cjs/query/extractors.d.cts +0 -22
  118. package/dist/cjs/query/functions.cjs +0 -152
  119. package/dist/cjs/query/functions.cjs.map +0 -1
  120. package/dist/cjs/query/functions.d.cts +0 -21
  121. package/dist/cjs/query/group-by.cjs +0 -88
  122. package/dist/cjs/query/group-by.cjs.map +0 -1
  123. package/dist/cjs/query/group-by.d.cts +0 -40
  124. package/dist/cjs/query/joins.cjs +0 -141
  125. package/dist/cjs/query/joins.cjs.map +0 -1
  126. package/dist/cjs/query/joins.d.cts +0 -14
  127. package/dist/cjs/query/order-by.cjs +0 -185
  128. package/dist/cjs/query/order-by.cjs.map +0 -1
  129. package/dist/cjs/query/order-by.d.cts +0 -3
  130. package/dist/cjs/query/pipeline-compiler.cjs +0 -89
  131. package/dist/cjs/query/pipeline-compiler.cjs.map +0 -1
  132. package/dist/cjs/query/pipeline-compiler.d.cts +0 -10
  133. package/dist/cjs/query/query-builder.cjs +0 -307
  134. package/dist/cjs/query/query-builder.cjs.map +0 -1
  135. package/dist/cjs/query/query-builder.d.cts +0 -225
  136. package/dist/cjs/query/schema.d.cts +0 -100
  137. package/dist/cjs/query/select.cjs +0 -130
  138. package/dist/cjs/query/select.cjs.map +0 -1
  139. package/dist/cjs/query/select.d.cts +0 -3
  140. package/dist/cjs/query/types.d.cts +0 -189
  141. package/dist/cjs/query/utils.cjs +0 -154
  142. package/dist/cjs/query/utils.cjs.map +0 -1
  143. package/dist/cjs/query/utils.d.cts +0 -37
  144. package/dist/cjs/utils.cjs +0 -17
  145. package/dist/cjs/utils.cjs.map +0 -1
  146. package/dist/cjs/utils.d.cts +0 -3
  147. package/dist/esm/query/compiled-query.d.ts +0 -20
  148. package/dist/esm/query/compiled-query.js +0 -160
  149. package/dist/esm/query/compiled-query.js.map +0 -1
  150. package/dist/esm/query/evaluators.d.ts +0 -14
  151. package/dist/esm/query/evaluators.js +0 -161
  152. package/dist/esm/query/evaluators.js.map +0 -1
  153. package/dist/esm/query/extractors.d.ts +0 -22
  154. package/dist/esm/query/extractors.js +0 -122
  155. package/dist/esm/query/extractors.js.map +0 -1
  156. package/dist/esm/query/functions.d.ts +0 -21
  157. package/dist/esm/query/functions.js +0 -152
  158. package/dist/esm/query/functions.js.map +0 -1
  159. package/dist/esm/query/group-by.d.ts +0 -40
  160. package/dist/esm/query/group-by.js +0 -88
  161. package/dist/esm/query/group-by.js.map +0 -1
  162. package/dist/esm/query/joins.d.ts +0 -14
  163. package/dist/esm/query/joins.js +0 -141
  164. package/dist/esm/query/joins.js.map +0 -1
  165. package/dist/esm/query/order-by.d.ts +0 -3
  166. package/dist/esm/query/order-by.js +0 -185
  167. package/dist/esm/query/order-by.js.map +0 -1
  168. package/dist/esm/query/pipeline-compiler.d.ts +0 -10
  169. package/dist/esm/query/pipeline-compiler.js +0 -89
  170. package/dist/esm/query/pipeline-compiler.js.map +0 -1
  171. package/dist/esm/query/query-builder.d.ts +0 -225
  172. package/dist/esm/query/query-builder.js +0 -307
  173. package/dist/esm/query/query-builder.js.map +0 -1
  174. package/dist/esm/query/schema.d.ts +0 -100
  175. package/dist/esm/query/select.d.ts +0 -3
  176. package/dist/esm/query/select.js +0 -130
  177. package/dist/esm/query/select.js.map +0 -1
  178. package/dist/esm/query/types.d.ts +0 -189
  179. package/dist/esm/query/utils.d.ts +0 -37
  180. package/dist/esm/query/utils.js +0 -154
  181. package/dist/esm/query/utils.js.map +0 -1
  182. package/dist/esm/utils.d.ts +0 -3
  183. package/dist/esm/utils.js +0 -17
  184. package/dist/esm/utils.js.map +0 -1
  185. package/src/query/compiled-query.ts +0 -234
  186. package/src/query/evaluators.ts +0 -250
  187. package/src/query/extractors.ts +0 -214
  188. package/src/query/functions.ts +0 -297
  189. package/src/query/group-by.ts +0 -139
  190. package/src/query/joins.ts +0 -260
  191. package/src/query/order-by.ts +0 -264
  192. package/src/query/pipeline-compiler.ts +0 -149
  193. package/src/query/query-builder.ts +0 -902
  194. package/src/query/schema.ts +0 -268
  195. package/src/query/select.ts +0 -208
  196. package/src/query/types.ts +0 -418
  197. package/src/query/utils.ts +0 -245
  198. package/src/utils.ts +0 -15
@@ -1,6 +1,5 @@
1
- import { Store } from '@tanstack/store';
2
- import { Transaction } from './transactions.js';
3
1
  import { SortedMap } from './SortedMap.js';
2
+ import { Transaction } from './transactions.js';
4
3
  import { ChangeListener, ChangeMessage, CollectionConfig, CollectionStatus, Fn, InsertConfig, OperationConfig, OptimisticChangeMessage, ResolveType, Transaction as TransactionType, UtilsRecord } from './types.js';
5
4
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
5
  export declare const collectionsStore: Map<string, CollectionImpl<any, any>>;
@@ -73,8 +72,8 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
73
72
  pendingSyncedTransactions: Array<PendingSyncedTransaction<T>>;
74
73
  syncedData: Map<TKey, T> | SortedMap<TKey, T>;
75
74
  syncedMetadata: Map<TKey, unknown>;
76
- derivedUpserts: Map<TKey, T>;
77
- derivedDeletes: Set<TKey>;
75
+ optimisticUpserts: Map<TKey, T>;
76
+ optimisticDeletes: Set<TKey>;
78
77
  private _size;
79
78
  private changeListeners;
80
79
  private changeKeyListeners;
@@ -85,6 +84,8 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
85
84
  private hasReceivedFirstCommit;
86
85
  private isCommittingSyncTransactions;
87
86
  private onFirstCommitCallbacks;
87
+ private batchedEvents;
88
+ private shouldBatchEvents;
88
89
  private _status;
89
90
  private activeSubscribersCount;
90
91
  private gcTimeoutId;
@@ -178,7 +179,7 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
178
179
  */
179
180
  private getPreviousValue;
180
181
  /**
181
- * Emit multiple events at once to all listeners
182
+ * Emit events either immediately or batch them for later emission
182
183
  */
183
184
  private emitEvents;
184
185
  /**
@@ -205,6 +206,18 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
205
206
  * Get all entries (virtual derived state)
206
207
  */
207
208
  entries(): IterableIterator<[TKey, T]>;
209
+ /**
210
+ * Get all entries (virtual derived state)
211
+ */
212
+ [Symbol.iterator](): IterableIterator<[TKey, T]>;
213
+ /**
214
+ * Execute a callback for each entry in the collection
215
+ */
216
+ forEach(callbackfn: (value: T, key: TKey, index: number) => void): void;
217
+ /**
218
+ * Create a new array with the results of calling a function for each entry in the collection
219
+ */
220
+ map<U>(callbackfn: (value: T, key: TKey, index: number) => U): Array<U>;
208
221
  /**
209
222
  * Attempts to commit pending synced transactions if there are no active transactions
210
223
  * This method processes operations from pending transactions and applies them to the synced data
@@ -348,21 +361,5 @@ export declare class CollectionImpl<T extends object = Record<string, unknown>,
348
361
  * This method should be called by the Transaction class when state changes
349
362
  */
350
363
  onTransactionStateChange(): void;
351
- private _storeMap;
352
- /**
353
- * Returns a Tanstack Store Map that is updated when the collection changes
354
- * This is a temporary solution to enable the existing framework hooks to work
355
- * with the new internals of Collection until they are rewritten.
356
- * TODO: Remove this once the framework hooks are rewritten.
357
- */
358
- asStoreMap(): Store<Map<TKey, T>>;
359
- private _storeArray;
360
- /**
361
- * Returns a Tanstack Store Array that is updated when the collection changes
362
- * This is a temporary solution to enable the existing framework hooks to work
363
- * with the new internals of Collection until they are rewritten.
364
- * TODO: Remove this once the framework hooks are rewritten.
365
- */
366
- asStoreArray(): Store<Array<T>>;
367
364
  }
368
365
  export {};
@@ -1,6 +1,5 @@
1
- import { Store } from "@tanstack/store";
2
1
  import { withArrayChangeTracking, withChangeTracking } from "./proxy.js";
3
- import { getActiveTransaction, Transaction } from "./transactions.js";
2
+ import { getActiveTransaction, createTransaction } from "./transactions.js";
4
3
  import { SortedMap } from "./SortedMap.js";
5
4
  const collectionsStore = /* @__PURE__ */ new Map();
6
5
  function createCollection(options) {
@@ -32,8 +31,8 @@ class CollectionImpl {
32
31
  constructor(config) {
33
32
  this.pendingSyncedTransactions = [];
34
33
  this.syncedMetadata = /* @__PURE__ */ new Map();
35
- this.derivedUpserts = /* @__PURE__ */ new Map();
36
- this.derivedDeletes = /* @__PURE__ */ new Set();
34
+ this.optimisticUpserts = /* @__PURE__ */ new Map();
35
+ this.optimisticDeletes = /* @__PURE__ */ new Set();
37
36
  this._size = 0;
38
37
  this.changeListeners = /* @__PURE__ */ new Set();
39
38
  this.changeKeyListeners = /* @__PURE__ */ new Map();
@@ -44,6 +43,8 @@ class CollectionImpl {
44
43
  this.hasReceivedFirstCommit = false;
45
44
  this.isCommittingSyncTransactions = false;
46
45
  this.onFirstCommitCallbacks = [];
46
+ this.batchedEvents = [];
47
+ this.shouldBatchEvents = false;
47
48
  this._status = `idle`;
48
49
  this.activeSubscribersCount = 0;
49
50
  this.gcTimeoutId = null;
@@ -77,6 +78,7 @@ class CollectionImpl {
77
78
  }
78
79
  }
79
80
  const events = [];
81
+ const rowUpdateMode = this.config.sync.rowUpdateMode || `partial`;
80
82
  for (const transaction of this.pendingSyncedTransactions) {
81
83
  for (const operation of transaction.operations) {
82
84
  const key = operation.key;
@@ -104,12 +106,16 @@ class CollectionImpl {
104
106
  this.syncedData.set(key, operation.value);
105
107
  break;
106
108
  case `update`: {
107
- const updatedValue = Object.assign(
108
- {},
109
- this.syncedData.get(key),
110
- operation.value
111
- );
112
- this.syncedData.set(key, updatedValue);
109
+ if (rowUpdateMode === `partial`) {
110
+ const updatedValue = Object.assign(
111
+ {},
112
+ this.syncedData.get(key),
113
+ operation.value
114
+ );
115
+ this.syncedData.set(key, updatedValue);
116
+ } else {
117
+ this.syncedData.set(key, operation.value);
118
+ }
113
119
  break;
114
120
  }
115
121
  case `delete`:
@@ -118,8 +124,8 @@ class CollectionImpl {
118
124
  }
119
125
  }
120
126
  }
121
- this.derivedUpserts.clear();
122
- this.derivedDeletes.clear();
127
+ this.optimisticUpserts.clear();
128
+ this.optimisticDeletes.clear();
123
129
  this.isCommittingSyncTransactions = false;
124
130
  for (const transaction of this.transactions.values()) {
125
131
  if (![`completed`, `failed`].includes(transaction.state)) {
@@ -128,12 +134,15 @@ class CollectionImpl {
128
134
  switch (mutation.type) {
129
135
  case `insert`:
130
136
  case `update`:
131
- this.derivedUpserts.set(mutation.key, mutation.modified);
132
- this.derivedDeletes.delete(mutation.key);
137
+ this.optimisticUpserts.set(
138
+ mutation.key,
139
+ mutation.modified
140
+ );
141
+ this.optimisticDeletes.delete(mutation.key);
133
142
  break;
134
143
  case `delete`:
135
- this.derivedUpserts.delete(mutation.key);
136
- this.derivedDeletes.add(mutation.key);
144
+ this.optimisticUpserts.delete(mutation.key);
145
+ this.optimisticDeletes.add(mutation.key);
137
146
  break;
138
147
  }
139
148
  }
@@ -182,7 +191,7 @@ class CollectionImpl {
182
191
  }
183
192
  }
184
193
  this._size = this.calculateSize();
185
- this.emitEvents(events);
194
+ this.emitEvents(events, true);
186
195
  this.pendingSyncedTransactions = [];
187
196
  this.preSyncVisibleState.clear();
188
197
  Promise.resolve().then(() => {
@@ -236,7 +245,7 @@ class CollectionImpl {
236
245
  this.recomputeOptimisticState();
237
246
  return ambientTransaction;
238
247
  } else {
239
- const directOpTransaction = new Transaction({
248
+ const directOpTransaction = createTransaction({
240
249
  mutationFn: async (params) => {
241
250
  return this.config.onInsert(params);
242
251
  }
@@ -290,7 +299,7 @@ class CollectionImpl {
290
299
  this.recomputeOptimisticState();
291
300
  return ambientTransaction;
292
301
  }
293
- const directOpTransaction = new Transaction({
302
+ const directOpTransaction = createTransaction({
294
303
  autoCommit: true,
295
304
  mutationFn: async (params) => {
296
305
  return this.config.onDelete(params);
@@ -314,7 +323,7 @@ class CollectionImpl {
314
323
  throw new Error(`Collection requires a sync config`);
315
324
  }
316
325
  this.transactions = new SortedMap(
317
- (a, b) => a.createdAt.getTime() - b.createdAt.getTime()
326
+ (a, b) => a.compareCreatedAt(b)
318
327
  );
319
328
  this.config = config;
320
329
  collectionsStore.set(this.id, this);
@@ -448,10 +457,10 @@ class CollectionImpl {
448
457
  );
449
458
  }
450
459
  pendingTransaction.committed = true;
451
- this.commitPendingTransactions();
452
460
  if (this._status === `loading`) {
453
461
  this.setStatus(`ready`);
454
462
  }
463
+ this.commitPendingTransactions();
455
464
  }
456
465
  });
457
466
  this.syncCleanupFn = typeof cleanupFn === `function` ? cleanupFn : null;
@@ -523,14 +532,16 @@ class CollectionImpl {
523
532
  }
524
533
  this.syncedData.clear();
525
534
  this.syncedMetadata.clear();
526
- this.derivedUpserts.clear();
527
- this.derivedDeletes.clear();
535
+ this.optimisticUpserts.clear();
536
+ this.optimisticDeletes.clear();
528
537
  this._size = 0;
529
538
  this.pendingSyncedTransactions = [];
530
539
  this.syncedKeys.clear();
531
540
  this.hasReceivedFirstCommit = false;
532
541
  this.onFirstCommitCallbacks = [];
533
542
  this.preloadPromise = null;
543
+ this.batchedEvents = [];
544
+ this.shouldBatchEvents = false;
534
545
  this.setStatus(`cleaned-up`);
535
546
  return Promise.resolve();
536
547
  }
@@ -590,10 +601,10 @@ class CollectionImpl {
590
601
  if (this.isCommittingSyncTransactions) {
591
602
  return;
592
603
  }
593
- const previousState = new Map(this.derivedUpserts);
594
- const previousDeletes = new Set(this.derivedDeletes);
595
- this.derivedUpserts.clear();
596
- this.derivedDeletes.clear();
604
+ const previousState = new Map(this.optimisticUpserts);
605
+ const previousDeletes = new Set(this.optimisticDeletes);
606
+ this.optimisticUpserts.clear();
607
+ this.optimisticDeletes.clear();
597
608
  const activeTransactions = [];
598
609
  const completedTransactions = [];
599
610
  for (const transaction of this.transactions.values()) {
@@ -609,12 +620,12 @@ class CollectionImpl {
609
620
  switch (mutation.type) {
610
621
  case `insert`:
611
622
  case `update`:
612
- this.derivedUpserts.set(mutation.key, mutation.modified);
613
- this.derivedDeletes.delete(mutation.key);
623
+ this.optimisticUpserts.set(mutation.key, mutation.modified);
624
+ this.optimisticDeletes.delete(mutation.key);
614
625
  break;
615
626
  case `delete`:
616
- this.derivedUpserts.delete(mutation.key);
617
- this.derivedDeletes.add(mutation.key);
627
+ this.optimisticUpserts.delete(mutation.key);
628
+ this.optimisticDeletes.add(mutation.key);
618
629
  break;
619
630
  }
620
631
  }
@@ -664,10 +675,10 @@ class CollectionImpl {
664
675
  */
665
676
  calculateSize() {
666
677
  const syncedSize = this.syncedData.size;
667
- const deletesFromSynced = Array.from(this.derivedDeletes).filter(
668
- (key) => this.syncedData.has(key) && !this.derivedUpserts.has(key)
678
+ const deletesFromSynced = Array.from(this.optimisticDeletes).filter(
679
+ (key) => this.syncedData.has(key) && !this.optimisticUpserts.has(key)
669
680
  ).length;
670
- const upsertsNotInSynced = Array.from(this.derivedUpserts.keys()).filter(
681
+ const upsertsNotInSynced = Array.from(this.optimisticUpserts.keys()).filter(
671
682
  (key) => !this.syncedData.has(key)
672
683
  ).length;
673
684
  return syncedSize - deletesFromSynced + upsertsNotInSynced;
@@ -678,9 +689,9 @@ class CollectionImpl {
678
689
  collectOptimisticChanges(previousUpserts, previousDeletes, events) {
679
690
  const allKeys = /* @__PURE__ */ new Set([
680
691
  ...previousUpserts.keys(),
681
- ...this.derivedUpserts.keys(),
692
+ ...this.optimisticUpserts.keys(),
682
693
  ...previousDeletes,
683
- ...this.derivedDeletes
694
+ ...this.optimisticDeletes
684
695
  ]);
685
696
  for (const key of allKeys) {
686
697
  const currentValue = this.get(key);
@@ -716,28 +727,39 @@ class CollectionImpl {
716
727
  return this.syncedData.get(key);
717
728
  }
718
729
  /**
719
- * Emit multiple events at once to all listeners
730
+ * Emit events either immediately or batch them for later emission
720
731
  */
721
- emitEvents(changes) {
722
- if (changes.length > 0) {
723
- for (const listener of this.changeListeners) {
724
- listener(changes);
732
+ emitEvents(changes, endBatching = false) {
733
+ if (this.shouldBatchEvents && !endBatching) {
734
+ this.batchedEvents.push(...changes);
735
+ return;
736
+ }
737
+ let eventsToEmit = changes;
738
+ if (endBatching) {
739
+ if (this.batchedEvents.length > 0) {
740
+ eventsToEmit = [...this.batchedEvents, ...changes];
725
741
  }
726
- if (this.changeKeyListeners.size > 0) {
727
- const changesByKey = /* @__PURE__ */ new Map();
728
- for (const change of changes) {
729
- if (this.changeKeyListeners.has(change.key)) {
730
- if (!changesByKey.has(change.key)) {
731
- changesByKey.set(change.key, []);
732
- }
733
- changesByKey.get(change.key).push(change);
742
+ this.batchedEvents = [];
743
+ this.shouldBatchEvents = false;
744
+ }
745
+ if (eventsToEmit.length === 0) return;
746
+ for (const listener of this.changeListeners) {
747
+ listener(eventsToEmit);
748
+ }
749
+ if (this.changeKeyListeners.size > 0) {
750
+ const changesByKey = /* @__PURE__ */ new Map();
751
+ for (const change of eventsToEmit) {
752
+ if (this.changeKeyListeners.has(change.key)) {
753
+ if (!changesByKey.has(change.key)) {
754
+ changesByKey.set(change.key, []);
734
755
  }
756
+ changesByKey.get(change.key).push(change);
735
757
  }
736
- for (const [key, keyChanges] of changesByKey) {
737
- const keyListeners = this.changeKeyListeners.get(key);
738
- for (const listener of keyListeners) {
739
- listener(keyChanges);
740
- }
758
+ }
759
+ for (const [key, keyChanges] of changesByKey) {
760
+ const keyListeners = this.changeKeyListeners.get(key);
761
+ for (const listener of keyListeners) {
762
+ listener(keyChanges);
741
763
  }
742
764
  }
743
765
  }
@@ -746,11 +768,11 @@ class CollectionImpl {
746
768
  * Get the current value for a key (virtual derived state)
747
769
  */
748
770
  get(key) {
749
- if (this.derivedDeletes.has(key)) {
771
+ if (this.optimisticDeletes.has(key)) {
750
772
  return void 0;
751
773
  }
752
- if (this.derivedUpserts.has(key)) {
753
- return this.derivedUpserts.get(key);
774
+ if (this.optimisticUpserts.has(key)) {
775
+ return this.optimisticUpserts.get(key);
754
776
  }
755
777
  return this.syncedData.get(key);
756
778
  }
@@ -758,10 +780,10 @@ class CollectionImpl {
758
780
  * Check if a key exists in the collection (virtual derived state)
759
781
  */
760
782
  has(key) {
761
- if (this.derivedDeletes.has(key)) {
783
+ if (this.optimisticDeletes.has(key)) {
762
784
  return false;
763
785
  }
764
- if (this.derivedUpserts.has(key)) {
786
+ if (this.optimisticUpserts.has(key)) {
765
787
  return true;
766
788
  }
767
789
  return this.syncedData.has(key);
@@ -777,12 +799,12 @@ class CollectionImpl {
777
799
  */
778
800
  *keys() {
779
801
  for (const key of this.syncedData.keys()) {
780
- if (!this.derivedDeletes.has(key)) {
802
+ if (!this.optimisticDeletes.has(key)) {
781
803
  yield key;
782
804
  }
783
805
  }
784
- for (const key of this.derivedUpserts.keys()) {
785
- if (!this.syncedData.has(key) && !this.derivedDeletes.has(key)) {
806
+ for (const key of this.optimisticUpserts.keys()) {
807
+ if (!this.syncedData.has(key) && !this.optimisticDeletes.has(key)) {
786
808
  yield key;
787
809
  }
788
810
  }
@@ -794,8 +816,7 @@ class CollectionImpl {
794
816
  for (const key of this.keys()) {
795
817
  const value = this.get(key);
796
818
  if (value !== void 0) {
797
- const { _orderByIndex, ...copy } = value;
798
- yield copy;
819
+ yield value;
799
820
  }
800
821
  }
801
822
  }
@@ -806,11 +827,38 @@ class CollectionImpl {
806
827
  for (const key of this.keys()) {
807
828
  const value = this.get(key);
808
829
  if (value !== void 0) {
809
- const { _orderByIndex, ...copy } = value;
810
- yield [key, copy];
830
+ yield [key, value];
811
831
  }
812
832
  }
813
833
  }
834
+ /**
835
+ * Get all entries (virtual derived state)
836
+ */
837
+ *[Symbol.iterator]() {
838
+ for (const [key, value] of this.entries()) {
839
+ yield [key, value];
840
+ }
841
+ }
842
+ /**
843
+ * Execute a callback for each entry in the collection
844
+ */
845
+ forEach(callbackfn) {
846
+ let index = 0;
847
+ for (const [key, value] of this.entries()) {
848
+ callbackfn(value, key, index++);
849
+ }
850
+ }
851
+ /**
852
+ * Create a new array with the results of calling a function for each entry in the collection
853
+ */
854
+ map(callbackfn) {
855
+ const result = [];
856
+ let index = 0;
857
+ for (const [key, value] of this.entries()) {
858
+ result.push(callbackfn(value, key, index++));
859
+ }
860
+ return result;
861
+ }
814
862
  ensureStandardSchema(schema) {
815
863
  if (schema && typeof schema === `object` && `~standard` in schema) {
816
864
  return schema;
@@ -968,7 +1016,7 @@ class CollectionImpl {
968
1016
  };
969
1017
  }).filter(Boolean);
970
1018
  if (mutations.length === 0) {
971
- const emptyTransaction = new Transaction({
1019
+ const emptyTransaction = createTransaction({
972
1020
  mutationFn: async () => {
973
1021
  }
974
1022
  });
@@ -981,7 +1029,7 @@ class CollectionImpl {
981
1029
  this.recomputeOptimisticState();
982
1030
  return ambientTransaction;
983
1031
  }
984
- const directOpTransaction = new Transaction({
1032
+ const directOpTransaction = createTransaction({
985
1033
  mutationFn: async (params) => {
986
1034
  return this.config.onUpdate(params);
987
1035
  }
@@ -1026,13 +1074,7 @@ class CollectionImpl {
1026
1074
  * @returns An Array containing all items in the collection
1027
1075
  */
1028
1076
  get toArray() {
1029
- const array = Array.from(this.values());
1030
- if (array[0] && array[0]._orderByIndex) {
1031
- return array.sort(
1032
- (a, b) => a._orderByIndex - b._orderByIndex
1033
- );
1034
- }
1035
- return array;
1077
+ return Array.from(this.values());
1036
1078
  }
1037
1079
  /**
1038
1080
  * Gets the current state of the collection as an Array, but only resolves when data is available
@@ -1134,39 +1176,10 @@ class CollectionImpl {
1134
1176
  * This method should be called by the Transaction class when state changes
1135
1177
  */
1136
1178
  onTransactionStateChange() {
1179
+ this.shouldBatchEvents = this.pendingSyncedTransactions.length > 0;
1137
1180
  this.capturePreSyncVisibleState();
1138
1181
  this.recomputeOptimisticState();
1139
1182
  }
1140
- /**
1141
- * Returns a Tanstack Store Map that is updated when the collection changes
1142
- * This is a temporary solution to enable the existing framework hooks to work
1143
- * with the new internals of Collection until they are rewritten.
1144
- * TODO: Remove this once the framework hooks are rewritten.
1145
- */
1146
- asStoreMap() {
1147
- if (!this._storeMap) {
1148
- this._storeMap = new Store(new Map(this.entries()));
1149
- this.changeListeners.add(() => {
1150
- this._storeMap.setState(() => new Map(this.entries()));
1151
- });
1152
- }
1153
- return this._storeMap;
1154
- }
1155
- /**
1156
- * Returns a Tanstack Store Array that is updated when the collection changes
1157
- * This is a temporary solution to enable the existing framework hooks to work
1158
- * with the new internals of Collection until they are rewritten.
1159
- * TODO: Remove this once the framework hooks are rewritten.
1160
- */
1161
- asStoreArray() {
1162
- if (!this._storeArray) {
1163
- this._storeArray = new Store(this.toArray);
1164
- this.changeListeners.add(() => {
1165
- this._storeArray.setState(() => this.toArray);
1166
- });
1167
- }
1168
- return this._storeArray;
1169
- }
1170
1183
  }
1171
1184
  export {
1172
1185
  CollectionImpl,