@tanstack/db 0.3.2 → 0.4.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 (164) hide show
  1. package/dist/cjs/{change-events.cjs → collection/change-events.cjs} +13 -42
  2. package/dist/cjs/collection/change-events.cjs.map +1 -0
  3. package/dist/{esm/change-events.d.ts → cjs/collection/change-events.d.cts} +6 -6
  4. package/dist/cjs/collection/changes.cjs +108 -0
  5. package/dist/cjs/collection/changes.cjs.map +1 -0
  6. package/dist/cjs/collection/changes.d.cts +53 -0
  7. package/dist/cjs/{collection-events.cjs → collection/events.cjs} +7 -5
  8. package/dist/cjs/collection/events.cjs.map +1 -0
  9. package/dist/cjs/{collection-events.d.cts → collection/events.d.cts} +7 -4
  10. package/dist/cjs/collection/index.cjs +417 -0
  11. package/dist/cjs/collection/index.cjs.map +1 -0
  12. package/dist/{esm/collection.d.ts → cjs/collection/index.d.cts} +46 -184
  13. package/dist/cjs/collection/indexes.cjs +124 -0
  14. package/dist/cjs/collection/indexes.cjs.map +1 -0
  15. package/dist/cjs/collection/indexes.d.cts +47 -0
  16. package/dist/cjs/collection/lifecycle.cjs +150 -0
  17. package/dist/cjs/collection/lifecycle.cjs.map +1 -0
  18. package/dist/cjs/collection/lifecycle.d.cts +70 -0
  19. package/dist/cjs/collection/mutations.cjs +315 -0
  20. package/dist/cjs/collection/mutations.cjs.map +1 -0
  21. package/dist/cjs/collection/mutations.d.cts +33 -0
  22. package/dist/cjs/collection/state.cjs +597 -0
  23. package/dist/cjs/collection/state.cjs.map +1 -0
  24. package/dist/cjs/collection/state.d.cts +122 -0
  25. package/dist/cjs/collection/subscription.cjs +160 -0
  26. package/dist/cjs/collection/subscription.cjs.map +1 -0
  27. package/dist/cjs/collection/subscription.d.cts +57 -0
  28. package/dist/cjs/collection/sync.cjs +154 -0
  29. package/dist/cjs/collection/sync.cjs.map +1 -0
  30. package/dist/cjs/collection/sync.d.cts +34 -0
  31. package/dist/cjs/index.cjs +8 -8
  32. package/dist/cjs/index.d.cts +2 -2
  33. package/dist/cjs/indexes/auto-index.cjs.map +1 -1
  34. package/dist/cjs/indexes/auto-index.d.cts +1 -1
  35. package/dist/cjs/indexes/base-index.cjs.map +1 -1
  36. package/dist/cjs/indexes/base-index.d.cts +2 -2
  37. package/dist/cjs/indexes/btree-index.cjs +2 -2
  38. package/dist/cjs/indexes/btree-index.cjs.map +1 -1
  39. package/dist/cjs/indexes/btree-index.d.cts +1 -1
  40. package/dist/cjs/query/builder/index.cjs +2 -2
  41. package/dist/cjs/query/builder/index.cjs.map +1 -1
  42. package/dist/cjs/query/builder/types.d.cts +1 -1
  43. package/dist/cjs/query/compiler/index.cjs +5 -2
  44. package/dist/cjs/query/compiler/index.cjs.map +1 -1
  45. package/dist/cjs/query/compiler/index.d.cts +3 -2
  46. package/dist/cjs/query/compiler/joins.cjs +22 -24
  47. package/dist/cjs/query/compiler/joins.cjs.map +1 -1
  48. package/dist/cjs/query/compiler/joins.d.cts +3 -2
  49. package/dist/cjs/query/compiler/order-by.cjs.map +1 -1
  50. package/dist/cjs/query/compiler/order-by.d.cts +1 -1
  51. package/dist/cjs/query/ir.cjs.map +1 -1
  52. package/dist/cjs/query/ir.d.cts +1 -1
  53. package/dist/cjs/query/live/collection-config-builder.cjs +29 -12
  54. package/dist/cjs/query/live/collection-config-builder.cjs.map +1 -1
  55. package/dist/cjs/query/live/collection-config-builder.d.cts +3 -0
  56. package/dist/cjs/query/live/collection-subscriber.cjs +43 -104
  57. package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
  58. package/dist/cjs/query/live/collection-subscriber.d.cts +4 -7
  59. package/dist/cjs/query/live-query-collection.cjs +2 -2
  60. package/dist/cjs/query/live-query-collection.cjs.map +1 -1
  61. package/dist/cjs/query/live-query-collection.d.cts +1 -1
  62. package/dist/cjs/transactions.cjs +3 -3
  63. package/dist/cjs/transactions.cjs.map +1 -1
  64. package/dist/cjs/types.d.cts +12 -10
  65. package/dist/{cjs/change-events.d.cts → esm/collection/change-events.d.ts} +6 -6
  66. package/dist/esm/{change-events.js → collection/change-events.js} +13 -42
  67. package/dist/esm/collection/change-events.js.map +1 -0
  68. package/dist/esm/collection/changes.d.ts +53 -0
  69. package/dist/esm/collection/changes.js +108 -0
  70. package/dist/esm/collection/changes.js.map +1 -0
  71. package/dist/esm/{collection-events.d.ts → collection/events.d.ts} +7 -4
  72. package/dist/esm/{collection-events.js → collection/events.js} +7 -5
  73. package/dist/esm/collection/events.js.map +1 -0
  74. package/dist/{cjs/collection.d.cts → esm/collection/index.d.ts} +46 -184
  75. package/dist/esm/collection/index.js +417 -0
  76. package/dist/esm/collection/index.js.map +1 -0
  77. package/dist/esm/collection/indexes.d.ts +47 -0
  78. package/dist/esm/collection/indexes.js +124 -0
  79. package/dist/esm/collection/indexes.js.map +1 -0
  80. package/dist/esm/collection/lifecycle.d.ts +70 -0
  81. package/dist/esm/collection/lifecycle.js +150 -0
  82. package/dist/esm/collection/lifecycle.js.map +1 -0
  83. package/dist/esm/collection/mutations.d.ts +33 -0
  84. package/dist/esm/collection/mutations.js +315 -0
  85. package/dist/esm/collection/mutations.js.map +1 -0
  86. package/dist/esm/collection/state.d.ts +122 -0
  87. package/dist/esm/collection/state.js +597 -0
  88. package/dist/esm/collection/state.js.map +1 -0
  89. package/dist/esm/collection/subscription.d.ts +57 -0
  90. package/dist/esm/collection/subscription.js +160 -0
  91. package/dist/esm/collection/subscription.js.map +1 -0
  92. package/dist/esm/collection/sync.d.ts +34 -0
  93. package/dist/esm/collection/sync.js +154 -0
  94. package/dist/esm/collection/sync.js.map +1 -0
  95. package/dist/esm/index.d.ts +2 -2
  96. package/dist/esm/index.js +1 -1
  97. package/dist/esm/indexes/auto-index.d.ts +1 -1
  98. package/dist/esm/indexes/auto-index.js.map +1 -1
  99. package/dist/esm/indexes/base-index.d.ts +2 -2
  100. package/dist/esm/indexes/base-index.js.map +1 -1
  101. package/dist/esm/indexes/btree-index.d.ts +1 -1
  102. package/dist/esm/indexes/btree-index.js +2 -2
  103. package/dist/esm/indexes/btree-index.js.map +1 -1
  104. package/dist/esm/proxy.js +1 -1
  105. package/dist/esm/query/builder/index.js +1 -1
  106. package/dist/esm/query/builder/index.js.map +1 -1
  107. package/dist/esm/query/builder/types.d.ts +1 -1
  108. package/dist/esm/query/compiler/index.d.ts +3 -2
  109. package/dist/esm/query/compiler/index.js +5 -2
  110. package/dist/esm/query/compiler/index.js.map +1 -1
  111. package/dist/esm/query/compiler/joins.d.ts +3 -2
  112. package/dist/esm/query/compiler/joins.js +22 -24
  113. package/dist/esm/query/compiler/joins.js.map +1 -1
  114. package/dist/esm/query/compiler/order-by.d.ts +1 -1
  115. package/dist/esm/query/compiler/order-by.js.map +1 -1
  116. package/dist/esm/query/ir.d.ts +1 -1
  117. package/dist/esm/query/ir.js.map +1 -1
  118. package/dist/esm/query/live/collection-config-builder.d.ts +3 -0
  119. package/dist/esm/query/live/collection-config-builder.js +29 -12
  120. package/dist/esm/query/live/collection-config-builder.js.map +1 -1
  121. package/dist/esm/query/live/collection-subscriber.d.ts +4 -7
  122. package/dist/esm/query/live/collection-subscriber.js +43 -104
  123. package/dist/esm/query/live/collection-subscriber.js.map +1 -1
  124. package/dist/esm/query/live-query-collection.d.ts +1 -1
  125. package/dist/esm/query/live-query-collection.js +1 -1
  126. package/dist/esm/query/live-query-collection.js.map +1 -1
  127. package/dist/esm/transactions.js +3 -3
  128. package/dist/esm/transactions.js.map +1 -1
  129. package/dist/esm/types.d.ts +12 -10
  130. package/package.json +2 -2
  131. package/src/{change-events.ts → collection/change-events.ts} +25 -39
  132. package/src/collection/changes.ts +163 -0
  133. package/src/{collection-events.ts → collection/events.ts} +8 -6
  134. package/src/collection/index.ts +808 -0
  135. package/src/collection/indexes.ts +172 -0
  136. package/src/collection/lifecycle.ts +221 -0
  137. package/src/collection/mutations.ts +535 -0
  138. package/src/collection/state.ts +866 -0
  139. package/src/collection/subscription.ts +239 -0
  140. package/src/collection/sync.ts +235 -0
  141. package/src/index.ts +2 -2
  142. package/src/indexes/auto-index.ts +1 -1
  143. package/src/indexes/base-index.ts +3 -3
  144. package/src/indexes/btree-index.ts +2 -2
  145. package/src/query/builder/index.ts +1 -1
  146. package/src/query/builder/types.ts +1 -1
  147. package/src/query/compiler/index.ts +7 -1
  148. package/src/query/compiler/joins.ts +28 -41
  149. package/src/query/compiler/order-by.ts +1 -1
  150. package/src/query/ir.ts +1 -1
  151. package/src/query/live/collection-config-builder.ts +48 -22
  152. package/src/query/live/collection-subscriber.ts +63 -168
  153. package/src/query/live-query-collection.ts +2 -2
  154. package/src/transactions.ts +3 -3
  155. package/src/types.ts +14 -15
  156. package/dist/cjs/change-events.cjs.map +0 -1
  157. package/dist/cjs/collection-events.cjs.map +0 -1
  158. package/dist/cjs/collection.cjs +0 -1625
  159. package/dist/cjs/collection.cjs.map +0 -1
  160. package/dist/esm/change-events.js.map +0 -1
  161. package/dist/esm/collection-events.js.map +0 -1
  162. package/dist/esm/collection.js +0 -1625
  163. package/dist/esm/collection.js.map +0 -1
  164. package/src/collection.ts +0 -2564
