@tanstack/db 0.0.4 → 0.0.6
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 +182 -113
- package/dist/cjs/collection.cjs.map +1 -1
- package/dist/cjs/collection.d.cts +43 -15
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/proxy.cjs +87 -248
- package/dist/cjs/proxy.cjs.map +1 -1
- package/dist/cjs/proxy.d.cts +5 -5
- package/dist/cjs/query/compiled-query.cjs +23 -14
- package/dist/cjs/query/compiled-query.cjs.map +1 -1
- package/dist/cjs/query/compiled-query.d.cts +3 -1
- package/dist/cjs/query/evaluators.cjs +35 -20
- package/dist/cjs/query/evaluators.cjs.map +1 -1
- package/dist/cjs/query/evaluators.d.cts +8 -3
- package/dist/cjs/query/extractors.cjs +20 -20
- package/dist/cjs/query/extractors.cjs.map +1 -1
- package/dist/cjs/query/extractors.d.cts +3 -3
- package/dist/cjs/query/group-by.cjs +12 -15
- package/dist/cjs/query/group-by.cjs.map +1 -1
- package/dist/cjs/query/group-by.d.cts +7 -7
- package/dist/cjs/query/joins.cjs +41 -55
- package/dist/cjs/query/joins.cjs.map +1 -1
- package/dist/cjs/query/joins.d.cts +3 -3
- package/dist/cjs/query/order-by.cjs +37 -84
- package/dist/cjs/query/order-by.cjs.map +1 -1
- package/dist/cjs/query/order-by.d.cts +2 -2
- package/dist/cjs/query/pipeline-compiler.cjs +13 -18
- package/dist/cjs/query/pipeline-compiler.cjs.map +1 -1
- package/dist/cjs/query/pipeline-compiler.d.cts +2 -1
- package/dist/cjs/query/query-builder.cjs +22 -29
- package/dist/cjs/query/query-builder.cjs.map +1 -1
- package/dist/cjs/query/query-builder.d.cts +16 -10
- package/dist/cjs/query/schema.d.cts +12 -11
- package/dist/cjs/query/select.cjs +47 -24
- package/dist/cjs/query/select.cjs.map +1 -1
- package/dist/cjs/query/select.d.cts +2 -2
- package/dist/cjs/query/types.d.cts +1 -0
- package/dist/cjs/transactions.cjs +20 -9
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/types.d.cts +66 -7
- package/dist/esm/collection.d.ts +43 -15
- package/dist/esm/collection.js +183 -114
- package/dist/esm/collection.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/proxy.d.ts +5 -5
- package/dist/esm/proxy.js +87 -248
- package/dist/esm/proxy.js.map +1 -1
- package/dist/esm/query/compiled-query.d.ts +3 -1
- package/dist/esm/query/compiled-query.js +23 -14
- package/dist/esm/query/compiled-query.js.map +1 -1
- package/dist/esm/query/evaluators.d.ts +8 -3
- package/dist/esm/query/evaluators.js +36 -21
- package/dist/esm/query/evaluators.js.map +1 -1
- package/dist/esm/query/extractors.d.ts +3 -3
- package/dist/esm/query/extractors.js +20 -20
- package/dist/esm/query/extractors.js.map +1 -1
- package/dist/esm/query/group-by.d.ts +7 -7
- package/dist/esm/query/group-by.js +14 -17
- package/dist/esm/query/group-by.js.map +1 -1
- package/dist/esm/query/joins.d.ts +3 -3
- package/dist/esm/query/joins.js +42 -56
- package/dist/esm/query/joins.js.map +1 -1
- package/dist/esm/query/order-by.d.ts +2 -2
- package/dist/esm/query/order-by.js +39 -86
- package/dist/esm/query/order-by.js.map +1 -1
- package/dist/esm/query/pipeline-compiler.d.ts +2 -1
- package/dist/esm/query/pipeline-compiler.js +14 -19
- package/dist/esm/query/pipeline-compiler.js.map +1 -1
- package/dist/esm/query/query-builder.d.ts +16 -10
- package/dist/esm/query/query-builder.js +22 -29
- package/dist/esm/query/query-builder.js.map +1 -1
- package/dist/esm/query/schema.d.ts +12 -11
- package/dist/esm/query/select.d.ts +2 -2
- package/dist/esm/query/select.js +48 -25
- package/dist/esm/query/select.js.map +1 -1
- package/dist/esm/query/types.d.ts +1 -0
- package/dist/esm/transactions.js +20 -9
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +66 -7
- package/package.json +2 -2
- package/src/collection.ts +286 -146
- package/src/proxy.ts +141 -358
- package/src/query/compiled-query.ts +30 -15
- package/src/query/evaluators.ts +49 -21
- package/src/query/extractors.ts +24 -21
- package/src/query/group-by.ts +24 -22
- package/src/query/joins.ts +88 -75
- package/src/query/order-by.ts +56 -106
- package/src/query/pipeline-compiler.ts +34 -37
- package/src/query/query-builder.ts +49 -46
- package/src/query/schema.ts +18 -15
- package/src/query/select.ts +68 -33
- package/src/query/types.ts +1 -0
- package/src/transactions.ts +30 -14
- package/src/types.ts +76 -7
- package/dist/cjs/query/key-by.cjs +0 -43
- package/dist/cjs/query/key-by.cjs.map +0 -1
- package/dist/cjs/query/key-by.d.cts +0 -3
- package/dist/esm/query/key-by.d.ts +0 -3
- package/dist/esm/query/key-by.js +0 -43
- package/dist/esm/query/key-by.js.map +0 -1
- package/src/query/key-by.ts +0 -61
package/dist/cjs/collection.cjs
CHANGED
|
@@ -6,7 +6,13 @@ const transactions = require("./transactions.cjs");
|
|
|
6
6
|
const SortedMap = require("./SortedMap.cjs");
|
|
7
7
|
const collectionsStore = new store.Store(/* @__PURE__ */ new Map());
|
|
8
8
|
const loadingCollections = /* @__PURE__ */ new Map();
|
|
9
|
+
function createCollection(config) {
|
|
10
|
+
return new Collection(config);
|
|
11
|
+
}
|
|
9
12
|
function preloadCollection(config) {
|
|
13
|
+
if (!config.id) {
|
|
14
|
+
throw new Error(`The id property is required for preloadCollection`);
|
|
15
|
+
}
|
|
10
16
|
if (collectionsStore.state.has(config.id) && !loadingCollections.has(config.id)) {
|
|
11
17
|
return Promise.resolve(
|
|
12
18
|
collectionsStore.state.get(config.id)
|
|
@@ -18,10 +24,14 @@ function preloadCollection(config) {
|
|
|
18
24
|
if (!collectionsStore.state.has(config.id)) {
|
|
19
25
|
collectionsStore.setState((prev) => {
|
|
20
26
|
const next = new Map(prev);
|
|
27
|
+
if (!config.id) {
|
|
28
|
+
throw new Error(`The id property is required for preloadCollection`);
|
|
29
|
+
}
|
|
21
30
|
next.set(
|
|
22
31
|
config.id,
|
|
23
32
|
new Collection({
|
|
24
33
|
id: config.id,
|
|
34
|
+
getId: config.getId,
|
|
25
35
|
sync: config.sync,
|
|
26
36
|
schema: config.schema
|
|
27
37
|
})
|
|
@@ -37,6 +47,9 @@ function preloadCollection(config) {
|
|
|
37
47
|
};
|
|
38
48
|
});
|
|
39
49
|
collection.onFirstCommit(() => {
|
|
50
|
+
if (!config.id) {
|
|
51
|
+
throw new Error(`The id property is required for preloadCollection`);
|
|
52
|
+
}
|
|
40
53
|
if (loadingCollections.has(config.id)) {
|
|
41
54
|
loadingCollections.delete(config.id);
|
|
42
55
|
resolveFirstCommit();
|
|
@@ -70,18 +83,15 @@ class Collection {
|
|
|
70
83
|
this.pendingSyncedTransactions = [];
|
|
71
84
|
this.syncedKeys = /* @__PURE__ */ new Set();
|
|
72
85
|
this.hasReceivedFirstCommit = false;
|
|
73
|
-
this.objectKeyMap = /* @__PURE__ */ new WeakMap();
|
|
74
86
|
this.onFirstCommitCallbacks = [];
|
|
75
|
-
this.id =
|
|
87
|
+
this.id = ``;
|
|
76
88
|
this.commitPendingTransactions = () => {
|
|
77
89
|
if (!Array.from(this.transactions.state.values()).some(
|
|
78
90
|
({ state }) => state === `persisting`
|
|
79
91
|
)) {
|
|
80
|
-
const keys = /* @__PURE__ */ new Set();
|
|
81
92
|
store.batch(() => {
|
|
82
93
|
for (const transaction of this.pendingSyncedTransactions) {
|
|
83
94
|
for (const operation of transaction.operations) {
|
|
84
|
-
keys.add(operation.key);
|
|
85
95
|
this.syncedKeys.add(operation.key);
|
|
86
96
|
this.syncedMetadata.setState((prevData) => {
|
|
87
97
|
switch (operation.type) {
|
|
@@ -120,12 +130,6 @@ class Collection {
|
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
});
|
|
123
|
-
keys.forEach((key) => {
|
|
124
|
-
const curValue = this.state.get(key);
|
|
125
|
-
if (curValue) {
|
|
126
|
-
this.objectKeyMap.set(curValue, key);
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
133
|
this.pendingSyncedTransactions = [];
|
|
130
134
|
if (!this.hasReceivedFirstCommit) {
|
|
131
135
|
this.hasReceivedFirstCommit = true;
|
|
@@ -136,26 +140,25 @@ class Collection {
|
|
|
136
140
|
}
|
|
137
141
|
};
|
|
138
142
|
this.insert = (data, config2) => {
|
|
139
|
-
const
|
|
140
|
-
if (
|
|
141
|
-
throw
|
|
143
|
+
const ambientTransaction = transactions.getActiveTransaction();
|
|
144
|
+
if (!ambientTransaction && !this.config.onInsert) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Collection.insert called directly (not within an explicit transaction) but no 'onInsert' handler is configured.`
|
|
147
|
+
);
|
|
142
148
|
}
|
|
143
149
|
const items = Array.isArray(data) ? data : [data];
|
|
144
150
|
const mutations = [];
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (Array.isArray(config2.key) && configKeys.length > items.length) {
|
|
149
|
-
throw new Error(`More keys provided than items to insert`);
|
|
150
|
-
}
|
|
151
|
-
keys = items.map((_, i) => configKeys[i] ?? this.generateKey(items[i]));
|
|
152
|
-
} else {
|
|
153
|
-
keys = items.map((item) => this.generateKey(item));
|
|
154
|
-
}
|
|
151
|
+
const keys = items.map(
|
|
152
|
+
(item) => this.generateObjectKey(this.config.getId(item), item)
|
|
153
|
+
);
|
|
155
154
|
items.forEach((item, index) => {
|
|
156
155
|
var _a, _b;
|
|
157
156
|
const validatedData = this.validateData(item, `insert`);
|
|
158
157
|
const key = keys[index];
|
|
158
|
+
const id = this.config.getId(item);
|
|
159
|
+
if (this.state.has(this.getKeyFromId(id))) {
|
|
160
|
+
throw `Cannot insert document with ID "${id}" because it already exists in the collection`;
|
|
161
|
+
}
|
|
159
162
|
const mutation = {
|
|
160
163
|
mutationId: crypto.randomUUID(),
|
|
161
164
|
original: {},
|
|
@@ -171,45 +174,48 @@ class Collection {
|
|
|
171
174
|
};
|
|
172
175
|
mutations.push(mutation);
|
|
173
176
|
});
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
if (ambientTransaction) {
|
|
178
|
+
ambientTransaction.applyMutations(mutations);
|
|
179
|
+
this.transactions.setState((sortedMap) => {
|
|
180
|
+
sortedMap.set(ambientTransaction.id, ambientTransaction);
|
|
181
|
+
return sortedMap;
|
|
182
|
+
});
|
|
183
|
+
return ambientTransaction;
|
|
184
|
+
} else {
|
|
185
|
+
const directOpTransaction = new transactions.Transaction({
|
|
186
|
+
mutationFn: async (params) => {
|
|
187
|
+
return this.config.onInsert(params);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
directOpTransaction.applyMutations(mutations);
|
|
191
|
+
directOpTransaction.commit();
|
|
192
|
+
this.transactions.setState((sortedMap) => {
|
|
193
|
+
sortedMap.set(directOpTransaction.id, directOpTransaction);
|
|
194
|
+
return sortedMap;
|
|
195
|
+
});
|
|
196
|
+
return directOpTransaction;
|
|
197
|
+
}
|
|
180
198
|
};
|
|
181
|
-
this.delete = (
|
|
182
|
-
const
|
|
183
|
-
if (
|
|
184
|
-
throw
|
|
199
|
+
this.delete = (ids, config2) => {
|
|
200
|
+
const ambientTransaction = transactions.getActiveTransaction();
|
|
201
|
+
if (!ambientTransaction && !this.config.onDelete) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`Collection.delete called directly (not within an explicit transaction) but no 'onDelete' handler is configured.`
|
|
204
|
+
);
|
|
185
205
|
}
|
|
186
|
-
const
|
|
206
|
+
const idsArray = (Array.isArray(ids) ? ids : [ids]).map(
|
|
207
|
+
(id) => this.getKeyFromId(id)
|
|
208
|
+
);
|
|
187
209
|
const mutations = [];
|
|
188
|
-
for (const
|
|
189
|
-
let key;
|
|
190
|
-
if (typeof item === `object` && item !== null) {
|
|
191
|
-
const objectKey = this.objectKeyMap.get(item);
|
|
192
|
-
if (objectKey === void 0) {
|
|
193
|
-
throw new Error(
|
|
194
|
-
`Object not found in collection: ${JSON.stringify(item)}`
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
key = objectKey;
|
|
198
|
-
} else if (typeof item === `string`) {
|
|
199
|
-
key = item;
|
|
200
|
-
} else {
|
|
201
|
-
throw new Error(
|
|
202
|
-
`Invalid item type for delete - must be an object or string key`
|
|
203
|
-
);
|
|
204
|
-
}
|
|
210
|
+
for (const id of idsArray) {
|
|
205
211
|
const mutation = {
|
|
206
212
|
mutationId: crypto.randomUUID(),
|
|
207
|
-
original: this.state.get(
|
|
208
|
-
modified:
|
|
209
|
-
changes:
|
|
210
|
-
key,
|
|
213
|
+
original: this.state.get(id) || {},
|
|
214
|
+
modified: this.state.get(id) || {},
|
|
215
|
+
changes: this.state.get(id) || {},
|
|
216
|
+
key: id,
|
|
211
217
|
metadata: config2 == null ? void 0 : config2.metadata,
|
|
212
|
-
syncMetadata: this.syncedMetadata.state.get(
|
|
218
|
+
syncMetadata: this.syncedMetadata.state.get(id) || {},
|
|
213
219
|
type: `delete`,
|
|
214
220
|
createdAt: /* @__PURE__ */ new Date(),
|
|
215
221
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
@@ -217,20 +223,37 @@ class Collection {
|
|
|
217
223
|
};
|
|
218
224
|
mutations.push(mutation);
|
|
219
225
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
226
|
+
if (ambientTransaction) {
|
|
227
|
+
ambientTransaction.applyMutations(mutations);
|
|
228
|
+
this.transactions.setState((sortedMap) => {
|
|
229
|
+
sortedMap.set(ambientTransaction.id, ambientTransaction);
|
|
230
|
+
return sortedMap;
|
|
231
|
+
});
|
|
232
|
+
return ambientTransaction;
|
|
233
|
+
}
|
|
234
|
+
const directOpTransaction = new transactions.Transaction({
|
|
235
|
+
autoCommit: true,
|
|
236
|
+
mutationFn: async (transaction) => {
|
|
237
|
+
return this.config.onDelete(transaction);
|
|
224
238
|
}
|
|
225
239
|
});
|
|
226
|
-
|
|
240
|
+
directOpTransaction.applyMutations(mutations);
|
|
241
|
+
directOpTransaction.commit();
|
|
227
242
|
this.transactions.setState((sortedMap) => {
|
|
228
|
-
sortedMap.set(
|
|
243
|
+
sortedMap.set(directOpTransaction.id, directOpTransaction);
|
|
229
244
|
return sortedMap;
|
|
230
245
|
});
|
|
231
|
-
return
|
|
246
|
+
return directOpTransaction;
|
|
232
247
|
};
|
|
233
|
-
if (!
|
|
248
|
+
if (!config) {
|
|
249
|
+
throw new Error(`Collection requires a config`);
|
|
250
|
+
}
|
|
251
|
+
if (config.id) {
|
|
252
|
+
this.id = config.id;
|
|
253
|
+
} else {
|
|
254
|
+
this.id = crypto.randomUUID();
|
|
255
|
+
}
|
|
256
|
+
if (!config.sync) {
|
|
234
257
|
throw new Error(`Collection requires a sync config`);
|
|
235
258
|
}
|
|
236
259
|
this.transactions = new store.Store(
|
|
@@ -265,9 +288,7 @@ class Collection {
|
|
|
265
288
|
this.derivedState = new store.Derived({
|
|
266
289
|
fn: ({ currDepVals: [syncedData, operations] }) => {
|
|
267
290
|
const combined = new Map(syncedData);
|
|
268
|
-
const optimisticKeys = /* @__PURE__ */ new Set();
|
|
269
291
|
for (const operation of operations) {
|
|
270
|
-
optimisticKeys.add(operation.key);
|
|
271
292
|
if (operation.isActive) {
|
|
272
293
|
switch (operation.type) {
|
|
273
294
|
case `insert`:
|
|
@@ -282,11 +303,6 @@ class Collection {
|
|
|
282
303
|
}
|
|
283
304
|
}
|
|
284
305
|
}
|
|
285
|
-
optimisticKeys.forEach((key) => {
|
|
286
|
-
if (combined.has(key)) {
|
|
287
|
-
this.objectKeyMap.set(combined.get(key), key);
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
306
|
return combined;
|
|
291
307
|
},
|
|
292
308
|
deps: [this.syncedData, this.optimisticOperations]
|
|
@@ -363,7 +379,7 @@ class Collection {
|
|
|
363
379
|
operations: []
|
|
364
380
|
});
|
|
365
381
|
},
|
|
366
|
-
write: (
|
|
382
|
+
write: (messageWithoutKey) => {
|
|
367
383
|
const pendingTransaction = this.pendingSyncedTransactions[this.pendingSyncedTransactions.length - 1];
|
|
368
384
|
if (!pendingTransaction) {
|
|
369
385
|
throw new Error(`No pending sync transaction to write to`);
|
|
@@ -373,6 +389,24 @@ class Collection {
|
|
|
373
389
|
`The pending sync transaction is already committed, you can't still write to it.`
|
|
374
390
|
);
|
|
375
391
|
}
|
|
392
|
+
const key = this.generateObjectKey(
|
|
393
|
+
this.config.getId(messageWithoutKey.value),
|
|
394
|
+
messageWithoutKey.value
|
|
395
|
+
);
|
|
396
|
+
if (messageWithoutKey.type === `insert`) {
|
|
397
|
+
if (this.syncedData.state.has(key) && !pendingTransaction.operations.some(
|
|
398
|
+
(op) => op.key === key && op.type === `delete`
|
|
399
|
+
)) {
|
|
400
|
+
const id = this.config.getId(messageWithoutKey.value);
|
|
401
|
+
throw new Error(
|
|
402
|
+
`Cannot insert document with ID "${id}" from sync because it already exists in the collection "${this.id}"`
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const message = {
|
|
407
|
+
...messageWithoutKey,
|
|
408
|
+
key
|
|
409
|
+
};
|
|
376
410
|
pendingTransaction.operations.push(message);
|
|
377
411
|
},
|
|
378
412
|
commit: () => {
|
|
@@ -406,6 +440,24 @@ class Collection {
|
|
|
406
440
|
`Schema must either implement the standard-schema interface or be a Zod schema`
|
|
407
441
|
);
|
|
408
442
|
}
|
|
443
|
+
getKeyFromId(id) {
|
|
444
|
+
if (typeof id === `undefined`) {
|
|
445
|
+
throw new Error(`id is undefined`);
|
|
446
|
+
}
|
|
447
|
+
if (typeof id === `string` && id.startsWith(`KEY::`)) {
|
|
448
|
+
return id;
|
|
449
|
+
} else {
|
|
450
|
+
return this.generateObjectKey(id, null);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
generateObjectKey(id, item) {
|
|
454
|
+
if (typeof id === `undefined`) {
|
|
455
|
+
throw new Error(
|
|
456
|
+
`An object was created without a defined id: ${JSON.stringify(item)}`
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
return `KEY::${this.id}/${id}`;
|
|
460
|
+
}
|
|
409
461
|
validateData(data, type, key) {
|
|
410
462
|
if (!this.config.schema) return data;
|
|
411
463
|
const standardSchema = this.ensureStandardSchema(this.config.schema);
|
|
@@ -446,39 +498,31 @@ class Collection {
|
|
|
446
498
|
}
|
|
447
499
|
return result.value;
|
|
448
500
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
let h = 0;
|
|
452
|
-
for (let i = 0; i < str.length; i++) {
|
|
453
|
-
h = Math.imul(31, h) + str.charCodeAt(i) | 0;
|
|
454
|
-
}
|
|
455
|
-
return `${this.id}/${Math.abs(h).toString(36)}`;
|
|
456
|
-
}
|
|
457
|
-
update(items, configOrCallback, maybeCallback) {
|
|
458
|
-
if (typeof items === `undefined`) {
|
|
501
|
+
update(ids, configOrCallback, maybeCallback) {
|
|
502
|
+
if (typeof ids === `undefined`) {
|
|
459
503
|
throw new Error(`The first argument to update is missing`);
|
|
460
504
|
}
|
|
461
|
-
const
|
|
462
|
-
if (
|
|
463
|
-
throw
|
|
505
|
+
const ambientTransaction = transactions.getActiveTransaction();
|
|
506
|
+
if (!ambientTransaction && !this.config.onUpdate) {
|
|
507
|
+
throw new Error(
|
|
508
|
+
`Collection.update called directly (not within an explicit transaction) but no 'onUpdate' handler is configured.`
|
|
509
|
+
);
|
|
464
510
|
}
|
|
465
|
-
const isArray = Array.isArray(
|
|
466
|
-
const
|
|
511
|
+
const isArray = Array.isArray(ids);
|
|
512
|
+
const idsArray = (Array.isArray(ids) ? ids : [ids]).map(
|
|
513
|
+
(id) => this.getKeyFromId(id)
|
|
514
|
+
);
|
|
467
515
|
const callback = typeof configOrCallback === `function` ? configOrCallback : maybeCallback;
|
|
468
516
|
const config = typeof configOrCallback === `function` ? {} : configOrCallback;
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
return key;
|
|
517
|
+
const currentObjects = idsArray.map((id) => {
|
|
518
|
+
const item = this.state.get(id);
|
|
519
|
+
if (!item) {
|
|
520
|
+
throw new Error(
|
|
521
|
+
`The id "${id}" was passed to update but an object for this ID was not found in the collection`
|
|
522
|
+
);
|
|
476
523
|
}
|
|
477
|
-
|
|
524
|
+
return item;
|
|
478
525
|
});
|
|
479
|
-
const currentObjects = keys.map((key) => ({
|
|
480
|
-
...this.state.get(key) || {}
|
|
481
|
-
}));
|
|
482
526
|
let changesArray;
|
|
483
527
|
if (isArray) {
|
|
484
528
|
changesArray = proxy.withArrayChangeTracking(
|
|
@@ -492,23 +536,33 @@ class Collection {
|
|
|
492
536
|
);
|
|
493
537
|
changesArray = [result];
|
|
494
538
|
}
|
|
495
|
-
const mutations =
|
|
496
|
-
const
|
|
497
|
-
if (!
|
|
539
|
+
const mutations = idsArray.map((id, index) => {
|
|
540
|
+
const itemChanges = changesArray[index];
|
|
541
|
+
if (!itemChanges || Object.keys(itemChanges).length === 0) {
|
|
498
542
|
return null;
|
|
499
543
|
}
|
|
500
|
-
const
|
|
544
|
+
const originalItem = currentObjects[index];
|
|
545
|
+
const validatedUpdatePayload = this.validateData(
|
|
546
|
+
itemChanges,
|
|
547
|
+
`update`,
|
|
548
|
+
id
|
|
549
|
+
);
|
|
550
|
+
const modifiedItem = { ...originalItem, ...validatedUpdatePayload };
|
|
551
|
+
const originalItemId = this.config.getId(originalItem);
|
|
552
|
+
const modifiedItemId = this.config.getId(modifiedItem);
|
|
553
|
+
if (originalItemId !== modifiedItemId) {
|
|
554
|
+
throw new Error(
|
|
555
|
+
`Updating the ID of an item is not allowed. Original ID: "${originalItemId}", Attempted new ID: "${modifiedItemId}". Please delete the old item and create a new one if an ID change is necessary.`
|
|
556
|
+
);
|
|
557
|
+
}
|
|
501
558
|
return {
|
|
502
559
|
mutationId: crypto.randomUUID(),
|
|
503
|
-
original:
|
|
504
|
-
modified:
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
},
|
|
508
|
-
changes: validatedData,
|
|
509
|
-
key,
|
|
560
|
+
original: originalItem,
|
|
561
|
+
modified: modifiedItem,
|
|
562
|
+
changes: validatedUpdatePayload,
|
|
563
|
+
key: id,
|
|
510
564
|
metadata: config.metadata,
|
|
511
|
-
syncMetadata: this.syncedMetadata.state.get(
|
|
565
|
+
syncMetadata: this.syncedMetadata.state.get(id) || {},
|
|
512
566
|
type: `update`,
|
|
513
567
|
createdAt: /* @__PURE__ */ new Date(),
|
|
514
568
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
@@ -518,12 +572,26 @@ class Collection {
|
|
|
518
572
|
if (mutations.length === 0) {
|
|
519
573
|
throw new Error(`No changes were made to any of the objects`);
|
|
520
574
|
}
|
|
521
|
-
|
|
575
|
+
if (ambientTransaction) {
|
|
576
|
+
ambientTransaction.applyMutations(mutations);
|
|
577
|
+
this.transactions.setState((sortedMap) => {
|
|
578
|
+
sortedMap.set(ambientTransaction.id, ambientTransaction);
|
|
579
|
+
return sortedMap;
|
|
580
|
+
});
|
|
581
|
+
return ambientTransaction;
|
|
582
|
+
}
|
|
583
|
+
const directOpTransaction = new transactions.Transaction({
|
|
584
|
+
mutationFn: async (transaction) => {
|
|
585
|
+
return this.config.onUpdate(transaction);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
directOpTransaction.applyMutations(mutations);
|
|
589
|
+
directOpTransaction.commit();
|
|
522
590
|
this.transactions.setState((sortedMap) => {
|
|
523
|
-
sortedMap.set(
|
|
591
|
+
sortedMap.set(directOpTransaction.id, directOpTransaction);
|
|
524
592
|
return sortedMap;
|
|
525
593
|
});
|
|
526
|
-
return
|
|
594
|
+
return directOpTransaction;
|
|
527
595
|
}
|
|
528
596
|
/**
|
|
529
597
|
* Gets the current state of the collection as a Map
|
|
@@ -601,5 +669,6 @@ class Collection {
|
|
|
601
669
|
exports.Collection = Collection;
|
|
602
670
|
exports.SchemaValidationError = SchemaValidationError;
|
|
603
671
|
exports.collectionsStore = collectionsStore;
|
|
672
|
+
exports.createCollection = createCollection;
|
|
604
673
|
exports.preloadCollection = preloadCollection;
|
|
605
674
|
//# sourceMappingURL=collection.cjs.map
|