@aws-amplify/datastore 3.7.3 → 3.7.4-custom-pk.79
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/CHANGELOG.md +144 -17
- package/README.md +154 -0
- package/dist/aws-amplify-datastore.js +3344 -1405
- package/dist/aws-amplify-datastore.js.map +1 -1
- package/dist/aws-amplify-datastore.min.js +25 -95
- package/dist/aws-amplify-datastore.min.js.map +1 -1
- package/lib/authModeStrategies/multiAuthStrategy.d.ts +2 -2
- package/lib/authModeStrategies/multiAuthStrategy.js +32 -26
- package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib/datastore/datastore.d.ts +17 -16
- package/lib/datastore/datastore.js +250 -78
- package/lib/datastore/datastore.js.map +1 -1
- package/lib/index.d.ts +3 -19
- package/lib/predicates/index.d.ts +3 -2
- package/lib/predicates/index.js +12 -2
- package/lib/predicates/index.js.map +1 -1
- package/lib/storage/adapter/AsyncStorageAdapter.d.ts +6 -2
- package/lib/storage/adapter/AsyncStorageAdapter.js +140 -66
- package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib/storage/adapter/AsyncStorageDatabase.d.ts +4 -4
- package/lib/storage/adapter/AsyncStorageDatabase.js +57 -27
- package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib/storage/adapter/InMemoryStore.js +2 -2
- package/lib/storage/adapter/InMemoryStore.js.map +1 -1
- package/lib/storage/adapter/IndexedDBAdapter.d.ts +7 -2
- package/lib/storage/adapter/IndexedDBAdapter.js +460 -253
- package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib/storage/adapter/index.d.ts +1 -1
- package/lib/storage/storage.d.ts +3 -3
- package/lib/storage/storage.js +106 -28
- package/lib/storage/storage.js.map +1 -1
- package/lib/sync/index.d.ts +23 -7
- package/lib/sync/index.js +18 -17
- package/lib/sync/index.js.map +1 -1
- package/lib/sync/merger.d.ts +3 -3
- package/lib/sync/merger.js +8 -6
- package/lib/sync/merger.js.map +1 -1
- package/lib/sync/outbox.d.ts +2 -2
- package/lib/sync/outbox.js +12 -9
- package/lib/sync/outbox.js.map +1 -1
- package/lib/sync/processors/errorMaps.d.ts +17 -0
- package/lib/sync/processors/errorMaps.js +125 -0
- package/lib/sync/processors/errorMaps.js.map +1 -0
- package/lib/sync/processors/mutation.d.ts +22 -4
- package/lib/sync/processors/mutation.js +119 -51
- package/lib/sync/processors/mutation.js.map +1 -1
- package/lib/sync/processors/subscription.d.ts +4 -2
- package/lib/sync/processors/subscription.js +76 -41
- package/lib/sync/processors/subscription.js.map +1 -1
- package/lib/sync/processors/sync.d.ts +4 -2
- package/lib/sync/processors/sync.js +62 -27
- package/lib/sync/processors/sync.js.map +1 -1
- package/lib/sync/utils.d.ts +3 -2
- package/lib/sync/utils.js +54 -7
- package/lib/sync/utils.js.map +1 -1
- package/lib/types.d.ts +85 -33
- package/lib/types.js +31 -2
- package/lib/types.js.map +1 -1
- package/lib/util.d.ts +43 -33
- package/lib/util.js +161 -21
- package/lib/util.js.map +1 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +2 -2
- package/lib-esm/authModeStrategies/multiAuthStrategy.js +32 -26
- package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib-esm/datastore/datastore.d.ts +17 -16
- package/lib-esm/datastore/datastore.js +252 -80
- package/lib-esm/datastore/datastore.js.map +1 -1
- package/lib-esm/index.d.ts +3 -19
- package/lib-esm/predicates/index.d.ts +3 -2
- package/lib-esm/predicates/index.js +13 -3
- package/lib-esm/predicates/index.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +6 -2
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js +140 -66
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +4 -4
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js +57 -27
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib-esm/storage/adapter/InMemoryStore.js +2 -2
- package/lib-esm/storage/adapter/InMemoryStore.js.map +1 -1
- package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +7 -2
- package/lib-esm/storage/adapter/IndexedDBAdapter.js +460 -253
- package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/index.d.ts +1 -1
- package/lib-esm/storage/storage.d.ts +3 -3
- package/lib-esm/storage/storage.js +106 -28
- package/lib-esm/storage/storage.js.map +1 -1
- package/lib-esm/sync/index.d.ts +23 -7
- package/lib-esm/sync/index.js +20 -19
- package/lib-esm/sync/index.js.map +1 -1
- package/lib-esm/sync/merger.d.ts +3 -3
- package/lib-esm/sync/merger.js +8 -6
- package/lib-esm/sync/merger.js.map +1 -1
- package/lib-esm/sync/outbox.d.ts +2 -2
- package/lib-esm/sync/outbox.js +13 -10
- package/lib-esm/sync/outbox.js.map +1 -1
- package/lib-esm/sync/processors/errorMaps.d.ts +17 -0
- package/lib-esm/sync/processors/errorMaps.js +119 -0
- package/lib-esm/sync/processors/errorMaps.js.map +1 -0
- package/lib-esm/sync/processors/mutation.d.ts +22 -4
- package/lib-esm/sync/processors/mutation.js +122 -54
- package/lib-esm/sync/processors/mutation.js.map +1 -1
- package/lib-esm/sync/processors/subscription.d.ts +4 -2
- package/lib-esm/sync/processors/subscription.js +77 -42
- package/lib-esm/sync/processors/subscription.js.map +1 -1
- package/lib-esm/sync/processors/sync.d.ts +4 -2
- package/lib-esm/sync/processors/sync.js +62 -27
- package/lib-esm/sync/processors/sync.js.map +1 -1
- package/lib-esm/sync/utils.d.ts +3 -2
- package/lib-esm/sync/utils.js +54 -8
- package/lib-esm/sync/utils.js.map +1 -1
- package/lib-esm/types.d.ts +85 -33
- package/lib-esm/types.js +29 -3
- package/lib-esm/types.js.map +1 -1
- package/lib-esm/util.d.ts +43 -33
- package/lib-esm/util.js +151 -18
- package/lib-esm/util.js.map +1 -1
- package/package.json +10 -9
- package/src/authModeStrategies/multiAuthStrategy.ts +24 -21
- package/src/datastore/datastore.ts +396 -143
- package/src/predicates/index.ts +32 -10
- package/src/storage/adapter/AsyncStorageAdapter.ts +161 -61
- package/src/storage/adapter/AsyncStorageDatabase.ts +62 -25
- package/src/storage/adapter/InMemoryStore.ts +2 -2
- package/src/storage/adapter/IndexedDBAdapter.ts +355 -101
- package/src/storage/adapter/index.ts +1 -1
- package/src/storage/storage.ts +85 -24
- package/src/sync/index.ts +74 -58
- package/src/sync/merger.ts +16 -4
- package/src/sync/outbox.ts +22 -8
- package/src/sync/processors/errorMaps.ts +93 -0
- package/src/sync/processors/mutation.ts +143 -84
- package/src/sync/processors/subscription.ts +67 -36
- package/src/sync/processors/sync.ts +37 -12
- package/src/sync/utils.ts +63 -15
- package/src/types.ts +242 -49
- package/src/util.ts +212 -35
- package/ssr/package.json +1 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import API from '@aws-amplify/api';
|
|
1
2
|
import { Amplify, ConsoleLogger as Logger, Hub, JS } from '@aws-amplify/core';
|
|
3
|
+
import { Auth } from '@aws-amplify/auth';
|
|
4
|
+
import Cache from '@aws-amplify/cache';
|
|
2
5
|
import {
|
|
3
6
|
Draft,
|
|
4
7
|
immerable,
|
|
@@ -54,6 +57,12 @@ import {
|
|
|
54
57
|
isNonModelFieldType,
|
|
55
58
|
isModelFieldType,
|
|
56
59
|
ObserveQueryOptions,
|
|
60
|
+
ManagedIdentifier,
|
|
61
|
+
PersistentModelMetaData,
|
|
62
|
+
IdentifierFieldOrIdentifierObject,
|
|
63
|
+
__modelMeta__,
|
|
64
|
+
isIdentifierObject,
|
|
65
|
+
AmplifyContext,
|
|
57
66
|
} from '../types';
|
|
58
67
|
import {
|
|
59
68
|
DATASTORE,
|
|
@@ -69,6 +78,11 @@ import {
|
|
|
69
78
|
registerNonModelClass,
|
|
70
79
|
sortCompareFunction,
|
|
71
80
|
DeferredCallbackResolver,
|
|
81
|
+
extractPrimaryKeyFieldNames,
|
|
82
|
+
isIdManaged,
|
|
83
|
+
isIdOptionallyManaged,
|
|
84
|
+
validatePredicate,
|
|
85
|
+
mergePatches,
|
|
72
86
|
} from '../util';
|
|
73
87
|
|
|
74
88
|
setAutoFreeze(true);
|
|
@@ -79,11 +93,16 @@ const logger = new Logger('DataStore');
|
|
|
79
93
|
const ulid = monotonicUlidFactory(Date.now());
|
|
80
94
|
const { isNode } = JS.browserOrNode();
|
|
81
95
|
|
|
96
|
+
type SettingMetaData = {
|
|
97
|
+
identifier: ManagedIdentifier<Setting, 'id'>;
|
|
98
|
+
readOnlyFields: never;
|
|
99
|
+
};
|
|
82
100
|
declare class Setting {
|
|
83
|
-
|
|
101
|
+
public readonly [__modelMeta__]: SettingMetaData;
|
|
102
|
+
constructor(init: ModelInit<Setting, SettingMetaData>);
|
|
84
103
|
static copyOf(
|
|
85
104
|
src: Setting,
|
|
86
|
-
mutator: (draft: MutableModel<Setting>) => void | Setting
|
|
105
|
+
mutator: (draft: MutableModel<Setting, SettingMetaData>) => void | Setting
|
|
87
106
|
): Setting;
|
|
88
107
|
public readonly id: string;
|
|
89
108
|
public readonly key: string;
|
|
@@ -222,6 +241,20 @@ const initSchema = (userSchema: Schema) => {
|
|
|
222
241
|
return userClasses;
|
|
223
242
|
};
|
|
224
243
|
|
|
244
|
+
/* Checks if the schema has been initialized by initSchema().
|
|
245
|
+
*
|
|
246
|
+
* Call this function before accessing schema.
|
|
247
|
+
* Currently this only needs to be called in start() and clear() because all other functions will call start first.
|
|
248
|
+
*/
|
|
249
|
+
const checkSchemaInitialized = () => {
|
|
250
|
+
if (schema === undefined) {
|
|
251
|
+
const message =
|
|
252
|
+
'Schema is not initialized. DataStore will not function as expected. This could happen if you have multiple versions of DataStore installed. Please see https://docs.amplify.aws/lib/troubleshooting/upgrading/q/platform/js/#check-for-duplicate-versions';
|
|
253
|
+
logger.error(message);
|
|
254
|
+
throw new Error(message);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
|
|
225
258
|
const createTypeClasses: (
|
|
226
259
|
namespace: SchemaNamespace
|
|
227
260
|
) => TypeConstructorMap = namespace => {
|
|
@@ -246,16 +279,15 @@ const createTypeClasses: (
|
|
|
246
279
|
|
|
247
280
|
export declare type ModelInstanceCreator = typeof modelInstanceCreator;
|
|
248
281
|
|
|
249
|
-
const instancesMetadata = new WeakSet<
|
|
250
|
-
|
|
251
|
-
>(
|
|
252
|
-
function modelInstanceCreator<T extends PersistentModel = PersistentModel>(
|
|
282
|
+
const instancesMetadata = new WeakSet<ModelInit<unknown, unknown>>();
|
|
283
|
+
|
|
284
|
+
function modelInstanceCreator<T extends PersistentModel>(
|
|
253
285
|
modelConstructor: PersistentModelConstructor<T>,
|
|
254
|
-
init:
|
|
286
|
+
init: Partial<T>
|
|
255
287
|
): T {
|
|
256
288
|
instancesMetadata.add(init);
|
|
257
289
|
|
|
258
|
-
return
|
|
290
|
+
return new modelConstructor(<ModelInit<T, PersistentModelMetaData<T>>>init);
|
|
259
291
|
}
|
|
260
292
|
|
|
261
293
|
const validateModelFields =
|
|
@@ -383,7 +415,7 @@ const castInstanceType = (
|
|
|
383
415
|
return v;
|
|
384
416
|
};
|
|
385
417
|
|
|
386
|
-
const initializeInstance = <T>(
|
|
418
|
+
const initializeInstance = <T extends PersistentModel>(
|
|
387
419
|
init: ModelInit<T>,
|
|
388
420
|
modelDefinition: SchemaModel | SchemaNonModel,
|
|
389
421
|
draft: Draft<T & ModelInstanceMetadata>
|
|
@@ -407,31 +439,39 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
407
439
|
(draft: Draft<T & ModelInstanceMetadata>) => {
|
|
408
440
|
initializeInstance(init, modelDefinition, draft);
|
|
409
441
|
|
|
442
|
+
// model is initialized inside a DataStore component (e.g. by Sync Engine, Storage Engine, etc.)
|
|
443
|
+
const isInternallyInitialized = instancesMetadata.has(init);
|
|
444
|
+
|
|
410
445
|
const modelInstanceMetadata: ModelInstanceMetadata =
|
|
411
|
-
|
|
446
|
+
isInternallyInitialized
|
|
412
447
|
? <ModelInstanceMetadata>(<unknown>init)
|
|
413
448
|
: <ModelInstanceMetadata>{};
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if (
|
|
449
|
+
|
|
450
|
+
type ModelWithIDIdentifier = { id: string };
|
|
451
|
+
|
|
452
|
+
const { id: _id } =
|
|
453
|
+
modelInstanceMetadata as unknown as ModelWithIDIdentifier;
|
|
454
|
+
|
|
455
|
+
if (isIdManaged(modelDefinition)) {
|
|
456
|
+
const isInternalModel = _id !== null && _id !== undefined;
|
|
457
|
+
|
|
458
|
+
const id = isInternalModel
|
|
459
|
+
? _id
|
|
460
|
+
: modelDefinition.syncable
|
|
461
|
+
? uuid4()
|
|
462
|
+
: ulid();
|
|
463
|
+
|
|
464
|
+
(<ModelWithIDIdentifier>(<unknown>draft)).id = id;
|
|
465
|
+
} else if (isIdOptionallyManaged(modelDefinition)) {
|
|
466
|
+
// only auto-populate if the id was not provided
|
|
467
|
+
(<ModelWithIDIdentifier>(<unknown>draft)).id = draft.id || uuid4();
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (!isInternallyInitialized) {
|
|
431
471
|
checkReadOnlyPropertyOnCreate(draft, modelDefinition);
|
|
432
472
|
}
|
|
433
473
|
|
|
434
|
-
|
|
474
|
+
const { _version, _lastChangedAt, _deleted } = modelInstanceMetadata;
|
|
435
475
|
|
|
436
476
|
if (modelDefinition.syncable) {
|
|
437
477
|
draft._version = _version;
|
|
@@ -456,8 +496,14 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
456
496
|
const model = produce(
|
|
457
497
|
source,
|
|
458
498
|
draft => {
|
|
459
|
-
fn(<MutableModel<T>>
|
|
460
|
-
|
|
499
|
+
fn(<MutableModel<T>>draft);
|
|
500
|
+
|
|
501
|
+
const keyNames = extractPrimaryKeyFieldNames(modelDefinition);
|
|
502
|
+
// Keys are immutable
|
|
503
|
+
// CPK TODO: Previous comment from Ivan:
|
|
504
|
+
// @ts-ignore TODO: fix type
|
|
505
|
+
keyNames.forEach(key => (draft[key] = source[key]));
|
|
506
|
+
|
|
461
507
|
const modelValidator = validateModelFields(modelDefinition);
|
|
462
508
|
Object.entries(draft).forEach(([k, v]) => {
|
|
463
509
|
const parsedValue = castInstanceType(modelDefinition, k, v);
|
|
@@ -468,9 +514,21 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
468
514
|
p => (patches = p)
|
|
469
515
|
);
|
|
470
516
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
517
|
+
const hasExistingPatches = modelPatchesMap.has(source);
|
|
518
|
+
if (patches.length || hasExistingPatches) {
|
|
519
|
+
if (hasExistingPatches) {
|
|
520
|
+
const [existingPatches, existingSource] = modelPatchesMap.get(source);
|
|
521
|
+
const mergedPatches = mergePatches(
|
|
522
|
+
existingSource,
|
|
523
|
+
existingPatches,
|
|
524
|
+
patches
|
|
525
|
+
);
|
|
526
|
+
modelPatchesMap.set(model, [mergedPatches, existingSource]);
|
|
527
|
+
checkReadOnlyPropertyOnUpdate(mergedPatches, modelDefinition);
|
|
528
|
+
} else {
|
|
529
|
+
modelPatchesMap.set(model, [patches, source]);
|
|
530
|
+
checkReadOnlyPropertyOnUpdate(patches, modelDefinition);
|
|
531
|
+
}
|
|
474
532
|
}
|
|
475
533
|
|
|
476
534
|
return model;
|
|
@@ -484,6 +542,7 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
484
542
|
}
|
|
485
543
|
|
|
486
544
|
const instance = modelInstanceCreator(clazz, json);
|
|
545
|
+
|
|
487
546
|
const modelValidator = validateModelFields(modelDefinition);
|
|
488
547
|
|
|
489
548
|
Object.entries(instance).forEach(([k, v]) => {
|
|
@@ -531,7 +590,9 @@ const checkReadOnlyPropertyOnUpdate = (
|
|
|
531
590
|
});
|
|
532
591
|
};
|
|
533
592
|
|
|
534
|
-
const createNonModelClass = <T>(
|
|
593
|
+
const createNonModelClass = <T extends PersistentModel>(
|
|
594
|
+
typeDefinition: SchemaNonModel
|
|
595
|
+
) => {
|
|
535
596
|
const clazz = <NonModelTypeConstructor<T>>(<unknown>class Model {
|
|
536
597
|
constructor(init: ModelInit<T>) {
|
|
537
598
|
const instance = produce(
|
|
@@ -564,7 +625,7 @@ function defaultConflictHandler(conflictData: SyncConflict): PersistentModel {
|
|
|
564
625
|
return modelInstanceCreator(modelConstructor, { ...localModel, _version });
|
|
565
626
|
}
|
|
566
627
|
|
|
567
|
-
function defaultErrorHandler(error: SyncError) {
|
|
628
|
+
function defaultErrorHandler(error: SyncError<PersistentModel>): void {
|
|
568
629
|
logger.warn(error);
|
|
569
630
|
}
|
|
570
631
|
|
|
@@ -615,7 +676,6 @@ async function checkSchemaVersion(
|
|
|
615
676
|
const [schemaVersionSetting] = await s.query(
|
|
616
677
|
Setting,
|
|
617
678
|
ModelPredicateCreator.createFromExisting(modelDefinition, c =>
|
|
618
|
-
// @ts-ignore Argument of type '"eq"' is not assignable to parameter of type 'never'.
|
|
619
679
|
c.key('eq', SETTING_SCHEMA_VERSION)
|
|
620
680
|
),
|
|
621
681
|
{ page: 0, limit: 1 }
|
|
@@ -682,23 +742,34 @@ function getNamespace(): SchemaNamespace {
|
|
|
682
742
|
}
|
|
683
743
|
|
|
684
744
|
class DataStore {
|
|
745
|
+
// reference to configured category instances. Used for preserving SSR context
|
|
746
|
+
Auth = Auth;
|
|
747
|
+
API = API;
|
|
748
|
+
Cache = Cache;
|
|
749
|
+
|
|
685
750
|
private amplifyConfig: Record<string, any> = {};
|
|
686
751
|
private authModeStrategy: AuthModeStrategy;
|
|
687
752
|
private conflictHandler: ConflictHandler;
|
|
688
|
-
private errorHandler: (error: SyncError) => void;
|
|
753
|
+
private errorHandler: (error: SyncError<PersistentModel>) => void;
|
|
689
754
|
private fullSyncInterval: number;
|
|
690
|
-
private initialized
|
|
755
|
+
private initialized?: Promise<void>;
|
|
691
756
|
private initReject: Function;
|
|
692
757
|
private initResolve: Function;
|
|
693
758
|
private maxRecordsToSync: number;
|
|
694
|
-
private storage
|
|
695
|
-
private sync
|
|
759
|
+
private storage?: Storage;
|
|
760
|
+
private sync?: SyncEngine;
|
|
696
761
|
private syncPageSize: number;
|
|
697
762
|
private syncExpressions: SyncExpression[];
|
|
698
763
|
private syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>> =
|
|
699
764
|
new WeakMap<SchemaModel, ModelPredicate<any>>();
|
|
700
765
|
private sessionId: string;
|
|
701
766
|
private storageAdapter: Adapter;
|
|
767
|
+
// object that gets passed to descendent classes. Allows us to pass these down by reference
|
|
768
|
+
private amplifyContext: AmplifyContext = {
|
|
769
|
+
Auth: this.Auth,
|
|
770
|
+
API: this.API,
|
|
771
|
+
Cache: this.Cache,
|
|
772
|
+
};
|
|
702
773
|
|
|
703
774
|
getModuleName() {
|
|
704
775
|
return 'DataStore';
|
|
@@ -728,6 +799,7 @@ class DataStore {
|
|
|
728
799
|
|
|
729
800
|
await this.storage.init();
|
|
730
801
|
|
|
802
|
+
checkSchemaInitialized();
|
|
731
803
|
await checkSchemaVersion(this.storage, schema.version);
|
|
732
804
|
|
|
733
805
|
const { aws_appsync_graphqlEndpoint } = this.amplifyConfig;
|
|
@@ -744,13 +816,12 @@ class DataStore {
|
|
|
744
816
|
userClasses,
|
|
745
817
|
this.storage,
|
|
746
818
|
modelInstanceCreator,
|
|
747
|
-
this.maxRecordsToSync,
|
|
748
|
-
this.syncPageSize,
|
|
749
819
|
this.conflictHandler,
|
|
750
820
|
this.errorHandler,
|
|
751
821
|
this.syncPredicates,
|
|
752
822
|
this.amplifyConfig,
|
|
753
|
-
this.authModeStrategy
|
|
823
|
+
this.authModeStrategy,
|
|
824
|
+
this.amplifyContext
|
|
754
825
|
);
|
|
755
826
|
|
|
756
827
|
// tslint:disable-next-line:max-line-length
|
|
@@ -796,7 +867,10 @@ class DataStore {
|
|
|
796
867
|
query: {
|
|
797
868
|
<T extends PersistentModel>(
|
|
798
869
|
modelConstructor: PersistentModelConstructor<T>,
|
|
799
|
-
|
|
870
|
+
identifier: IdentifierFieldOrIdentifierObject<
|
|
871
|
+
T,
|
|
872
|
+
PersistentModelMetaData<T>
|
|
873
|
+
>
|
|
800
874
|
): Promise<T | undefined>;
|
|
801
875
|
<T extends PersistentModel>(
|
|
802
876
|
modelConstructor: PersistentModelConstructor<T>,
|
|
@@ -805,7 +879,10 @@ class DataStore {
|
|
|
805
879
|
): Promise<T[]>;
|
|
806
880
|
} = async <T extends PersistentModel>(
|
|
807
881
|
modelConstructor: PersistentModelConstructor<T>,
|
|
808
|
-
|
|
882
|
+
identifierOrCriteria?:
|
|
883
|
+
| IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
|
|
884
|
+
| ProducerModelPredicate<T>
|
|
885
|
+
| typeof PredicateAll,
|
|
809
886
|
paginationProducer?: ProducerPaginationInput<T>
|
|
810
887
|
): Promise<T | T[] | undefined> => {
|
|
811
888
|
await this.start();
|
|
@@ -819,28 +896,37 @@ class DataStore {
|
|
|
819
896
|
throw new Error(msg);
|
|
820
897
|
}
|
|
821
898
|
|
|
822
|
-
if (typeof
|
|
899
|
+
if (typeof identifierOrCriteria === 'string') {
|
|
823
900
|
if (paginationProducer !== undefined) {
|
|
824
901
|
logger.warn('Pagination is ignored when querying by id');
|
|
825
902
|
}
|
|
826
903
|
}
|
|
827
904
|
|
|
828
905
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
906
|
+
const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
|
|
907
|
+
|
|
829
908
|
let predicate: ModelPredicate<T>;
|
|
830
909
|
|
|
831
|
-
if (isQueryOne(
|
|
832
|
-
predicate = ModelPredicateCreator.
|
|
910
|
+
if (isQueryOne(identifierOrCriteria)) {
|
|
911
|
+
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
833
912
|
modelDefinition,
|
|
834
|
-
|
|
913
|
+
keyFields[0],
|
|
914
|
+
identifierOrCriteria
|
|
835
915
|
);
|
|
836
916
|
} else {
|
|
837
|
-
|
|
917
|
+
// Object is being queried using object literal syntax
|
|
918
|
+
if (isIdentifierObject(<T>identifierOrCriteria, modelDefinition)) {
|
|
919
|
+
predicate = ModelPredicateCreator.createForPk<T>(
|
|
920
|
+
modelDefinition,
|
|
921
|
+
<T>identifierOrCriteria
|
|
922
|
+
);
|
|
923
|
+
} else if (isPredicatesAll(identifierOrCriteria)) {
|
|
838
924
|
// Predicates.ALL means "all records", so no predicate (undefined)
|
|
839
925
|
predicate = undefined;
|
|
840
926
|
} else {
|
|
841
927
|
predicate = ModelPredicateCreator.createFromExisting(
|
|
842
928
|
modelDefinition,
|
|
843
|
-
|
|
929
|
+
<any>identifierOrCriteria
|
|
844
930
|
);
|
|
845
931
|
}
|
|
846
932
|
}
|
|
@@ -870,7 +956,13 @@ class DataStore {
|
|
|
870
956
|
pagination
|
|
871
957
|
);
|
|
872
958
|
|
|
873
|
-
|
|
959
|
+
const isSingleFieldIdentifier = keyFields.length === 1;
|
|
960
|
+
const returnOne =
|
|
961
|
+
isSingleFieldIdentifier &&
|
|
962
|
+
(isQueryOne(identifierOrCriteria) ||
|
|
963
|
+
isIdentifierObject(identifierOrCriteria, modelDefinition));
|
|
964
|
+
|
|
965
|
+
return returnOne ? result[0] : result;
|
|
874
966
|
};
|
|
875
967
|
|
|
876
968
|
save = async <T extends PersistentModel>(
|
|
@@ -883,7 +975,7 @@ class DataStore {
|
|
|
883
975
|
// Allows us to only include changed fields for updates
|
|
884
976
|
const patchesTuple = modelPatchesMap.get(model);
|
|
885
977
|
|
|
886
|
-
const modelConstructor: PersistentModelConstructor<T> = model
|
|
978
|
+
const modelConstructor: PersistentModelConstructor<T> | undefined = model
|
|
887
979
|
? <PersistentModelConstructor<T>>model.constructor
|
|
888
980
|
: undefined;
|
|
889
981
|
|
|
@@ -898,15 +990,15 @@ class DataStore {
|
|
|
898
990
|
|
|
899
991
|
const producedCondition = ModelPredicateCreator.createFromExisting(
|
|
900
992
|
modelDefinition,
|
|
901
|
-
condition
|
|
993
|
+
condition!
|
|
902
994
|
);
|
|
903
995
|
|
|
904
996
|
const [savedModel] = await this.storage.runExclusive(async s => {
|
|
905
997
|
await s.save(model, producedCondition, undefined, patchesTuple);
|
|
906
998
|
|
|
907
|
-
return s.query(
|
|
999
|
+
return s.query<T>(
|
|
908
1000
|
modelConstructor,
|
|
909
|
-
ModelPredicateCreator.
|
|
1001
|
+
ModelPredicateCreator.createForPk(modelDefinition, model)
|
|
910
1002
|
);
|
|
911
1003
|
});
|
|
912
1004
|
|
|
@@ -946,22 +1038,28 @@ class DataStore {
|
|
|
946
1038
|
};
|
|
947
1039
|
|
|
948
1040
|
delete: {
|
|
949
|
-
<T extends PersistentModel>(
|
|
950
|
-
model: T,
|
|
951
|
-
condition?: ProducerModelPredicate<T>
|
|
952
|
-
): Promise<T>;
|
|
953
1041
|
<T extends PersistentModel>(
|
|
954
1042
|
modelConstructor: PersistentModelConstructor<T>,
|
|
955
|
-
|
|
1043
|
+
identifier: IdentifierFieldOrIdentifierObject<
|
|
1044
|
+
T,
|
|
1045
|
+
PersistentModelMetaData<T>
|
|
1046
|
+
>
|
|
956
1047
|
): Promise<T[]>;
|
|
957
1048
|
<T extends PersistentModel>(
|
|
958
1049
|
modelConstructor: PersistentModelConstructor<T>,
|
|
959
1050
|
condition: ProducerModelPredicate<T> | typeof PredicateAll
|
|
960
1051
|
): Promise<T[]>;
|
|
1052
|
+
<T extends PersistentModel>(
|
|
1053
|
+
model: T,
|
|
1054
|
+
condition?: ProducerModelPredicate<T>
|
|
1055
|
+
): Promise<T>;
|
|
961
1056
|
} = async <T extends PersistentModel>(
|
|
962
1057
|
modelOrConstructor: T | PersistentModelConstructor<T>,
|
|
963
|
-
|
|
964
|
-
|
|
1058
|
+
identifierOrCriteria?:
|
|
1059
|
+
| IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
|
|
1060
|
+
| ProducerModelPredicate<T>
|
|
1061
|
+
| typeof PredicateAll
|
|
1062
|
+
): Promise<T | T[]> => {
|
|
965
1063
|
await this.start();
|
|
966
1064
|
|
|
967
1065
|
let condition: ModelPredicate<T>;
|
|
@@ -973,31 +1071,43 @@ class DataStore {
|
|
|
973
1071
|
throw new Error(msg);
|
|
974
1072
|
}
|
|
975
1073
|
|
|
976
|
-
if (isValidModelConstructor(modelOrConstructor)) {
|
|
1074
|
+
if (isValidModelConstructor<T>(modelOrConstructor)) {
|
|
977
1075
|
const modelConstructor = modelOrConstructor;
|
|
978
1076
|
|
|
979
|
-
if (!
|
|
1077
|
+
if (!identifierOrCriteria) {
|
|
980
1078
|
const msg =
|
|
981
1079
|
'Id to delete or criteria required. Do you want to delete all? Pass Predicates.ALL';
|
|
982
|
-
logger.error(msg, {
|
|
1080
|
+
logger.error(msg, { identifierOrCriteria });
|
|
983
1081
|
|
|
984
1082
|
throw new Error(msg);
|
|
985
1083
|
}
|
|
986
1084
|
|
|
987
|
-
|
|
988
|
-
|
|
1085
|
+
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1086
|
+
|
|
1087
|
+
if (typeof identifierOrCriteria === 'string') {
|
|
1088
|
+
const [keyField] = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1089
|
+
|
|
1090
|
+
condition = ModelPredicateCreator.createForSingleField<T>(
|
|
989
1091
|
getModelDefinition(modelConstructor),
|
|
990
|
-
|
|
1092
|
+
keyField,
|
|
1093
|
+
identifierOrCriteria
|
|
991
1094
|
);
|
|
992
1095
|
} else {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1096
|
+
if (isIdentifierObject(identifierOrCriteria, modelDefinition)) {
|
|
1097
|
+
condition = ModelPredicateCreator.createForPk<T>(
|
|
1098
|
+
modelDefinition,
|
|
1099
|
+
<T>identifierOrCriteria
|
|
1100
|
+
);
|
|
1101
|
+
} else {
|
|
1102
|
+
condition = ModelPredicateCreator.createFromExisting(
|
|
1103
|
+
modelDefinition,
|
|
1104
|
+
/**
|
|
1105
|
+
* idOrCriteria is always a ProducerModelPredicate<T>, never a symbol.
|
|
1106
|
+
* The symbol is used only for typing purposes. e.g. see Predicates.ALL
|
|
1107
|
+
*/
|
|
1108
|
+
identifierOrCriteria as ProducerModelPredicate<T>
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1001
1111
|
|
|
1002
1112
|
if (!condition || !ModelPredicateCreator.isValidPredicate(condition)) {
|
|
1003
1113
|
const msg =
|
|
@@ -1025,22 +1135,24 @@ class DataStore {
|
|
|
1025
1135
|
|
|
1026
1136
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1027
1137
|
|
|
1028
|
-
const
|
|
1138
|
+
const pkPredicate = ModelPredicateCreator.createForPk<T>(
|
|
1029
1139
|
modelDefinition,
|
|
1030
|
-
model
|
|
1140
|
+
model
|
|
1031
1141
|
);
|
|
1032
1142
|
|
|
1033
|
-
if (
|
|
1034
|
-
if (typeof
|
|
1143
|
+
if (identifierOrCriteria) {
|
|
1144
|
+
if (typeof identifierOrCriteria !== 'function') {
|
|
1035
1145
|
const msg = 'Invalid criteria';
|
|
1036
|
-
logger.error(msg, {
|
|
1146
|
+
logger.error(msg, { identifierOrCriteria });
|
|
1037
1147
|
|
|
1038
1148
|
throw new Error(msg);
|
|
1039
1149
|
}
|
|
1040
1150
|
|
|
1041
|
-
condition =
|
|
1151
|
+
condition = (<ProducerModelPredicate<T>>identifierOrCriteria)(
|
|
1152
|
+
pkPredicate
|
|
1153
|
+
);
|
|
1042
1154
|
} else {
|
|
1043
|
-
condition =
|
|
1155
|
+
condition = pkPredicate;
|
|
1044
1156
|
}
|
|
1045
1157
|
|
|
1046
1158
|
const [[deleted]] = await this.storage.delete(model, condition);
|
|
@@ -1052,20 +1164,28 @@ class DataStore {
|
|
|
1052
1164
|
observe: {
|
|
1053
1165
|
(): Observable<SubscriptionMessage<PersistentModel>>;
|
|
1054
1166
|
|
|
1055
|
-
<T extends PersistentModel>(
|
|
1167
|
+
<T extends PersistentModel>(
|
|
1168
|
+
modelConstructor: PersistentModelConstructor<T>,
|
|
1169
|
+
identifier: string
|
|
1170
|
+
): Observable<SubscriptionMessage<T>>;
|
|
1056
1171
|
|
|
1057
1172
|
<T extends PersistentModel>(
|
|
1058
1173
|
modelConstructor: PersistentModelConstructor<T>,
|
|
1059
|
-
criteria?:
|
|
1174
|
+
criteria?: ProducerModelPredicate<T> | typeof PredicateAll
|
|
1060
1175
|
): Observable<SubscriptionMessage<T>>;
|
|
1061
|
-
|
|
1176
|
+
|
|
1177
|
+
<T extends PersistentModel>(model: T): Observable<SubscriptionMessage<T>>;
|
|
1178
|
+
} = <T extends PersistentModel>(
|
|
1062
1179
|
modelOrConstructor?: T | PersistentModelConstructor<T>,
|
|
1063
|
-
|
|
1180
|
+
identifierOrCriteria?:
|
|
1181
|
+
| string
|
|
1182
|
+
| ProducerModelPredicate<T>
|
|
1183
|
+
| typeof PredicateAll
|
|
1064
1184
|
): Observable<SubscriptionMessage<T>> => {
|
|
1065
1185
|
let predicate: ModelPredicate<T>;
|
|
1066
1186
|
|
|
1067
|
-
const modelConstructor: PersistentModelConstructor<T> =
|
|
1068
|
-
modelOrConstructor && isValidModelConstructor(modelOrConstructor)
|
|
1187
|
+
const modelConstructor: PersistentModelConstructor<T> | undefined =
|
|
1188
|
+
modelOrConstructor && isValidModelConstructor<T>(modelOrConstructor)
|
|
1069
1189
|
? modelOrConstructor
|
|
1070
1190
|
: undefined;
|
|
1071
1191
|
|
|
@@ -1075,10 +1195,10 @@ class DataStore {
|
|
|
1075
1195
|
model && (<Object>Object.getPrototypeOf(model)).constructor;
|
|
1076
1196
|
|
|
1077
1197
|
if (isValidModelConstructor<T>(modelConstructor)) {
|
|
1078
|
-
if (
|
|
1198
|
+
if (identifierOrCriteria) {
|
|
1079
1199
|
logger.warn('idOrCriteria is ignored when using a model instance', {
|
|
1080
1200
|
model,
|
|
1081
|
-
|
|
1201
|
+
identifierOrCriteria,
|
|
1082
1202
|
});
|
|
1083
1203
|
}
|
|
1084
1204
|
|
|
@@ -1092,9 +1212,9 @@ class DataStore {
|
|
|
1092
1212
|
}
|
|
1093
1213
|
}
|
|
1094
1214
|
|
|
1095
|
-
if (
|
|
1215
|
+
if (identifierOrCriteria !== undefined && modelConstructor === undefined) {
|
|
1096
1216
|
const msg = 'Cannot provide criteria without a modelConstructor';
|
|
1097
|
-
logger.error(msg,
|
|
1217
|
+
logger.error(msg, identifierOrCriteria);
|
|
1098
1218
|
throw new Error(msg);
|
|
1099
1219
|
}
|
|
1100
1220
|
|
|
@@ -1105,18 +1225,26 @@ class DataStore {
|
|
|
1105
1225
|
throw new Error(msg);
|
|
1106
1226
|
}
|
|
1107
1227
|
|
|
1108
|
-
if (typeof
|
|
1109
|
-
|
|
1228
|
+
if (typeof identifierOrCriteria === 'string') {
|
|
1229
|
+
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1230
|
+
const [keyField] = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1231
|
+
|
|
1232
|
+
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
1110
1233
|
getModelDefinition(modelConstructor),
|
|
1111
|
-
|
|
1234
|
+
keyField,
|
|
1235
|
+
identifierOrCriteria
|
|
1112
1236
|
);
|
|
1113
1237
|
} else {
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1238
|
+
if (isPredicatesAll(identifierOrCriteria)) {
|
|
1239
|
+
predicate = undefined;
|
|
1240
|
+
} else {
|
|
1241
|
+
predicate =
|
|
1242
|
+
modelConstructor &&
|
|
1243
|
+
ModelPredicateCreator.createFromExisting<T>(
|
|
1244
|
+
getModelDefinition(modelConstructor),
|
|
1245
|
+
identifierOrCriteria
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1120
1248
|
}
|
|
1121
1249
|
|
|
1122
1250
|
return new Observable<SubscriptionMessage<T>>(observer => {
|
|
@@ -1125,10 +1253,37 @@ class DataStore {
|
|
|
1125
1253
|
(async () => {
|
|
1126
1254
|
await this.start();
|
|
1127
1255
|
|
|
1256
|
+
// Filter the events returned by Storage according to namespace,
|
|
1257
|
+
// append original element data, and subscribe to the observable
|
|
1128
1258
|
handle = this.storage
|
|
1129
1259
|
.observe(modelConstructor, predicate)
|
|
1130
1260
|
.filter(({ model }) => namespaceResolver(model) === USER)
|
|
1131
|
-
.subscribe(
|
|
1261
|
+
.subscribe({
|
|
1262
|
+
next: async item => {
|
|
1263
|
+
// the `element` doesn't necessarily contain all item details or
|
|
1264
|
+
// have related records attached consistently with that of a query()
|
|
1265
|
+
// result item. for consistency, we attach them here.
|
|
1266
|
+
|
|
1267
|
+
let message = item;
|
|
1268
|
+
|
|
1269
|
+
// as lnog as we're not dealing with a DELETE, we need to fetch a fresh
|
|
1270
|
+
// item from storage to ensure it's fully populated.
|
|
1271
|
+
if (item.opType !== 'DELETE') {
|
|
1272
|
+
const freshElement = await this.query(
|
|
1273
|
+
item.model,
|
|
1274
|
+
item.element.id
|
|
1275
|
+
);
|
|
1276
|
+
message = {
|
|
1277
|
+
...message,
|
|
1278
|
+
element: freshElement as T,
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
observer.next(message as SubscriptionMessage<T>);
|
|
1283
|
+
},
|
|
1284
|
+
error: err => observer.error(err),
|
|
1285
|
+
complete: () => observer.complete(),
|
|
1286
|
+
});
|
|
1132
1287
|
})();
|
|
1133
1288
|
|
|
1134
1289
|
return () => {
|
|
@@ -1145,7 +1300,7 @@ class DataStore {
|
|
|
1145
1300
|
criteria?: ProducerModelPredicate<T> | typeof PredicateAll,
|
|
1146
1301
|
paginationProducer?: ObserveQueryOptions<T>
|
|
1147
1302
|
): Observable<DataStoreSnapshot<T>>;
|
|
1148
|
-
} = <T extends PersistentModel
|
|
1303
|
+
} = <T extends PersistentModel>(
|
|
1149
1304
|
model: PersistentModelConstructor<T>,
|
|
1150
1305
|
criteria?: ProducerModelPredicate<T> | typeof PredicateAll,
|
|
1151
1306
|
options?: ObserveQueryOptions<T>
|
|
@@ -1155,7 +1310,18 @@ class DataStore {
|
|
|
1155
1310
|
const itemsChanged = new Map<string, T>();
|
|
1156
1311
|
let deletedItemIds: string[] = [];
|
|
1157
1312
|
let handle: ZenObservable.Subscription;
|
|
1158
|
-
|
|
1313
|
+
let predicate: ModelPredicate<T>;
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* As the name suggests, this geneates a snapshot in the form of
|
|
1317
|
+
* `{items: T[], isSynced: boolean}`
|
|
1318
|
+
* and sends it to the observer.
|
|
1319
|
+
*
|
|
1320
|
+
* SIDE EFFECT: The underlying generation and emission methods may touch:
|
|
1321
|
+
* `items`, `itemsChanged`, and `deletedItemIds`.
|
|
1322
|
+
*
|
|
1323
|
+
* Refer to `generateSnapshot` and `emitSnapshot` for more details.
|
|
1324
|
+
*/
|
|
1159
1325
|
const generateAndEmitSnapshot = (): void => {
|
|
1160
1326
|
const snapshot = generateSnapshot();
|
|
1161
1327
|
emitSnapshot(snapshot);
|
|
@@ -1172,6 +1338,31 @@ class DataStore {
|
|
|
1172
1338
|
const { sort } = options || {};
|
|
1173
1339
|
const sortOptions = sort ? { sort } : undefined;
|
|
1174
1340
|
|
|
1341
|
+
const modelDefinition = getModelDefinition(model);
|
|
1342
|
+
const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1343
|
+
|
|
1344
|
+
if (isQueryOne(criteria)) {
|
|
1345
|
+
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
1346
|
+
modelDefinition,
|
|
1347
|
+
keyFields[0],
|
|
1348
|
+
criteria
|
|
1349
|
+
);
|
|
1350
|
+
} else {
|
|
1351
|
+
if (isPredicatesAll(criteria)) {
|
|
1352
|
+
// Predicates.ALL means "all records", so no predicate (undefined)
|
|
1353
|
+
predicate = undefined;
|
|
1354
|
+
} else {
|
|
1355
|
+
predicate = ModelPredicateCreator.createFromExisting(
|
|
1356
|
+
modelDefinition,
|
|
1357
|
+
criteria
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
const { predicates, type: predicateGroupType } =
|
|
1363
|
+
ModelPredicateCreator.getPredicates(predicate, false) || {};
|
|
1364
|
+
const hasPredicate = !!predicates;
|
|
1365
|
+
|
|
1175
1366
|
(async () => {
|
|
1176
1367
|
try {
|
|
1177
1368
|
// first, query and return any locally-available records
|
|
@@ -1179,34 +1370,54 @@ class DataStore {
|
|
|
1179
1370
|
items.set(item.id, item)
|
|
1180
1371
|
);
|
|
1181
1372
|
|
|
1182
|
-
//
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1373
|
+
// Observe the model and send a stream of updates (debounced).
|
|
1374
|
+
// We need to post-filter results instead of passing criteria through
|
|
1375
|
+
// to have visibility into items that move from in-set to out-of-set.
|
|
1376
|
+
// We need to explicitly remove those items from the existing snapshot.
|
|
1377
|
+
handle = this.observe(model).subscribe(
|
|
1378
|
+
({ element, model, opType }) => {
|
|
1379
|
+
if (
|
|
1380
|
+
hasPredicate &&
|
|
1381
|
+
!validatePredicate(element, predicateGroupType, predicates)
|
|
1382
|
+
) {
|
|
1383
|
+
if (
|
|
1384
|
+
opType === 'UPDATE' &&
|
|
1385
|
+
(items.has(element.id) || itemsChanged.has(element.id))
|
|
1386
|
+
) {
|
|
1387
|
+
// tracking as a "deleted item" will include the item in
|
|
1388
|
+
// page limit calculations and ensure it is removed from the
|
|
1389
|
+
// final items collection, regardless of which collection(s)
|
|
1390
|
+
// it is currently in. (I mean, it could be in both, right!?)
|
|
1391
|
+
deletedItemIds.push(element.id);
|
|
1392
|
+
} else {
|
|
1393
|
+
// ignore updates for irrelevant/filtered items.
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1197
1397
|
|
|
1198
|
-
|
|
1398
|
+
// Flag items which have been recently deleted
|
|
1399
|
+
// NOTE: Merging of separate operations to the same model instance is handled upstream
|
|
1400
|
+
// in the `mergePage` method within src/sync/merger.ts. The final state of a model instance
|
|
1401
|
+
// depends on the LATEST record (for a given id).
|
|
1402
|
+
if (opType === 'DELETE') {
|
|
1403
|
+
deletedItemIds.push(element.id);
|
|
1404
|
+
} else {
|
|
1405
|
+
itemsChanged.set(element.id, element);
|
|
1406
|
+
}
|
|
1199
1407
|
|
|
1200
|
-
|
|
1201
|
-
itemsChanged.size - deletedItemIds.length >= this.syncPageSize;
|
|
1408
|
+
const isSynced = this.sync?.getModelSyncedStatus(model) ?? false;
|
|
1202
1409
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
}
|
|
1410
|
+
const limit =
|
|
1411
|
+
itemsChanged.size - deletedItemIds.length >= this.syncPageSize;
|
|
1206
1412
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1413
|
+
if (limit || isSynced) {
|
|
1414
|
+
limitTimerRace.resolve();
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
// kicks off every subsequent race as results sync down
|
|
1418
|
+
limitTimerRace.start();
|
|
1419
|
+
}
|
|
1420
|
+
);
|
|
1210
1421
|
|
|
1211
1422
|
// returns a set of initial/locally-available results
|
|
1212
1423
|
generateAndEmitSnapshot();
|
|
@@ -1215,7 +1426,12 @@ class DataStore {
|
|
|
1215
1426
|
}
|
|
1216
1427
|
})();
|
|
1217
1428
|
|
|
1218
|
-
|
|
1429
|
+
/**
|
|
1430
|
+
* Combines the `items`, `itemsChanged`, and `deletedItemIds` collections into
|
|
1431
|
+
* a snapshot in the form of `{ items: T[], isSynced: boolean}`.
|
|
1432
|
+
*
|
|
1433
|
+
* SIDE EFFECT: The shared `items` collection is recreated.
|
|
1434
|
+
*/
|
|
1219
1435
|
const generateSnapshot = (): DataStoreSnapshot<T> => {
|
|
1220
1436
|
const isSynced = this.sync?.getModelSyncedStatus(model) ?? false;
|
|
1221
1437
|
const itemsArray = [
|
|
@@ -1239,6 +1455,14 @@ class DataStore {
|
|
|
1239
1455
|
};
|
|
1240
1456
|
};
|
|
1241
1457
|
|
|
1458
|
+
/**
|
|
1459
|
+
* Emits the list of items to the observer.
|
|
1460
|
+
*
|
|
1461
|
+
* SIDE EFFECT: `itemsChanged` and `deletedItemIds` are cleared to prepare
|
|
1462
|
+
* for the next snapshot.
|
|
1463
|
+
*
|
|
1464
|
+
* @param snapshot The generated items data to emit.
|
|
1465
|
+
*/
|
|
1242
1466
|
const emitSnapshot = (snapshot: DataStoreSnapshot<T>): void => {
|
|
1243
1467
|
// send the generated snapshot to the primary subscription
|
|
1244
1468
|
observer.next(snapshot);
|
|
@@ -1248,6 +1472,12 @@ class DataStore {
|
|
|
1248
1472
|
deletedItemIds = [];
|
|
1249
1473
|
};
|
|
1250
1474
|
|
|
1475
|
+
/**
|
|
1476
|
+
* Sorts an `Array` of `T` according to the sort instructions given in the
|
|
1477
|
+
* original `observeQuery()` call.
|
|
1478
|
+
*
|
|
1479
|
+
* @param itemsToSort A array of model type.
|
|
1480
|
+
*/
|
|
1251
1481
|
const sortItems = (itemsToSort: T[]): void => {
|
|
1252
1482
|
const modelDefinition = getModelDefinition(model);
|
|
1253
1483
|
const pagination = this.processPagination(modelDefinition, options);
|
|
@@ -1262,7 +1492,14 @@ class DataStore {
|
|
|
1262
1492
|
}
|
|
1263
1493
|
};
|
|
1264
1494
|
|
|
1265
|
-
|
|
1495
|
+
/**
|
|
1496
|
+
* Force one last snapshot when the model is fully synced.
|
|
1497
|
+
*
|
|
1498
|
+
* This reduces latency for that last snapshot, which will otherwise
|
|
1499
|
+
* wait for the configured timeout.
|
|
1500
|
+
*
|
|
1501
|
+
* @param payload The payload from the Hub event.
|
|
1502
|
+
*/
|
|
1266
1503
|
const hubCallback = ({ payload }): void => {
|
|
1267
1504
|
const { event, data } = payload;
|
|
1268
1505
|
if (
|
|
@@ -1284,6 +1521,10 @@ class DataStore {
|
|
|
1284
1521
|
};
|
|
1285
1522
|
|
|
1286
1523
|
configure = (config: DataStoreConfig = {}) => {
|
|
1524
|
+
this.amplifyContext.Auth = this.Auth;
|
|
1525
|
+
this.amplifyContext.API = this.API;
|
|
1526
|
+
this.amplifyContext.Cache = this.Cache;
|
|
1527
|
+
|
|
1287
1528
|
const {
|
|
1288
1529
|
DataStore: configDataStore,
|
|
1289
1530
|
authModeStrategyType: configAuthModeStrategyType,
|
|
@@ -1313,7 +1554,7 @@ class DataStore {
|
|
|
1313
1554
|
|
|
1314
1555
|
switch (authModeStrategyType) {
|
|
1315
1556
|
case AuthModeStrategyType.MULTI_AUTH:
|
|
1316
|
-
this.authModeStrategy = multiAuthStrategy;
|
|
1557
|
+
this.authModeStrategy = multiAuthStrategy(this.amplifyContext);
|
|
1317
1558
|
break;
|
|
1318
1559
|
case AuthModeStrategyType.DEFAULT:
|
|
1319
1560
|
this.authModeStrategy = defaultAuthStrategy;
|
|
@@ -1329,12 +1570,13 @@ class DataStore {
|
|
|
1329
1570
|
|
|
1330
1571
|
this.syncExpressions =
|
|
1331
1572
|
(configDataStore && configDataStore.syncExpressions) ||
|
|
1332
|
-
|
|
1333
|
-
|
|
1573
|
+
configSyncExpressions ||
|
|
1574
|
+
this.syncExpressions;
|
|
1334
1575
|
|
|
1335
1576
|
this.maxRecordsToSync =
|
|
1336
1577
|
(configDataStore && configDataStore.maxRecordsToSync) ||
|
|
1337
1578
|
configMaxRecordsToSync ||
|
|
1579
|
+
this.maxRecordsToSync ||
|
|
1338
1580
|
10000;
|
|
1339
1581
|
|
|
1340
1582
|
// store on config object, so that Sync, Subscription, and Mutation processors can have access
|
|
@@ -1343,6 +1585,7 @@ class DataStore {
|
|
|
1343
1585
|
this.syncPageSize =
|
|
1344
1586
|
(configDataStore && configDataStore.syncPageSize) ||
|
|
1345
1587
|
configSyncPageSize ||
|
|
1588
|
+
this.syncPageSize ||
|
|
1346
1589
|
1000;
|
|
1347
1590
|
|
|
1348
1591
|
// store on config object, so that Sync, Subscription, and Mutation processors can have access
|
|
@@ -1350,22 +1593,32 @@ class DataStore {
|
|
|
1350
1593
|
|
|
1351
1594
|
this.fullSyncInterval =
|
|
1352
1595
|
(configDataStore && configDataStore.fullSyncInterval) ||
|
|
1353
|
-
this.fullSyncInterval ||
|
|
1354
1596
|
configFullSyncInterval ||
|
|
1597
|
+
this.fullSyncInterval ||
|
|
1355
1598
|
24 * 60; // 1 day
|
|
1356
1599
|
|
|
1357
1600
|
this.storageAdapter =
|
|
1358
1601
|
(configDataStore && configDataStore.storageAdapter) ||
|
|
1359
|
-
this.storageAdapter ||
|
|
1360
1602
|
configStorageAdapter ||
|
|
1603
|
+
this.storageAdapter ||
|
|
1361
1604
|
undefined;
|
|
1362
1605
|
|
|
1363
|
-
this.sessionId = this.retrieveSessionId()
|
|
1606
|
+
this.sessionId = this.retrieveSessionId()!;
|
|
1364
1607
|
};
|
|
1365
1608
|
|
|
1366
1609
|
clear = async function clear() {
|
|
1610
|
+
checkSchemaInitialized();
|
|
1367
1611
|
if (this.storage === undefined) {
|
|
1368
|
-
|
|
1612
|
+
// connect to storage so that it can be cleared without fully starting DataStore
|
|
1613
|
+
this.storage = new Storage(
|
|
1614
|
+
schema,
|
|
1615
|
+
namespaceResolver,
|
|
1616
|
+
getModelConstructorByModelName,
|
|
1617
|
+
modelInstanceCreator,
|
|
1618
|
+
this.storageAdapter,
|
|
1619
|
+
this.sessionId
|
|
1620
|
+
);
|
|
1621
|
+
await this.storage.init();
|
|
1369
1622
|
}
|
|
1370
1623
|
|
|
1371
1624
|
if (syncSubscription && !syncSubscription.closed) {
|
|
@@ -1384,7 +1637,7 @@ class DataStore {
|
|
|
1384
1637
|
this.syncPredicates = new WeakMap<SchemaModel, ModelPredicate<any>>();
|
|
1385
1638
|
};
|
|
1386
1639
|
|
|
1387
|
-
stop = async function stop() {
|
|
1640
|
+
stop = async function stop(this: InstanceType<typeof DataStore>) {
|
|
1388
1641
|
if (this.initialized !== undefined) {
|
|
1389
1642
|
await this.start();
|
|
1390
1643
|
}
|
|
@@ -1548,9 +1801,9 @@ class DataStore {
|
|
|
1548
1801
|
|
|
1549
1802
|
return `${sessionId}-${appSyncId}`;
|
|
1550
1803
|
}
|
|
1551
|
-
} catch {
|
|
1552
|
-
|
|
1553
|
-
|
|
1804
|
+
} catch {}
|
|
1805
|
+
|
|
1806
|
+
return undefined;
|
|
1554
1807
|
}
|
|
1555
1808
|
}
|
|
1556
1809
|
|