dexie 4.0.7 → 4.0.9-alpha.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.
package/dist/dexie.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * By David Fahlander, david.fahlander@gmail.com
6
6
  *
7
- * Version 4.0.7, Sun May 26 2024
7
+ * Version 4.0.9-alpha.1, Fri Aug 23 2024
8
8
  *
9
9
  * https://dexie.org
10
10
  *
@@ -1144,7 +1144,7 @@ function tempTransaction(db, mode, storeNames, fn) {
1144
1144
  }
1145
1145
  }
1146
1146
 
1147
- var DEXIE_VERSION = '4.0.7';
1147
+ var DEXIE_VERSION = '4.0.9-alpha.1';
1148
1148
  var maxString = String.fromCharCode(65535);
1149
1149
  var minKey = -Infinity;
1150
1150
  var INVALID_KEY_ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>.";
@@ -1262,6 +1262,95 @@ function getUint8Array(a) {
1262
1262
  return new Uint8Array(a);
1263
1263
  }
1264
1264
 
1265
+ function getDocCache(db) {
1266
+ var _a;
1267
+ var _b;
1268
+ return (_a = (_b = db._novip)['_docCache']) !== null && _a !== void 0 ? _a : (_b['_docCache'] = {
1269
+ cache: {},
1270
+ get size() {
1271
+ return Object.keys(this.cache).length;
1272
+ },
1273
+ find: function (table, primaryKey, ydocProp) {
1274
+ var cacheKey = getYDocCacheKey(table, primaryKey, ydocProp);
1275
+ var docRef = this.cache[cacheKey];
1276
+ return docRef ? docRef.deref() : undefined;
1277
+ },
1278
+ add: function (doc) {
1279
+ var _a = doc.meta, parentTable = _a.parentTable, parentId = _a.parentId, parentProp = _a.parentProp;
1280
+ if (!parentTable || !parentProp || parentId == null)
1281
+ throw new Error("Missing Dexie-related metadata in Y.Doc");
1282
+ var cacheKey = getYDocCacheKey(parentTable, parentId, parentProp);
1283
+ this.cache[cacheKey] = new WeakRef(doc);
1284
+ docRegistry.register(doc, { cache: this.cache, key: cacheKey });
1285
+ },
1286
+ delete: function (doc) {
1287
+ docRegistry.unregister(doc);
1288
+ delete this.cache[getYDocCacheKey(doc.meta.parentTable, doc.meta.parentId, doc.meta.parentProp)];
1289
+ },
1290
+ });
1291
+ }
1292
+ var docRegistry = new FinalizationRegistry(function (_a) {
1293
+ var cache = _a.cache, key = _a.key;
1294
+ delete cache[key];
1295
+ });
1296
+ var destroyed = new WeakSet();
1297
+ function throwIfDestroyed(doc) {
1298
+ if (destroyed.has(doc))
1299
+ throw new Error('Y.Doc has been destroyed');
1300
+ }
1301
+ function getYDocCacheKey(table, primaryKey, ydocProp) {
1302
+ return "".concat(table, "[").concat(primaryKey, "].").concat(ydocProp);
1303
+ }
1304
+
1305
+ function createYDocProperty(db, Y, table, prop, updatesTable) {
1306
+ var pkKeyPath = table.schema.primKey.keyPath;
1307
+ var docCache = getDocCache(db);
1308
+ return {
1309
+ get: function () {
1310
+ var id = getByKeyPath(this, pkKeyPath);
1311
+ var doc = docCache.find(table.name, id, prop);
1312
+ if (doc)
1313
+ return doc;
1314
+ doc = new Y.Doc({
1315
+ meta: {
1316
+ db: db,
1317
+ updatesTable: updatesTable,
1318
+ parentProp: prop,
1319
+ parentTable: table.name,
1320
+ parentId: id
1321
+ },
1322
+ });
1323
+ docCache.add(doc);
1324
+ doc.on('destroy', function () {
1325
+ destroyed.add(doc);
1326
+ docCache.delete(doc);
1327
+ });
1328
+ return doc;
1329
+ },
1330
+ };
1331
+ }
1332
+
1333
+ function builtInDeletionTrigger(table, keys, res) {
1334
+ var yProps = table.schema.yProps;
1335
+ if (!yProps)
1336
+ return res;
1337
+ if (keys && res.numFailures > 0)
1338
+ keys = keys.filter(function (_, i) { return !res.failures[i]; });
1339
+ return Promise.all(yProps.map(function (_a) {
1340
+ var updatesTable = _a.updatesTable;
1341
+ return keys
1342
+ ? table.db.table(updatesTable).where('k').anyOf(keys).delete()
1343
+ : table.db.table(updatesTable).clear();
1344
+ })).then(function () { return res; });
1345
+ }
1346
+
1347
+ function getYLibrary(db) {
1348
+ var Y = db._options.Y;
1349
+ if (!Y)
1350
+ throw new exceptions.MissingAPI('Y library not supplied to Dexie constructor');
1351
+ return Y;
1352
+ }
1353
+
1265
1354
  var Table = (function () {
1266
1355
  function Table() {
1267
1356
  }
@@ -1393,6 +1482,7 @@ var Table = (function () {
1393
1482
  return this.toCollection().reverse();
1394
1483
  };
1395
1484
  Table.prototype.mapToClass = function (constructor) {
1485
+ var _this = this;
1396
1486
  var _a = this, db = _a.db, tableName = _a.name;
1397
1487
  this.schema.mappedClass = constructor;
1398
1488
  if (constructor.prototype instanceof Entity) {
@@ -1410,6 +1500,20 @@ var Table = (function () {
1410
1500
  return class_1;
1411
1501
  }(constructor));
1412
1502
  }
1503
+ if (this.schema.yProps) {
1504
+ var Y_1 = getYLibrary(db);
1505
+ constructor = (function (_super) {
1506
+ __extends(class_2, _super);
1507
+ function class_2() {
1508
+ return _super !== null && _super.apply(this, arguments) || this;
1509
+ }
1510
+ return class_2;
1511
+ }(constructor));
1512
+ this.schema.yProps.forEach(function (_a) {
1513
+ var prop = _a.prop, updatesTable = _a.updatesTable;
1514
+ Object.defineProperty(constructor.prototype, prop, createYDocProperty(db, Y_1, _this, prop, updatesTable));
1515
+ });
1516
+ }
1413
1517
  var inheritedProps = new Set();
1414
1518
  for (var proto = constructor.prototype; proto; proto = getProto(proto)) {
1415
1519
  Object.getOwnPropertyNames(proto).forEach(function (propName) { return inheritedProps.add(propName); });
@@ -1491,12 +1595,14 @@ var Table = (function () {
1491
1595
  };
1492
1596
  Table.prototype.delete = function (key) {
1493
1597
  var _this = this;
1494
- return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'delete', keys: [key] }); })
1495
- .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : undefined; });
1598
+ return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'delete', keys: [key] })
1599
+ .then(function (res) { return builtInDeletionTrigger(_this, [key], res); })
1600
+ .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : undefined; }); });
1496
1601
  };
