@tanstack/db 0.0.7 → 0.0.8
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.
- package/dist/cjs/collection.cjs +441 -284
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +103 -30
- package/dist/cjs/proxy.cjs +2 -2
- package/dist/cjs/proxy.cjs.map +1 -1
- package/dist/cjs/query/compiled-query.cjs +23 -37
- package/dist/cjs/query/compiled-query.cjs.map +1 -1
- package/dist/cjs/query/compiled-query.d.cts +2 -2
- package/dist/cjs/query/order-by.cjs +41 -38
- package/dist/cjs/query/order-by.cjs.map +1 -1
- package/dist/cjs/query/schema.d.cts +3 -3
- package/dist/cjs/transactions.cjs +7 -6
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/transactions.d.cts +9 -9
- package/dist/cjs/types.d.cts +28 -22
- package/dist/esm/collection.d.ts +103 -30
- package/dist/esm/collection.js +442 -285
- package/dist/esm/collection.js.map +1 -1
- package/dist/esm/proxy.js +2 -2
- package/dist/esm/proxy.js.map +1 -1
- package/dist/esm/query/compiled-query.d.ts +2 -2
- package/dist/esm/query/compiled-query.js +23 -37
- package/dist/esm/query/compiled-query.js.map +1 -1
- package/dist/esm/query/order-by.js +41 -38
- package/dist/esm/query/order-by.js.map +1 -1
- package/dist/esm/query/schema.d.ts +3 -3
- package/dist/esm/transactions.d.ts +9 -9
- package/dist/esm/transactions.js +7 -6
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +28 -22
- package/package.json +2 -2
- package/src/collection.ts +624 -372
- package/src/proxy.ts +2 -2
- package/src/query/compiled-query.ts +26 -37
- package/src/query/order-by.ts +69 -67
- package/src/query/schema.ts +3 -3
- package/src/transactions.ts +24 -22
- package/src/types.ts +44 -22
package/dist/cjs/collection.cjs
CHANGED
|
@@ -4,10 +4,8 @@ const store = require("@tanstack/store");
|
|
|
4
4
|
const proxy = require("./proxy.cjs");
|
|
5
5
|
const transactions = require("./transactions.cjs");
|
|
6
6
|
const SortedMap = require("./SortedMap.cjs");
|
|
7
|
-
const collectionsStore = new
|
|
8
|
-
|
|
9
|
-
);
|
|
10
|
-
const loadingCollections = /* @__PURE__ */ new Map();
|
|
7
|
+
const collectionsStore = /* @__PURE__ */ new Map();
|
|
8
|
+
const loadingCollectionResolvers = /* @__PURE__ */ new Map();
|
|
11
9
|
function createCollection(options) {
|
|
12
10
|
const collection = new CollectionImpl(options);
|
|
13
11
|
if (options.utils) {
|
|
@@ -21,52 +19,44 @@ function preloadCollection(config) {
|
|
|
21
19
|
if (!config.id) {
|
|
22
20
|
throw new Error(`The id property is required for preloadCollection`);
|
|
23
21
|
}
|
|
24
|
-
if (collectionsStore.
|
|
22
|
+
if (collectionsStore.has(config.id) && !loadingCollectionResolvers.has(config.id)) {
|
|
25
23
|
return Promise.resolve(
|
|
26
|
-
collectionsStore.
|
|
24
|
+
collectionsStore.get(config.id)
|
|
27
25
|
);
|
|
28
26
|
}
|
|
29
|
-
if (
|
|
30
|
-
return
|
|
27
|
+
if (loadingCollectionResolvers.has(config.id)) {
|
|
28
|
+
return loadingCollectionResolvers.get(config.id).promise;
|
|
31
29
|
}
|
|
32
|
-
if (!collectionsStore.
|
|
33
|
-
collectionsStore.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
config.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
getId: config.getId,
|
|
43
|
-
sync: config.sync,
|
|
44
|
-
schema: config.schema
|
|
45
|
-
})
|
|
46
|
-
);
|
|
47
|
-
return next;
|
|
48
|
-
});
|
|
30
|
+
if (!collectionsStore.has(config.id)) {
|
|
31
|
+
collectionsStore.set(
|
|
32
|
+
config.id,
|
|
33
|
+
createCollection({
|
|
34
|
+
id: config.id,
|
|
35
|
+
getKey: config.getKey,
|
|
36
|
+
sync: config.sync,
|
|
37
|
+
schema: config.schema
|
|
38
|
+
})
|
|
39
|
+
);
|
|
49
40
|
}
|
|
50
|
-
const collection = collectionsStore.
|
|
41
|
+
const collection = collectionsStore.get(config.id);
|
|
51
42
|
let resolveFirstCommit;
|
|
52
43
|
const firstCommitPromise = new Promise((resolve) => {
|
|
53
|
-
resolveFirstCommit =
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
resolveFirstCommit = resolve;
|
|
45
|
+
});
|
|
46
|
+
loadingCollectionResolvers.set(config.id, {
|
|
47
|
+
promise: firstCommitPromise,
|
|
48
|
+
resolve: resolveFirstCommit
|
|
56
49
|
});
|
|
57
50
|
collection.onFirstCommit(() => {
|
|
58
51
|
if (!config.id) {
|
|
59
52
|
throw new Error(`The id property is required for preloadCollection`);
|
|
60
53
|
}
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
if (loadingCollectionResolvers.has(config.id)) {
|
|
55
|
+
const resolver = loadingCollectionResolvers.get(config.id);
|
|
56
|
+
loadingCollectionResolvers.delete(config.id);
|
|
57
|
+
resolver.resolve(collection);
|
|
64
58
|
}
|
|
65
59
|
});
|
|
66
|
-
loadingCollections.set(
|
|
67
|
-
config.id,
|
|
68
|
-
firstCommitPromise
|
|
69
|
-
);
|
|
70
60
|
return firstCommitPromise;
|
|
71
61
|
}
|
|
72
62
|
class SchemaValidationError extends Error {
|
|
@@ -86,59 +76,94 @@ class CollectionImpl {
|
|
|
86
76
|
* @throws Error if sync config is missing
|
|
87
77
|
*/
|
|
88
78
|
constructor(config) {
|
|
79
|
+
this.syncedData = /* @__PURE__ */ new Map();
|
|
80
|
+
this.syncedMetadata = /* @__PURE__ */ new Map();
|
|
81
|
+
this.derivedUpserts = /* @__PURE__ */ new Map();
|
|
82
|
+
this.derivedDeletes = /* @__PURE__ */ new Set();
|
|
83
|
+
this._size = 0;
|
|
84
|
+
this.changeListeners = /* @__PURE__ */ new Set();
|
|
85
|
+
this.changeKeyListeners = /* @__PURE__ */ new Map();
|
|
89
86
|
this.utils = {};
|
|
90
|
-
this.syncedData = new store.Store(/* @__PURE__ */ new Map());
|
|
91
|
-
this.syncedMetadata = new store.Store(/* @__PURE__ */ new Map());
|
|
92
87
|
this.pendingSyncedTransactions = [];
|
|
93
88
|
this.syncedKeys = /* @__PURE__ */ new Set();
|
|
94
89
|
this.hasReceivedFirstCommit = false;
|
|
95
90
|
this.onFirstCommitCallbacks = [];
|
|
96
91
|
this.id = ``;
|
|
97
92
|
this.commitPendingTransactions = () => {
|
|
98
|
-
if (!Array.from(this.transactions.
|
|
93
|
+
if (!Array.from(this.transactions.values()).some(
|
|
99
94
|
({ state }) => state === `persisting`
|
|
100
95
|
)) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
96
|
+
const changedKeys = /* @__PURE__ */ new Set();
|
|
97
|
+
const events = [];
|
|
98
|
+
for (const transaction of this.pendingSyncedTransactions) {
|
|
99
|
+
for (const operation of transaction.operations) {
|
|
100
|
+
const key = operation.key;
|
|
101
|
+
changedKeys.add(key);
|
|
102
|
+
this.syncedKeys.add(key);
|
|
103
|
+
switch (operation.type) {
|
|
104
|
+
case `insert`:
|
|
105
|
+
this.syncedMetadata.set(key, operation.metadata);
|
|
106
|
+
break;
|
|
107
|
+
case `update`:
|
|
108
|
+
this.syncedMetadata.set(
|
|
109
|
+
key,
|
|
110
|
+
Object.assign(
|
|
111
|
+
{},
|
|
112
|
+
this.syncedMetadata.get(key),
|
|
113
|
+
operation.metadata
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
break;
|
|
117
|
+
case `delete`:
|
|
118
|
+
this.syncedMetadata.delete(key);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
const previousValue = this.syncedData.get(key);
|
|
122
|
+
switch (operation.type) {
|
|
123
|
+
case `insert`:
|
|
124
|
+
this.syncedData.set(key, operation.value);
|
|
125
|
+
if (!this.derivedDeletes.has(key) && !this.derivedUpserts.has(key)) {
|
|
126
|
+
events.push({
|
|
127
|
+
type: `insert`,
|
|
128
|
+
key,
|
|
129
|
+
value: operation.value
|
|
130
|
+
});
|
|
119
131
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
break;
|
|
133
|
+
case `update`: {
|
|
134
|
+
const updatedValue = Object.assign(
|
|
135
|
+
{},
|
|
136
|
+
this.syncedData.get(key),
|
|
137
|
+
operation.value
|
|
138
|
+
);
|
|
139
|
+
this.syncedData.set(key, updatedValue);
|
|
140
|
+
if (!this.derivedDeletes.has(key) && !this.derivedUpserts.has(key)) {
|
|
141
|
+
events.push({
|
|
142
|
+
type: `update`,
|
|
143
|
+
key,
|
|
144
|
+
value: updatedValue,
|
|
145
|
+
previousValue
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case `delete`:
|
|
151
|
+
this.syncedData.delete(key);
|
|
152
|
+
if (!this.derivedDeletes.has(key) && !this.derivedUpserts.has(key)) {
|
|
153
|
+
if (previousValue) {
|
|
154
|
+
events.push({
|
|
155
|
+
type: `delete`,
|
|
156
|
+
key,
|
|
157
|
+
value: previousValue
|
|
131
158
|
});
|
|
132
|
-
|
|
133
|
-
case `delete`:
|
|
134
|
-
prevData.delete(operation.key);
|
|
135
|
-
break;
|
|
159
|
+
}
|
|
136
160
|
}
|
|
137
|
-
|
|
138
|
-
});
|
|
161
|
+
break;
|
|
139
162
|
}
|
|
140
163
|
}
|
|
141
|
-
}
|
|
164
|
+
}
|
|
165
|
+
this._size = this.calculateSize();
|
|
166
|
+
this.emitEvents(events);
|
|
142
167
|
this.pendingSyncedTransactions = [];
|
|
143
168
|
if (!this.hasReceivedFirstCommit) {
|
|
144
169
|
this.hasReceivedFirstCommit = true;
|
|
@@ -157,22 +182,20 @@ class CollectionImpl {
|
|
|
157
182
|
}
|
|
158
183
|
const items = Array.isArray(data) ? data : [data];
|
|
159
184
|
const mutations = [];
|
|
160
|
-
|
|
161
|
-
(item) => this.generateObjectKey(this.config.getId(item), item)
|
|
162
|
-
);
|
|
163
|
-
items.forEach((item, index) => {
|
|
185
|
+
items.forEach((item) => {
|
|
164
186
|
var _a, _b;
|
|
165
187
|
const validatedData = this.validateData(item, `insert`);
|
|
166
|
-
const key =
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
throw `Cannot insert document with ID "${id}" because it already exists in the collection`;
|
|
188
|
+
const key = this.getKeyFromItem(item);
|
|
189
|
+
if (this.has(key)) {
|
|
190
|
+
throw `Cannot insert document with ID "${key}" because it already exists in the collection`;
|
|
170
191
|
}
|
|
192
|
+
const globalKey = this.generateGlobalKey(key, item);
|
|
171
193
|
const mutation = {
|
|
172
194
|
mutationId: crypto.randomUUID(),
|
|
173
195
|
original: {},
|
|
174
196
|
modified: validatedData,
|
|
175
197
|
changes: validatedData,
|
|
198
|
+
globalKey,
|
|
176
199
|
key,
|
|
177
200
|
metadata: config2 == null ? void 0 : config2.metadata,
|
|
178
201
|
syncMetadata: ((_b = (_a = this.config.sync).getSyncMetadata) == null ? void 0 : _b.call(_a)) || {},
|
|
@@ -185,10 +208,8 @@ class CollectionImpl {
|
|
|
185
208
|
});
|
|
186
209
|
if (ambientTransaction) {
|
|
187
210
|
ambientTransaction.applyMutations(mutations);
|
|
188
|
-
this.transactions.
|
|
189
|
-
|
|
190
|
-
return sortedMap;
|
|
191
|
-
});
|
|
211
|
+
this.transactions.set(ambientTransaction.id, ambientTransaction);
|
|
212
|
+
this.recomputeOptimisticState();
|
|
192
213
|
return ambientTransaction;
|
|
193
214
|
} else {
|
|
194
215
|
const directOpTransaction = new transactions.Transaction({
|
|
@@ -198,33 +219,34 @@ class CollectionImpl {
|
|
|
198
219
|
});
|
|
199
220
|
directOpTransaction.applyMutations(mutations);
|
|
200
221
|
directOpTransaction.commit();
|
|
201
|
-
this.transactions.
|
|
202
|
-
|
|
203
|
-
return sortedMap;
|
|
204
|
-
});
|
|
222
|
+
this.transactions.set(directOpTransaction.id, directOpTransaction);
|
|
223
|
+
this.recomputeOptimisticState();
|
|
205
224
|
return directOpTransaction;
|
|
206
225
|
}
|
|
207
226
|
};
|
|
208
|
-
this.delete = (
|
|
227
|
+
this.delete = (keys, config2) => {
|
|
209
228
|
const ambientTransaction = transactions.getActiveTransaction();
|
|
210
229
|
if (!ambientTransaction && !this.config.onDelete) {
|
|
211
230
|
throw new Error(
|
|
212
231
|
`Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`
|
|
213
232
|
);
|
|
214
233
|
}
|
|
215
|
-
|
|
216
|
-
(
|
|
217
|
-
|
|
234
|
+
if (Array.isArray(keys) && keys.length === 0) {
|
|
235
|
+
throw new Error(`No keys were passed to delete`);
|
|
236
|
+
}
|
|
237
|
+
const keysArray = Array.isArray(keys) ? keys : [keys];
|
|
218
238
|
const mutations = [];
|
|
219
|
-
for (const
|
|
239
|
+
for (const key of keysArray) {
|
|
240
|
+
const globalKey = this.generateGlobalKey(key, this.get(key));
|
|
220
241
|
const mutation = {
|
|
221
242
|
mutationId: crypto.randomUUID(),
|
|
222
|
-
original: this.
|
|
223
|
-
modified: this.
|
|
224
|
-
changes: this.
|
|
225
|
-
|
|
243
|
+
original: this.get(key) || {},
|
|
244
|
+
modified: this.get(key),
|
|
245
|
+
changes: this.get(key) || {},
|
|
246
|
+
globalKey,
|
|
247
|
+
key,
|
|
226
248
|
metadata: config2 == null ? void 0 : config2.metadata,
|
|
227
|
-
syncMetadata: this.syncedMetadata.
|
|
249
|
+
syncMetadata: this.syncedMetadata.get(key) || {},
|
|
228
250
|
type: `delete`,
|
|
229
251
|
createdAt: /* @__PURE__ */ new Date(),
|
|
230
252
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
@@ -234,24 +256,20 @@ class CollectionImpl {
|
|
|
234
256
|
}
|
|
235
257
|
if (ambientTransaction) {
|
|
236
258
|
ambientTransaction.applyMutations(mutations);
|
|
237
|
-
this.transactions.
|
|
238
|
-
|
|
239
|
-
return sortedMap;
|
|
240
|
-
});
|
|
259
|
+
this.transactions.set(ambientTransaction.id, ambientTransaction);
|
|
260
|
+
this.recomputeOptimisticState();
|
|
241
261
|
return ambientTransaction;
|
|
242
262
|
}
|
|
243
263
|
const directOpTransaction = new transactions.Transaction({
|
|
244
264
|
autoCommit: true,
|
|
245
|
-
mutationFn: async (
|
|
246
|
-
return this.config.onDelete(
|
|
265
|
+
mutationFn: async (params) => {
|
|
266
|
+
return this.config.onDelete(params);
|
|
247
267
|
}
|
|
248
268
|
});
|
|
249
269
|
directOpTransaction.applyMutations(mutations);
|
|
250
270
|
directOpTransaction.commit();
|
|
251
|
-
this.transactions.
|
|
252
|
-
|
|
253
|
-
return sortedMap;
|
|
254
|
-
});
|
|
271
|
+
this.transactions.set(directOpTransaction.id, directOpTransaction);
|
|
272
|
+
this.recomputeOptimisticState();
|
|
255
273
|
return directOpTransaction;
|
|
256
274
|
};
|
|
257
275
|
if (!config) {
|
|
@@ -265,121 +283,10 @@ class CollectionImpl {
|
|
|
265
283
|
if (!config.sync) {
|
|
266
284
|
throw new Error(`Collection requires a sync config`);
|
|
267
285
|
}
|
|
268
|
-
this.transactions = new
|
|
269
|
-
|
|
270
|
-
(a, b) => a.createdAt.getTime() - b.createdAt.getTime()
|
|
271
|
-
)
|
|
286
|
+
this.transactions = new SortedMap.SortedMap(
|
|
287
|
+
(a, b) => a.createdAt.getTime() - b.createdAt.getTime()
|
|
272
288
|
);
|
|
273
|
-
this.optimisticOperations = new store.Derived({
|
|
274
|
-
fn: ({ currDepVals: [transactions2] }) => {
|
|
275
|
-
const result = Array.from(transactions2.values()).map((transaction) => {
|
|
276
|
-
const isActive = ![`completed`, `failed`].includes(
|
|
277
|
-
transaction.state
|
|
278
|
-
);
|
|
279
|
-
return transaction.mutations.filter((mutation) => mutation.collection === this).map((mutation) => {
|
|
280
|
-
const message = {
|
|
281
|
-
type: mutation.type,
|
|
282
|
-
key: mutation.key,
|
|
283
|
-
value: mutation.modified,
|
|
284
|
-
isActive
|
|
285
|
-
};
|
|
286
|
-
if (mutation.metadata !== void 0 && mutation.metadata !== null) {
|
|
287
|
-
message.metadata = mutation.metadata;
|
|
288
|
-
}
|
|
289
|
-
return message;
|
|
290
|
-
});
|
|
291
|
-
}).flat();
|
|
292
|
-
return result;
|
|
293
|
-
},
|
|
294
|
-
deps: [this.transactions]
|
|
295
|
-
});
|
|
296
|
-
this.optimisticOperations.mount();
|
|
297
|
-
this.derivedState = new store.Derived({
|
|
298
|
-
fn: ({ currDepVals: [syncedData, operations] }) => {
|
|
299
|
-
const combined = new Map(syncedData);
|
|
300
|
-
for (const operation of operations) {
|
|
301
|
-
if (operation.isActive) {
|
|
302
|
-
switch (operation.type) {
|
|
303
|
-
case `insert`:
|
|
304
|
-
combined.set(operation.key, operation.value);
|
|
305
|
-
break;
|
|
306
|
-
case `update`:
|
|
307
|
-
combined.set(operation.key, operation.value);
|
|
308
|
-
break;
|
|
309
|
-
case `delete`:
|
|
310
|
-
combined.delete(operation.key);
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return combined;
|
|
316
|
-
},
|
|
317
|
-
deps: [this.syncedData, this.optimisticOperations]
|
|
318
|
-
});
|
|
319
|
-
this.derivedArray = new store.Derived({
|
|
320
|
-
fn: ({ currDepVals: [stateMap] }) => {
|
|
321
|
-
const array = Array.from(
|
|
322
|
-
stateMap.values()
|
|
323
|
-
);
|
|
324
|
-
if (array[0] && `_orderByIndex` in array[0]) {
|
|
325
|
-
array.sort((a, b) => {
|
|
326
|
-
if (a._orderByIndex === b._orderByIndex) {
|
|
327
|
-
return 0;
|
|
328
|
-
}
|
|
329
|
-
return a._orderByIndex < b._orderByIndex ? -1 : 1;
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
return array;
|
|
333
|
-
},
|
|
334
|
-
deps: [this.derivedState]
|
|
335
|
-
});
|
|
336
|
-
this.derivedArray.mount();
|
|
337
|
-
this.derivedChanges = new store.Derived({
|
|
338
|
-
fn: ({
|
|
339
|
-
currDepVals: [derivedState, optimisticOperations],
|
|
340
|
-
prevDepVals
|
|
341
|
-
}) => {
|
|
342
|
-
const prevDerivedState = (prevDepVals == null ? void 0 : prevDepVals[0]) ?? /* @__PURE__ */ new Map();
|
|
343
|
-
const prevOptimisticOperations = (prevDepVals == null ? void 0 : prevDepVals[1]) ?? [];
|
|
344
|
-
const changedKeys = new Set(this.syncedKeys);
|
|
345
|
-
optimisticOperations.flat().filter((op) => op.isActive).forEach((op) => changedKeys.add(op.key));
|
|
346
|
-
prevOptimisticOperations.flat().forEach((op) => {
|
|
347
|
-
changedKeys.add(op.key);
|
|
348
|
-
});
|
|
349
|
-
if (changedKeys.size === 0) {
|
|
350
|
-
return [];
|
|
351
|
-
}
|
|
352
|
-
const changes = [];
|
|
353
|
-
for (const key of changedKeys) {
|
|
354
|
-
if (prevDerivedState.has(key) && !derivedState.has(key)) {
|
|
355
|
-
changes.push({
|
|
356
|
-
type: `delete`,
|
|
357
|
-
key,
|
|
358
|
-
value: prevDerivedState.get(key)
|
|
359
|
-
});
|
|
360
|
-
} else if (!prevDerivedState.has(key) && derivedState.has(key)) {
|
|
361
|
-
changes.push({ type: `insert`, key, value: derivedState.get(key) });
|
|
362
|
-
} else if (prevDerivedState.has(key) && derivedState.has(key)) {
|
|
363
|
-
const value = derivedState.get(key);
|
|
364
|
-
const previousValue = prevDerivedState.get(key);
|
|
365
|
-
if (value !== previousValue) {
|
|
366
|
-
changes.push({
|
|
367
|
-
type: `update`,
|
|
368
|
-
key,
|
|
369
|
-
value,
|
|
370
|
-
previousValue
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
this.syncedKeys.clear();
|
|
376
|
-
return changes;
|
|
377
|
-
},
|
|
378
|
-
deps: [this.derivedState, this.optimisticOperations]
|
|
379
|
-
});
|
|
380
|
-
this.derivedChanges.mount();
|
|
381
289
|
this.config = config;
|
|
382
|
-
this.derivedState.mount();
|
|
383
290
|
config.sync.sync({
|
|
384
291
|
collection: this,
|
|
385
292
|
begin: () => {
|
|
@@ -398,17 +305,13 @@ class CollectionImpl {
|
|
|
398
305
|
`The pending sync transaction is already committed, you can't still write to it.`
|
|
399
306
|
);
|
|
400
307
|
}
|
|
401
|
-
const key = this.
|
|
402
|
-
this.config.getId(messageWithoutKey.value),
|
|
403
|
-
messageWithoutKey.value
|
|
404
|
-
);
|
|
308
|
+
const key = this.getKeyFromItem(messageWithoutKey.value);
|
|
405
309
|
if (messageWithoutKey.type === `insert`) {
|
|
406
|
-
if (this.syncedData.
|
|
310
|
+
if (this.syncedData.has(key) && !pendingTransaction.operations.some(
|
|
407
311
|
(op) => op.key === key && op.type === `delete`
|
|
408
312
|
)) {
|
|
409
|
-
const id = this.config.getId(messageWithoutKey.value);
|
|
410
313
|
throw new Error(
|
|
411
|
-
`Cannot insert document with
|
|
314
|
+
`Cannot insert document with key "${key}" from sync because it already exists in the collection "${this.id}"`
|
|
412
315
|
);
|
|
413
316
|
}
|
|
414
317
|
}
|
|
@@ -441,6 +344,189 @@ class CollectionImpl {
|
|
|
441
344
|
onFirstCommit(callback) {
|
|
442
345
|
this.onFirstCommitCallbacks.push(callback);
|
|
443
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Recompute optimistic state from active transactions
|
|
349
|
+
*/
|
|
350
|
+
recomputeOptimisticState() {
|
|
351
|
+
const previousState = new Map(this.derivedUpserts);
|
|
352
|
+
const previousDeletes = new Set(this.derivedDeletes);
|
|
353
|
+
this.derivedUpserts.clear();
|
|
354
|
+
this.derivedDeletes.clear();
|
|
355
|
+
const activeTransactions = Array.from(this.transactions.values());
|
|
356
|
+
for (const transaction of activeTransactions) {
|
|
357
|
+
if (![`completed`, `failed`].includes(transaction.state)) {
|
|
358
|
+
for (const mutation of transaction.mutations) {
|
|
359
|
+
if (mutation.collection === this) {
|
|
360
|
+
switch (mutation.type) {
|
|
361
|
+
case `insert`:
|
|
362
|
+
case `update`:
|
|
363
|
+
this.derivedUpserts.set(mutation.key, mutation.modified);
|
|
364
|
+
this.derivedDeletes.delete(mutation.key);
|
|
365
|
+
break;
|
|
366
|
+
case `delete`:
|
|
367
|
+
this.derivedUpserts.delete(mutation.key);
|
|
368
|
+
this.derivedDeletes.add(mutation.key);
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
this._size = this.calculateSize();
|
|
376
|
+
const events = [];
|
|
377
|
+
this.collectOptimisticChanges(previousState, previousDeletes, events);
|
|
378
|
+
this.emitEvents(events);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Calculate the current size based on synced data and optimistic changes
|
|
382
|
+
*/
|
|
383
|
+
calculateSize() {
|
|
384
|
+
const syncedSize = this.syncedData.size;
|
|
385
|
+
const deletesFromSynced = Array.from(this.derivedDeletes).filter(
|
|
386
|
+
(key) => this.syncedData.has(key) && !this.derivedUpserts.has(key)
|
|
387
|
+
).length;
|
|
388
|
+
const upsertsNotInSynced = Array.from(this.derivedUpserts.keys()).filter(
|
|
389
|
+
(key) => !this.syncedData.has(key)
|
|
390
|
+
).length;
|
|
391
|
+
return syncedSize - deletesFromSynced + upsertsNotInSynced;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Collect events for optimistic changes
|
|
395
|
+
*/
|
|
396
|
+
collectOptimisticChanges(previousUpserts, previousDeletes, events) {
|
|
397
|
+
const allKeys = /* @__PURE__ */ new Set([
|
|
398
|
+
...previousUpserts.keys(),
|
|
399
|
+
...this.derivedUpserts.keys(),
|
|
400
|
+
...previousDeletes,
|
|
401
|
+
...this.derivedDeletes
|
|
402
|
+
]);
|
|
403
|
+
for (const key of allKeys) {
|
|
404
|
+
const currentValue = this.get(key);
|
|
405
|
+
const previousValue = this.getPreviousValue(
|
|
406
|
+
key,
|
|
407
|
+
previousUpserts,
|
|
408
|
+
previousDeletes
|
|
409
|
+
);
|
|
410
|
+
if (previousValue !== void 0 && currentValue === void 0) {
|
|
411
|
+
events.push({ type: `delete`, key, value: previousValue });
|
|
412
|
+
} else if (previousValue === void 0 && currentValue !== void 0) {
|
|
413
|
+
events.push({ type: `insert`, key, value: currentValue });
|
|
414
|
+
} else if (previousValue !== void 0 && currentValue !== void 0 && previousValue !== currentValue) {
|
|
415
|
+
events.push({
|
|
416
|
+
type: `update`,
|
|
417
|
+
key,
|
|
418
|
+
value: currentValue,
|
|
419
|
+
previousValue
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Get the previous value for a key given previous optimistic state
|
|
426
|
+
*/
|
|
427
|
+
getPreviousValue(key, previousUpserts, previousDeletes) {
|
|
428
|
+
if (previousDeletes.has(key)) {
|
|
429
|
+
return void 0;
|
|
430
|
+
}
|
|
431
|
+
if (previousUpserts.has(key)) {
|
|
432
|
+
return previousUpserts.get(key);
|
|
433
|
+
}
|
|
434
|
+
return this.syncedData.get(key);
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Emit multiple events at once to all listeners
|
|
438
|
+
*/
|
|
439
|
+
emitEvents(changes) {
|
|
440
|
+
if (changes.length > 0) {
|
|
441
|
+
for (const listener of this.changeListeners) {
|
|
442
|
+
listener(changes);
|
|
443
|
+
}
|
|
444
|
+
if (this.changeKeyListeners.size > 0) {
|
|
445
|
+
const changesByKey = /* @__PURE__ */ new Map();
|
|
446
|
+
for (const change of changes) {
|
|
447
|
+
if (this.changeKeyListeners.has(change.key)) {
|
|
448
|
+
if (!changesByKey.has(change.key)) {
|
|
449
|
+
changesByKey.set(change.key, []);
|
|
450
|
+
}
|
|
451
|
+
changesByKey.get(change.key).push(change);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
for (const [key, keyChanges] of changesByKey) {
|
|
455
|
+
const keyListeners = this.changeKeyListeners.get(key);
|
|
456
|
+
for (const listener of keyListeners) {
|
|
457
|
+
listener(keyChanges);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Get the current value for a key (virtual derived state)
|
|
465
|
+
*/
|
|
466
|
+
get(key) {
|
|
467
|
+
if (this.derivedDeletes.has(key)) {
|
|
468
|
+
return void 0;
|
|
469
|
+
}
|
|
470
|
+
if (this.derivedUpserts.has(key)) {
|
|
471
|
+
return this.derivedUpserts.get(key);
|
|
472
|
+
}
|
|
473
|
+
return this.syncedData.get(key);
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Check if a key exists in the collection (virtual derived state)
|
|
477
|
+
*/
|
|
478
|
+
has(key) {
|
|
479
|
+
if (this.derivedDeletes.has(key)) {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
if (this.derivedUpserts.has(key)) {
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
return this.syncedData.has(key);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Get the current size of the collection (cached)
|
|
489
|
+
*/
|
|
490
|
+
get size() {
|
|
491
|
+
return this._size;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Get all keys (virtual derived state)
|
|
495
|
+
*/
|
|
496
|
+
*keys() {
|
|
497
|
+
for (const key of this.syncedData.keys()) {
|
|
498
|
+
if (!this.derivedDeletes.has(key)) {
|
|
499
|
+
yield key;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
for (const key of this.derivedUpserts.keys()) {
|
|
503
|
+
if (!this.syncedData.has(key) && !this.derivedDeletes.has(key)) {
|
|
504
|
+
yield key;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Get all values (virtual derived state)
|
|
510
|
+
*/
|
|
511
|
+
*values() {
|
|
512
|
+
for (const key of this.keys()) {
|
|
513
|
+
const value = this.get(key);
|
|
514
|
+
if (value !== void 0) {
|
|
515
|
+
yield value;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Get all entries (virtual derived state)
|
|
521
|
+
*/
|
|
522
|
+
*entries() {
|
|
523
|
+
for (const key of this.keys()) {
|
|
524
|
+
const value = this.get(key);
|
|
525
|
+
if (value !== void 0) {
|
|
526
|
+
yield [key, value];
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
444
530
|
ensureStandardSchema(schema) {
|
|
445
531
|
if (schema && typeof schema === `object` && `~standard` in schema) {
|
|
446
532
|
return schema;
|
|
@@ -449,31 +535,24 @@ class CollectionImpl {
|
|
|
449
535
|
`Schema must either implement the standard-schema interface or be a Zod schema`
|
|
450
536
|
);
|
|
451
537
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
throw new Error(`id is undefined`);
|
|
455
|
-
}
|
|
456
|
-
if (typeof id === `string` && id.startsWith(`KEY::`)) {
|
|
457
|
-
return id;
|
|
458
|
-
} else {
|
|
459
|
-
return this.generateObjectKey(id, null);
|
|
460
|
-
}
|
|
538
|
+
getKeyFromItem(item) {
|
|
539
|
+
return this.config.getKey(item);
|
|
461
540
|
}
|
|
462
|
-
|
|
463
|
-
if (typeof
|
|
541
|
+
generateGlobalKey(key, item) {
|
|
542
|
+
if (typeof key === `undefined`) {
|
|
464
543
|
throw new Error(
|
|
465
|
-
`An object was created without a defined
|
|
544
|
+
`An object was created without a defined key: ${JSON.stringify(item)}`
|
|
466
545
|
);
|
|
467
546
|
}
|
|
468
|
-
return `KEY::${this.id}/${
|
|
547
|
+
return `KEY::${this.id}/${key}`;
|
|
469
548
|
}
|
|
470
549
|
validateData(data, type, key) {
|
|
471
550
|
if (!this.config.schema) return data;
|
|
472
551
|
const standardSchema = this.ensureStandardSchema(this.config.schema);
|
|
473
552
|
if (type === `update` && key) {
|
|
474
|
-
const existingData = this.
|
|
553
|
+
const existingData = this.get(key);
|
|
475
554
|
if (existingData && data && typeof data === `object` && typeof existingData === `object`) {
|
|
476
|
-
const mergedData = {
|
|
555
|
+
const mergedData = Object.assign({}, existingData, data);
|
|
477
556
|
const result2 = standardSchema[`~standard`].validate(mergedData);
|
|
478
557
|
if (result2 instanceof Promise) {
|
|
479
558
|
throw new TypeError(`Schema validation must be synchronous`);
|
|
@@ -507,8 +586,8 @@ class CollectionImpl {
|
|
|
507
586
|
}
|
|
508
587
|
return result.value;
|
|
509
588
|
}
|
|
510
|
-
update(
|
|
511
|
-
if (typeof
|
|
589
|
+
update(keys, configOrCallback, maybeCallback) {
|
|
590
|
+
if (typeof keys === `undefined`) {
|
|
512
591
|
throw new Error(`The first argument to update is missing`);
|
|
513
592
|
}
|
|
514
593
|
const ambientTransaction = transactions.getActiveTransaction();
|
|
@@ -517,17 +596,18 @@ class CollectionImpl {
|
|
|
517
596
|
`Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`
|
|
518
597
|
);
|
|
519
598
|
}
|
|
520
|
-
const isArray = Array.isArray(
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
|
|
599
|
+
const isArray = Array.isArray(keys);
|
|
600
|
+
const keysArray = isArray ? keys : [keys];
|
|
601
|
+
if (isArray && keysArray.length === 0) {
|
|
602
|
+
throw new Error(`No keys were passed to update`);
|
|
603
|
+
}
|
|
524
604
|
const callback = typeof configOrCallback === `function` ? configOrCallback : maybeCallback;
|
|
525
605
|
const config = typeof configOrCallback === `function` ? {} : configOrCallback;
|
|
526
|
-
const currentObjects =
|
|
527
|
-
const item = this.
|
|
606
|
+
const currentObjects = keysArray.map((key) => {
|
|
607
|
+
const item = this.get(key);
|
|
528
608
|
if (!item) {
|
|
529
609
|
throw new Error(
|
|
530
|
-
`The
|
|
610
|
+
`The key "${key}" was passed to update but an object for this key was not found in the collection`
|
|
531
611
|
);
|
|
532
612
|
}
|
|
533
613
|
return item;
|
|
@@ -545,7 +625,7 @@ class CollectionImpl {
|
|
|
545
625
|
);
|
|
546
626
|
changesArray = [result];
|
|
547
627
|
}
|
|
548
|
-
const mutations =
|
|
628
|
+
const mutations = keysArray.map((key, index) => {
|
|
549
629
|
const itemChanges = changesArray[index];
|
|
550
630
|
if (!itemChanges || Object.keys(itemChanges).length === 0) {
|
|
551
631
|
return null;
|
|
@@ -554,24 +634,30 @@ class CollectionImpl {
|
|
|
554
634
|
const validatedUpdatePayload = this.validateData(
|
|
555
635
|
itemChanges,
|
|
556
636
|
`update`,
|
|
557
|
-
|
|
637
|
+
key
|
|
638
|
+
);
|
|
639
|
+
const modifiedItem = Object.assign(
|
|
640
|
+
{},
|
|
641
|
+
originalItem,
|
|
642
|
+
validatedUpdatePayload
|
|
558
643
|
);
|
|
559
|
-
const
|
|
560
|
-
const
|
|
561
|
-
const modifiedItemId = this.config.getId(modifiedItem);
|
|
644
|
+
const originalItemId = this.getKeyFromItem(originalItem);
|
|
645
|
+
const modifiedItemId = this.getKeyFromItem(modifiedItem);
|
|
562
646
|
if (originalItemId !== modifiedItemId) {
|
|
563
647
|
throw new Error(
|
|
564
|
-
`Updating the
|
|
648
|
+
`Updating the key of an item is not allowed. Original key: "${originalItemId}", Attempted new key: "${modifiedItemId}". Please delete the old item and create a new one if a key change is necessary.`
|
|
565
649
|
);
|
|
566
650
|
}
|
|
651
|
+
const globalKey = this.generateGlobalKey(modifiedItemId, modifiedItem);
|
|
567
652
|
return {
|
|
568
653
|
mutationId: crypto.randomUUID(),
|
|
569
654
|
original: originalItem,
|
|
570
655
|
modified: modifiedItem,
|
|
571
656
|
changes: validatedUpdatePayload,
|
|
572
|
-
|
|
657
|
+
globalKey,
|
|
658
|
+
key,
|
|
573
659
|
metadata: config.metadata,
|
|
574
|
-
syncMetadata: this.syncedMetadata.
|
|
660
|
+
syncMetadata: this.syncedMetadata.get(key) || {},
|
|
575
661
|
type: `update`,
|
|
576
662
|
createdAt: /* @__PURE__ */ new Date(),
|
|
577
663
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
@@ -583,23 +669,19 @@ class CollectionImpl {
|
|
|
583
669
|
}
|
|
584
670
|
if (ambientTransaction) {
|
|
585
671
|
ambientTransaction.applyMutations(mutations);
|
|
586
|
-
this.transactions.
|
|
587
|
-
|
|
588
|
-
return sortedMap;
|
|
589
|
-
});
|
|
672
|
+
this.transactions.set(ambientTransaction.id, ambientTransaction);
|
|
673
|
+
this.recomputeOptimisticState();
|
|
590
674
|
return ambientTransaction;
|
|
591
675
|
}
|
|
592
676
|
const directOpTransaction = new transactions.Transaction({
|
|
593
|
-
mutationFn: async (
|
|
594
|
-
return this.config.onUpdate(
|
|
677
|
+
mutationFn: async (params) => {
|
|
678
|
+
return this.config.onUpdate(params);
|
|
595
679
|
}
|
|
596
680
|
});
|
|
597
681
|
directOpTransaction.applyMutations(mutations);
|
|
598
682
|
directOpTransaction.commit();
|
|
599
|
-
this.transactions.
|
|
600
|
-
|
|
601
|
-
return sortedMap;
|
|
602
|
-
});
|
|
683
|
+
this.transactions.set(directOpTransaction.id, directOpTransaction);
|
|
684
|
+
this.recomputeOptimisticState();
|
|
603
685
|
return directOpTransaction;
|
|
604
686
|
}
|
|
605
687
|
/**
|
|
@@ -608,7 +690,11 @@ class CollectionImpl {
|
|
|
608
690
|
* @returns A Map containing all items in the collection, with keys as identifiers
|
|
609
691
|
*/
|
|
610
692
|
get state() {
|
|
611
|
-
|
|
693
|
+
const result = /* @__PURE__ */ new Map();
|
|
694
|
+
for (const [key, value] of this.entries()) {
|
|
695
|
+
result.set(key, value);
|
|
696
|
+
}
|
|
697
|
+
return result;
|
|
612
698
|
}
|
|
613
699
|
/**
|
|
614
700
|
* Gets the current state of the collection as a Map, but only resolves when data is available
|
|
@@ -617,7 +703,7 @@ class CollectionImpl {
|
|
|
617
703
|
* @returns Promise that resolves to a Map containing all items in the collection
|
|
618
704
|
*/
|
|
619
705
|
stateWhenReady() {
|
|
620
|
-
if (this.
|
|
706
|
+
if (this.size > 0 || this.hasReceivedFirstCommit === true) {
|
|
621
707
|
return Promise.resolve(this.state);
|
|
622
708
|
}
|
|
623
709
|
return new Promise((resolve) => {
|
|
@@ -632,7 +718,13 @@ class CollectionImpl {
|
|
|
632
718
|
* @returns An Array containing all items in the collection
|
|
633
719
|
*/
|
|
634
720
|
get toArray() {
|
|
635
|
-
|
|
721
|
+
const array = Array.from(this.values());
|
|
722
|
+
if (array[0] && array[0]._orderByIndex) {
|
|
723
|
+
return array.sort(
|
|
724
|
+
(a, b) => a._orderByIndex - b._orderByIndex
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
return array;
|
|
636
728
|
}
|
|
637
729
|
/**
|
|
638
730
|
* Gets the current state of the collection as an Array, but only resolves when data is available
|
|
@@ -641,7 +733,7 @@ class CollectionImpl {
|
|
|
641
733
|
* @returns Promise that resolves to an Array containing all items in the collection
|
|
642
734
|
*/
|
|
643
735
|
toArrayWhenReady() {
|
|
644
|
-
if (this.
|
|
736
|
+
if (this.size > 0 || this.hasReceivedFirstCommit === true) {
|
|
645
737
|
return Promise.resolve(this.toArray);
|
|
646
738
|
}
|
|
647
739
|
return new Promise((resolve) => {
|
|
@@ -655,7 +747,7 @@ class CollectionImpl {
|
|
|
655
747
|
* @returns An array of changes
|
|
656
748
|
*/
|
|
657
749
|
currentStateAsChanges() {
|
|
658
|
-
return
|
|
750
|
+
return Array.from(this.entries()).map(([key, value]) => ({
|
|
659
751
|
type: `insert`,
|
|
660
752
|
key,
|
|
661
753
|
value
|
|
@@ -666,13 +758,78 @@ class CollectionImpl {
|
|
|
666
758
|
* @param callback - A function that will be called with the changes in the collection
|
|
667
759
|
* @returns A function that can be called to unsubscribe from the changes
|
|
668
760
|
*/
|
|
669
|
-
subscribeChanges(callback) {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
761
|
+
subscribeChanges(callback, { includeInitialState = false } = {}) {
|
|
762
|
+
if (includeInitialState) {
|
|
763
|
+
callback(this.currentStateAsChanges());
|
|
764
|
+
}
|
|
765
|
+
this.changeListeners.add(callback);
|
|
766
|
+
return () => {
|
|
767
|
+
this.changeListeners.delete(callback);
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Subscribe to changes for a specific key
|
|
772
|
+
*/
|
|
773
|
+
subscribeChangesKey(key, listener, { includeInitialState = false } = {}) {
|
|
774
|
+
if (!this.changeKeyListeners.has(key)) {
|
|
775
|
+
this.changeKeyListeners.set(key, /* @__PURE__ */ new Set());
|
|
776
|
+
}
|
|
777
|
+
if (includeInitialState) {
|
|
778
|
+
listener([
|
|
779
|
+
{
|
|
780
|
+
type: `insert`,
|
|
781
|
+
key,
|
|
782
|
+
value: this.get(key)
|
|
783
|
+
}
|
|
784
|
+
]);
|
|
785
|
+
}
|
|
786
|
+
this.changeKeyListeners.get(key).add(listener);
|
|
787
|
+
return () => {
|
|
788
|
+
const listeners = this.changeKeyListeners.get(key);
|
|
789
|
+
if (listeners) {
|
|
790
|
+
listeners.delete(listener);
|
|
791
|
+
if (listeners.size === 0) {
|
|
792
|
+
this.changeKeyListeners.delete(key);
|
|
793
|
+
}
|
|
674
794
|
}
|
|
675
|
-
}
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Trigger a recomputation when transactions change
|
|
799
|
+
* This method should be called by the Transaction class when state changes
|
|
800
|
+
*/
|
|
801
|
+
onTransactionStateChange() {
|
|
802
|
+
this.recomputeOptimisticState();
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Returns a Tanstack Store Map that is updated when the collection changes
|
|
806
|
+
* This is a temporary solution to enable the existing framework hooks to work
|
|
807
|
+
* with the new internals of Collection until they are rewritten.
|
|
808
|
+
* TODO: Remove this once the framework hooks are rewritten.
|
|
809
|
+
*/
|
|
810
|
+
asStoreMap() {
|
|
811
|
+
if (!this._storeMap) {
|
|
812
|
+
this._storeMap = new store.Store(new Map(this.entries()));
|
|
813
|
+
this.subscribeChanges(() => {
|
|
814
|
+
this._storeMap.setState(() => new Map(this.entries()));
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
return this._storeMap;
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Returns a Tanstack Store Array that is updated when the collection changes
|
|
821
|
+
* This is a temporary solution to enable the existing framework hooks to work
|
|
822
|
+
* with the new internals of Collection until they are rewritten.
|
|
823
|
+
* TODO: Remove this once the framework hooks are rewritten.
|
|
824
|
+
*/
|
|
825
|
+
asStoreArray() {
|
|
826
|
+
if (!this._storeArray) {
|
|
827
|
+
this._storeArray = new store.Store(this.toArray);
|
|
828
|
+
this.subscribeChanges(() => {
|
|
829
|
+
this._storeArray.setState(() => this.toArray);
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
return this._storeArray;
|
|
676
833
|
}
|
|
677
834
|
}
|
|
678
835
|
exports.CollectionImpl = CollectionImpl;
|