@aws-amplify/datastore 3.12.6-next.32 → 3.12.6-next.41
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/lib/authModeStrategies/defaultAuthStrategy.d.ts +2 -0
- package/lib/authModeStrategies/index.d.ts +2 -0
- package/lib/authModeStrategies/multiAuthStrategy.d.ts +13 -0
- package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib/datastore/datastore.d.ts +207 -0
- package/lib/datastore/datastore.js +641 -144
- package/lib/datastore/datastore.js.map +1 -1
- package/lib/index.d.ts +16 -0
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -1
- package/lib/predicates/index.d.ts +30 -0
- package/lib/predicates/index.js +127 -6
- package/lib/predicates/index.js.map +1 -1
- package/lib/predicates/next.d.ts +342 -0
- package/lib/predicates/next.js +801 -0
- package/lib/predicates/next.js.map +1 -0
- package/lib/predicates/sort.d.ts +8 -0
- package/lib/predicates/sort.js +10 -4
- package/lib/predicates/sort.js.map +1 -1
- package/lib/ssr/index.d.ts +3 -0
- package/lib/storage/adapter/AsyncStorageAdapter.d.ts +42 -0
- package/lib/storage/adapter/AsyncStorageAdapter.js +106 -293
- package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib/storage/adapter/AsyncStorageDatabase.d.ts +39 -0
- package/lib/storage/adapter/AsyncStorageDatabase.js +6 -5
- package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib/storage/adapter/InMemoryStore.d.ts +11 -0
- package/lib/storage/adapter/InMemoryStore.js.map +1 -1
- package/lib/storage/adapter/InMemoryStore.native.d.ts +1 -0
- package/lib/storage/adapter/IndexedDBAdapter.d.ts +61 -0
- package/lib/storage/adapter/IndexedDBAdapter.js +223 -289
- package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib/storage/adapter/getDefaultAdapter/index.d.ts +3 -0
- package/lib/storage/adapter/getDefaultAdapter/index.js.map +1 -1
- package/lib/storage/adapter/getDefaultAdapter/index.native.d.ts +3 -0
- package/lib/storage/adapter/index.d.ts +9 -0
- package/lib/storage/relationship.d.ts +140 -0
- package/lib/storage/relationship.js +335 -0
- package/lib/storage/relationship.js.map +1 -0
- package/lib/storage/storage.d.ts +50 -0
- package/lib/storage/storage.js +32 -16
- package/lib/storage/storage.js.map +1 -1
- package/lib/sync/datastoreConnectivity.d.ts +16 -0
- package/lib/sync/datastoreConnectivity.js.map +1 -1
- package/lib/sync/datastoreReachability/index.d.ts +3 -0
- package/lib/sync/datastoreReachability/index.native.d.ts +3 -0
- package/lib/sync/index.d.ts +89 -0
- package/lib/sync/index.js +2 -8
- package/lib/sync/index.js.map +1 -1
- package/lib/sync/merger.d.ts +17 -0
- package/lib/sync/merger.js.map +1 -1
- package/lib/sync/outbox.d.ts +27 -0
- package/lib/sync/outbox.js.map +1 -1
- package/lib/sync/processors/errorMaps.d.ts +17 -0
- package/lib/sync/processors/errorMaps.js +1 -1
- package/lib/sync/processors/errorMaps.js.map +1 -1
- package/lib/sync/processors/mutation.d.ts +58 -0
- package/lib/sync/processors/mutation.js +9 -6
- package/lib/sync/processors/mutation.js.map +1 -1
- package/lib/sync/processors/subscription.d.ts +33 -0
- package/lib/sync/processors/subscription.js +4 -1
- package/lib/sync/processors/subscription.js.map +1 -1
- package/lib/sync/processors/sync.d.ts +28 -0
- package/lib/sync/processors/sync.js.map +1 -1
- package/lib/sync/utils.d.ts +42 -0
- package/lib/sync/utils.js +30 -31
- package/lib/sync/utils.js.map +1 -1
- package/lib/types.d.ts +553 -0
- package/lib/types.js +6 -1
- package/lib/types.js.map +1 -1
- package/lib/util.d.ts +189 -0
- package/lib/util.js +174 -104
- package/lib/util.js.map +1 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib-esm/datastore/datastore.d.ts +59 -8
- package/lib-esm/datastore/datastore.js +643 -147
- package/lib-esm/datastore/datastore.js.map +1 -1
- package/lib-esm/index.d.ts +3 -2
- package/lib-esm/index.js +2 -1
- package/lib-esm/index.js.map +1 -1
- package/lib-esm/predicates/index.d.ts +16 -2
- package/lib-esm/predicates/index.js +128 -7
- package/lib-esm/predicates/index.js.map +1 -1
- package/lib-esm/predicates/next.d.ts +342 -0
- package/lib-esm/predicates/next.js +797 -0
- package/lib-esm/predicates/next.js.map +1 -0
- package/lib-esm/predicates/sort.js +10 -4
- package/lib-esm/predicates/sort.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +2 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js +108 -295
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js +6 -5
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib-esm/storage/adapter/InMemoryStore.d.ts +1 -1
- package/lib-esm/storage/adapter/InMemoryStore.js.map +1 -1
- package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +4 -2
- package/lib-esm/storage/adapter/IndexedDBAdapter.js +226 -292
- package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/getDefaultAdapter/index.js.map +1 -1
- package/lib-esm/storage/relationship.d.ts +140 -0
- package/lib-esm/storage/relationship.js +333 -0
- package/lib-esm/storage/relationship.js.map +1 -0
- package/lib-esm/storage/storage.d.ts +7 -6
- package/lib-esm/storage/storage.js +32 -16
- package/lib-esm/storage/storage.js.map +1 -1
- package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
- package/lib-esm/sync/index.js +3 -9
- package/lib-esm/sync/index.js.map +1 -1
- package/lib-esm/sync/merger.js.map +1 -1
- package/lib-esm/sync/outbox.js.map +1 -1
- package/lib-esm/sync/processors/errorMaps.js +1 -1
- package/lib-esm/sync/processors/errorMaps.js.map +1 -1
- package/lib-esm/sync/processors/mutation.js +10 -7
- package/lib-esm/sync/processors/mutation.js.map +1 -1
- package/lib-esm/sync/processors/subscription.js +4 -1
- package/lib-esm/sync/processors/subscription.js.map +1 -1
- package/lib-esm/sync/processors/sync.js.map +1 -1
- package/lib-esm/sync/utils.d.ts +1 -1
- package/lib-esm/sync/utils.js +31 -32
- package/lib-esm/sync/utils.js.map +1 -1
- package/lib-esm/types.d.ts +59 -7
- package/lib-esm/types.js +6 -2
- package/lib-esm/types.js.map +1 -1
- package/lib-esm/util.d.ts +39 -6
- package/lib-esm/util.js +170 -104
- package/lib-esm/util.js.map +1 -1
- package/package.json +14 -11
- package/src/authModeStrategies/multiAuthStrategy.ts +1 -1
- package/src/datastore/datastore.ts +680 -204
- package/src/index.ts +4 -0
- package/src/predicates/index.ts +143 -17
- package/src/predicates/next.ts +1016 -0
- package/src/predicates/sort.ts +8 -2
- package/src/storage/adapter/AsyncStorageAdapter.ts +56 -178
- package/src/storage/adapter/AsyncStorageDatabase.ts +16 -15
- package/src/storage/adapter/InMemoryStore.ts +5 -2
- package/src/storage/adapter/IndexedDBAdapter.ts +166 -191
- package/src/storage/adapter/getDefaultAdapter/index.ts +2 -2
- package/src/storage/relationship.ts +272 -0
- package/src/storage/storage.ts +56 -37
- package/src/sync/datastoreConnectivity.ts +4 -4
- package/src/sync/index.ts +22 -28
- package/src/sync/merger.ts +1 -1
- package/src/sync/outbox.ts +6 -6
- package/src/sync/processors/errorMaps.ts +1 -1
- package/src/sync/processors/mutation.ts +22 -17
- package/src/sync/processors/subscription.ts +19 -15
- package/src/sync/processors/sync.ts +16 -16
- package/src/sync/utils.ts +42 -48
- package/src/types.ts +116 -11
- package/src/util.ts +108 -150
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { ConsoleLogger as Logger } from '@aws-amplify/core';
|
|
2
2
|
import * as idb from 'idb';
|
|
3
3
|
import { ModelInstanceCreator } from '../../datastore/datastore';
|
|
4
|
-
import {
|
|
5
|
-
ModelPredicateCreator,
|
|
6
|
-
ModelSortPredicateCreator,
|
|
7
|
-
} from '../../predicates';
|
|
4
|
+
import { ModelPredicateCreator } from '../../predicates';
|
|
8
5
|
import {
|
|
9
6
|
InternalSchema,
|
|
10
7
|
isPredicateObj,
|
|
8
|
+
isPredicateGroup,
|
|
11
9
|
ModelInstanceMetadata,
|
|
12
10
|
ModelPredicate,
|
|
13
11
|
NamespaceResolver,
|
|
@@ -21,14 +19,14 @@ import {
|
|
|
21
19
|
RelationType,
|
|
22
20
|
} from '../../types';
|
|
23
21
|
import {
|
|
24
|
-
exhaustiveCheck,
|
|
25
22
|
getIndex,
|
|
26
23
|
getIndexFromAssociation,
|
|
27
24
|
isModelConstructor,
|
|
28
25
|
isPrivateMode,
|
|
29
26
|
traverseModel,
|
|
30
27
|
validatePredicate,
|
|
31
|
-
|
|
28
|
+
inMemoryPagination,
|
|
29
|
+
NAMESPACES,
|
|
32
30
|
keysEqual,
|
|
33
31
|
getStorename,
|
|
34
32
|
getIndexKeys,
|
|
@@ -41,17 +39,17 @@ const logger = new Logger('DataStore');
|
|
|
41
39
|
|
|
42
40
|
const DB_NAME = 'amplify-datastore';
|
|
43
41
|
class IndexedDBAdapter implements Adapter {
|
|
44
|
-
private schema
|
|
45
|
-
private namespaceResolver
|
|
46
|
-
private modelInstanceCreator
|
|
47
|
-
private getModelConstructorByModelName
|
|
48
|
-
namsespaceName:
|
|
42
|
+
private schema!: InternalSchema;
|
|
43
|
+
private namespaceResolver!: NamespaceResolver;
|
|
44
|
+
private modelInstanceCreator!: ModelInstanceCreator;
|
|
45
|
+
private getModelConstructorByModelName?: (
|
|
46
|
+
namsespaceName: NAMESPACES,
|
|
49
47
|
modelName: string
|
|
50
48
|
) => PersistentModelConstructor<any>;
|
|
51
|
-
private db
|
|
52
|
-
private initPromise
|
|
53
|
-
private resolve
|
|
54
|
-
private reject
|
|
49
|
+
private db!: idb.IDBPDatabase;
|
|
50
|
+
private initPromise!: Promise<void>;
|
|
51
|
+
private resolve!: (value?: any) => void;
|
|
52
|
+
private reject!: (value?: any) => void;
|
|
55
53
|
private dbName: string = DB_NAME;
|
|
56
54
|
private safariCompatabilityMode: boolean = false;
|
|
57
55
|
|
|
@@ -125,7 +123,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
125
123
|
namespaceResolver: NamespaceResolver,
|
|
126
124
|
modelInstanceCreator: ModelInstanceCreator,
|
|
127
125
|
getModelConstructorByModelName: (
|
|
128
|
-
namsespaceName:
|
|
126
|
+
namsespaceName: NAMESPACES,
|
|
129
127
|
modelName: string
|
|
130
128
|
) => PersistentModelConstructor<any>,
|
|
131
129
|
sessionId?: string
|
|
@@ -285,7 +283,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
285
283
|
model,
|
|
286
284
|
this.schema.namespaces[namespaceName],
|
|
287
285
|
this.modelInstanceCreator,
|
|
288
|
-
this.getModelConstructorByModelName
|
|
286
|
+
this.getModelConstructorByModelName!
|
|
289
287
|
);
|
|
290
288
|
|
|
291
289
|
const set = new Set<string>();
|
|
@@ -313,9 +311,13 @@ class IndexedDBAdapter implements Adapter {
|
|
|
313
311
|
|
|
314
312
|
if (condition && fromDB) {
|
|
315
313
|
const predicates = ModelPredicateCreator.getPredicates(condition);
|
|
316
|
-
const { predicates: predicateObjs, type } = predicates;
|
|
314
|
+
const { predicates: predicateObjs, type } = predicates || {};
|
|
317
315
|
|
|
318
|
-
const isValid = validatePredicate(
|
|
316
|
+
const isValid = validatePredicate(
|
|
317
|
+
fromDB as any,
|
|
318
|
+
type as any,
|
|
319
|
+
predicateObjs as any
|
|
320
|
+
);
|
|
319
321
|
|
|
320
322
|
if (!isValid) {
|
|
321
323
|
const msg = 'Conditional update failed';
|
|
@@ -326,7 +328,6 @@ class IndexedDBAdapter implements Adapter {
|
|
|
326
328
|
}
|
|
327
329
|
|
|
328
330
|
const result: [T, OpType.INSERT | OpType.UPDATE][] = [];
|
|
329
|
-
|
|
330
331
|
for await (const resItem of connectionStoreNames) {
|
|
331
332
|
const { storeName, item, instance, keys } = resItem;
|
|
332
333
|
const store = tx.objectStore(storeName);
|
|
@@ -351,7 +352,6 @@ class IndexedDBAdapter implements Adapter {
|
|
|
351
352
|
.index('byPk')
|
|
352
353
|
.getKey(this.canonicalKeyPath(itemKeyValues));
|
|
353
354
|
await store.put(item, key);
|
|
354
|
-
|
|
355
355
|
result.push([instance, opType]);
|
|
356
356
|
}
|
|
357
357
|
}
|
|
@@ -362,16 +362,16 @@ class IndexedDBAdapter implements Adapter {
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
private async load<T>(
|
|
365
|
-
namespaceName:
|
|
365
|
+
namespaceName: NAMESPACES,
|
|
366
366
|
srcModelName: string,
|
|
367
367
|
records: T[]
|
|
368
368
|
): Promise<T[]> {
|
|
369
369
|
const namespace = this.schema.namespaces[namespaceName];
|
|
370
|
-
const relations = namespace.relationships[srcModelName].relationTypes;
|
|
370
|
+
const relations = namespace.relationships![srcModelName].relationTypes;
|
|
371
371
|
const connectionStoreNames = relations.map(({ modelName }) => {
|
|
372
372
|
return getStorename(namespaceName, modelName);
|
|
373
373
|
});
|
|
374
|
-
const modelConstructor = this.getModelConstructorByModelName(
|
|
374
|
+
const modelConstructor = this.getModelConstructorByModelName!(
|
|
375
375
|
namespaceName,
|
|
376
376
|
srcModelName
|
|
377
377
|
);
|
|
@@ -382,116 +382,6 @@ class IndexedDBAdapter implements Adapter {
|
|
|
382
382
|
);
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
-
const tx = this.db.transaction([...connectionStoreNames], 'readonly');
|
|
386
|
-
|
|
387
|
-
for await (const relation of relations) {
|
|
388
|
-
// target name, metadata, set by init
|
|
389
|
-
const { fieldName, modelName, targetName, targetNames } = relation;
|
|
390
|
-
const storeName = getStorename(namespaceName, modelName);
|
|
391
|
-
const store = tx.objectStore(storeName);
|
|
392
|
-
const modelConstructor = this.getModelConstructorByModelName(
|
|
393
|
-
namespaceName,
|
|
394
|
-
modelName
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
switch (relation.relationType) {
|
|
398
|
-
case 'HAS_ONE':
|
|
399
|
-
for await (const recordItem of records) {
|
|
400
|
-
// POST CPK codegen changes:
|
|
401
|
-
if (targetNames?.length) {
|
|
402
|
-
let getByFields = [];
|
|
403
|
-
let allPresent;
|
|
404
|
-
// iterate through all targetnames to make sure they are all present in the recordItem
|
|
405
|
-
allPresent = targetNames.every(targetName => {
|
|
406
|
-
return recordItem[targetName] != null;
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
if (!allPresent) {
|
|
410
|
-
break;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
getByFields = targetNames as any;
|
|
414
|
-
|
|
415
|
-
// keys are the key values
|
|
416
|
-
const keys = getByFields.map(
|
|
417
|
-
getByField => recordItem[getByField]
|
|
418
|
-
);
|
|
419
|
-
|
|
420
|
-
const connectionRecord = await this._get(store, keys);
|
|
421
|
-
|
|
422
|
-
recordItem[fieldName] =
|
|
423
|
-
connectionRecord &&
|
|
424
|
-
this.modelInstanceCreator(modelConstructor, connectionRecord);
|
|
425
|
-
} else {
|
|
426
|
-
// If single target name, using old codegen
|
|
427
|
-
const getByfield = recordItem[targetName]
|
|
428
|
-
? targetName
|
|
429
|
-
: fieldName;
|
|
430
|
-
|
|
431
|
-
// We break here, because the recordItem does not have 'team', the `getByField`
|
|
432
|
-
// extract the keys on the related model.
|
|
433
|
-
if (!recordItem[getByfield]) break;
|
|
434
|
-
|
|
435
|
-
const key = [recordItem[getByfield]];
|
|
436
|
-
|
|
437
|
-
const connectionRecord = await this._get(store, key);
|
|
438
|
-
|
|
439
|
-
recordItem[fieldName] =
|
|
440
|
-
connectionRecord &&
|
|
441
|
-
this.modelInstanceCreator(modelConstructor, connectionRecord);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
break;
|
|
445
|
-
case 'BELONGS_TO':
|
|
446
|
-
for await (const recordItem of records) {
|
|
447
|
-
// POST CPK codegen changes:
|
|
448
|
-
if (targetNames?.length) {
|
|
449
|
-
let allPresent;
|
|
450
|
-
// iterate through all targetnames to make sure they are all present in the recordItem
|
|
451
|
-
allPresent = targetNames.every(targetName => {
|
|
452
|
-
return recordItem[targetName] != null;
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
// If not present, there is not yet a connected record
|
|
456
|
-
if (!allPresent) {
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
const keys = targetNames.map(
|
|
461
|
-
targetName => recordItem[targetName]
|
|
462
|
-
);
|
|
463
|
-
|
|
464
|
-
// Retrieve the connected record
|
|
465
|
-
const connectionRecord = await this._get(store, keys);
|
|
466
|
-
|
|
467
|
-
recordItem[fieldName] =
|
|
468
|
-
connectionRecord &&
|
|
469
|
-
this.modelInstanceCreator(modelConstructor, connectionRecord);
|
|
470
|
-
|
|
471
|
-
targetNames?.map(targetName => {
|
|
472
|
-
delete recordItem[targetName];
|
|
473
|
-
});
|
|
474
|
-
} else if (recordItem[targetName]) {
|
|
475
|
-
const key = [recordItem[targetName]];
|
|
476
|
-
|
|
477
|
-
const connectionRecord = await this._get(store, key);
|
|
478
|
-
|
|
479
|
-
recordItem[fieldName] =
|
|
480
|
-
connectionRecord &&
|
|
481
|
-
this.modelInstanceCreator(modelConstructor, connectionRecord);
|
|
482
|
-
delete recordItem[targetName];
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
break;
|
|
486
|
-
case 'HAS_MANY':
|
|
487
|
-
// TODO: Lazy loading
|
|
488
|
-
break;
|
|
489
|
-
default:
|
|
490
|
-
exhaustiveCheck(relation.relationType);
|
|
491
|
-
break;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
385
|
return records.map(record =>
|
|
496
386
|
this.modelInstanceCreator(modelConstructor, record)
|
|
497
387
|
);
|
|
@@ -504,7 +394,9 @@ class IndexedDBAdapter implements Adapter {
|
|
|
504
394
|
): Promise<T[]> {
|
|
505
395
|
await this.checkPrivate();
|
|
506
396
|
const storeName = this.getStorenameForModel(modelConstructor);
|
|
507
|
-
const namespaceName = this.namespaceResolver(
|
|
397
|
+
const namespaceName = this.namespaceResolver(
|
|
398
|
+
modelConstructor
|
|
399
|
+
) as NAMESPACES;
|
|
508
400
|
|
|
509
401
|
const predicates =
|
|
510
402
|
predicate && ModelPredicateCreator.getPredicates(predicate);
|
|
@@ -518,7 +410,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
518
410
|
const hasSort = pagination && pagination.sort;
|
|
519
411
|
const hasPagination = pagination && pagination.limit;
|
|
520
412
|
|
|
521
|
-
const records: T[] = await (async () => {
|
|
413
|
+
const records: T[] = (await (async () => {
|
|
522
414
|
if (queryByKey) {
|
|
523
415
|
const record = await this.getByKey(storeName, queryByKey);
|
|
524
416
|
return record ? [record] : [];
|
|
@@ -539,7 +431,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
539
431
|
}
|
|
540
432
|
|
|
541
433
|
return this.getAll(storeName);
|
|
542
|
-
})();
|
|
434
|
+
})()) as T[];
|
|
543
435
|
|
|
544
436
|
return await this.load(namespaceName, modelConstructor.name, records);
|
|
545
437
|
}
|
|
@@ -548,8 +440,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
548
440
|
storeName: string,
|
|
549
441
|
keyValue: string[]
|
|
550
442
|
): Promise<T> {
|
|
551
|
-
|
|
552
|
-
return record;
|
|
443
|
+
return <T>await this._get(storeName, keyValue);
|
|
553
444
|
}
|
|
554
445
|
|
|
555
446
|
private async getAll<T extends PersistentModel>(
|
|
@@ -568,7 +459,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
568
459
|
return;
|
|
569
460
|
}
|
|
570
461
|
|
|
571
|
-
const keyValues = [];
|
|
462
|
+
const keyValues = [] as any[];
|
|
572
463
|
|
|
573
464
|
for (const key of keyPath) {
|
|
574
465
|
const predicateObj = predicateObjs.find(
|
|
@@ -581,17 +472,116 @@ class IndexedDBAdapter implements Adapter {
|
|
|
581
472
|
return keyValues.length === keyPath.length ? keyValues : undefined;
|
|
582
473
|
}
|
|
583
474
|
|
|
475
|
+
private matchingIndex(
|
|
476
|
+
storeName: string,
|
|
477
|
+
fieldName: string,
|
|
478
|
+
transaction: idb.IDBPTransaction<unknown, [string]>
|
|
479
|
+
) {
|
|
480
|
+
const store = transaction.objectStore(storeName);
|
|
481
|
+
for (const name of store.indexNames) {
|
|
482
|
+
const idx = store.index(name);
|
|
483
|
+
if (idx.keyPath === fieldName) {
|
|
484
|
+
return idx;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
584
489
|
private async filterOnPredicate<T extends PersistentModel>(
|
|
585
490
|
storeName: string,
|
|
586
491
|
predicates: PredicatesGroup<T>
|
|
587
492
|
) {
|
|
588
|
-
|
|
493
|
+
let { predicates: predicateObjs, type } = predicates;
|
|
494
|
+
|
|
495
|
+
// the predicate objects we care about tend to be nested at least
|
|
496
|
+
// one level down: `{and: {or: {and: { <the predicates we want> }}}}`
|
|
497
|
+
// so, we unpack and/or groups until we find a group with more than 1
|
|
498
|
+
// child OR a child that is not a group (and is therefore a predicate "object").
|
|
499
|
+
while (predicateObjs.length === 1 && isPredicateGroup(predicateObjs[0])) {
|
|
500
|
+
type = (predicateObjs[0] as PredicatesGroup<T>).type;
|
|
501
|
+
predicateObjs = (predicateObjs[0] as PredicatesGroup<T>).predicates;
|
|
502
|
+
}
|
|
589
503
|
|
|
590
|
-
|
|
504
|
+
// where we'll accumulate candidate results, which will be filtered at the end.
|
|
505
|
+
let candidateResults: T[];
|
|
506
|
+
|
|
507
|
+
// AFAIK, this will always be a homogenous group of predicate objects at this point.
|
|
508
|
+
// but, if that ever changes, this pulls out just the predicates from the list that
|
|
509
|
+
// are field-level predicate objects we can potentially smash against an index.
|
|
510
|
+
const fieldPredicates = predicateObjs.filter(p =>
|
|
511
|
+
isPredicateObj(p)
|
|
512
|
+
) as PredicateObject<T>[];
|
|
513
|
+
|
|
514
|
+
// several sub-queries could occur here. explicitly start a txn here to avoid
|
|
515
|
+
// opening/closing multiple txns.
|
|
516
|
+
const txn = this.db.transaction(storeName);
|
|
517
|
+
|
|
518
|
+
// our potential indexes or lacks thereof.
|
|
519
|
+
const predicateIndexes = fieldPredicates.map(p => {
|
|
520
|
+
return {
|
|
521
|
+
predicate: p,
|
|
522
|
+
index: this.matchingIndex(storeName, String(p.field), txn),
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// Explicitly wait for txns from index queries to complete before proceding.
|
|
527
|
+
// This helps ensure IndexedDB is in a stable, ready state. Else, subseqeuent
|
|
528
|
+
// qeuries can sometimes appear to deadlock (at least in FakeIndexedDB).
|
|
529
|
+
await txn.done;
|
|
530
|
+
|
|
531
|
+
// semi-naive implementation:
|
|
532
|
+
if (type === 'and') {
|
|
533
|
+
// each condition must be satsified, we can form a base set with any
|
|
534
|
+
// ONE of those conditions and then filter.
|
|
535
|
+
const actualPredicateIndexes = predicateIndexes.filter(
|
|
536
|
+
i => i.index && i.predicate.operator === 'eq'
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
if (actualPredicateIndexes.length > 0) {
|
|
540
|
+
const predicateIndex = actualPredicateIndexes[0];
|
|
541
|
+
candidateResults = <T[]>(
|
|
542
|
+
await predicateIndex.index!.getAll(predicateIndex.predicate.operand)
|
|
543
|
+
);
|
|
544
|
+
} else {
|
|
545
|
+
// no usable indexes
|
|
546
|
+
candidateResults = <T[]>await this.getAll(storeName);
|
|
547
|
+
}
|
|
548
|
+
} else if (type === 'or') {
|
|
549
|
+
// NOTE: each condition implies a potentially distinct set. we only benefit
|
|
550
|
+
// from using indexes here if EVERY condition uses an index. if any one
|
|
551
|
+
// index requires a table scan, we gain nothing from the indexes.
|
|
552
|
+
// NOTE: results must be DISTINCT-ified if we leverage indexes.
|
|
553
|
+
if (
|
|
554
|
+
predicateIndexes.length > 0 &&
|
|
555
|
+
predicateIndexes.every(i => i.index && i.predicate.operator === 'eq')
|
|
556
|
+
) {
|
|
557
|
+
const distinctResults = new Map<string, T>();
|
|
558
|
+
for (const predicateIndex of predicateIndexes) {
|
|
559
|
+
const resultGroup = <T[]>(
|
|
560
|
+
await predicateIndex.index!.getAll(predicateIndex.predicate.operand)
|
|
561
|
+
);
|
|
562
|
+
for (const item of resultGroup) {
|
|
563
|
+
// TODO: custom PK
|
|
564
|
+
distinctResults.set(item.id, item);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// we could conceivably check for special conditions and return early here.
|
|
569
|
+
// but, this is simpler and has not yet had a measurable performance impact.
|
|
570
|
+
candidateResults = Array.from(distinctResults.values());
|
|
571
|
+
} else {
|
|
572
|
+
// either no usable indexes or not all conditions can use one.
|
|
573
|
+
candidateResults = <T[]>await this.getAll(storeName);
|
|
574
|
+
}
|
|
575
|
+
} else {
|
|
576
|
+
// nothing intelligent we can do with `not` groups unless or until we start
|
|
577
|
+
// smashing comparison operators against indexes -- at which point we could
|
|
578
|
+
// perform some reversal here.
|
|
579
|
+
candidateResults = <T[]>await this.getAll(storeName);
|
|
580
|
+
}
|
|
591
581
|
|
|
592
582
|
const filtered = predicateObjs
|
|
593
|
-
?
|
|
594
|
-
:
|
|
583
|
+
? candidateResults.filter(m => validatePredicate(m, type, predicateObjs))
|
|
584
|
+
: candidateResults;
|
|
595
585
|
|
|
596
586
|
return filtered;
|
|
597
587
|
}
|
|
@@ -600,26 +590,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
600
590
|
records: T[],
|
|
601
591
|
pagination?: PaginationInput<T>
|
|
602
592
|
): T[] {
|
|
603
|
-
|
|
604
|
-
if (pagination.sort) {
|
|
605
|
-
const sortPredicates = ModelSortPredicateCreator.getPredicates(
|
|
606
|
-
pagination.sort
|
|
607
|
-
);
|
|
608
|
-
|
|
609
|
-
if (sortPredicates.length) {
|
|
610
|
-
const compareFn = sortCompareFunction(sortPredicates);
|
|
611
|
-
records.sort(compareFn);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
const { page = 0, limit = 0 } = pagination;
|
|
616
|
-
const start = Math.max(0, page * limit) || 0;
|
|
617
|
-
|
|
618
|
-
const end = limit > 0 ? start + limit : records.length;
|
|
619
|
-
|
|
620
|
-
return records.slice(start, end);
|
|
621
|
-
}
|
|
622
|
-
return records;
|
|
593
|
+
return inMemoryPagination(records, pagination);
|
|
623
594
|
}
|
|
624
595
|
|
|
625
596
|
private async enginePagination<T extends PersistentModel>(
|
|
@@ -687,14 +658,15 @@ class IndexedDBAdapter implements Adapter {
|
|
|
687
658
|
const deleteQueue: { storeName: string; items: T[] }[] = [];
|
|
688
659
|
|
|
689
660
|
if (isModelConstructor(modelOrModelConstructor)) {
|
|
690
|
-
const modelConstructor =
|
|
691
|
-
|
|
661
|
+
const modelConstructor =
|
|
662
|
+
modelOrModelConstructor as PersistentModelConstructor<T>;
|
|
663
|
+
const nameSpace = this.namespaceResolver(modelConstructor) as NAMESPACES;
|
|
692
664
|
|
|
693
665
|
const storeName = this.getStorenameForModel(modelConstructor);
|
|
694
666
|
|
|
695
667
|
const models = await this.query(modelConstructor, condition);
|
|
696
668
|
const relations =
|
|
697
|
-
this.schema.namespaces[nameSpace].relationships[modelConstructor.name]
|
|
669
|
+
this.schema.namespaces![nameSpace].relationships![modelConstructor.name]
|
|
698
670
|
.relationTypes;
|
|
699
671
|
|
|
700
672
|
if (condition !== undefined) {
|
|
@@ -737,11 +709,13 @@ class IndexedDBAdapter implements Adapter {
|
|
|
737
709
|
return [models, deletedModels];
|
|
738
710
|
}
|
|
739
711
|
} else {
|
|
740
|
-
const model = modelOrModelConstructor;
|
|
712
|
+
const model = modelOrModelConstructor as T;
|
|
741
713
|
|
|
742
714
|
const modelConstructor = Object.getPrototypeOf(model)
|
|
743
715
|
.constructor as PersistentModelConstructor<T>;
|
|
744
|
-
const namespaceName = this.namespaceResolver(
|
|
716
|
+
const namespaceName = this.namespaceResolver(
|
|
717
|
+
modelConstructor
|
|
718
|
+
) as NAMESPACES;
|
|
745
719
|
|
|
746
720
|
const storeName = this.getStorenameForModel(modelConstructor);
|
|
747
721
|
|
|
@@ -760,9 +734,10 @@ class IndexedDBAdapter implements Adapter {
|
|
|
760
734
|
}
|
|
761
735
|
|
|
762
736
|
const predicates = ModelPredicateCreator.getPredicates(condition);
|
|
763
|
-
const { predicates: predicateObjs, type } =
|
|
737
|
+
const { predicates: predicateObjs, type } =
|
|
738
|
+
predicates as PredicatesGroup<T>;
|
|
764
739
|
|
|
765
|
-
const isValid = validatePredicate(fromDB, type, predicateObjs);
|
|
740
|
+
const isValid = validatePredicate(fromDB as T, type, predicateObjs);
|
|
766
741
|
|
|
767
742
|
if (!isValid) {
|
|
768
743
|
const msg = 'Conditional update failed';
|
|
@@ -773,7 +748,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
773
748
|
await tx.done;
|
|
774
749
|
|
|
775
750
|
const relations =
|
|
776
|
-
this.schema.namespaces[namespaceName].relationships[
|
|
751
|
+
this.schema.namespaces[namespaceName].relationships![
|
|
777
752
|
modelConstructor.name
|
|
778
753
|
].relationTypes;
|
|
779
754
|
|
|
@@ -786,7 +761,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
786
761
|
);
|
|
787
762
|
} else {
|
|
788
763
|
const relations =
|
|
789
|
-
this.schema.namespaces[namespaceName].relationships[
|
|
764
|
+
this.schema.namespaces[namespaceName].relationships![
|
|
790
765
|
modelConstructor.name
|
|
791
766
|
].relationTypes;
|
|
792
767
|
|
|
@@ -816,18 +791,18 @@ class IndexedDBAdapter implements Adapter {
|
|
|
816
791
|
items: T[] | IDBValidKey[];
|
|
817
792
|
}[]
|
|
818
793
|
) {
|
|
819
|
-
const connectionStoreNames = deleteQueue
|
|
794
|
+
const connectionStoreNames = deleteQueue!.map(({ storeName }) => {
|
|
820
795
|
return storeName;
|
|
821
796
|
});
|
|
822
797
|
|
|
823
798
|
const tx = this.db.transaction([...connectionStoreNames], 'readwrite');
|
|
824
|
-
for await (const deleteItem of deleteQueue) {
|
|
799
|
+
for await (const deleteItem of deleteQueue!) {
|
|
825
800
|
const { storeName, items } = deleteItem;
|
|
826
801
|
const store = tx.objectStore(storeName);
|
|
827
802
|
|
|
828
803
|
for await (const item of items) {
|
|
829
804
|
if (item) {
|
|
830
|
-
let key: IDBValidKey;
|
|
805
|
+
let key: IDBValidKey | undefined;
|
|
831
806
|
|
|
832
807
|
if (typeof item === 'object') {
|
|
833
808
|
const keyValues = this.getIndexKeyValuesFromModel(item as T);
|
|
@@ -851,7 +826,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
851
826
|
relations: RelationType[],
|
|
852
827
|
models: T[],
|
|
853
828
|
srcModel: string,
|
|
854
|
-
nameSpace:
|
|
829
|
+
nameSpace: NAMESPACES,
|
|
855
830
|
deleteQueue: { storeName: string; items: T[] }[]
|
|
856
831
|
): Promise<void> {
|
|
857
832
|
for await (const rel of relations) {
|
|
@@ -885,7 +860,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
885
860
|
);
|
|
886
861
|
|
|
887
862
|
await this.deleteTraverse(
|
|
888
|
-
this.schema.namespaces[nameSpace].relationships[modelName]
|
|
863
|
+
this.schema.namespaces[nameSpace].relationships![modelName]
|
|
889
864
|
.relationTypes,
|
|
890
865
|
recordToDelete ? [recordToDelete] : [],
|
|
891
866
|
modelName,
|
|
@@ -908,7 +883,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
908
883
|
// If we deprecate, we'll need to re-gen the MIPR in __tests__/schema.ts > newSchema
|
|
909
884
|
// otherwise some unit tests will fail
|
|
910
885
|
index = getIndex(
|
|
911
|
-
this.schema.namespaces[nameSpace].relationships[modelName]
|
|
886
|
+
this.schema.namespaces[nameSpace].relationships![modelName]
|
|
912
887
|
.relationTypes,
|
|
913
888
|
srcModel
|
|
914
889
|
);
|
|
@@ -926,7 +901,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
926
901
|
);
|
|
927
902
|
|
|
928
903
|
await this.deleteTraverse(
|
|
929
|
-
this.schema.namespaces[nameSpace].relationships[modelName]
|
|
904
|
+
this.schema.namespaces[nameSpace].relationships![modelName]
|
|
930
905
|
.relationTypes,
|
|
931
906
|
recordToDelete ? [recordToDelete] : [],
|
|
932
907
|
modelName,
|
|
@@ -941,15 +916,15 @@ class IndexedDBAdapter implements Adapter {
|
|
|
941
916
|
const index =
|
|
942
917
|
// explicit bi-directional @hasMany and @manyToMany
|
|
943
918
|
getIndex(
|
|
944
|
-
this.schema.namespaces[nameSpace].relationships[modelName]
|
|
919
|
+
this.schema.namespaces[nameSpace].relationships![modelName]
|
|
945
920
|
.relationTypes,
|
|
946
921
|
srcModel
|
|
947
922
|
) ||
|
|
948
923
|
// uni and/or implicit @hasMany
|
|
949
924
|
getIndexFromAssociation(
|
|
950
|
-
this.schema.namespaces[nameSpace].relationships[modelName]
|
|
925
|
+
this.schema.namespaces[nameSpace].relationships![modelName]
|
|
951
926
|
.indexes,
|
|
952
|
-
associatedWith
|
|
927
|
+
associatedWith!
|
|
953
928
|
);
|
|
954
929
|
const keyValues = this.getIndexKeyValuesFromModel(model);
|
|
955
930
|
|
|
@@ -960,7 +935,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
960
935
|
.getAll(this.canonicalKeyPath(keyValues));
|
|
961
936
|
|
|
962
937
|
await this.deleteTraverse(
|
|
963
|
-
this.schema.namespaces[nameSpace].relationships[modelName]
|
|
938
|
+
this.schema.namespaces[nameSpace].relationships![modelName]
|
|
964
939
|
.relationTypes,
|
|
965
940
|
childrenArray,
|
|
966
941
|
modelName,
|
|
@@ -973,7 +948,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
973
948
|
// Intentionally blank
|
|
974
949
|
break;
|
|
975
950
|
default:
|
|
976
|
-
|
|
951
|
+
throw new Error(`Invalid relation type ${relationType}`);
|
|
977
952
|
break;
|
|
978
953
|
}
|
|
979
954
|
}
|
|
@@ -982,7 +957,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
982
957
|
storeName: getStorename(nameSpace, srcModel),
|
|
983
958
|
items: models.map(record =>
|
|
984
959
|
this.modelInstanceCreator(
|
|
985
|
-
this.getModelConstructorByModelName(nameSpace, srcModel),
|
|
960
|
+
this.getModelConstructorByModelName!(nameSpace, srcModel),
|
|
986
961
|
record
|
|
987
962
|
)
|
|
988
963
|
),
|
|
@@ -996,8 +971,8 @@ class IndexedDBAdapter implements Adapter {
|
|
|
996
971
|
|
|
997
972
|
await idb.deleteDB(this.dbName);
|
|
998
973
|
|
|
999
|
-
this.db = undefined
|
|
1000
|
-
this.initPromise = undefined
|
|
974
|
+
this.db = undefined!;
|
|
975
|
+
this.initPromise = undefined!;
|
|
1001
976
|
}
|
|
1002
977
|
|
|
1003
978
|
async batchSave<T extends PersistentModel>(
|
|
@@ -1027,7 +1002,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
1027
1002
|
model,
|
|
1028
1003
|
this.schema.namespaces[namespaceName],
|
|
1029
1004
|
this.modelInstanceCreator,
|
|
1030
|
-
this.getModelConstructorByModelName
|
|
1005
|
+
this.getModelConstructorByModelName!
|
|
1031
1006
|
);
|
|
1032
1007
|
|
|
1033
1008
|
const keyValues = this.getIndexKeyValuesFromModel(model);
|
|
@@ -1041,7 +1016,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
1041
1016
|
const { instance } = connectedModels.find(({ instance }) => {
|
|
1042
1017
|
const instanceKeyValues = this.getIndexKeyValuesFromModel(instance);
|
|
1043
1018
|
return keysEqual(instanceKeyValues, keyValues);
|
|
1044
|
-
})
|
|
1019
|
+
})!;
|
|
1045
1020
|
|
|
1046
1021
|
result.push([
|
|
1047
1022
|
<T>(<unknown>instance),
|
|
@@ -1073,7 +1048,7 @@ class IndexedDBAdapter implements Adapter {
|
|
|
1073
1048
|
});
|
|
1074
1049
|
|
|
1075
1050
|
const { indexes } =
|
|
1076
|
-
this.schema.namespaces[namespaceName].relationships[modelName];
|
|
1051
|
+
this.schema.namespaces[namespaceName].relationships![modelName];
|
|
1077
1052
|
|
|
1078
1053
|
indexes.forEach(([idxName, keyPath, options]) => {
|
|
1079
1054
|
store.createIndex(idxName, keyPath, options);
|
|
@@ -7,10 +7,10 @@ const getDefaultAdapter: () => Adapter = () => {
|
|
|
7
7
|
const { isBrowser } = browserOrNode();
|
|
8
8
|
|
|
9
9
|
if ((isBrowser && window.indexedDB) || (isWebWorker() && self.indexedDB)) {
|
|
10
|
-
return IndexedDBAdapter;
|
|
10
|
+
return IndexedDBAdapter as Adapter;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
return AsyncStorageAdapter;
|
|
13
|
+
return AsyncStorageAdapter as Adapter;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export default getDefaultAdapter;
|