cry-synced-db-client 0.1.50 → 0.1.51
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/index.js +179 -34
- package/dist/src/db/SyncedDb.d.ts +31 -0
- package/dist/src/types/I_SyncedDb.d.ts +55 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1127,6 +1127,8 @@ class SyncedDb {
|
|
|
1127
1127
|
closing = false;
|
|
1128
1128
|
releasingLeadershipDueToVisibility = false;
|
|
1129
1129
|
visibilityChangeHandler;
|
|
1130
|
+
useObjectMetadata;
|
|
1131
|
+
_metadata = {};
|
|
1130
1132
|
constructor(config) {
|
|
1131
1133
|
this.tenant = config.tenant;
|
|
1132
1134
|
this.dexieDb = config.dexieDb;
|
|
@@ -1158,6 +1160,7 @@ class SyncedDb {
|
|
|
1158
1160
|
this.onBecameLeader = config.onBecameLeader;
|
|
1159
1161
|
this.onLostLeadership = config.onLostLeadership;
|
|
1160
1162
|
this.onInfrastructureError = config.onInfrastructureError;
|
|
1163
|
+
this.useObjectMetadata = config.useObjectMetadata ?? false;
|
|
1161
1164
|
this.updaterId = Math.random().toString(36).substring(2, 15);
|
|
1162
1165
|
this.syncedDbInstanceId = `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
1163
1166
|
for (const col of config.collections) {
|
|
@@ -1339,7 +1342,7 @@ class SyncedDb {
|
|
|
1339
1342
|
for (const [name] of this.collections) {
|
|
1340
1343
|
const data = await this.dexieDb.getAll(name);
|
|
1341
1344
|
const activeData = data.filter((item) => !item._deleted);
|
|
1342
|
-
this.
|
|
1345
|
+
this._initCollectionInMem(name, activeData);
|
|
1343
1346
|
const meta = await this.dexieDb.getSyncMeta(name);
|
|
1344
1347
|
if (meta) {
|
|
1345
1348
|
this.syncMetaCache.set(name, meta);
|
|
@@ -1617,10 +1620,11 @@ class SyncedDb {
|
|
|
1617
1620
|
_lastUpdaterId: this.updaterId
|
|
1618
1621
|
};
|
|
1619
1622
|
this.schedulePendingChange(collection, id, newData, 0, "save");
|
|
1623
|
+
const currentMem = this.inMemDb.getById(collection, id);
|
|
1624
|
+
const merged = { ...currentMem || existing || { _id: id }, ...update };
|
|
1620
1625
|
if (existing?._deleted) {} else {
|
|
1621
|
-
this.
|
|
1626
|
+
this._writeToInMemBatch(collection, [merged], "upsert");
|
|
1622
1627
|
}
|
|
1623
|
-
const merged = { ...existing || { _id: id }, ...update };
|
|
1624
1628
|
return this.stripLocalFields(merged);
|
|
1625
1629
|
}
|
|
1626
1630
|
async upsert(collection, query, update) {
|
|
@@ -1653,7 +1657,7 @@ class SyncedDb {
|
|
|
1653
1657
|
_lastUpdaterId: this.updaterId
|
|
1654
1658
|
};
|
|
1655
1659
|
this.schedulePendingChange(collection, id, newData, 0, "insert");
|
|
1656
|
-
this.
|
|
1660
|
+
this._writeToInMemBatch(collection, [this.stripLocalFields(newData)], "upsert");
|
|
1657
1661
|
return this.stripLocalFields(newData);
|
|
1658
1662
|
}
|
|
1659
1663
|
async deleteOne(collection, id) {
|
|
@@ -1668,7 +1672,7 @@ class SyncedDb {
|
|
|
1668
1672
|
_lastUpdaterId: this.updaterId
|
|
1669
1673
|
};
|
|
1670
1674
|
this.schedulePendingChange(collection, id, deleteUpdate, 0, "deleteOne");
|
|
1671
|
-
this.
|
|
1675
|
+
this._writeToInMemBatch(collection, [{ _id: id }], "delete");
|
|
1672
1676
|
return this.stripLocalFields(existing);
|
|
1673
1677
|
}
|
|
1674
1678
|
async deleteMany(collection, query) {
|
|
@@ -1702,7 +1706,7 @@ class SyncedDb {
|
|
|
1702
1706
|
await this.dexieDb.addDirtyChangesBatch(collection, dirtyChangesBatch);
|
|
1703
1707
|
}
|
|
1704
1708
|
if (idsToDelete.length > 0) {
|
|
1705
|
-
this.
|
|
1709
|
+
this._writeToInMemBatch(collection, idsToDelete.map((id) => ({ _id: id })), "delete");
|
|
1706
1710
|
}
|
|
1707
1711
|
return idsToDelete.length;
|
|
1708
1712
|
}
|
|
@@ -1717,7 +1721,7 @@ class SyncedDb {
|
|
|
1717
1721
|
}
|
|
1718
1722
|
await this.withRestTimeout(this.restInterface.deleteOne(collection, { _id: id }), "hardDeleteOne");
|
|
1719
1723
|
await this.dexieDb.deleteOne(collection, id);
|
|
1720
|
-
this.
|
|
1724
|
+
this._writeToInMemBatch(collection, [{ _id: id }], "delete");
|
|
1721
1725
|
return this.stripLocalFields(existing);
|
|
1722
1726
|
}
|
|
1723
1727
|
async hardDelete(collection, query) {
|
|
@@ -1750,7 +1754,7 @@ class SyncedDb {
|
|
|
1750
1754
|
try {
|
|
1751
1755
|
await this.withRestTimeout(this.restInterface.deleteOne(collection, { _id: item.id }), "hardDelete");
|
|
1752
1756
|
await this.dexieDb.deleteOne(collection, item.id);
|
|
1753
|
-
this.
|
|
1757
|
+
this._writeToInMemBatch(collection, [{ _id: item.id }], "delete");
|
|
1754
1758
|
results.push(true);
|
|
1755
1759
|
} catch (err) {
|
|
1756
1760
|
console.error(`Failed to hard delete ${String(item.id)}:`, err);
|
|
@@ -1970,7 +1974,7 @@ class SyncedDb {
|
|
|
1970
1974
|
}
|
|
1971
1975
|
}
|
|
1972
1976
|
await this.dexieDb.deleteCollection(collection);
|
|
1973
|
-
this.
|
|
1977
|
+
this._clearCollectionInMem(collection);
|
|
1974
1978
|
await this.dexieDb.deleteSyncMeta(collection);
|
|
1975
1979
|
await this.dexieDb.clearDirtyChanges(collection);
|
|
1976
1980
|
this.syncMetaCache.delete(collection);
|
|
@@ -2005,7 +2009,7 @@ class SyncedDb {
|
|
|
2005
2009
|
}
|
|
2006
2010
|
for (const collectionName of collectionNames) {
|
|
2007
2011
|
await this.dexieDb.deleteCollection(collectionName);
|
|
2008
|
-
this.
|
|
2012
|
+
this._clearCollectionInMem(collectionName);
|
|
2009
2013
|
await this.dexieDb.deleteSyncMeta(collectionName);
|
|
2010
2014
|
await this.dexieDb.clearDirtyChanges(collectionName);
|
|
2011
2015
|
}
|
|
@@ -2019,6 +2023,75 @@ class SyncedDb {
|
|
|
2019
2023
|
stripLocalFields(item) {
|
|
2020
2024
|
return item;
|
|
2021
2025
|
}
|
|
2026
|
+
_writeToInMemBatch(collection, items, operation) {
|
|
2027
|
+
if (items.length === 0)
|
|
2028
|
+
return;
|
|
2029
|
+
const config = this.collections.get(collection);
|
|
2030
|
+
if (operation === "upsert") {
|
|
2031
|
+
this.inMemDb.saveMany(collection, items);
|
|
2032
|
+
if (this.useObjectMetadata && config?.hasMetadata) {
|
|
2033
|
+
const ids = items.map((item) => item._id);
|
|
2034
|
+
let metadatas;
|
|
2035
|
+
if (config.onObjectsUpdated) {
|
|
2036
|
+
metadatas = config.onObjectsUpdated(items);
|
|
2037
|
+
} else if (config.onObjectUpdated) {
|
|
2038
|
+
metadatas = items.map((item) => config.onObjectUpdated(item));
|
|
2039
|
+
} else {
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
this._setObjectsMetadataInternal(collection, ids, metadatas);
|
|
2043
|
+
}
|
|
2044
|
+
} else if (operation === "delete") {
|
|
2045
|
+
const ids = items.map((item) => item._id);
|
|
2046
|
+
this.inMemDb.deleteManyByIds(collection, ids);
|
|
2047
|
+
if (this.useObjectMetadata && config?.hasMetadata) {
|
|
2048
|
+
this._deleteObjectsMetadataInternal(collection, ids);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
_initCollectionInMem(collection, items) {
|
|
2053
|
+
this.inMemDb.saveCollection(collection, items);
|
|
2054
|
+
if (this.useObjectMetadata && items.length > 0) {
|
|
2055
|
+
const config = this.collections.get(collection);
|
|
2056
|
+
if (config?.hasMetadata) {
|
|
2057
|
+
const ids = items.map((item) => item._id);
|
|
2058
|
+
let metadatas;
|
|
2059
|
+
if (config.onObjectsUpdated) {
|
|
2060
|
+
metadatas = config.onObjectsUpdated(items);
|
|
2061
|
+
} else if (config.onObjectUpdated) {
|
|
2062
|
+
metadatas = items.map((item) => config.onObjectUpdated(item));
|
|
2063
|
+
} else {
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
this._setObjectsMetadataInternal(collection, ids, metadatas);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
_clearCollectionInMem(collection) {
|
|
2071
|
+
this.inMemDb.deleteCollection(collection);
|
|
2072
|
+
if (this.useObjectMetadata) {
|
|
2073
|
+
this._metadata[collection]?.clear();
|
|
2074
|
+
delete this._metadata[collection];
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
_setObjectsMetadataInternal(collection, ids, metadatas) {
|
|
2078
|
+
let map = this._metadata[collection];
|
|
2079
|
+
if (!map) {
|
|
2080
|
+
map = new Map;
|
|
2081
|
+
this._metadata[collection] = map;
|
|
2082
|
+
}
|
|
2083
|
+
for (let i = 0;i < ids.length; i++) {
|
|
2084
|
+
map.set(String(ids[i]), metadatas[i]);
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
_deleteObjectsMetadataInternal(collection, ids) {
|
|
2088
|
+
const map = this._metadata[collection];
|
|
2089
|
+
if (map) {
|
|
2090
|
+
for (const id of ids) {
|
|
2091
|
+
map.delete(String(id));
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2022
2095
|
getPendingKey(collection, id) {
|
|
2023
2096
|
return `${collection}:${String(id)}`;
|
|
2024
2097
|
}
|
|
@@ -2232,6 +2305,7 @@ class SyncedDb {
|
|
|
2232
2305
|
const idsToUpdate = insertedAndUpdated.map((e) => e._id);
|
|
2233
2306
|
const existingItems = await this.dexieDb.getByIds(collection, idsToUpdate);
|
|
2234
2307
|
const dexieSaveBatch = [];
|
|
2308
|
+
const inMemUpdateBatch = [];
|
|
2235
2309
|
for (let i = 0;i < insertedAndUpdated.length; i++) {
|
|
2236
2310
|
const entity = insertedAndUpdated[i];
|
|
2237
2311
|
const existing = existingItems[i];
|
|
@@ -2242,20 +2316,27 @@ class SyncedDb {
|
|
|
2242
2316
|
_ts: entity._ts
|
|
2243
2317
|
});
|
|
2244
2318
|
}
|
|
2245
|
-
this.inMemDb.
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2319
|
+
const inMemItem = this.inMemDb.getById(collection, entity._id);
|
|
2320
|
+
if (inMemItem) {
|
|
2321
|
+
inMemUpdateBatch.push({
|
|
2322
|
+
...inMemItem,
|
|
2323
|
+
_rev: entity._rev,
|
|
2324
|
+
_ts: entity._ts
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2249
2327
|
}
|
|
2250
2328
|
if (dexieSaveBatch.length > 0) {
|
|
2251
2329
|
await this.dexieDb.saveMany(collection, dexieSaveBatch);
|
|
2252
2330
|
}
|
|
2331
|
+
if (inMemUpdateBatch.length > 0) {
|
|
2332
|
+
this._writeToInMemBatch(collection, inMemUpdateBatch, "upsert");
|
|
2333
|
+
}
|
|
2253
2334
|
sentCount += insertedAndUpdated.length;
|
|
2254
2335
|
}
|
|
2255
2336
|
if (deleted.length > 0) {
|
|
2256
2337
|
const deleteIds = deleted.map((e) => e._id);
|
|
2257
2338
|
await this.dexieDb.deleteMany(collection, deleteIds);
|
|
2258
|
-
this.
|
|
2339
|
+
this._writeToInMemBatch(collection, deleteIds.map((id) => ({ _id: id })), "delete");
|
|
2259
2340
|
sentCount += deleted.length;
|
|
2260
2341
|
}
|
|
2261
2342
|
const allItems = [...inserted, ...updated, ...deleted];
|
|
@@ -2380,10 +2461,10 @@ class SyncedDb {
|
|
|
2380
2461
|
await this.dexieDb.saveMany(collectionName, dexieBatch);
|
|
2381
2462
|
}
|
|
2382
2463
|
if (inMemSaveBatch.length > 0) {
|
|
2383
|
-
this.
|
|
2464
|
+
this._writeToInMemBatch(collectionName, inMemSaveBatch, "upsert");
|
|
2384
2465
|
}
|
|
2385
2466
|
if (inMemDeleteIds.length > 0) {
|
|
2386
|
-
this.
|
|
2467
|
+
this._writeToInMemBatch(collectionName, inMemDeleteIds.map((id) => ({ _id: id })), "delete");
|
|
2387
2468
|
}
|
|
2388
2469
|
if (maxTs) {
|
|
2389
2470
|
await this.dexieDb.setSyncMeta(collectionName, maxTs);
|
|
@@ -2517,18 +2598,28 @@ class SyncedDb {
|
|
|
2517
2598
|
if (dexieSaveBatch.length > 0) {
|
|
2518
2599
|
await this.dexieDb.saveMany(collection, dexieSaveBatch);
|
|
2519
2600
|
}
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2601
|
+
if (inMemSaveIds.length > 0) {
|
|
2602
|
+
const inMemUpdateBatch = [];
|
|
2603
|
+
for (const item of inMemSaveIds) {
|
|
2604
|
+
const inMemItem = this.inMemDb.getById(collection, item.id);
|
|
2605
|
+
if (inMemItem) {
|
|
2606
|
+
inMemUpdateBatch.push({
|
|
2607
|
+
...inMemItem,
|
|
2608
|
+
_rev: item.rev,
|
|
2609
|
+
_ts: item.ts
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
if (inMemUpdateBatch.length > 0) {
|
|
2614
|
+
this._writeToInMemBatch(collection, inMemUpdateBatch, "upsert");
|
|
2615
|
+
}
|
|
2525
2616
|
}
|
|
2526
2617
|
sentCount += insertedAndUpdated.length;
|
|
2527
2618
|
}
|
|
2528
2619
|
if (deleted.length > 0) {
|
|
2529
2620
|
const deleteIds = deleted.map((e) => e._id);
|
|
2530
2621
|
await this.dexieDb.deleteMany(collection, deleteIds);
|
|
2531
|
-
this.
|
|
2622
|
+
this._writeToInMemBatch(collection, deleteIds.map((id) => ({ _id: id })), "delete");
|
|
2532
2623
|
sentCount += deleted.length;
|
|
2533
2624
|
}
|
|
2534
2625
|
const allItems = [...inserted, ...updated, ...deleted];
|
|
@@ -2658,17 +2749,30 @@ class SyncedDb {
|
|
|
2658
2749
|
}
|
|
2659
2750
|
try {
|
|
2660
2751
|
const items = await this.dexieDb.getByIds(collection, ids);
|
|
2752
|
+
const upsertBatch = [];
|
|
2753
|
+
const deleteBatch = [];
|
|
2661
2754
|
let newItemsCount = 0;
|
|
2662
|
-
for (
|
|
2663
|
-
|
|
2755
|
+
for (let i = 0;i < ids.length; i++) {
|
|
2756
|
+
const item = items[i];
|
|
2757
|
+
const id = ids[i];
|
|
2758
|
+
if (!item) {
|
|
2759
|
+
deleteBatch.push({ _id: id });
|
|
2760
|
+
newItemsCount++;
|
|
2664
2761
|
continue;
|
|
2762
|
+
}
|
|
2665
2763
|
if (item._deleted) {
|
|
2666
|
-
|
|
2764
|
+
deleteBatch.push({ _id: item._id });
|
|
2667
2765
|
} else {
|
|
2668
|
-
|
|
2766
|
+
upsertBatch.push(this.stripLocalFields(item));
|
|
2669
2767
|
}
|
|
2670
2768
|
newItemsCount++;
|
|
2671
2769
|
}
|
|
2770
|
+
if (upsertBatch.length > 0) {
|
|
2771
|
+
this._writeToInMemBatch(collection, upsertBatch, "upsert");
|
|
2772
|
+
}
|
|
2773
|
+
if (deleteBatch.length > 0) {
|
|
2774
|
+
this._writeToInMemBatch(collection, deleteBatch, "delete");
|
|
2775
|
+
}
|
|
2672
2776
|
if (this.onCrossTabSync && newItemsCount > 0) {
|
|
2673
2777
|
try {
|
|
2674
2778
|
this.onCrossTabSync(collection, newItemsCount);
|
|
@@ -2786,13 +2890,13 @@ class SyncedDb {
|
|
|
2786
2890
|
if (!serverItem._deleted) {
|
|
2787
2891
|
const memItem = this.inMemDb.getById(collectionName, serverItem._id);
|
|
2788
2892
|
if (!memItem) {
|
|
2789
|
-
this.
|
|
2893
|
+
this._writeToInMemBatch(collectionName, [this.stripLocalFields(serverItem)], "upsert");
|
|
2790
2894
|
}
|
|
2791
2895
|
}
|
|
2792
2896
|
} else {
|
|
2793
2897
|
await this.dexieDb.insert(collectionName, serverItem);
|
|
2794
2898
|
if (!serverItem._deleted) {
|
|
2795
|
-
this.
|
|
2899
|
+
this._writeToInMemBatch(collectionName, [this.stripLocalFields(serverItem)], "upsert");
|
|
2796
2900
|
}
|
|
2797
2901
|
}
|
|
2798
2902
|
}
|
|
@@ -2816,7 +2920,7 @@ class SyncedDb {
|
|
|
2816
2920
|
if (currentMemItem) {
|
|
2817
2921
|
const merged = this.mergeLocalWithDelta(currentMemItem, serverDelta);
|
|
2818
2922
|
if (!merged._deleted) {
|
|
2819
|
-
this.
|
|
2923
|
+
this._writeToInMemBatch(collectionName, [this.stripLocalFields(merged)], "upsert");
|
|
2820
2924
|
}
|
|
2821
2925
|
pendingChange.data = {
|
|
2822
2926
|
...pendingChange.data,
|
|
@@ -2833,7 +2937,7 @@ class SyncedDb {
|
|
|
2833
2937
|
await this.dexieDb.save(collectionName, serverDelta._id, merged);
|
|
2834
2938
|
}
|
|
2835
2939
|
if (!merged._deleted) {
|
|
2836
|
-
this.
|
|
2940
|
+
this._writeToInMemBatch(collectionName, [this.stripLocalFields(merged)], "upsert");
|
|
2837
2941
|
}
|
|
2838
2942
|
} else {
|
|
2839
2943
|
if (!metaChanged) {
|
|
@@ -2842,9 +2946,9 @@ class SyncedDb {
|
|
|
2842
2946
|
const merged = this.mergeLocalWithDelta(localItem, serverDelta);
|
|
2843
2947
|
await this.dexieDb.save(collectionName, serverDelta._id, merged);
|
|
2844
2948
|
if (!merged._deleted) {
|
|
2845
|
-
this.
|
|
2949
|
+
this._writeToInMemBatch(collectionName, [this.stripLocalFields(merged)], "upsert");
|
|
2846
2950
|
} else {
|
|
2847
|
-
this.
|
|
2951
|
+
this._writeToInMemBatch(collectionName, [{ _id: serverDelta._id }], "delete");
|
|
2848
2952
|
}
|
|
2849
2953
|
}
|
|
2850
2954
|
}
|
|
@@ -2879,7 +2983,48 @@ class SyncedDb {
|
|
|
2879
2983
|
} else {
|
|
2880
2984
|
await this.dexieDb.deleteOne(collectionName, id);
|
|
2881
2985
|
}
|
|
2882
|
-
this.
|
|
2986
|
+
this._writeToInMemBatch(collectionName, [{ _id: id }], "delete");
|
|
2987
|
+
}
|
|
2988
|
+
getObjectMetadata(collection, _id) {
|
|
2989
|
+
return this._metadata[collection]?.get(String(_id));
|
|
2990
|
+
}
|
|
2991
|
+
getObjectsMetadata(collection, _ids) {
|
|
2992
|
+
const map = this._metadata[collection];
|
|
2993
|
+
if (!map) {
|
|
2994
|
+
return _ids.map(() => {
|
|
2995
|
+
return;
|
|
2996
|
+
});
|
|
2997
|
+
}
|
|
2998
|
+
return _ids.map((_id) => map.get(String(_id)));
|
|
2999
|
+
}
|
|
3000
|
+
setObjectMetadata(collection, _id, metadata) {
|
|
3001
|
+
let map = this._metadata[collection];
|
|
3002
|
+
if (!map) {
|
|
3003
|
+
map = new Map;
|
|
3004
|
+
this._metadata[collection] = map;
|
|
3005
|
+
}
|
|
3006
|
+
map.set(String(_id), metadata);
|
|
3007
|
+
}
|
|
3008
|
+
setObjectsMetadata(collection, _ids, metadatas) {
|
|
3009
|
+
let map = this._metadata[collection];
|
|
3010
|
+
if (!map) {
|
|
3011
|
+
map = new Map;
|
|
3012
|
+
this._metadata[collection] = map;
|
|
3013
|
+
}
|
|
3014
|
+
for (let i = 0;i < _ids.length; i++) {
|
|
3015
|
+
map.set(String(_ids[i]), metadatas[i]);
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
deleteObjectMetadata(collection, _id) {
|
|
3019
|
+
this._metadata[collection]?.delete(String(_id));
|
|
3020
|
+
}
|
|
3021
|
+
deleteObjectsMetadata(collection, _ids) {
|
|
3022
|
+
const map = this._metadata[collection];
|
|
3023
|
+
if (map) {
|
|
3024
|
+
for (const _id of _ids) {
|
|
3025
|
+
map.delete(String(_id));
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
2883
3028
|
}
|
|
2884
3029
|
}
|
|
2885
3030
|
// src/db/DexieDb.ts
|
|
@@ -81,6 +81,10 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
81
81
|
private releasingLeadershipDueToVisibility;
|
|
82
82
|
/** Visibility change handler reference for cleanup */
|
|
83
83
|
private visibilityChangeHandler?;
|
|
84
|
+
/** Whether object metadata feature is enabled */
|
|
85
|
+
private useObjectMetadata;
|
|
86
|
+
/** In-memory metadata store: collection -> (_id -> metadata) */
|
|
87
|
+
private _metadata;
|
|
84
88
|
constructor(config: SyncedDbConfig);
|
|
85
89
|
/** Get the unique instance ID for this SyncedDb */
|
|
86
90
|
getInstanceId(): string;
|
|
@@ -181,6 +185,27 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
181
185
|
dropDatabase(force?: boolean): Promise<void>;
|
|
182
186
|
private assertCollection;
|
|
183
187
|
private stripLocalFields;
|
|
188
|
+
/**
|
|
189
|
+
* Centralized method for ALL in-mem writes.
|
|
190
|
+
* Handles metadata callbacks automatically when useObjectMetadata is enabled.
|
|
191
|
+
*
|
|
192
|
+
* @param collection - Collection name
|
|
193
|
+
* @param items - Objects to write (for upsert) or objects with _id (for delete)
|
|
194
|
+
* @param operation - 'upsert' to save/update, 'delete' to remove
|
|
195
|
+
*/
|
|
196
|
+
private _writeToInMemBatch;
|
|
197
|
+
/**
|
|
198
|
+
* Initialize a collection in in-mem from Dexie data.
|
|
199
|
+
* Called during init().
|
|
200
|
+
*/
|
|
201
|
+
private _initCollectionInMem;
|
|
202
|
+
/**
|
|
203
|
+
* Clear all data and metadata for a collection.
|
|
204
|
+
* Used by dropCollection().
|
|
205
|
+
*/
|
|
206
|
+
private _clearCollectionInMem;
|
|
207
|
+
private _setObjectsMetadataInternal;
|
|
208
|
+
private _deleteObjectsMetadataInternal;
|
|
184
209
|
private getPendingKey;
|
|
185
210
|
private schedulePendingChange;
|
|
186
211
|
private executePendingChange;
|
|
@@ -262,4 +287,10 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
262
287
|
*/
|
|
263
288
|
private mergeLocalWithDelta;
|
|
264
289
|
private handleServerItemDelete;
|
|
290
|
+
getObjectMetadata<M>(collection: string, _id: Id): M | undefined;
|
|
291
|
+
getObjectsMetadata<M>(collection: string, _ids: Id[]): (M | undefined)[];
|
|
292
|
+
setObjectMetadata<M>(collection: string, _id: Id, metadata: M): void;
|
|
293
|
+
setObjectsMetadata<M>(collection: string, _ids: Id[], metadatas: M[]): void;
|
|
294
|
+
deleteObjectMetadata(collection: string, _id: Id): void;
|
|
295
|
+
deleteObjectsMetadata(collection: string, _ids: Id[]): void;
|
|
265
296
|
}
|
|
@@ -201,13 +201,19 @@ export interface SyncInfo {
|
|
|
201
201
|
/**
|
|
202
202
|
* Konfiguracija za posamezno kolekcijo
|
|
203
203
|
*/
|
|
204
|
-
export interface CollectionConfig<T extends DbEntity = any> {
|
|
204
|
+
export interface CollectionConfig<T extends DbEntity = any, M = any> {
|
|
205
205
|
/** Ime kolekcije */
|
|
206
206
|
name: string;
|
|
207
207
|
/** Opcijski filter za velike tabele - omeji obseg sinhronizacije */
|
|
208
208
|
query?: QuerySpec<any>;
|
|
209
209
|
/** Opcijska funkcija za razreševanje konfliktov */
|
|
210
210
|
resolveSyncConflict?(local: T, external: T): T;
|
|
211
|
+
/** Whether this collection uses in-memory metadata */
|
|
212
|
+
hasMetadata?: boolean;
|
|
213
|
+
/** Callback called when a single object is written to in-mem. Returns metadata to store. */
|
|
214
|
+
onObjectUpdated?(object: T): M;
|
|
215
|
+
/** Callback called when multiple objects are written to in-mem. Returns metadata array (same order as input). */
|
|
216
|
+
onObjectsUpdated?(objects: T[]): M[];
|
|
211
217
|
}
|
|
212
218
|
/**
|
|
213
219
|
* Konfiguracija za SyncedDb - dependencies so podani kot parametri (DI)
|
|
@@ -284,6 +290,12 @@ export interface SyncedDbConfig {
|
|
|
284
290
|
* Client code can use this to show warnings, log telemetry, or adjust behavior.
|
|
285
291
|
*/
|
|
286
292
|
onInfrastructureError?: (info: InfrastructureErrorInfo) => void;
|
|
293
|
+
/**
|
|
294
|
+
* Enable in-memory object metadata feature.
|
|
295
|
+
* When true, collections with hasMetadata=true will have their metadata callbacks invoked
|
|
296
|
+
* whenever objects are written to in-mem. Default: false.
|
|
297
|
+
*/
|
|
298
|
+
useObjectMetadata?: boolean;
|
|
287
299
|
}
|
|
288
300
|
/**
|
|
289
301
|
* Glavna logika za sinhronizirano bazo podatkov
|
|
@@ -434,4 +446,46 @@ export interface I_SyncedDb {
|
|
|
434
446
|
* @returns true if this instance holds the leader lock
|
|
435
447
|
*/
|
|
436
448
|
isLeaderTab(): boolean;
|
|
449
|
+
/**
|
|
450
|
+
* Get metadata for a single object.
|
|
451
|
+
* @param collection Collection name
|
|
452
|
+
* @param _id Object ID
|
|
453
|
+
* @returns Metadata for the object, or undefined if not found
|
|
454
|
+
*/
|
|
455
|
+
getObjectMetadata<M>(collection: string, _id: Id): M | undefined;
|
|
456
|
+
/**
|
|
457
|
+
* Get metadata for multiple objects.
|
|
458
|
+
* @param collection Collection name
|
|
459
|
+
* @param _ids Object IDs
|
|
460
|
+
* @returns Array of metadata in same order as input _ids (undefined for missing)
|
|
461
|
+
*/
|
|
462
|
+
getObjectsMetadata<M>(collection: string, _ids: Id[]): (M | undefined)[];
|
|
463
|
+
/**
|
|
464
|
+
* Manually set metadata for a single object.
|
|
465
|
+
* Rarely needed - metadata callbacks handle this automatically.
|
|
466
|
+
* @param collection Collection name
|
|
467
|
+
* @param _id Object ID
|
|
468
|
+
* @param metadata Metadata to store
|
|
469
|
+
*/
|
|
470
|
+
setObjectMetadata<M>(collection: string, _id: Id, metadata: M): void;
|
|
471
|
+
/**
|
|
472
|
+
* Manually set metadata for multiple objects.
|
|
473
|
+
* Rarely needed - metadata callbacks handle this automatically.
|
|
474
|
+
* @param collection Collection name
|
|
475
|
+
* @param _ids Object IDs
|
|
476
|
+
* @param metadatas Metadata array (same order as _ids)
|
|
477
|
+
*/
|
|
478
|
+
setObjectsMetadata<M>(collection: string, _ids: Id[], metadatas: M[]): void;
|
|
479
|
+
/**
|
|
480
|
+
* Delete metadata for a single object.
|
|
481
|
+
* @param collection Collection name
|
|
482
|
+
* @param _id Object ID
|
|
483
|
+
*/
|
|
484
|
+
deleteObjectMetadata(collection: string, _id: Id): void;
|
|
485
|
+
/**
|
|
486
|
+
* Delete metadata for multiple objects.
|
|
487
|
+
* @param collection Collection name
|
|
488
|
+
* @param _ids Object IDs
|
|
489
|
+
*/
|
|
490
|
+
deleteObjectsMetadata(collection: string, _ids: Id[]): void;
|
|
437
491
|
}
|