1497
1602
  Table.prototype.clear = function () {
1498
1603
  var _this = this;
1499
- return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'deleteRange', range: AnyRange }); })
1604
+ return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'deleteRange', range: AnyRange })
1605
+ .then(function (res) { return builtInDeletionTrigger(_this, null, res); }); })
1500
1606
  .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : undefined; });
1501
1607
  };
1502
1608
  Table.prototype.bulkGet = function (keys) {
@@ -1623,7 +1729,8 @@ var Table = (function () {
1623
1729
  var _this = this;
1624
1730
  var numKeys = keys.length;
1625
1731
  return this._trans('readwrite', function (trans) {
1626
- return _this.core.mutate({ trans: trans, type: 'delete', keys: keys });
1732
+ return _this.core.mutate({ trans: trans, type: 'delete', keys: keys })
1733
+ .then(function (res) { return builtInDeletionTrigger(_this, keys, res); });
1627
1734
  }).then(function (_a) {
1628
1735
  var numFailures = _a.numFailures, lastResult = _a.lastResult, failures = _a.failures;
1629
1736
  if (numFailures === 0)
@@ -2147,45 +2254,48 @@ var Collection = (function () {
2147
2254
  totalFailures.push(failures[pos]);
2148
2255
  }
2149
2256
  };
2257
+ var isUnconditionalDelete = changes === deleteCallback;
2150
2258
  return _this.clone().primaryKeys().then(function (keys) {
2151
2259
  var criteria = isPlainKeyRange(ctx) &&
2152
2260
  ctx.limit === Infinity &&
2153
- (typeof changes !== 'function' || changes === deleteCallback) && {
2261
+ (typeof changes !== 'function' || isUnconditionalDelete) && {
2154
2262
  index: ctx.index,
2155
2263
  range: ctx.range
2156
2264
  };
2157
2265
  var nextChunk = function (offset) {
2158
2266
  var count = Math.min(limit, keys.length - offset);
2159
- return coreTable.getMany({
2267
+ var keysInChunk = keys.slice(offset, offset + count);
2268
+ return (isUnconditionalDelete ? Promise.resolve([]) : coreTable.getMany({
2160
2269
  trans: trans,
2161
- keys: keys.slice(offset, offset + count),
2270
+ keys: keysInChunk,
2162
2271
  cache: "immutable"
2163
- }).then(function (values) {
2272
+ })).then(function (values) {
2164
2273
  var addValues = [];
2165
2274
  var putValues = [];
2166
2275
  var putKeys = outbound ? [] : null;
2167
- var deleteKeys = [];
2168
- for (var i = 0; i < count; ++i) {
2169
- var origValue = values[i];
2170
- var ctx_1 = {
2171
- value: deepClone(origValue),
2172
- primKey: keys[offset + i]
2173
- };
2174
- if (modifyer.call(ctx_1, ctx_1.value, ctx_1) !== false) {
2175
- if (ctx_1.value == null) {
2176
- deleteKeys.push(keys[offset + i]);
2177
- }
2178
- else if (!outbound && cmp(extractKey(origValue), extractKey(ctx_1.value)) !== 0) {
2179
- deleteKeys.push(keys[offset + i]);
2180
- addValues.push(ctx_1.value);
2181
- }
2182
- else {
2183
- putValues.push(ctx_1.value);
2184
- if (outbound)
2185
- putKeys.push(keys[offset + i]);
2276
+ var deleteKeys = isUnconditionalDelete ? keysInChunk : [];
2277
+ if (!isUnconditionalDelete)
2278
+ for (var i = 0; i < count; ++i) {
2279
+ var origValue = values[i];
2280
+ var ctx_1 = {
2281
+ value: deepClone(origValue),
2282
+ primKey: keys[offset + i]
2283
+ };
2284
+ if (modifyer.call(ctx_1, ctx_1.value, ctx_1) !== false) {
2285
+ if (ctx_1.value == null) {
2286
+ deleteKeys.push(keys[offset + i]);
2287
+ }
2288
+ else if (!outbound && cmp(extractKey(origValue), extractKey(ctx_1.value)) !== 0) {
2289
+ deleteKeys.push(keys[offset + i]);
2290
+ addValues.push(ctx_1.value);
2291
+ }
2292
+ else {
2293
+ putValues.push(ctx_1.value);
2294
+ if (outbound)
2295
+ putKeys.push(keys[offset + i]);
2296
+ }
2186
2297
  }
2187
2298
  }
2188
- }
2189
2299
  return Promise.resolve(addValues.length > 0 &&
2190
2300
  coreTable.mutate({ trans: trans, type: 'add', values: addValues })
2191
2301
  .then(function (res) {
@@ -2203,14 +2313,15 @@ var Collection = (function () {
2203
2313
  changeSpec: typeof changes !== 'function'
2204
2314
  && changes,
2205
2315
  isAdditionalChunk: offset > 0
2206
- }).then(function (res) { return applyMutateResult(putValues.length, res); }); }).then(function () { return (deleteKeys.length > 0 || (criteria && changes === deleteCallback)) &&
2316
+ }).then(function (res) { return applyMutateResult(putValues.length, res); }); }).then(function () { return (deleteKeys.length > 0 || (criteria && isUnconditionalDelete)) &&
2207
2317
  coreTable.mutate({
2208
2318
  trans: trans,
2209
2319
  type: 'delete',
2210
2320
  keys: deleteKeys,
2211
2321
  criteria: criteria,
2212
2322
  isAdditionalChunk: offset > 0
2213
- }).then(function (res) { return applyMutateResult(deleteKeys.length, res); }); }).then(function () {
2323
+ }).then(function (res) { return builtInDeletionTrigger(ctx.table, deleteKeys, res); })
2324
+ .then(function (res) { return applyMutateResult(deleteKeys.length, res); }); }).then(function () {
2214
2325
  return keys.length > offset + count && nextChunk(offset + limit);
2215
2326
  });
2216
2327
  });
@@ -2226,6 +2337,7 @@ var Collection = (function () {
2226
2337
  Collection.prototype.delete = function () {
2227
2338
  var ctx = this._ctx, range = ctx.range;
2228
2339
  if (isPlainKeyRange(ctx) &&
2340
+ !ctx.table.schema.yProps &&
2229
2341
  (ctx.isPrimKey || range.type === 3 ))
2230
2342
  {
2231
2343
  return this._write(function (trans) {
@@ -2234,7 +2346,7 @@ var Collection = (function () {
2234
2346
  return ctx.table.core.count({ trans: trans, query: { index: primaryKey, range: coreRange } }).then(function (count) {
2235
2347
  return ctx.table.core.mutate({ trans: trans, type: 'deleteRange', range: coreRange })
2236
2348
  .then(function (_a) {
2237
- var failures = _a.failures; _a.lastResult; _a.results; var numFailures = _a.numFailures;
2349
+ var failures = _a.failures, numFailures = _a.numFailures;
2238
2350
  if (numFailures)
2239
2351
  throw new ModifyError("Could not delete some values", Object.keys(failures).map(function (pos) { return failures[pos]; }), count - numFailures);
2240
2352
  return count - numFailures;
@@ -2836,6 +2948,13 @@ var Transaction = (function () {
2836
2948
  function createTransactionConstructor(db) {
2837
2949
  return makeClassConstructor(Transaction.prototype, function Transaction(mode, storeNames, dbschema, chromeTransactionDurability, parent) {
2838
2950
  var _this = this;
2951
+ if (mode !== 'readonly')
2952
+ storeNames.forEach(function (storeName) {
2953
+ var _a;
2954
+ var yProps = (_a = dbschema[storeName]) === null || _a === void 0 ? void 0 : _a.yProps;
2955
+ if (yProps)
2956
+ storeNames = storeNames.concat(yProps.map(function (p) { return p.updatesTable; }));
2957
+ });
2839
2958
  this.db = db;
2840
2959
  this.mode = mode;
2841
2960
  this.storeNames = storeNames;
@@ -2871,7 +2990,7 @@ function createTransactionConstructor(db) {
2871
2990
  });
2872
2991
  }
2873
2992
 
2874
- function createIndexSpec(name, keyPath, unique, multi, auto, compound, isPrimKey) {
2993
+ function createIndexSpec(name, keyPath, unique, multi, auto, compound, isPrimKey, type) {
2875
2994
  return {
2876
2995
  name: name,
2877
2996
  keyPath: keyPath,
@@ -2879,7 +2998,8 @@ function createIndexSpec(name, keyPath, unique, multi, auto, compound, isPrimKey
2879
2998
  multi: multi,
2880
2999
  auto: auto,
2881
3000
  compound: compound,
2882
- src: (unique && !isPrimKey ? '&' : '') + (multi ? '*' : '') + (auto ? "++" : "") + nameFromKeyPath(keyPath)
3001
+ src: (unique && !isPrimKey ? '&' : '') + (multi ? '*' : '') + (auto ? "++" : "") + nameFromKeyPath(keyPath),
3002
+ type: type
2883
3003
  };
2884
3004
  }
2885
3005
  function nameFromKeyPath(keyPath) {
@@ -2888,13 +3008,17 @@ function nameFromKeyPath(keyPath) {
2888
3008
  keyPath ? ('[' + [].join.call(keyPath, '+') + ']') : "";
2889
3009
  }
2890
3010
 
2891
- function createTableSchema(name, primKey, indexes) {
3011
+ function createTableSchema(name, primKey, indexes, yProps) {
2892
3012
  return {
2893
3013
  name: name,
2894
3014
  primKey: primKey,
2895
3015
  indexes: indexes,
2896
3016
  mappedClass: null,
2897
- idxByName: arrayToObject(indexes, function (index) { return [index.name, index]; })
3017
+ yProps: yProps === null || yProps === void 0 ? void 0 : yProps.map(function (prop) { return ({
3018
+ prop: prop,
3019
+ updatesTable: "$".concat(name, ".").concat(prop, "_updates"),
3020
+ }); }),
3021
+ idxByName: arrayToObject(indexes, function (index) { return [index.name, index]; }),
2898
3022
  };
2899
3023
  }
2900
3024
 
@@ -3638,10 +3762,15 @@ function adjustToExistingIndexNames(db, schema, idbtrans) {
3638
3762
  }
3639
3763
  function parseIndexSyntax(primKeyAndIndexes) {
3640
3764
  return primKeyAndIndexes.split(',').map(function (index, indexNum) {
3641
- index = index.trim();
3765
+ var _a;
3766
+ var typeSplit = index.split(':');
3767
+ var type = (_a = typeSplit[1]) === null || _a === void 0 ? void 0 : _a.trim();
3768
+ index = typeSplit[0].trim();
3769
+ if (type && type !== 'Y')
3770
+ throw new exceptions.Schema("Unsupported type '".concat(type, "'"));
3642
3771
  var name = index.replace(/([&*]|\+\+)/g, "");
3643
3772
  var keyPath = /^\[/.test(name) ? name.match(/^\[(.*)\]$/)[1].split('+') : name;
3644
- return createIndexSpec(name, keyPath || null, /\&/.test(index), /\*/.test(index), /\+\+/.test(index), isArray(keyPath), indexNum === 0);
3773
+ return createIndexSpec(name, keyPath || null, /\&/.test(index), /\*/.test(index), /\+\+/.test(index), isArray(keyPath), indexNum === 0, type);
3645
3774
  });
3646
3775
  }
3647
3776
 
@@ -3649,40 +3778,57 @@ var Version = (function () {
3649
3778
  function Version() {
3650
3779
  }
3651
3780
  Version.prototype._parseStoresSpec = function (stores, outSchema) {
3781
+ var _this = this;
3652
3782
  keys(stores).forEach(function (tableName) {
3783
+ var _a;
3653
3784
  if (stores[tableName] !== null) {
3654
3785
  var indexes = parseIndexSyntax(stores[tableName]);
3786
+ var yProps = indexes.filter(function (idx) { return idx.type === 'Y'; }).map(function (idx) { return idx.name; });
3787
+ indexes = indexes.filter(function (idx) { return idx.type !== 'Y'; });
3655
3788
  var primKey = indexes.shift();
3789
+ if (!primKey) {
3790
+ throw new exceptions.Schema('Invalid schema for table ' + tableName + ': ' + stores[tableName]);
3791
+ }
3656
3792
  primKey.unique = true;
3657
3793
  if (primKey.multi)
3658
- throw new exceptions.Schema("Primary key cannot be multi-valued");
3794
+ throw new exceptions.Schema('Primary key cannot be multiEntry*');
3659
3795
  indexes.forEach(function (idx) {
3660
3796
  if (idx.auto)
3661
- throw new exceptions.Schema("Only primary key can be marked as autoIncrement (++)");
3797
+ throw new exceptions.Schema('Only primary key can be marked as autoIncrement (++)');
3662
3798
  if (!idx.keyPath)
3663
- throw new exceptions.Schema("Index must have a name and cannot be an empty string");
3799
+ throw new exceptions.Schema('Index must have a name and cannot be an empty string');
3664
3800
  });
3665
- outSchema[tableName] = createTableSchema(tableName, primKey, indexes);
3801
+ var tblSchema = createTableSchema(tableName, primKey, indexes, yProps.length ? yProps : undefined);
3802
+ outSchema[tableName] = tblSchema;
3803
+ for (var _i = 0, _b = tblSchema.yProps || []; _i < _b.length; _i++) {
3804
+ var yProp = _b[_i];
3805
+ _this._parseStoresSpec((_a = {}, _a[yProp.updatesTable] = '++i,k', _a), outSchema);
3806
+ }
3666
3807
  }
3667
3808
  });
3668
3809
  };
3669
3810
  Version.prototype.stores = function (stores) {
3670
3811
  var db = this.db;
3671
- this._cfg.storesSource = this._cfg.storesSource ?
3672
- extend(this._cfg.storesSource, stores) :
3673
- stores;
3812
+ this._cfg.storesSource = this._cfg.storesSource
3813
+ ? extend(this._cfg.storesSource, stores)
3814
+ : stores;
3674
3815
  var versions = db._versions;
3675
3816
  var storesSpec = {};
3676
3817
  var dbschema = {};
3677
3818
  versions.forEach(function (version) {
3678
3819
  extend(storesSpec, version._cfg.storesSource);
3679
- dbschema = (version._cfg.dbschema = {});
3820
+ dbschema = version._cfg.dbschema = {};
3680
3821
  version._parseStoresSpec(storesSpec, dbschema);
3681
3822
  });
3682
3823
  db._dbSchema = dbschema;
3683
3824
  removeTablesApi(db, [db._allTables, db, db.Transaction.prototype]);
3684
3825
  setApiOnPlace(db, [db._allTables, db, db.Transaction.prototype, this._cfg.tables], keys(dbschema), dbschema);
3685
3826
  db._storeNames = keys(dbschema);
3827
+ db._storeNames.forEach(function (tableName) {
3828
+ if (dbschema[tableName].yProps) {
3829
+ db.table(tableName).mapToClass(dbschema[tableName].mappedClass || Object);
3830
+ }
3831
+ });
3686
3832
  return this;
3687
3833
  };
3688
3834
  Version.prototype.upgrade = function (upgradeFunction) {
@@ -3793,6 +3939,10 @@ props(RangeSet.prototype, (_a = {
3793
3939
  var _this = this;
3794
3940
  keys.forEach(function (key) { return addRange(_this, key, key); });
3795
3941
  return this;
3942
+ },
3943
+ hasKey: function (key) {
3944
+ var node = getRangeSetIterator(this).next(key).value;
3945
+ return node && cmp(node.from, key) <= 0 && cmp(node.to, key) >= 0;
3796
3946
  }
3797
3947
  },
3798
3948
  _a[iteratorSymbol] = function () {
@@ -4854,19 +5004,23 @@ function applyOptimisticOps(result, req, ops, table, cacheEntry, immutable) {
4854
5004
  var extractLowLevelIndex = (index.lowLevelIndex || index).extractKey;
4855
5005
  var finalResult = ops.reduce(function (result, op) {
4856
5006
  var modifedResult = result;
4857
- var includedValues = op.type === 'add' || op.type === 'put'
4858
- ? op.values.filter(function (v) {
4859
- var key = extractIndex(v);
4860
- return multiEntry && isArray(key)
5007
+ var includedValues = [];
5008
+ if (op.type === 'add' || op.type === 'put') {
5009
+ var includedPKs = new RangeSet();
5010
+ for (var i = op.values.length - 1; i >= 0; --i) {
5011
+ var value = op.values[i];
5012
+ var pk = extractPrimKey(value);
5013
+ if (includedPKs.hasKey(pk))
5014
+ continue;
5015
+ var key = extractIndex(value);
5016
+ if (multiEntry && isArray(key)
4861
5017
  ? key.some(function (k) { return isWithinRange(k, queryRange); })
4862
- : isWithinRange(key, queryRange);
4863
- }).map(function (v) {
4864
- v = deepClone(v);
4865
- if (immutable)
4866
- Object.freeze(v);
4867
- return v;
4868
- })
4869
- : [];
5018
+ : isWithinRange(key, queryRange)) {
5019
+ includedPKs.addKey(pk);
5020
+ includedValues.push(value);
5021
+ }
5022
+ }
5023
+ }
4870
5024
  switch (op.type) {
4871
5025
  case 'add':
4872
5026
  modifedResult = result.concat(req.values
@@ -4876,20 +5030,16 @@ function applyOptimisticOps(result, req, ops, table, cacheEntry, immutable) {
4876
5030
  case 'put':
4877
5031
  var keySet_1 = new RangeSet().addKeys(op.values.map(function (v) { return extractPrimKey(v); }));
4878
5032
  modifedResult = result
4879
- .filter(function (item) {
4880
- var key = req.values ? extractPrimKey(item) : item;
4881
- return !rangesOverlap(new RangeSet(key), keySet_1);
4882
- })
4883
- .concat(req.values
5033
+ .filter(
5034
+ function (item) { return !keySet_1.hasKey(req.values ? extractPrimKey(item) : item); })
5035
+ .concat(
5036
+ req.values
4884
5037
  ? includedValues
4885
5038
  : includedValues.map(function (v) { return extractPrimKey(v); }));
4886
5039
  break;
4887
5040
  case 'delete':
4888
5041
  var keysToDelete_1 = new RangeSet().addKeys(op.keys);
4889
- modifedResult = result.filter(function (item) {
4890
- var key = req.values ? extractPrimKey(item) : item;
4891
- return !rangesOverlap(new RangeSet(key), keysToDelete_1);
4892
- });
5042
+ modifedResult = result.filter(function (item) { return !keysToDelete_1.hasKey(req.values ? extractPrimKey(item) : item); });
4893
5043
  break;
4894
5044
  case 'deleteRange':
4895
5045
  var range_1 = op.range;
@@ -5225,6 +5375,140 @@ function vipify(target, vipDb) {
5225
5375
  });
5226
5376
  }
5227
5377
 
5378
+ function compressYDocs(db, interval) {
5379
+ var p = Promise.resolve();
5380
+ for (var _i = 0, _a = db.tables; _i < _a.length; _i++) {
5381
+ var table = _a[_i];
5382
+ var _loop_1 = function (yProp) {
5383
+ p = p.then(function () { return compressYDocsTable(db, yProp, interval); });
5384
+ };
5385
+ for (var _b = 0, _c = table.schema.yProps || []; _b < _c.length; _b++) {
5386
+ var yProp = _c[_b];
5387
+ _loop_1(yProp);
5388
+ }
5389
+ }
5390
+ return p;
5391
+ }
5392
+ function compressYDocsTable(db, _a, skipIfRunnedSince
5393
+ ) {
5394
+ var updatesTable = _a.updatesTable;
5395
+ var updTbl = db.table(updatesTable);
5396
+ return Promise.all([
5397
+ updTbl
5398
+ .where('i')
5399
+ .startsWith('')
5400
+ .toArray(),
5401
+ db.transaction('rw', updatesTable, function () {
5402
+ return updTbl.get(0).then(function (lastCompressed) {
5403
+ if (lastCompressed &&
5404
+ skipIfRunnedSince &&
5405
+ lastCompressed.lastRun.getTime() > Date.now() - skipIfRunnedSince) {
5406
+ return null;
5407
+ }
5408
+ lastCompressed = lastCompressed || { i: 0, lastCompressed: 0 };
5409
+ return updTbl
5410
+ .put(__assign(__assign({}, lastCompressed), { lastRun: new Date() }))
5411
+ .then(function () { return lastCompressed; });
5412
+ });
5413
+ }),
5414
+ ]).then(function (_a) {
5415
+ var syncers = _a[0], stamp = _a[1];
5416
+ if (!stamp)
5417
+ return;
5418
+ var lastCompressedUpdate = stamp.lastCompressed;
5419
+ var unsentFrom = Math.min.apply(Math, syncers.map(function (s) { return s.unsentFrom || Infinity; }));
5420
+ return updTbl
5421
+ .where('i')
5422
+ .between(lastCompressedUpdate, Infinity, false)
5423
+ .toArray(function (addedUpdates) {
5424
+ if (addedUpdates.length <= 1)
5425
+ return;
5426
+ var docsToCompress = [];
5427
+ var lastUpdateToCompress = lastCompressedUpdate + 1;
5428
+ var _loop_2 = function (j) {
5429
+ var updateRow = addedUpdates[j];
5430
+ var i = updateRow.i, f = updateRow.f, k = updateRow.k;
5431
+ if (i >= unsentFrom && (f & 0x01))
5432
+ return "break";
5433
+ var entry = docsToCompress.find(function (entry) { return cmp(entry.docId, k) === 0; });
5434
+ if (entry)
5435
+ entry.updates.push(updateRow);
5436
+ else
5437
+ docsToCompress.push({ docId: k, updates: [updateRow] });
5438
+ lastUpdateToCompress = i;
5439
+ };
5440
+ for (var j = 0; j < addedUpdates.length; ++j) {
5441
+ var state_1 = _loop_2(j);
5442
+ if (state_1 === "break")
5443
+ break;
5444
+ }
5445
+ var p = Promise.resolve();
5446
+ var _loop_3 = function (docId, updates) {
5447
+ p = p.then(function () { return compressUpdatesForDoc(db, updatesTable, docId, updates); });
5448
+ };
5449
+ for (var _i = 0, docsToCompress_1 = docsToCompress; _i < docsToCompress_1.length; _i++) {
5450
+ var _a = docsToCompress_1[_i], docId = _a.docId, updates = _a.updates;
5451
+ _loop_3(docId, updates);
5452
+ }
5453
+ return p.then(function () {
5454
+ return db.transaction('rw', updTbl, function () {
5455
+ return updTbl.get(0).then(function (current) {
5456
+ return updTbl.put(__assign(__assign({}, current), { lastCompressed: Math.max(lastUpdateToCompress, (current === null || current === void 0 ? void 0 : current.lastCompressed) || 0) }));
5457
+ });
5458
+ });
5459
+ });
5460
+ });
5461
+ });
5462
+ }
5463
+ function compressUpdatesForDoc(db, updatesTable, parentId, addedUpdatesToCompress) {
5464
+ if (addedUpdatesToCompress.length < 1)
5465
+ throw new Error('Invalid input');
5466
+ return db.transaction('rw', updatesTable, function (tx) {
5467
+ var updTbl = tx.table(updatesTable);
5468
+ return updTbl.where({ k: parentId }).first(function (mainUpdate) {
5469
+ var updates = [mainUpdate].concat(addedUpdatesToCompress);
5470
+ var Y = getYLibrary(db);
5471
+ var doc = new Y.Doc({ gc: true });
5472
+ updates.forEach(function (update) {
5473
+ Y.applyUpdateV2(doc, update.u);
5474
+ });
5475
+ var compressedUpdate = Y.encodeStateAsUpdateV2(doc);
5476
+ var lastUpdate = updates.pop();
5477
+ return updTbl
5478
+ .put({
5479
+ i: lastUpdate.i,
5480
+ k: parentId,
5481
+ u: compressedUpdate,
5482
+ })
5483
+ .then(function () { return updTbl.bulkDelete(updates.map(function (update) { return update.i; })); });
5484
+ });
5485
+ });
5486
+ }
5487
+
5488
+ var INTERVAL = 10000;
5489
+ function periodicGC(db) {
5490
+ var timer = null;
5491
+ db.on('ready', function (db) {
5492
+ if (db.tables.some(function (tbl) { return tbl.schema.yProps; })) {
5493
+ var gc_1 = function () {
5494
+ if (!db.isOpen())
5495
+ return;
5496
+ compressYDocs(db, INTERVAL).catch(function (err) {
5497
+ console.debug('Error during periodic GC', err);
5498
+ }).then(function () {
5499
+ timer = setTimeout(gc_1, INTERVAL);
5500
+ });
5501
+ };
5502
+ timer = setTimeout(gc_1, INTERVAL);
5503
+ }
5504
+ }, true);
5505
+ db.on('close', function () {
5506
+ if (timer)
5507
+ clearTimeout(timer);
5508
+ timer = null;
5509
+ });
5510
+ }
5511
+
5228
5512
  var Dexie$1 = (function () {
5229
5513
  function Dexie(name, options) {
5230
5514
  var _this = this;
@@ -5266,7 +5550,18 @@ var Dexie$1 = (function () {
5266
5550
  });
5267
5551
  this._state = state;
5268
5552
  this.name = name;
5269
- this.on = Events(this, "populate", "blocked", "versionchange", "close", { ready: [promisableChain, nop] });
5553
+ this.on = Events(this, "populate", "blocked", "versionchange", "close", "y", { ready: [promisableChain, nop] });
5554
+ this.once = function (event, callback) {
5555
+ var fn = function () {
5556
+ var args = [];
5557
+ for (var _i = 0; _i < arguments.length; _i++) {
5558
+ args[_i] = arguments[_i];
5559
+ }
5560
+ _this.on(event).unsubscribe(fn);
5561
+ callback.apply(_this, args);
5562
+ };
5563
+ return _this.on(event, fn);
5564
+ };
5270
5565
  this.on.ready.subscribe = override(this.on.ready.subscribe, function (subscribe) {
5271
5566
  return function (subscriber, bSticky) {
5272
5567
  Dexie.vip(function () {
@@ -5345,6 +5640,8 @@ var Dexie$1 = (function () {
5345
5640
  }
5346
5641
  });
5347
5642
  this.vip = vipDB;
5643
+ if (options === null || options === void 0 ? void 0 : options.Y)
5644
+ periodicGC(this);
5348
5645
  addons.forEach(function (addon) { return addon(_this); });
5349
5646
  }
5350
5647
  Dexie.prototype.version = function (versionNumber) {
@@ -5407,6 +5704,7 @@ var Dexie$1 = (function () {
5407
5704
  function () { return dexieOpen(_this); });
5408
5705
  };
5409
5706
  Dexie.prototype._close = function () {
5707
+ this.on.close.fire(new CustomEvent('close'));
5410
5708
  var state = this._state;
5411
5709
  var idx = connections.indexOf(this);
5412
5710
  if (idx >= 0)
@@ -5564,6 +5862,9 @@ var Dexie$1 = (function () {
5564
5862
  }
5565
5863
  return this._allTables[tableName];
5566
5864
  };
5865
+ Dexie.prototype.gc = function () {
5866
+ return compressYDocs(this);
5867
+ };
5567
5868
  return Dexie;
5568
5869
  }());
5569
5870
 
@@ -5864,8 +6165,118 @@ function replacePrefix(a, b) {
5864
6165
  return new PropModification({ replacePrefix: [a, b] });
5865
6166
  }
5866
6167
 
6168
+ function observeYDocUpdates(provider, doc, db, parentTableName, updatesTableName, parentId, Y) {
6169
+ var lastUpdateId = 0;
6170
+ var initial = true;
6171
+ var subscription = liveQuery(function () {
6172
+ throwIfDestroyed(doc);
6173
+ var updatesTable = db.table(updatesTableName);
6174
+ return Promise.all([
6175
+ (lastUpdateId > 0
6176
+ ? updatesTable
6177
+ .where('i')
6178
+ .between(lastUpdateId, Infinity, false)
6179
+ .toArray()
6180
+ .then(function (updates) {
6181
+ return updates.filter(function (update) { return cmp(update.k, parentId) === 0; });
6182
+ })
6183
+ : updatesTable.where({ k: parentId }).toArray()).then(function (updates) {
6184
+ if (updates.length > 0)
6185
+ lastUpdateId = updates[updates.length - 1].i;
6186
+ return updates;
6187
+ }),
6188
+ db.table(parentTableName).where(':id').equals(parentId).toArray(),
6189
+ ]);
6190
+ }).subscribe(function (_a) {
6191
+ var updates = _a[0], parentRow = _a[1];
6192
+ if (parentRow.length === 0) {
6193
+ doc.destroy();
6194
+ return;
6195
+ }
6196
+ throwIfDestroyed(doc);
6197
+ if (updates.length > 0) {
6198
+ Y.transact(doc, function () {
6199
+ updates.forEach(function (update) {
6200
+ Y.applyUpdateV2(doc, update.u);
6201
+ });
6202
+ }, provider, false);
6203
+ }
6204
+ if (initial) {
6205
+ initial = false;
6206
+ provider.on('load').fire(provider);
6207
+ doc.emit('load', [doc]);
6208
+ }
6209
+ }, function (error) {
6210
+ provider.on('error').fire(error);
6211
+ });
6212
+ var onUpdate = function (update, origin) {
6213
+ if (origin === provider)
6214
+ return;
6215
+ db.table(updatesTableName)
6216
+ .add({
6217
+ k: parentId,
6218
+ u: update,
6219
+ f: 1,
6220
+ })
6221
+ .then(function (i) {
6222
+ if (i === lastUpdateId - 1)
6223
+ ++lastUpdateId;
6224
+ })
6225
+ .catch(function (error) {
6226
+ provider.on('error').fire(error);
6227
+ });
6228
+ };
6229
+ var stopObserving = function () {
6230
+ subscription.unsubscribe();
6231
+ doc.off('updateV2', onUpdate);
6232
+ doc.off('destroy', stopObserving);
6233
+ };
6234
+ doc.on('updateV2', onUpdate);
6235
+ doc.on('destroy', stopObserving);
6236
+ return stopObserving;
6237
+ }
6238
+
6239
+ function DexieYProvider(doc) {
6240
+ var _a = (doc || {}).meta, db = _a.db, parentTable = _a.parentTable, parentId = _a.parentId, updatesTable = _a.updatesTable;
6241
+ if (!db || !parentTable || !updatesTable)
6242
+ throw new Error('Y.Doc not generated by Dexie');
6243
+ if (!db.table(parentTable) || !db.table(updatesTable)) {
6244
+ throw new Error("Table ".concat(parentTable, " or ").concat(updatesTable, " not found in db"));
6245
+ }
6246
+ throwIfDestroyed(doc);
6247
+ var Y = getYLibrary(db);
6248
+ function createEvents() {
6249
+ return Events(null, "load", "sync", "error");
6250
+ }
6251
+ var on = createEvents();
6252
+ var provider = {
6253
+ destroyed: false,
6254
+ doc: doc,
6255
+ on: on,
6256
+ off: function (name, f) { var _a; (_a = on[name]) === null || _a === void 0 ? void 0 : _a.unsubscribe(f); },
6257
+ whenLoaded: new Promise(function (resolve, reject) {
6258
+ on('load', resolve);
6259
+ on('error', reject);
6260
+ }),
6261
+ whenSynced: new Promise(function (resolve, reject) {
6262
+ on('sync', resolve);
6263
+ on('error', reject);
6264
+ }),
6265
+ destroy: function () {
6266
+ this.destroyed = true;
6267
+ stopObserving();
6268
+ on = this.on = createEvents();
6269
+ }
6270
+ };
6271
+ var stopObserving = observeYDocUpdates(provider, doc, db, parentTable, updatesTable, parentId, Y);
6272
+ doc.on('destroy', provider.destroy.bind(provider));
6273
+ db.on.y.fire(provider, Y);
6274
+ return provider;
6275
+ }
6276
+ DexieYProvider.getDocCache = getDocCache;
6277
+
5867
6278
  DexiePromise.rejectionMapper = mapError;
5868
6279
  setDebug(debug);
5869
6280
 
5870
- export { Dexie$1 as Dexie, Entity, PropModSymbol, PropModification, RangeSet, add, cmp, Dexie$1 as default, liveQuery, mergeRanges, rangesOverlap, remove, replacePrefix };
6281
+ export { Dexie$1 as Dexie, DexieYProvider, Entity, PropModSymbol, PropModification, RangeSet, add, cmp, Dexie$1 as default, liveQuery, mergeRanges, rangesOverlap, remove, replacePrefix };
5871
6282
  //# sourceMappingURL=dexie.mjs.map