@signaldb/core 2.0.0-beta.16 → 2.0.0-beta.18
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/WorkerDataAdapter.d.ts +5 -0
- package/dist/index34.cjs.js +100 -24
- package/dist/index34.mjs +100 -24
- package/package.json +1 -1
|
@@ -42,10 +42,15 @@ export default class WorkerDataAdapter implements DataAdapter {
|
|
|
42
42
|
private execInBackground;
|
|
43
43
|
private queryItemsById;
|
|
44
44
|
private flattenPendingWrites;
|
|
45
|
+
private static pushPendingEntry;
|
|
46
|
+
private static dropPendingEntry;
|
|
47
|
+
private static writeFlatEntry;
|
|
45
48
|
private static providesFullItems;
|
|
46
49
|
private observableItems;
|
|
47
50
|
private observableItemsByIds;
|
|
48
51
|
private servedResult;
|
|
52
|
+
private advanceServedResult;
|
|
53
|
+
private changesetForIds;
|
|
49
54
|
private computeServedResult;
|
|
50
55
|
/**
|
|
51
56
|
* Registers a write's effect locally and notifies every active query it
|
package/dist/index34.cjs.js
CHANGED
|
@@ -185,24 +185,44 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
185
185
|
return query.itemsById;
|
|
186
186
|
}
|
|
187
187
|
flattenPendingWrites(collectionName) {
|
|
188
|
-
const
|
|
189
|
-
if (!
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
write.deletes.forEach((id) => {
|
|
198
|
-
deletes.add(id);
|
|
199
|
-
upserts.delete(id);
|
|
200
|
-
});
|
|
188
|
+
const state = this.pendingWrites.get(collectionName);
|
|
189
|
+
if (!state || state.writes.size === 0) return null;
|
|
190
|
+
return state.flat;
|
|
191
|
+
}
|
|
192
|
+
static pushPendingEntry(state, id, item, seq) {
|
|
193
|
+
const stack = state.byId.get(id);
|
|
194
|
+
if (stack) stack.push({
|
|
195
|
+
seq,
|
|
196
|
+
item
|
|
201
197
|
});
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
};
|
|
198
|
+
else state.byId.set(id, [{
|
|
199
|
+
seq,
|
|
200
|
+
item
|
|
201
|
+
}]);
|
|
202
|
+
WorkerDataAdapter.writeFlatEntry(state, id, item);
|
|
203
|
+
}
|
|
204
|
+
static dropPendingEntry(state, id, seq) {
|
|
205
|
+
const stack = state.byId.get(id);
|
|
206
|
+
if (!stack) return;
|
|
207
|
+
const index = stack.findIndex((entry) => entry.seq === seq);
|
|
208
|
+
if (index !== -1) stack.splice(index, 1);
|
|
209
|
+
const top = stack.at(-1);
|
|
210
|
+
if (!top) {
|
|
211
|
+
state.byId.delete(id);
|
|
212
|
+
state.flat.upserts.delete(id);
|
|
213
|
+
state.flat.deletes.delete(id);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
WorkerDataAdapter.writeFlatEntry(state, id, top.item);
|
|
217
|
+
}
|
|
218
|
+
static writeFlatEntry(state, id, item) {
|
|
219
|
+
if (item === null) {
|
|
220
|
+
state.flat.deletes.add(id);
|
|
221
|
+
state.flat.upserts.delete(id);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
state.flat.upserts.set(id, item);
|
|
225
|
+
state.flat.deletes.delete(id);
|
|
206
226
|
}
|
|
207
227
|
static providesFullItems(query) {
|
|
208
228
|
return query.options?.fields == null;
|
|
@@ -246,7 +266,7 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
246
266
|
servedResult(collectionName, query) {
|
|
247
267
|
const pendingVersion = this.pendingWriteVersions.get(collectionName) ?? 0;
|
|
248
268
|
if (query.served && query.served.fromItems === query.items && query.served.pendingVersion === pendingVersion) return query.served.items;
|
|
249
|
-
const items = this.computeServedResult(collectionName, query);
|
|
269
|
+
const items = this.advanceServedResult(collectionName, query, pendingVersion) ?? this.computeServedResult(collectionName, query);
|
|
250
270
|
query.served = {
|
|
251
271
|
items,
|
|
252
272
|
fromItems: query.items,
|
|
@@ -254,6 +274,39 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
254
274
|
};
|
|
255
275
|
return items;
|
|
256
276
|
}
|
|
277
|
+
advanceServedResult(collectionName, query, pendingVersion) {
|
|
278
|
+
const served = query.served;
|
|
279
|
+
if (!served || served.fromItems !== query.items) return null;
|
|
280
|
+
if (served.pendingVersion !== pendingVersion - 1) return null;
|
|
281
|
+
if (!WorkerDataAdapter.providesFullItems(query) || query.options?.limit != null) return null;
|
|
282
|
+
const state = this.pendingWrites.get(collectionName);
|
|
283
|
+
if (state?.lastChange == null || state.lastChange.version !== pendingVersion) return null;
|
|
284
|
+
return require_incrementalQueryUpdate.mergeChangesetIntoResult(served.items, query.selector, query.options, this.changesetForIds(collectionName, query, state.lastChange.ids));
|
|
285
|
+
}
|
|
286
|
+
changesetForIds(collectionName, query, ids) {
|
|
287
|
+
const pending = this.flattenPendingWrites(collectionName);
|
|
288
|
+
const stored = this.queryItemsById(query);
|
|
289
|
+
const upserts = [];
|
|
290
|
+
const deletes = [];
|
|
291
|
+
ids.forEach((id) => {
|
|
292
|
+
const pendingItem = pending?.upserts.get(id);
|
|
293
|
+
if (pendingItem) {
|
|
294
|
+
upserts.push(pendingItem);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (pending?.deletes.has(id)) {
|
|
298
|
+
deletes.push(id);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const storedItem = stored.get(id);
|
|
302
|
+
if (storedItem) upserts.push(storedItem);
|
|
303
|
+
else deletes.push(id);
|
|
304
|
+
});
|
|
305
|
+
return {
|
|
306
|
+
upserts,
|
|
307
|
+
deletes
|
|
308
|
+
};
|
|
309
|
+
}
|
|
257
310
|
computeServedResult(collectionName, query) {
|
|
258
311
|
const pending = this.flattenPendingWrites(collectionName);
|
|
259
312
|
if (!pending) return query.items;
|
|
@@ -288,22 +341,45 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
288
341
|
const affected = this.affectedQueries(collectionName, upserts, affectedIds);
|
|
289
342
|
const servedBefore = this.servedResults(collectionName, affected);
|
|
290
343
|
const seq = this.pendingWriteSeq += 1;
|
|
291
|
-
const
|
|
292
|
-
|
|
344
|
+
const state = this.pendingWrites.get(collectionName) ?? {
|
|
345
|
+
writes: /* @__PURE__ */ new Map(),
|
|
346
|
+
byId: /* @__PURE__ */ new Map(),
|
|
347
|
+
flat: {
|
|
348
|
+
upserts: /* @__PURE__ */ new Map(),
|
|
349
|
+
deletes: /* @__PURE__ */ new Set()
|
|
350
|
+
},
|
|
351
|
+
lastChange: null
|
|
352
|
+
};
|
|
353
|
+
const write = {
|
|
293
354
|
upserts: new Map(upserts.map((item) => [item.id, item])),
|
|
294
355
|
deletes: new Set(deletes)
|
|
295
|
-
}
|
|
296
|
-
|
|
356
|
+
};
|
|
357
|
+
state.writes.set(seq, write);
|
|
358
|
+
write.upserts.forEach((item, id) => WorkerDataAdapter.pushPendingEntry(state, id, item, seq));
|
|
359
|
+
write.deletes.forEach((id) => WorkerDataAdapter.pushPendingEntry(state, id, null, seq));
|
|
360
|
+
this.pendingWrites.set(collectionName, state);
|
|
297
361
|
this.bumpPendingWriteVersion(collectionName);
|
|
362
|
+
state.lastChange = {
|
|
363
|
+
version: this.pendingWriteVersions.get(collectionName) ?? 0,
|
|
364
|
+
ids: [...affectedIds]
|
|
365
|
+
};
|
|
298
366
|
this.notifyWithDeltas(collectionName, affected, servedBefore);
|
|
299
367
|
return () => {
|
|
300
368
|
const current = this.pendingWrites.get(collectionName);
|
|
301
369
|
if (!current) return;
|
|
370
|
+
const settled = current.writes.get(seq);
|
|
371
|
+
if (!settled) return;
|
|
302
372
|
const affectedOnDrop = this.affectedQueries(collectionName, upserts, affectedIds);
|
|
303
373
|
const beforeDrop = this.servedResults(collectionName, affectedOnDrop);
|
|
304
|
-
current.delete(seq);
|
|
305
|
-
|
|
374
|
+
current.writes.delete(seq);
|
|
375
|
+
settled.upserts.forEach((item, id) => WorkerDataAdapter.dropPendingEntry(current, id, seq));
|
|
376
|
+
settled.deletes.forEach((id) => WorkerDataAdapter.dropPendingEntry(current, id, seq));
|
|
377
|
+
if (current.writes.size === 0) this.pendingWrites.delete(collectionName);
|
|
306
378
|
this.bumpPendingWriteVersion(collectionName);
|
|
379
|
+
if (current.writes.size > 0) current.lastChange = {
|
|
380
|
+
version: this.pendingWriteVersions.get(collectionName) ?? 0,
|
|
381
|
+
ids: [...affectedIds]
|
|
382
|
+
};
|
|
307
383
|
this.notifyWithDeltas(collectionName, affectedOnDrop, beforeDrop);
|
|
308
384
|
};
|
|
309
385
|
}
|
package/dist/index34.mjs
CHANGED
|
@@ -185,24 +185,44 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
185
185
|
return query.itemsById;
|
|
186
186
|
}
|
|
187
187
|
flattenPendingWrites(collectionName) {
|
|
188
|
-
const
|
|
189
|
-
if (!
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
write.deletes.forEach((id) => {
|
|
198
|
-
deletes.add(id);
|
|
199
|
-
upserts.delete(id);
|
|
200
|
-
});
|
|
188
|
+
const state = this.pendingWrites.get(collectionName);
|
|
189
|
+
if (!state || state.writes.size === 0) return null;
|
|
190
|
+
return state.flat;
|
|
191
|
+
}
|
|
192
|
+
static pushPendingEntry(state, id, item, seq) {
|
|
193
|
+
const stack = state.byId.get(id);
|
|
194
|
+
if (stack) stack.push({
|
|
195
|
+
seq,
|
|
196
|
+
item
|
|
201
197
|
});
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
};
|
|
198
|
+
else state.byId.set(id, [{
|
|
199
|
+
seq,
|
|
200
|
+
item
|
|
201
|
+
}]);
|
|
202
|
+
WorkerDataAdapter.writeFlatEntry(state, id, item);
|
|
203
|
+
}
|
|
204
|
+
static dropPendingEntry(state, id, seq) {
|
|
205
|
+
const stack = state.byId.get(id);
|
|
206
|
+
if (!stack) return;
|
|
207
|
+
const index = stack.findIndex((entry) => entry.seq === seq);
|
|
208
|
+
if (index !== -1) stack.splice(index, 1);
|
|
209
|
+
const top = stack.at(-1);
|
|
210
|
+
if (!top) {
|
|
211
|
+
state.byId.delete(id);
|
|
212
|
+
state.flat.upserts.delete(id);
|
|
213
|
+
state.flat.deletes.delete(id);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
WorkerDataAdapter.writeFlatEntry(state, id, top.item);
|
|
217
|
+
}
|
|
218
|
+
static writeFlatEntry(state, id, item) {
|
|
219
|
+
if (item === null) {
|
|
220
|
+
state.flat.deletes.add(id);
|
|
221
|
+
state.flat.upserts.delete(id);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
state.flat.upserts.set(id, item);
|
|
225
|
+
state.flat.deletes.delete(id);
|
|
206
226
|
}
|
|
207
227
|
static providesFullItems(query) {
|
|
208
228
|
return query.options?.fields == null;
|
|
@@ -246,7 +266,7 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
246
266
|
servedResult(collectionName, query) {
|
|
247
267
|
const pendingVersion = this.pendingWriteVersions.get(collectionName) ?? 0;
|
|
248
268
|
if (query.served && query.served.fromItems === query.items && query.served.pendingVersion === pendingVersion) return query.served.items;
|
|
249
|
-
const items = this.computeServedResult(collectionName, query);
|
|
269
|
+
const items = this.advanceServedResult(collectionName, query, pendingVersion) ?? this.computeServedResult(collectionName, query);
|
|
250
270
|
query.served = {
|
|
251
271
|
items,
|
|
252
272
|
fromItems: query.items,
|
|
@@ -254,6 +274,39 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
254
274
|
};
|
|
255
275
|
return items;
|
|
256
276
|
}
|
|
277
|
+
advanceServedResult(collectionName, query, pendingVersion) {
|
|
278
|
+
const served = query.served;
|
|
279
|
+
if (!served || served.fromItems !== query.items) return null;
|
|
280
|
+
if (served.pendingVersion !== pendingVersion - 1) return null;
|
|
281
|
+
if (!WorkerDataAdapter.providesFullItems(query) || query.options?.limit != null) return null;
|
|
282
|
+
const state = this.pendingWrites.get(collectionName);
|
|
283
|
+
if (state?.lastChange == null || state.lastChange.version !== pendingVersion) return null;
|
|
284
|
+
return mergeChangesetIntoResult(served.items, query.selector, query.options, this.changesetForIds(collectionName, query, state.lastChange.ids));
|
|
285
|
+
}
|
|
286
|
+
changesetForIds(collectionName, query, ids) {
|
|
287
|
+
const pending = this.flattenPendingWrites(collectionName);
|
|
288
|
+
const stored = this.queryItemsById(query);
|
|
289
|
+
const upserts = [];
|
|
290
|
+
const deletes = [];
|
|
291
|
+
ids.forEach((id) => {
|
|
292
|
+
const pendingItem = pending?.upserts.get(id);
|
|
293
|
+
if (pendingItem) {
|
|
294
|
+
upserts.push(pendingItem);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (pending?.deletes.has(id)) {
|
|
298
|
+
deletes.push(id);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const storedItem = stored.get(id);
|
|
302
|
+
if (storedItem) upserts.push(storedItem);
|
|
303
|
+
else deletes.push(id);
|
|
304
|
+
});
|
|
305
|
+
return {
|
|
306
|
+
upserts,
|
|
307
|
+
deletes
|
|
308
|
+
};
|
|
309
|
+
}
|
|
257
310
|
computeServedResult(collectionName, query) {
|
|
258
311
|
const pending = this.flattenPendingWrites(collectionName);
|
|
259
312
|
if (!pending) return query.items;
|
|
@@ -288,22 +341,45 @@ var WorkerDataAdapter = class WorkerDataAdapter {
|
|
|
288
341
|
const affected = this.affectedQueries(collectionName, upserts, affectedIds);
|
|
289
342
|
const servedBefore = this.servedResults(collectionName, affected);
|
|
290
343
|
const seq = this.pendingWriteSeq += 1;
|
|
291
|
-
const
|
|
292
|
-
|
|
344
|
+
const state = this.pendingWrites.get(collectionName) ?? {
|
|
345
|
+
writes: /* @__PURE__ */ new Map(),
|
|
346
|
+
byId: /* @__PURE__ */ new Map(),
|
|
347
|
+
flat: {
|
|
348
|
+
upserts: /* @__PURE__ */ new Map(),
|
|
349
|
+
deletes: /* @__PURE__ */ new Set()
|
|
350
|
+
},
|
|
351
|
+
lastChange: null
|
|
352
|
+
};
|
|
353
|
+
const write = {
|
|
293
354
|
upserts: new Map(upserts.map((item) => [item.id, item])),
|
|
294
355
|
deletes: new Set(deletes)
|
|
295
|
-
}
|
|
296
|
-
|
|
356
|
+
};
|
|
357
|
+
state.writes.set(seq, write);
|
|
358
|
+
write.upserts.forEach((item, id) => WorkerDataAdapter.pushPendingEntry(state, id, item, seq));
|
|
359
|
+
write.deletes.forEach((id) => WorkerDataAdapter.pushPendingEntry(state, id, null, seq));
|
|
360
|
+
this.pendingWrites.set(collectionName, state);
|
|
297
361
|
this.bumpPendingWriteVersion(collectionName);
|
|
362
|
+
state.lastChange = {
|
|
363
|
+
version: this.pendingWriteVersions.get(collectionName) ?? 0,
|
|
364
|
+
ids: [...affectedIds]
|
|
365
|
+
};
|
|
298
366
|
this.notifyWithDeltas(collectionName, affected, servedBefore);
|
|
299
367
|
return () => {
|
|
300
368
|
const current = this.pendingWrites.get(collectionName);
|
|
301
369
|
if (!current) return;
|
|
370
|
+
const settled = current.writes.get(seq);
|
|
371
|
+
if (!settled) return;
|
|
302
372
|
const affectedOnDrop = this.affectedQueries(collectionName, upserts, affectedIds);
|
|
303
373
|
const beforeDrop = this.servedResults(collectionName, affectedOnDrop);
|
|
304
|
-
current.delete(seq);
|
|
305
|
-
|
|
374
|
+
current.writes.delete(seq);
|
|
375
|
+
settled.upserts.forEach((item, id) => WorkerDataAdapter.dropPendingEntry(current, id, seq));
|
|
376
|
+
settled.deletes.forEach((id) => WorkerDataAdapter.dropPendingEntry(current, id, seq));
|
|
377
|
+
if (current.writes.size === 0) this.pendingWrites.delete(collectionName);
|
|
306
378
|
this.bumpPendingWriteVersion(collectionName);
|
|
379
|
+
if (current.writes.size > 0) current.lastChange = {
|
|
380
|
+
version: this.pendingWriteVersions.get(collectionName) ?? 0,
|
|
381
|
+
ids: [...affectedIds]
|
|
382
|
+
};
|
|
307
383
|
this.notifyWithDeltas(collectionName, affectedOnDrop, beforeDrop);
|
|
308
384
|
};
|
|
309
385
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaldb/core",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.18",
|
|
4
4
|
"description": "SignalDB is a client-side database that provides a simple MongoDB-like interface to the data with first-class typescript support to achieve an optimistic UI. Data persistence can be achieved by using storage providers that store the data through a JSON interface to places such as localStorage.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "rimraf dist && vite build",
|