@verdant-web/store 2.5.8 → 2.7.0
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/bundle/index.js +15 -10
- package/dist/bundle/index.js.map +4 -4
- package/dist/cjs/{entities/FakeWeakRef.d.ts → FakeWeakRef.d.ts} +2 -2
- package/dist/cjs/{entities/FakeWeakRef.js → FakeWeakRef.js} +4 -4
- package/dist/cjs/FakeWeakRef.js.map +1 -0
- package/dist/cjs/IDBService.d.ts +1 -1
- package/dist/cjs/IDBService.js +18 -1
- package/dist/cjs/IDBService.js.map +1 -1
- package/dist/cjs/__tests__/documents.test.js +17 -0
- package/dist/cjs/__tests__/documents.test.js.map +1 -1
- package/dist/cjs/__tests__/fixtures/testStorage.d.ts +1 -1
- package/dist/cjs/__tests__/fixtures/testStorage.js +3 -2
- package/dist/cjs/__tests__/fixtures/testStorage.js.map +1 -1
- package/dist/cjs/__tests__/mutations.test.d.ts +1 -0
- package/dist/cjs/__tests__/mutations.test.js +42 -0
- package/dist/cjs/__tests__/mutations.test.js.map +1 -0
- package/dist/cjs/__tests__/queries.test.js +2 -0
- package/dist/cjs/__tests__/queries.test.js.map +1 -1
- package/dist/cjs/client/Client.d.ts +6 -4
- package/dist/cjs/client/Client.js +24 -16
- package/dist/cjs/client/Client.js.map +1 -1
- package/dist/cjs/client/ClientDescriptor.d.ts +15 -4
- package/dist/cjs/client/ClientDescriptor.js +117 -36
- package/dist/cjs/client/ClientDescriptor.js.map +1 -1
- package/dist/cjs/context.d.ts +1 -0
- package/dist/cjs/entities/DocumentFamiliyCache.d.ts +22 -2
- package/dist/cjs/entities/DocumentFamiliyCache.js +39 -21
- package/dist/cjs/entities/DocumentFamiliyCache.js.map +1 -1
- package/dist/cjs/entities/Entity.d.ts +7 -2
- package/dist/cjs/entities/Entity.js +33 -3
- package/dist/cjs/entities/Entity.js.map +1 -1
- package/dist/cjs/entities/EntityStore.d.ts +2 -1
- package/dist/cjs/entities/EntityStore.js +50 -20
- package/dist/cjs/entities/EntityStore.js.map +1 -1
- package/dist/cjs/idb.d.ts +2 -0
- package/dist/cjs/idb.js +9 -1
- package/dist/cjs/idb.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/metadata/BaselinesStore.js +15 -5
- package/dist/cjs/metadata/BaselinesStore.js.map +1 -1
- package/dist/cjs/metadata/openMetadataDatabase.d.ts +11 -2
- package/dist/cjs/metadata/openMetadataDatabase.js +56 -3
- package/dist/cjs/metadata/openMetadataDatabase.js.map +1 -1
- package/dist/cjs/migration/db.d.ts +1 -1
- package/dist/cjs/migration/db.js +5 -2
- package/dist/cjs/migration/db.js.map +1 -1
- package/dist/cjs/migration/openDatabase.d.ts +8 -0
- package/dist/cjs/migration/openDatabase.js +217 -165
- package/dist/cjs/migration/openDatabase.js.map +1 -1
- package/dist/cjs/queries/BaseQuery.js +12 -1
- package/dist/cjs/queries/BaseQuery.js.map +1 -1
- package/dist/cjs/sync/Sync.d.ts +6 -5
- package/dist/cjs/sync/Sync.js.map +1 -1
- package/dist/cjs/sync/WebSocketSync.js +4 -3
- package/dist/cjs/sync/WebSocketSync.js.map +1 -1
- package/dist/esm/{entities/FakeWeakRef.d.ts → FakeWeakRef.d.ts} +2 -2
- package/dist/esm/{entities/FakeWeakRef.js → FakeWeakRef.js} +2 -2
- package/dist/esm/FakeWeakRef.js.map +1 -0
- package/dist/esm/IDBService.d.ts +1 -1
- package/dist/esm/IDBService.js +18 -1
- package/dist/esm/IDBService.js.map +1 -1
- package/dist/esm/__tests__/documents.test.js +17 -0
- package/dist/esm/__tests__/documents.test.js.map +1 -1
- package/dist/esm/__tests__/fixtures/testStorage.d.ts +1 -1
- package/dist/esm/__tests__/fixtures/testStorage.js +4 -3
- package/dist/esm/__tests__/fixtures/testStorage.js.map +1 -1
- package/dist/esm/__tests__/mutations.test.d.ts +1 -0
- package/dist/esm/__tests__/mutations.test.js +40 -0
- package/dist/esm/__tests__/mutations.test.js.map +1 -0
- package/dist/esm/__tests__/queries.test.js +2 -0
- package/dist/esm/__tests__/queries.test.js.map +1 -1
- package/dist/esm/client/Client.d.ts +6 -4
- package/dist/esm/client/Client.js +25 -17
- package/dist/esm/client/Client.js.map +1 -1
- package/dist/esm/client/ClientDescriptor.d.ts +15 -4
- package/dist/esm/client/ClientDescriptor.js +121 -40
- package/dist/esm/client/ClientDescriptor.js.map +1 -1
- package/dist/esm/context.d.ts +1 -0
- package/dist/esm/entities/DocumentFamiliyCache.d.ts +22 -2
- package/dist/esm/entities/DocumentFamiliyCache.js +39 -21
- package/dist/esm/entities/DocumentFamiliyCache.js.map +1 -1
- package/dist/esm/entities/Entity.d.ts +7 -2
- package/dist/esm/entities/Entity.js +33 -3
- package/dist/esm/entities/Entity.js.map +1 -1
- package/dist/esm/entities/EntityStore.d.ts +2 -1
- package/dist/esm/entities/EntityStore.js +51 -21
- package/dist/esm/entities/EntityStore.js.map +1 -1
- package/dist/esm/idb.d.ts +2 -0
- package/dist/esm/idb.js +6 -0
- package/dist/esm/idb.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/metadata/BaselinesStore.js +16 -6
- package/dist/esm/metadata/BaselinesStore.js.map +1 -1
- package/dist/esm/metadata/openMetadataDatabase.d.ts +11 -2
- package/dist/esm/metadata/openMetadataDatabase.js +54 -2
- package/dist/esm/metadata/openMetadataDatabase.js.map +1 -1
- package/dist/esm/migration/db.d.ts +1 -1
- package/dist/esm/migration/db.js +5 -2
- package/dist/esm/migration/db.js.map +1 -1
- package/dist/esm/migration/openDatabase.d.ts +8 -0
- package/dist/esm/migration/openDatabase.js +215 -164
- package/dist/esm/migration/openDatabase.js.map +1 -1
- package/dist/esm/queries/BaseQuery.js +12 -1
- package/dist/esm/queries/BaseQuery.js.map +1 -1
- package/dist/esm/sync/Sync.d.ts +6 -5
- package/dist/esm/sync/Sync.js.map +1 -1
- package/dist/esm/sync/WebSocketSync.js +4 -3
- package/dist/esm/sync/WebSocketSync.js.map +1 -1
- package/dist/tsconfig-cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -4
- package/src/{entities/FakeWeakRef.ts → FakeWeakRef.ts} +2 -2
- package/src/IDBService.ts +20 -2
- package/src/__tests__/documents.test.ts +19 -0
- package/src/__tests__/fixtures/testStorage.ts +4 -7
- package/src/__tests__/mutations.test.ts +51 -0
- package/src/__tests__/queries.test.ts +3 -0
- package/src/client/Client.ts +29 -21
- package/src/client/ClientDescriptor.ts +176 -53
- package/src/context.ts +1 -0
- package/src/entities/DocumentFamiliyCache.ts +66 -21
- package/src/entities/Entity.ts +41 -6
- package/src/entities/EntityStore.ts +68 -21
- package/src/idb.ts +10 -0
- package/src/index.ts +1 -0
- package/src/metadata/BaselinesStore.ts +17 -6
- package/src/metadata/openMetadataDatabase.ts +96 -13
- package/src/migration/db.ts +14 -1
- package/src/migration/openDatabase.ts +350 -219
- package/src/queries/BaseQuery.ts +14 -1
- package/src/sync/Sync.ts +13 -9
- package/src/sync/WebSocketSync.ts +1 -0
- package/dist/cjs/entities/FakeWeakRef.js.map +0 -1
- package/dist/cjs/indexes.d.ts +0 -3
- package/dist/cjs/indexes.js +0 -20
- package/dist/cjs/indexes.js.map +0 -1
- package/dist/esm/entities/FakeWeakRef.js.map +0 -1
- package/dist/esm/indexes.d.ts +0 -3
- package/dist/esm/indexes.js +0 -15
- package/dist/esm/indexes.js.map +0 -1
- package/src/indexes.ts +0 -31
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
DocumentBaseline,
|
|
10
10
|
EventSubscriber,
|
|
11
11
|
generateId,
|
|
12
|
+
getIndexValues,
|
|
12
13
|
getOidRoot,
|
|
13
14
|
getUndoOperations,
|
|
14
15
|
groupBaselinesByRootOid,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
Operation,
|
|
19
20
|
removeOidsFromAllSubObjects,
|
|
20
21
|
StorageCollectionSchema,
|
|
22
|
+
StorageObjectFieldSchema,
|
|
21
23
|
} from '@verdant-web/common';
|
|
22
24
|
import { Context } from '../context.js';
|
|
23
25
|
import { FileManager } from '../files/FileManager.js';
|
|
@@ -98,24 +100,37 @@ export class EntityStore {
|
|
|
98
100
|
this.context = context;
|
|
99
101
|
};
|
|
100
102
|
|
|
101
|
-
private getDocumentSchema = (
|
|
103
|
+
private getDocumentSchema = (
|
|
104
|
+
oid: ObjectIdentifier,
|
|
105
|
+
): { schema: StorageObjectFieldSchema | null; readonlyKeys: string[] } => {
|
|
102
106
|
const { collection } = decomposeOid(oid);
|
|
103
107
|
if (!this.schema.collections[collection]) {
|
|
104
108
|
this.log('warn', `Missing schema for collection: ${collection}`);
|
|
105
|
-
return null;
|
|
109
|
+
return { schema: null, readonlyKeys: [] };
|
|
106
110
|
}
|
|
111
|
+
const schema = this.schema.collections[collection];
|
|
107
112
|
return {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
readonlyKeys: [schema.primaryKey],
|
|
114
|
+
schema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: schema.fields as any,
|
|
117
|
+
} as const,
|
|
118
|
+
};
|
|
111
119
|
};
|
|
112
120
|
|
|
113
121
|
private refreshFamilyCache = async (
|
|
114
122
|
familyCache: DocumentFamilyCache,
|
|
115
123
|
dropUnconfirmed = false,
|
|
124
|
+
dropAll = false,
|
|
116
125
|
) => {
|
|
117
126
|
// avoid writing to disposed db
|
|
118
|
-
if (this._disposed)
|
|
127
|
+
if (this._disposed) {
|
|
128
|
+
this.context.log(
|
|
129
|
+
'debug',
|
|
130
|
+
`EntityStore is disposed, not refreshing ${familyCache.oid} cache`,
|
|
131
|
+
);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
119
134
|
|
|
120
135
|
// metadata must be loaded from database to initialize family cache
|
|
121
136
|
const transaction = this.meta.createTransaction([
|
|
@@ -146,21 +161,40 @@ export class EntityStore {
|
|
|
146
161
|
{ transaction, mode: 'readwrite' },
|
|
147
162
|
),
|
|
148
163
|
]);
|
|
149
|
-
familyCache.reset(
|
|
164
|
+
familyCache.reset({
|
|
165
|
+
operations,
|
|
166
|
+
baselines,
|
|
167
|
+
dropExistingUnconfirmed: dropUnconfirmed,
|
|
168
|
+
dropAll,
|
|
169
|
+
});
|
|
150
170
|
};
|
|
151
171
|
|
|
152
172
|
private openFamilyCache = async (oid: ObjectIdentifier) => {
|
|
153
173
|
const documentOid = getOidRoot(oid);
|
|
154
174
|
let familyCache = this.documentFamilyCaches.get(documentOid);
|
|
155
175
|
if (!familyCache) {
|
|
176
|
+
this.context.log('debug', 'opening family cache for', documentOid);
|
|
156
177
|
// metadata must be loaded from database to initialize family cache
|
|
157
178
|
familyCache = new DocumentFamilyCache({
|
|
158
179
|
oid: documentOid,
|
|
159
180
|
store: this,
|
|
160
181
|
context: this.context,
|
|
161
182
|
});
|
|
183
|
+
|
|
184
|
+
// PROBLEM: because the next line is async, it yields to
|
|
185
|
+
// queued promises which may need data from this cache,
|
|
186
|
+
// but the cache is empty. But if we move the set to
|
|
187
|
+
// after the async, we can clobber an existing cache
|
|
188
|
+
// with race conditions...
|
|
189
|
+
// So as an attempt to fix that, I've added a promise
|
|
190
|
+
// on DocumentFamilyCache which I manually resolve
|
|
191
|
+
// with setInitialized, then await initializedPromise
|
|
192
|
+
// further down even if there was a cache hit.
|
|
193
|
+
// Surely there is a better pattern for this.
|
|
194
|
+
// FIXME:
|
|
162
195
|
this.documentFamilyCaches.set(documentOid, familyCache);
|
|
163
196
|
await this.refreshFamilyCache(familyCache);
|
|
197
|
+
familyCache.setInitialized();
|
|
164
198
|
|
|
165
199
|
// this.unsubscribes.push(
|
|
166
200
|
// familyCache.subscribe('change:*', this.onEntityChange),
|
|
@@ -168,6 +202,7 @@ export class EntityStore {
|
|
|
168
202
|
|
|
169
203
|
// TODO: cleanup cache when all documents are disposed
|
|
170
204
|
}
|
|
205
|
+
await familyCache.initializedPromise;
|
|
171
206
|
|
|
172
207
|
return familyCache;
|
|
173
208
|
};
|
|
@@ -192,10 +227,10 @@ export class EntityStore {
|
|
|
192
227
|
|
|
193
228
|
const snapshot = entity?.getSnapshot();
|
|
194
229
|
if (snapshot) {
|
|
195
|
-
const stored =
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
230
|
+
const stored = getIndexValues(
|
|
231
|
+
this.schema.collections[collection],
|
|
232
|
+
snapshot,
|
|
233
|
+
);
|
|
199
234
|
try {
|
|
200
235
|
const tx = this.db.transaction(collection, 'readwrite');
|
|
201
236
|
const store = tx.objectStore(collection);
|
|
@@ -221,11 +256,11 @@ export class EntityStore {
|
|
|
221
256
|
|
|
222
257
|
get = async (oid: ObjectIdentifier) => {
|
|
223
258
|
const familyCache = await this.openFamilyCache(oid);
|
|
224
|
-
const schema = this.getDocumentSchema(oid);
|
|
259
|
+
const { schema, readonlyKeys } = this.getDocumentSchema(oid);
|
|
225
260
|
if (!schema) {
|
|
226
261
|
return null;
|
|
227
262
|
}
|
|
228
|
-
return familyCache.getEntity(oid, schema);
|
|
263
|
+
return familyCache.getEntity(oid, schema, undefined, readonlyKeys);
|
|
229
264
|
};
|
|
230
265
|
|
|
231
266
|
/**
|
|
@@ -236,11 +271,11 @@ export class EntityStore {
|
|
|
236
271
|
getCached = (oid: ObjectIdentifier) => {
|
|
237
272
|
const cache = this.documentFamilyCaches.get(oid);
|
|
238
273
|
if (cache) {
|
|
239
|
-
const schema = this.getDocumentSchema(oid);
|
|
274
|
+
const { schema, readonlyKeys } = this.getDocumentSchema(oid);
|
|
240
275
|
if (!schema) {
|
|
241
276
|
return null;
|
|
242
277
|
}
|
|
243
|
-
return cache.getEntity(oid, schema);
|
|
278
|
+
return cache.getEntity(oid, schema, undefined, readonlyKeys);
|
|
244
279
|
}
|
|
245
280
|
return null;
|
|
246
281
|
};
|
|
@@ -268,7 +303,7 @@ export class EntityStore {
|
|
|
268
303
|
// only holding it in memory would introduce lag before it shows up
|
|
269
304
|
// in other queries.
|
|
270
305
|
await this.submitOperations(operations, options);
|
|
271
|
-
const schema = this.getDocumentSchema(oid);
|
|
306
|
+
const { schema, readonlyKeys } = this.getDocumentSchema(oid);
|
|
272
307
|
if (!schema) {
|
|
273
308
|
throw new Error(
|
|
274
309
|
`Cannot create a document in the ${
|
|
@@ -276,7 +311,7 @@ export class EntityStore {
|
|
|
276
311
|
} collection; it is not defined in the current schema version.`,
|
|
277
312
|
);
|
|
278
313
|
}
|
|
279
|
-
return familyCache.getEntity(oid, schema);
|
|
314
|
+
return familyCache.getEntity(oid, schema, undefined, readonlyKeys);
|
|
280
315
|
};
|
|
281
316
|
|
|
282
317
|
private addOperationsToOpenCaches = async (
|
|
@@ -384,6 +419,10 @@ export class EntityStore {
|
|
|
384
419
|
baselines: DocumentBaseline[];
|
|
385
420
|
reset?: boolean;
|
|
386
421
|
}) => {
|
|
422
|
+
if (this._disposed) {
|
|
423
|
+
this.log('warn', 'EntityStore is disposed, not adding data');
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
387
426
|
// convert operations to tagged operations with confirmed = false
|
|
388
427
|
// while we process and store them. this is in-place so as to
|
|
389
428
|
// not allocate a bunch of objects...
|
|
@@ -427,7 +466,7 @@ export class EntityStore {
|
|
|
427
466
|
await this.meta.insertRemoteOperations(operations);
|
|
428
467
|
|
|
429
468
|
if (reset) {
|
|
430
|
-
await this.refreshAllCaches(true);
|
|
469
|
+
await this.refreshAllCaches(true, true);
|
|
431
470
|
}
|
|
432
471
|
|
|
433
472
|
// recompute all affected documents for querying
|
|
@@ -511,6 +550,10 @@ export class EntityStore {
|
|
|
511
550
|
await this.operationBatcher.flush(this.currentBatchKey);
|
|
512
551
|
};
|
|
513
552
|
|
|
553
|
+
flushAllBatches = async () => {
|
|
554
|
+
await Promise.all(this.operationBatcher.flushAll());
|
|
555
|
+
};
|
|
556
|
+
|
|
514
557
|
private flushOperations = async (
|
|
515
558
|
operations: Operation[],
|
|
516
559
|
batchKey: string,
|
|
@@ -632,7 +675,7 @@ export class EntityStore {
|
|
|
632
675
|
// );
|
|
633
676
|
};
|
|
634
677
|
|
|
635
|
-
destroy = () => {
|
|
678
|
+
destroy = async () => {
|
|
636
679
|
this._disposed = true;
|
|
637
680
|
for (const unsubscribe of this.unsubscribes) {
|
|
638
681
|
unsubscribe();
|
|
@@ -641,6 +684,7 @@ export class EntityStore {
|
|
|
641
684
|
cache.dispose();
|
|
642
685
|
}
|
|
643
686
|
this.documentFamilyCaches.clear();
|
|
687
|
+
await this.flushAllBatches();
|
|
644
688
|
};
|
|
645
689
|
|
|
646
690
|
private handleRebase = (baselines: DocumentBaseline[]) => {
|
|
@@ -661,9 +705,12 @@ export class EntityStore {
|
|
|
661
705
|
}
|
|
662
706
|
};
|
|
663
707
|
|
|
664
|
-
private refreshAllCaches = async (
|
|
708
|
+
private refreshAllCaches = async (
|
|
709
|
+
dropUnconfirmed = false,
|
|
710
|
+
dropAll = false,
|
|
711
|
+
) => {
|
|
665
712
|
for (const [_, cache] of this.documentFamilyCaches) {
|
|
666
|
-
await this.refreshFamilyCache(cache, dropUnconfirmed);
|
|
713
|
+
await this.refreshFamilyCache(cache, dropUnconfirmed, dropAll);
|
|
667
714
|
}
|
|
668
715
|
};
|
|
669
716
|
}
|
package/src/idb.ts
CHANGED
|
@@ -105,3 +105,13 @@ export async function deleteAllDatabases(
|
|
|
105
105
|
]);
|
|
106
106
|
window.location.reload();
|
|
107
107
|
}
|
|
108
|
+
|
|
109
|
+
export function deleteDatabase(name: string, indexedDB = window.indexedDB) {
|
|
110
|
+
return storeRequestPromise(indexedDB.deleteDatabase(name));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function getAllDatabaseNamesAndVersions(
|
|
114
|
+
indexedDB: IDBFactory = window.indexedDB,
|
|
115
|
+
) {
|
|
116
|
+
return indexedDB.databases();
|
|
117
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DocumentBaseline,
|
|
3
|
-
|
|
3
|
+
getOidSubIdRange,
|
|
4
|
+
getOidRoot,
|
|
4
5
|
ObjectIdentifier,
|
|
5
6
|
} from '@verdant-web/common';
|
|
6
7
|
import { IDBService } from '../IDBService.js';
|
|
@@ -38,8 +39,14 @@ export class BaselinesStore extends IDBService {
|
|
|
38
39
|
return this.iterate(
|
|
39
40
|
'baselines',
|
|
40
41
|
(store) => {
|
|
41
|
-
const
|
|
42
|
-
|
|
42
|
+
const root = getOidRoot(oid);
|
|
43
|
+
const [start, end] = getOidSubIdRange(oid);
|
|
44
|
+
return [
|
|
45
|
+
// first the root itself
|
|
46
|
+
store.openCursor(IDBKeyRange.only(root)),
|
|
47
|
+
// then the range of its possible subdocuments
|
|
48
|
+
store.openCursor(IDBKeyRange.bound(start, end, false, false)),
|
|
49
|
+
];
|
|
43
50
|
},
|
|
44
51
|
iterator,
|
|
45
52
|
mode,
|
|
@@ -54,9 +61,13 @@ export class BaselinesStore extends IDBService {
|
|
|
54
61
|
const result = await this.runAll<DocumentBaseline[]>(
|
|
55
62
|
'baselines',
|
|
56
63
|
(store) => {
|
|
57
|
-
return docOids.
|
|
58
|
-
const
|
|
59
|
-
|
|
64
|
+
return docOids.flatMap((oid) => {
|
|
65
|
+
const root = getOidRoot(oid);
|
|
66
|
+
const [start, end] = getOidSubIdRange(oid);
|
|
67
|
+
return [
|
|
68
|
+
store.get(root),
|
|
69
|
+
store.getAll(IDBKeyRange.bound(start, end, false, false)),
|
|
70
|
+
];
|
|
60
71
|
});
|
|
61
72
|
},
|
|
62
73
|
mode,
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
+
import { closeDatabase, storeRequestPromise } from '../idb.js';
|
|
2
|
+
|
|
1
3
|
const migrations = [version1, version2, version3, version4];
|
|
2
4
|
|
|
3
|
-
export function openMetadataDatabase(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
log?: (...args: any[]) => void;
|
|
13
|
-
},
|
|
14
|
-
): Promise<{ wasInitialized: boolean; db: IDBDatabase }> {
|
|
5
|
+
export function openMetadataDatabase({
|
|
6
|
+
indexedDB = window.indexedDB,
|
|
7
|
+
namespace,
|
|
8
|
+
log,
|
|
9
|
+
}: {
|
|
10
|
+
indexedDB?: IDBFactory;
|
|
11
|
+
namespace: string;
|
|
12
|
+
log?: (...args: any[]) => void;
|
|
13
|
+
}): Promise<{ wasInitialized: boolean; db: IDBDatabase }> {
|
|
15
14
|
return new Promise<{ wasInitialized: boolean; db: IDBDatabase }>(
|
|
16
15
|
(resolve, reject) => {
|
|
17
|
-
const request = indexedDB.open(
|
|
16
|
+
const request = indexedDB.open(`${namespace}_meta`, 4);
|
|
18
17
|
let wasInitialized = false;
|
|
19
18
|
request.onupgradeneeded = async (event) => {
|
|
20
19
|
const db = request.result;
|
|
@@ -40,6 +39,90 @@ export function openMetadataDatabase(
|
|
|
40
39
|
);
|
|
41
40
|
}
|
|
42
41
|
|
|
42
|
+
export async function openWIPMetadataDatabase({
|
|
43
|
+
wipNamespace,
|
|
44
|
+
namespace,
|
|
45
|
+
indexedDB,
|
|
46
|
+
log,
|
|
47
|
+
}: {
|
|
48
|
+
indexedDB?: IDBFactory;
|
|
49
|
+
namespace: string;
|
|
50
|
+
wipNamespace: string;
|
|
51
|
+
log?: (...args: any[]) => void;
|
|
52
|
+
}): Promise<{ wasInitialized: boolean; db: IDBDatabase }> {
|
|
53
|
+
const result = await openMetadataDatabase({
|
|
54
|
+
namespace: wipNamespace,
|
|
55
|
+
indexedDB,
|
|
56
|
+
log,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// this WIP database was already set up.
|
|
60
|
+
if (!result.wasInitialized) {
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
log?.('debug', 'Beginning copy of production metadata database to WIP');
|
|
65
|
+
// copy all data from production metadata database
|
|
66
|
+
const { db: prodDb } = await openMetadataDatabase({
|
|
67
|
+
namespace,
|
|
68
|
+
indexedDB,
|
|
69
|
+
log,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const tx = prodDb.transaction(
|
|
73
|
+
['baselines', 'operations', 'info'],
|
|
74
|
+
'readonly',
|
|
75
|
+
);
|
|
76
|
+
const [baselines, operations, info] = await Promise.all([
|
|
77
|
+
storeRequestPromise(tx.objectStore('baselines').getAll()),
|
|
78
|
+
storeRequestPromise(tx.objectStore('operations').getAll()),
|
|
79
|
+
storeRequestPromise(tx.objectStore('info').getAll()),
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
const wipTx = result.db.transaction(
|
|
83
|
+
['baselines', 'operations', 'info'],
|
|
84
|
+
'readwrite',
|
|
85
|
+
);
|
|
86
|
+
const wipBaselines = wipTx.objectStore('baselines');
|
|
87
|
+
const wipOperations = wipTx.objectStore('operations');
|
|
88
|
+
const wipInfo = wipTx.objectStore('info');
|
|
89
|
+
|
|
90
|
+
for (const baseline of baselines) {
|
|
91
|
+
wipBaselines.put(baseline);
|
|
92
|
+
}
|
|
93
|
+
for (const operation of operations) {
|
|
94
|
+
wipOperations.put(operation);
|
|
95
|
+
}
|
|
96
|
+
for (const infoItem of info) {
|
|
97
|
+
wipInfo.put(infoItem);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await new Promise<void>((resolve, reject) => {
|
|
101
|
+
wipTx.oncomplete = () => {
|
|
102
|
+
resolve();
|
|
103
|
+
};
|
|
104
|
+
wipTx.onerror = (event) => {
|
|
105
|
+
reject(event);
|
|
106
|
+
};
|
|
107
|
+
wipTx.onabort = (event) => {
|
|
108
|
+
reject(event);
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await closeDatabase(prodDb);
|
|
113
|
+
|
|
114
|
+
log?.(
|
|
115
|
+
'debug',
|
|
116
|
+
'Finished copy of production metadata database to WIP. Copied:',
|
|
117
|
+
baselines.length,
|
|
118
|
+
'baselines,',
|
|
119
|
+
operations.length,
|
|
120
|
+
'operations',
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
43
126
|
async function version1(db: IDBDatabase, tx: IDBTransaction) {
|
|
44
127
|
const baselinesStore = db.createObjectStore('baselines', {
|
|
45
128
|
keyPath: 'oid',
|
package/src/migration/db.ts
CHANGED
|
@@ -114,7 +114,9 @@ export async function openDatabase(
|
|
|
114
114
|
indexedDb: IDBFactory,
|
|
115
115
|
namespace: string,
|
|
116
116
|
version: number,
|
|
117
|
+
log?: (...args: any[]) => void,
|
|
117
118
|
): Promise<IDBDatabase> {
|
|
119
|
+
log?.('debug', 'Opening database', namespace, 'at version', version);
|
|
118
120
|
const db = await new Promise<IDBDatabase>((resolve, reject) => {
|
|
119
121
|
const request = indexedDb.open(
|
|
120
122
|
[namespace, 'collections'].join('_'),
|
|
@@ -124,8 +126,19 @@ export async function openDatabase(
|
|
|
124
126
|
const transaction = request.transaction!;
|
|
125
127
|
transaction.abort();
|
|
126
128
|
|
|
129
|
+
log?.(
|
|
130
|
+
'error',
|
|
131
|
+
'Database upgrade needed, but not expected',
|
|
132
|
+
'Expected',
|
|
133
|
+
version,
|
|
134
|
+
'Got',
|
|
135
|
+
request.result.version,
|
|
136
|
+
);
|
|
127
137
|
reject(
|
|
128
|
-
|
|
138
|
+
request.error ||
|
|
139
|
+
new Error(
|
|
140
|
+
`Migration error: database version changed unexpectedly when reading current data. Expected ${version}, got ${request.result.version}`,
|
|
141
|
+
),
|
|
129
142
|
);
|
|
130
143
|
};
|
|
131
144
|
request.onsuccess = (event) => {
|