@@ -0,0 +1,597 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const utils = require("../utils.cjs");
4
+ const SortedMap = require("../SortedMap.cjs");
5
+ class CollectionStateManager {
6
+ /**
7
+ * Creates a new CollectionState manager
8
+ */
9
+ constructor(config) {
10
+ this.pendingSyncedTransactions = [];
11
+ this.syncedMetadata = /* @__PURE__ */ new Map();
12
+ this.optimisticUpserts = /* @__PURE__ */ new Map();
13
+ this.optimisticDeletes = /* @__PURE__ */ new Set();
14
+ this.size = 0;
15
+ this.syncedKeys = /* @__PURE__ */ new Set();
16
+ this.preSyncVisibleState = /* @__PURE__ */ new Map();
17
+ this.recentlySyncedKeys = /* @__PURE__ */ new Set();
18
+ this.hasReceivedFirstCommit = false;
19
+ this.isCommittingSyncTransactions = false;
20
+ this.commitPendingTransactions = () => {
21
+ let hasPersistingTransaction = false;
22
+ for (const transaction of this.transactions.values()) {
23
+ if (transaction.state === `persisting`) {
24
+ hasPersistingTransaction = true;
25
+ break;
26
+ }
27
+ }
28
+ const {
29
+ committedSyncedTransactions,
30
+ uncommittedSyncedTransactions,
31
+ hasTruncateSync
32
+ } = this.pendingSyncedTransactions.reduce(
33
+ (acc, t) => {
34
+ if (t.committed) {
35
+ acc.committedSyncedTransactions.push(t);
36
+ if (t.truncate === true) {
37
+ acc.hasTruncateSync = true;
38
+ }
39
+ } else {
40
+ acc.uncommittedSyncedTransactions.push(t);
41
+ }
42
+ return acc;
43
+ },
44
+ {
45
+ committedSyncedTransactions: [],
46
+ uncommittedSyncedTransactions: [],
47
+ hasTruncateSync: false
48
+ }
49
+ );
50
+ if (!hasPersistingTransaction || hasTruncateSync) {
51
+ this.isCommittingSyncTransactions = true;
52
+ const changedKeys = /* @__PURE__ */ new Set();
53
+ for (const transaction of committedSyncedTransactions) {
54
+ for (const operation of transaction.operations) {
55
+ changedKeys.add(operation.key);
56
+ }
57
+ }
58
+ let currentVisibleState = this.preSyncVisibleState;
59
+ if (currentVisibleState.size === 0) {
60
+ currentVisibleState = /* @__PURE__ */ new Map();
61
+ for (const key of changedKeys) {
62
+ const currentValue = this.get(key);
63
+ if (currentValue !== void 0) {
64
+ currentVisibleState.set(key, currentValue);
65
+ }
66
+ }
67
+ }
68
+ const events = [];
69
+ const rowUpdateMode = this.config.sync.rowUpdateMode || `partial`;
70
+ for (const transaction of committedSyncedTransactions) {
71
+ if (transaction.truncate) {
72
+ for (const key of this.syncedData.keys()) {
73
+ if (this.optimisticDeletes.has(key)) continue;
74
+ const previousValue = this.optimisticUpserts.get(key) || this.syncedData.get(key);
75
+ if (previousValue !== void 0) {
76
+ events.push({ type: `delete`, key, value: previousValue });
77
+ }
78
+ }
79
+ this.syncedData.clear();
80
+ this.syncedMetadata.clear();
81
+ this.syncedKeys.clear();
82
+ for (const key of changedKeys) {
83
+ currentVisibleState.delete(key);
84
+ }
85
+ }
86
+ for (const operation of transaction.operations) {
87
+ const key = operation.key;
88
+ this.syncedKeys.add(key);
89
+ switch (operation.type) {
90
+ case `insert`:
91
+ this.syncedMetadata.set(key, operation.metadata);
92
+ break;
93
+ case `update`:
94
+ this.syncedMetadata.set(
95
+ key,
96
+ Object.assign(
97
+ {},
98
+ this.syncedMetadata.get(key),
99
+ operation.metadata
100
+ )
101
+ );
102
+ break;
103
+ case `delete`:
104
+ this.syncedMetadata.delete(key);
105
+ break;
106
+ }
107
+ switch (operation.type) {
108
+ case `insert`:
109
+ this.syncedData.set(key, operation.value);
110
+ break;
111
+ case `update`: {
112
+ if (rowUpdateMode === `partial`) {
113
+ const updatedValue = Object.assign(
114
+ {},
115
+ this.syncedData.get(key),
116
+ operation.value
117
+ );
118
+ this.syncedData.set(key, updatedValue);
119
+ } else {
120
+ this.syncedData.set(key, operation.value);
121
+ }
122
+ break;
123
+ }
124
+ case `delete`:
125
+ this.syncedData.delete(key);
126
+ break;
127
+ }
128
+ }
129
+ }
130
+ if (hasTruncateSync) {
131
+ const syncedInsertedOrUpdatedKeys = /* @__PURE__ */ new Set();
132
+ for (const t of committedSyncedTransactions) {
133
+ for (const op of t.operations) {
134
+ if (op.type === `insert` || op.type === `update`) {
135
+ syncedInsertedOrUpdatedKeys.add(op.key);
136
+ }
137
+ }
138
+ }
139
+ const reapplyUpserts = /* @__PURE__ */ new Map();
140
+ const reapplyDeletes = /* @__PURE__ */ new Set();
141
+ for (const tx of this.transactions.values()) {
142
+ if ([`completed`, `failed`].includes(tx.state)) continue;
143
+ for (const mutation of tx.mutations) {
144
+ if (!this.isThisCollection(mutation.collection) || !mutation.optimistic)
145
+ continue;
146
+ const key = mutation.key;
147
+ switch (mutation.type) {
148
+ case `insert`:
149
+ reapplyUpserts.set(key, mutation.modified);
150
+ reapplyDeletes.delete(key);
151
+ break;
152
+ case `update`: {
153
+ const base = this.syncedData.get(key);
154
+ const next = base ? Object.assign({}, base, mutation.changes) : mutation.modified;
155
+ reapplyUpserts.set(key, next);
156
+ reapplyDeletes.delete(key);
157
+ break;
158
+ }
159
+ case `delete`:
160
+ reapplyUpserts.delete(key);
161
+ reapplyDeletes.add(key);
162
+ break;
163
+ }
164
+ }
165
+ }
166
+ for (const [key, value] of reapplyUpserts) {
167
+ if (reapplyDeletes.has(key)) continue;
168
+ if (syncedInsertedOrUpdatedKeys.has(key)) {
169
+ let foundInsert = false;
170
+ for (let i = events.length - 1; i >= 0; i--) {
171
+ const evt = events[i];
172
+ if (evt.key === key && evt.type === `insert`) {
173
+ evt.value = value;
174
+ foundInsert = true;
175
+ break;
176
+ }
177
+ }
178
+ if (!foundInsert) {
179
+ events.push({ type: `insert`, key, value });
180
+ }
181
+ } else {
182
+ events.push({ type: `insert`, key, value });
183
+ }
184
+ }
185
+ if (events.length > 0 && reapplyDeletes.size > 0) {
186
+ const filtered = [];
187
+ for (const evt of events) {
188
+ if (evt.type === `insert` && reapplyDeletes.has(evt.key)) {
189
+ continue;
190
+ }
191
+ filtered.push(evt);
192
+ }
193
+ events.length = 0;
194
+ events.push(...filtered);
195
+ }
196
+ if (this.lifecycle.status !== `ready`) {
197
+ this.lifecycle.setStatus(`ready`);
198
+ }
199
+ }
200
+ this.optimisticUpserts.clear();
201
+ this.optimisticDeletes.clear();
202
+ this.isCommittingSyncTransactions = false;
203
+ for (const transaction of this.transactions.values()) {
204
+ if (![`completed`, `failed`].includes(transaction.state)) {
205
+ for (const mutation of transaction.mutations) {
206
+ if (this.isThisCollection(mutation.collection) && mutation.optimistic) {
207
+ switch (mutation.type) {
208
+ case `insert`:
209
+ case `update`:
210
+ this.optimisticUpserts.set(
211
+ mutation.key,
212
+ mutation.modified
213
+ );
214
+ this.optimisticDeletes.delete(mutation.key);
215
+ break;
216
+ case `delete`:
217
+ this.optimisticUpserts.delete(mutation.key);
218
+ this.optimisticDeletes.add(mutation.key);
219
+ break;
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+ const completedOptimisticOps = /* @__PURE__ */ new Map();
226
+ for (const transaction of this.transactions.values()) {
227
+ if (transaction.state === `completed`) {
228
+ for (const mutation of transaction.mutations) {
229
+ if (this.isThisCollection(mutation.collection) && changedKeys.has(mutation.key)) {
230
+ completedOptimisticOps.set(mutation.key, {
231
+ type: mutation.type,
232
+ value: mutation.modified
233
+ });
234
+ }
235
+ }
236
+ }
237
+ }
238
+ for (const key of changedKeys) {
239
+ const previousVisibleValue = currentVisibleState.get(key);
240
+ const newVisibleValue = this.get(key);
241
+ const completedOp = completedOptimisticOps.get(key);
242
+ const isRedundantSync = completedOp && newVisibleValue !== void 0 && utils.deepEquals(completedOp.value, newVisibleValue);
243
+ if (!isRedundantSync) {
244
+ if (previousVisibleValue === void 0 && newVisibleValue !== void 0) {
245
+ events.push({
246
+ type: `insert`,
247
+ key,
248
+ value: newVisibleValue
249
+ });
250
+ } else if (previousVisibleValue !== void 0 && newVisibleValue === void 0) {
251
+ events.push({
252
+ type: `delete`,
253
+ key,
254
+ value: previousVisibleValue
255
+ });
256
+ } else if (previousVisibleValue !== void 0 && newVisibleValue !== void 0 && !utils.deepEquals(previousVisibleValue, newVisibleValue)) {
257
+ events.push({
258
+ type: `update`,
259
+ key,
260
+ value: newVisibleValue,
261
+ previousValue: previousVisibleValue
262
+ });
263
+ }
264
+ }
265
+ }
266
+ this.size = this.calculateSize();
267
+ if (events.length > 0) {
268
+ this.indexes.updateIndexes(events);
269
+ }
270
+ this.changes.emitEvents(events, true);
271
+ this.pendingSyncedTransactions = uncommittedSyncedTransactions;
272
+ this.preSyncVisibleState.clear();
273
+ Promise.resolve().then(() => {
274
+ this.recentlySyncedKeys.clear();
275
+ });
276
+ if (!this.hasReceivedFirstCommit) {
277
+ this.hasReceivedFirstCommit = true;
278
+ const callbacks = [...this.lifecycle.onFirstReadyCallbacks];
279
+ this.lifecycle.onFirstReadyCallbacks = [];
280
+ callbacks.forEach((callback) => callback());
281
+ }
282
+ }
283
+ };
284
+ this.config = config;
285
+ this.transactions = new SortedMap.SortedMap(
286
+ (a, b) => a.compareCreatedAt(b)
287
+ );
288
+ if (config.compare) {
289
+ this.syncedData = new SortedMap.SortedMap(config.compare);
290
+ } else {
291
+ this.syncedData = /* @__PURE__ */ new Map();
292
+ }
293
+ }
294
+ setDeps(deps) {
295
+ this.collection = deps.collection;
296
+ this.lifecycle = deps.lifecycle;
297
+ this.changes = deps.changes;
298
+ this.indexes = deps.indexes;
299
+ }
300
+ /**
301
+ * Get the current value for a key (virtual derived state)
302
+ */
303
+ get(key) {
304
+ const { optimisticDeletes, optimisticUpserts, syncedData } = this;
305
+ if (optimisticDeletes.has(key)) {
306
+ return void 0;
307
+ }
308
+ if (optimisticUpserts.has(key)) {
309
+ return optimisticUpserts.get(key);
310
+ }
311
+ return syncedData.get(key);
312
+ }
313
+ /**
314
+ * Check if a key exists in the collection (virtual derived state)
315
+ */
316
+ has(key) {
317
+ const { optimisticDeletes, optimisticUpserts, syncedData } = this;
318
+ if (optimisticDeletes.has(key)) {
319
+ return false;
320
+ }
321
+ if (optimisticUpserts.has(key)) {
322
+ return true;
323
+ }
324
+ return syncedData.has(key);
325
+ }
326
+ /**
327
+ * Get all keys (virtual derived state)
328
+ */
329
+ *keys() {
330
+ const { syncedData, optimisticDeletes, optimisticUpserts } = this;
331
+ for (const key of syncedData.keys()) {
332
+ if (!optimisticDeletes.has(key)) {
333
+ yield key;
334
+ }
335
+ }
336
+ for (const key of optimisticUpserts.keys()) {
337
+ if (!syncedData.has(key) && !optimisticDeletes.has(key)) {
338
+ yield key;
339
+ }
340
+ }
341
+ }
342
+ /**
343
+ * Get all values (virtual derived state)
344
+ */
345
+ *values() {
346
+ for (const key of this.keys()) {
347
+ const value = this.get(key);
348
+ if (value !== void 0) {
349
+ yield value;
350
+ }
351
+ }
352
+ }
353
+ /**
354
+ * Get all entries (virtual derived state)
355
+ */
356
+ *entries() {
357
+ for (const key of this.keys()) {
358
+ const value = this.get(key);
359
+ if (value !== void 0) {
360
+ yield [key, value];
361
+ }
362
+ }
363
+ }
364
+ /**
365
+ * Get all entries (virtual derived state)
366
+ */
367
+ *[Symbol.iterator]() {
368
+ for (const [key, value] of this.entries()) {
369
+ yield [key, value];
370
+ }
371
+ }
372
+ /**
373
+ * Execute a callback for each entry in the collection
374
+ */
375
+ forEach(callbackfn) {
376
+ let index = 0;
377
+ for (const [key, value] of this.entries()) {
378
+ callbackfn(value, key, index++);
379
+ }
380
+ }
381
+ /**
382
+ * Create a new array with the results of calling a function for each entry in the collection
383
+ */
384
+ map(callbackfn) {
385
+ const result = [];
386
+ let index = 0;
387
+ for (const [key, value] of this.entries()) {
388
+ result.push(callbackfn(value, key, index++));
389
+ }
390
+ return result;
391
+ }
392
+ /**
393
+ * Check if the given collection is this collection
394
+ * @param collection The collection to check
395
+ * @returns True if the given collection is this collection, false otherwise
396
+ */
397
+ isThisCollection(collection) {
398
+ return collection === this.collection;
399
+ }
400
+ /**
401
+ * Recompute optimistic state from active transactions
402
+ */
403
+ recomputeOptimisticState(triggeredByUserAction = false) {
404
+ if (this.isCommittingSyncTransactions) {
405
+ return;
406
+ }
407
+ const previousState = new Map(this.optimisticUpserts);
408
+ const previousDeletes = new Set(this.optimisticDeletes);
409
+ this.optimisticUpserts.clear();
410
+ this.optimisticDeletes.clear();
411
+ const activeTransactions = [];
412
+ for (const transaction of this.transactions.values()) {
413
+ if (![`completed`, `failed`].includes(transaction.state)) {
414
+ activeTransactions.push(transaction);
415
+ }
416
+ }
417
+ for (const transaction of activeTransactions) {
418
+ for (const mutation of transaction.mutations) {
419
+ if (this.isThisCollection(mutation.collection) && mutation.optimistic) {
420
+ switch (mutation.type) {
421
+ case `insert`:
422
+ case `update`:
423
+ this.optimisticUpserts.set(
424
+ mutation.key,
425
+ mutation.modified
426
+ );
427
+ this.optimisticDeletes.delete(mutation.key);
428
+ break;
429
+ case `delete`:
430
+ this.optimisticUpserts.delete(mutation.key);
431
+ this.optimisticDeletes.add(mutation.key);
432
+ break;
433
+ }
434
+ }
435
+ }
436
+ }
437
+ this.size = this.calculateSize();
438
+ const events = [];
439
+ this.collectOptimisticChanges(previousState, previousDeletes, events);
440
+ const filteredEventsBySyncStatus = events.filter((event) => {
441
+ if (!this.recentlySyncedKeys.has(event.key)) {
442
+ return true;
443
+ }
444
+ if (triggeredByUserAction) {
445
+ return true;
446
+ }
447
+ return false;
448
+ });
449
+ if (this.pendingSyncedTransactions.length > 0 && !triggeredByUserAction) {
450
+ const pendingSyncKeys = /* @__PURE__ */ new Set();
451
+ for (const transaction of this.pendingSyncedTransactions) {
452
+ for (const operation of transaction.operations) {
453
+ pendingSyncKeys.add(operation.key);
454
+ }
455
+ }
456
+ const filteredEvents = filteredEventsBySyncStatus.filter((event) => {
457
+ if (event.type === `delete` && pendingSyncKeys.has(event.key)) {
458
+ const hasActiveOptimisticMutation = activeTransactions.some(
459
+ (tx) => tx.mutations.some(
460
+ (m) => this.isThisCollection(m.collection) && m.key === event.key
461
+ )
462
+ );
463
+ if (!hasActiveOptimisticMutation) {
464
+ return false;
465
+ }
466
+ }
467
+ return true;
468
+ });
469
+ if (filteredEvents.length > 0) {
470
+ this.indexes.updateIndexes(filteredEvents);
471
+ }
472
+ this.changes.emitEvents(filteredEvents, triggeredByUserAction);
473
+ } else {
474
+ if (filteredEventsBySyncStatus.length > 0) {
475
+ this.indexes.updateIndexes(filteredEventsBySyncStatus);
476
+ }
477
+ this.changes.emitEvents(filteredEventsBySyncStatus, triggeredByUserAction);
478
+ }
479
+ }
480
+ /**
481
+ * Calculate the current size based on synced data and optimistic changes
482
+ */
483
+ calculateSize() {
484
+ const syncedSize = this.syncedData.size;
485
+ const deletesFromSynced = Array.from(this.optimisticDeletes).filter(
486
+ (key) => this.syncedData.has(key) && !this.optimisticUpserts.has(key)
487
+ ).length;
488
+ const upsertsNotInSynced = Array.from(this.optimisticUpserts.keys()).filter(
489
+ (key) => !this.syncedData.has(key)
490
+ ).length;
491
+ return syncedSize - deletesFromSynced + upsertsNotInSynced;
492
+ }
493
+ /**
494
+ * Collect events for optimistic changes
495
+ */
496
+ collectOptimisticChanges(previousUpserts, previousDeletes, events) {
497
+ const allKeys = /* @__PURE__ */ new Set([
498
+ ...previousUpserts.keys(),
499
+ ...this.optimisticUpserts.keys(),
500
+ ...previousDeletes,
501
+ ...this.optimisticDeletes
502
+ ]);
503
+ for (const key of allKeys) {
504
+ const currentValue = this.get(key);
505
+ const previousValue = this.getPreviousValue(
506
+ key,
507
+ previousUpserts,
508
+ previousDeletes
509
+ );
510
+ if (previousValue !== void 0 && currentValue === void 0) {
511
+ events.push({ type: `delete`, key, value: previousValue });
512
+ } else if (previousValue === void 0 && currentValue !== void 0) {
513
+ events.push({ type: `insert`, key, value: currentValue });
514
+ } else if (previousValue !== void 0 && currentValue !== void 0 && previousValue !== currentValue) {
515
+ events.push({
516
+ type: `update`,
517
+ key,
518
+ value: currentValue,
519
+ previousValue
520
+ });
521
+ }
522
+ }
523
+ }
524
+ /**
525
+ * Get the previous value for a key given previous optimistic state
526
+ */
527
+ getPreviousValue(key, previousUpserts, previousDeletes) {
528
+ if (previousDeletes.has(key)) {
529
+ return void 0;
530
+ }
531
+ if (previousUpserts.has(key)) {
532
+ return previousUpserts.get(key);
533
+ }
534
+ return this.syncedData.get(key);
535
+ }
536
+ /**
537
+ * Schedule cleanup of a transaction when it completes
538
+ */
539
+ scheduleTransactionCleanup(transaction) {
540
+ if (transaction.state === `completed`) {
541
+ this.transactions.delete(transaction.id);
542
+ return;
543
+ }
544
+ transaction.isPersisted.promise.then(() => {
545
+ this.transactions.delete(transaction.id);
546
+ }).catch(() => {
547
+ });
548
+ }
549
+ /**
550
+ * Capture visible state for keys that will be affected by pending sync operations
551
+ * This must be called BEFORE onTransactionStateChange clears optimistic state
552
+ */
553
+ capturePreSyncVisibleState() {
554
+ if (this.pendingSyncedTransactions.length === 0) return;
555
+ this.preSyncVisibleState.clear();
556
+ const syncedKeys = /* @__PURE__ */ new Set();
557
+ for (const transaction of this.pendingSyncedTransactions) {
558
+ for (const operation of transaction.operations) {
559
+ syncedKeys.add(operation.key);
560
+ }
561
+ }
562
+ for (const key of syncedKeys) {
563
+ this.recentlySyncedKeys.add(key);
564
+ }
565
+ for (const key of syncedKeys) {
566
+ const currentValue = this.get(key);
567
+ if (currentValue !== void 0) {
568
+ this.preSyncVisibleState.set(key, currentValue);
569
+ }
570
+ }
571
+ }
572
+ /**
573
+ * Trigger a recomputation when transactions change
574
+ * This method should be called by the Transaction class when state changes
575
+ */
576
+ onTransactionStateChange() {
577
+ this.changes.shouldBatchEvents = this.pendingSyncedTransactions.length > 0;
578
+ this.capturePreSyncVisibleState();
579
+ this.recomputeOptimisticState(false);
580
+ }
581
+ /**
582
+ * Clean up the collection by stopping sync and clearing data
583
+ * This can be called manually or automatically by garbage collection
584
+ */
585
+ cleanup() {
586
+ this.syncedData.clear();
587
+ this.syncedMetadata.clear();
588
+ this.optimisticUpserts.clear();
589
+ this.optimisticDeletes.clear();
590
+ this.size = 0;
591
+ this.pendingSyncedTransactions = [];
592
+ this.syncedKeys.clear();
593
+ this.hasReceivedFirstCommit = false;
594
+ }
595
+ }
596
+ exports.CollectionStateManager = CollectionStateManager;
597
+ //# sourceMappingURL=state.cjs.map