dexie-cloud-addon 4.2.0-rc.1 → 4.2.1

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.
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ==========================================================================
10
10
  *
11
- * Version 4.2.0-rc.1, Wed Aug 06 2025
11
+ * Version 4.2.1, Wed Oct 01 2025
12
12
  *
13
13
  * https://dexie.org
14
14
  *
@@ -409,17 +409,14 @@
409
409
  : mutationTable;
410
410
  if (limit < Infinity)
411
411
  query = query.limit(limit);
412
- const muts = yield query.toArray();
413
- //const objTable = db.table(tableName);
414
- /*for (const mut of muts) {
415
- if (mut.type === "insert" || mut.type === "upsert") {
416
- mut.values = await objTable.bulkGet(mut.keys);
417
- }
418
- }*/
419
- return muts.map((mut) => ({
412
+ let muts = yield query.toArray();
413
+ muts = canonicalizeToUpdateOps(muts);
414
+ muts = removeRedundantUpdateOps(muts);
415
+ const rv = muts.map((mut) => ({
420
416
  table: tableName,
421
417
  mut,
422
418
  }));
419
+ return rv;
423
420
  })));
424
421
  // Sort by time to get a true order of the operations (between tables)
425
422
  const sorted = flatten(allMutsOnTables).sort((a, b) => a.mut.txid === b.mut.txid
@@ -448,6 +445,69 @@
448
445
  return result;
449
446
  });
450
447
  }
448
+ function removeRedundantUpdateOps(muts) {
449
+ const updateCoverage = new Map();
450
+ for (const mut of muts) {
451
+ if (mut.type === 'update') {
452
+ if (mut.keys.length !== 1 || mut.changeSpecs.length !== 1) {
453
+ continue; // Don't optimize multi-key updates
454
+ }
455
+ const strKey = '' + mut.keys[0];
456
+ const changeSpecs = mut.changeSpecs[0];
457
+ if (Object.values(changeSpecs).some(v => typeof v === "object" && v && "@@propmod" in v)) {
458
+ continue; // Cannot optimize if any PropModification is present
459
+ }
460
+ let keyCoverage = updateCoverage.get(strKey);
461
+ if (keyCoverage) {
462
+ keyCoverage.push({ txid: mut.txid, updateSpec: changeSpecs });
463
+ }
464
+ else {
465
+ updateCoverage.set(strKey, [{ txid: mut.txid, updateSpec: changeSpecs }]);
466
+ }
467
+ }
468
+ }
469
+ muts = muts.filter(mut => {
470
+ // Only apply optimization to update mutations that are single-key
471
+ if (mut.type !== 'update')
472
+ return true;
473
+ if (mut.keys.length !== 1 || mut.changeSpecs.length !== 1)
474
+ return true;
475
+ // Keep track of properties that aren't overlapped by later transactions
476
+ const unoverlappedProps = new Set(Object.keys(mut.changeSpecs[0]));
477
+ const strKey = '' + mut.keys[0];
478
+ const keyCoverage = updateCoverage.get(strKey);
479
+ for (let i = keyCoverage.length - 1; i >= 0; --i) {
480
+ const { txid, updateSpec } = keyCoverage[i];
481
+ if (txid === mut.txid)
482
+ break; // Stop when reaching own txid
483
+ // If all changes in updateSpec are covered by all props on all mut.changeSpecs then
484
+ // txid is redundant and can be removed.
485
+ for (const keyPath of Object.keys(updateSpec)) {
486
+ unoverlappedProps.delete(keyPath);
487
+ }
488
+ }
489
+ if (unoverlappedProps.size === 0) {
490
+ // This operation is completely overlapped by later operations. It can be removed.
491
+ return false;
492
+ }
493
+ return true;
494
+ });
495
+ return muts;
496
+ }
497
+ function canonicalizeToUpdateOps(muts) {
498
+ muts = muts.map(mut => {
499
+ if (mut.type === 'modify' && mut.criteria.index === null) {
500
+ // The criteria is on primary key. Convert to an update operation instead.
501
+ // It is simpler for the server to handle and also more efficient.
502
+ const updateMut = Object.assign(Object.assign({}, mut), { criteria: undefined, changeSpec: undefined, type: 'update', keys: mut.keys, changeSpecs: [mut.changeSpec] });
503
+ delete updateMut.criteria;
504
+ delete updateMut.changeSpec;
505
+ return updateMut;
506
+ }
507
+ return mut;
508
+ });
509
+ return muts;
510
+ }
451
511
 
452
512
  function randomString$1(bytes) {
453
513
  const buf = new Uint8Array(bytes);
@@ -13889,7 +13949,7 @@
13889
13949
  *
13890
13950
  * ==========================================================================
13891
13951
  *
13892
- * Version 4.2.0-rc.1, Wed Aug 06 2025
13952
+ * Version 4.2.1, Wed Oct 01 2025
13893
13953
  *
13894
13954
  * https://dexie.org
13895
13955
  *
@@ -18009,7 +18069,7 @@
18009
18069
  const syncComplete = new rxjs.Subject();
18010
18070
  dexie.cloud = {
18011
18071
  // @ts-ignore
18012
- version: "4.2.0-rc.1",
18072
+ version: "4.2.1",
18013
18073
  options: Object.assign({}, DEFAULT_OPTIONS),
18014
18074
  schema: null,
18015
18075
  get currentUserId() {
@@ -18326,7 +18386,7 @@
18326
18386
  }
18327
18387
  }
18328
18388
  // @ts-ignore
18329
- dexieCloud.version = "4.2.0-rc.1";
18389
+ dexieCloud.version = "4.2.1";
18330
18390
  Dexie.Cloud = dexieCloud;
18331
18391
 
18332
18392
  // In case the SW lives for a while, let it reuse already opened connections: