@aws-amplify/datastore 3.7.3-webpack5.5 → 3.7.4-custom-pk.80
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 +153 -15
- package/README.md +154 -0
- package/dist/aws-amplify-datastore.js +4638 -2685
- 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 +249 -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 +454 -252
- 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 +58 -7
- package/lib/sync/utils.js.map +1 -1
- package/lib/types.d.ts +90 -34
- package/lib/types.js +31 -2
- package/lib/types.js.map +1 -1
- package/lib/util.d.ts +44 -33
- package/lib/util.js +210 -57
- 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 +251 -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 +454 -252
- 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 +58 -8
- package/lib-esm/sync/utils.js.map +1 -1
- package/lib-esm/types.d.ts +90 -34
- package/lib-esm/types.js +29 -3
- package/lib-esm/types.js.map +1 -1
- package/lib-esm/util.d.ts +44 -33
- package/lib-esm/util.js +199 -54
- 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 +395 -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 +345 -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 +67 -16
- package/src/types.ts +252 -50
- package/src/util.ts +241 -42
- 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,13 @@ 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
|
+
// @ts-ignore TODO: fix type
|
|
504
|
+
keyNames.forEach(key => (draft[key] = source[key]));
|
|
505
|
+
|
|
461
506
|
const modelValidator = validateModelFields(modelDefinition);
|
|
462
507
|
Object.entries(draft).forEach(([k, v]) => {
|
|
463
508
|
const parsedValue = castInstanceType(modelDefinition, k, v);
|
|
@@ -468,9 +513,21 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
468
513
|
p => (patches = p)
|
|
469
514
|
);
|
|
470
515
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
516
|
+
const hasExistingPatches = modelPatchesMap.has(source);
|
|
517
|
+
if (patches.length || hasExistingPatches) {
|
|
518
|
+
if (hasExistingPatches) {
|
|
519
|
+
const [existingPatches, existingSource] = modelPatchesMap.get(source);
|
|
520
|
+
const mergedPatches = mergePatches(
|
|
521
|
+
existingSource,
|
|
522
|
+
existingPatches,
|
|
523
|
+
patches
|
|
524
|
+
);
|
|
525
|
+
modelPatchesMap.set(model, [mergedPatches, existingSource]);
|
|
526
|
+
checkReadOnlyPropertyOnUpdate(mergedPatches, modelDefinition);
|
|
527
|
+
} else {
|
|
528
|
+
modelPatchesMap.set(model, [patches, source]);
|
|
529
|
+
checkReadOnlyPropertyOnUpdate(patches, modelDefinition);
|
|
530
|
+
}
|
|
474
531
|
}
|
|
475
532
|
|
|
476
533
|
return model;
|
|
@@ -484,6 +541,7 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
484
541
|
}
|
|
485
542
|
|
|
486
543
|
const instance = modelInstanceCreator(clazz, json);
|
|
544
|
+
|
|
487
545
|
const modelValidator = validateModelFields(modelDefinition);
|
|
488
546
|
|
|
489
547
|
Object.entries(instance).forEach(([k, v]) => {
|
|
@@ -531,7 +589,9 @@ const checkReadOnlyPropertyOnUpdate = (
|
|
|
531
589
|
});
|
|
532
590
|
};
|
|
533
591
|
|
|
534
|
-
const createNonModelClass = <T>(
|
|
592
|
+
const createNonModelClass = <T extends PersistentModel>(
|
|
593
|
+
typeDefinition: SchemaNonModel
|
|
594
|
+
) => {
|
|
535
595
|
const clazz = <NonModelTypeConstructor<T>>(<unknown>class Model {
|
|
536
596
|
constructor(init: ModelInit<T>) {
|
|
537
597
|
const instance = produce(
|
|
@@ -564,7 +624,7 @@ function defaultConflictHandler(conflictData: SyncConflict): PersistentModel {
|
|
|
564
624
|
return modelInstanceCreator(modelConstructor, { ...localModel, _version });
|
|
565
625
|
}
|
|
566
626
|
|
|
567
|
-
function defaultErrorHandler(error: SyncError) {
|
|
627
|
+
function defaultErrorHandler(error: SyncError<PersistentModel>): void {
|
|
568
628
|
logger.warn(error);
|
|
569
629
|
}
|
|
570
630
|
|
|
@@ -615,7 +675,6 @@ async function checkSchemaVersion(
|
|
|
615
675
|
const [schemaVersionSetting] = await s.query(
|
|
616
676
|
Setting,
|
|
617
677
|
ModelPredicateCreator.createFromExisting(modelDefinition, c =>
|
|
618
|
-
// @ts-ignore Argument of type '"eq"' is not assignable to parameter of type 'never'.
|
|
619
678
|
c.key('eq', SETTING_SCHEMA_VERSION)
|
|
620
679
|
),
|
|
621
680
|
{ page: 0, limit: 1 }
|
|
@@ -682,23 +741,34 @@ function getNamespace(): SchemaNamespace {
|
|
|
682
741
|
}
|
|
683
742
|
|
|
684
743
|
class DataStore {
|
|
744
|
+
// reference to configured category instances. Used for preserving SSR context
|
|
745
|
+
Auth = Auth;
|
|
746
|
+
API = API;
|
|
747
|
+
Cache = Cache;
|
|
748
|
+
|
|
685
749
|
private amplifyConfig: Record<string, any> = {};
|
|
686
750
|
private authModeStrategy: AuthModeStrategy;
|
|
687
751
|
private conflictHandler: ConflictHandler;
|
|
688
|
-
private errorHandler: (error: SyncError) => void;
|
|
752
|
+
private errorHandler: (error: SyncError<PersistentModel>) => void;
|
|
689
753
|
private fullSyncInterval: number;
|
|
690
|
-
private initialized
|
|
754
|
+
private initialized?: Promise<void>;
|
|
691
755
|
private initReject: Function;
|
|
692
756
|
private initResolve: Function;
|
|
693
757
|
private maxRecordsToSync: number;
|
|
694
|
-
private storage
|
|
695
|
-
private sync
|
|
758
|
+
private storage?: Storage;
|
|
759
|
+
private sync?: SyncEngine;
|
|
696
760
|
private syncPageSize: number;
|
|
697
761
|
private syncExpressions: SyncExpression[];
|
|
698
762
|
private syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>> =
|
|
699
763
|
new WeakMap<SchemaModel, ModelPredicate<any>>();
|
|
700
764
|
private sessionId: string;
|
|
701
765
|
private storageAdapter: Adapter;
|
|
766
|
+
// object that gets passed to descendent classes. Allows us to pass these down by reference
|
|
767
|
+
private amplifyContext: AmplifyContext = {
|
|
768
|
+
Auth: this.Auth,
|
|
769
|
+
API: this.API,
|
|
770
|
+
Cache: this.Cache,
|
|
771
|
+
};
|
|
702
772
|
|
|
703
773
|
getModuleName() {
|
|
704
774
|
return 'DataStore';
|
|
@@ -728,6 +798,7 @@ class DataStore {
|
|
|
728
798
|
|
|
729
799
|
await this.storage.init();
|
|
730
800
|
|
|
801
|
+
checkSchemaInitialized();
|
|
731
802
|
await checkSchemaVersion(this.storage, schema.version);
|
|
732
803
|
|
|
733
804
|
const { aws_appsync_graphqlEndpoint } = this.amplifyConfig;
|
|
@@ -744,13 +815,12 @@ class DataStore {
|
|
|
744
815
|
userClasses,
|
|
745
816
|
this.storage,
|
|
746
817
|
modelInstanceCreator,
|
|
747
|
-
this.maxRecordsToSync,
|
|
748
|
-
this.syncPageSize,
|
|
749
818
|
this.conflictHandler,
|
|
750
819
|
this.errorHandler,
|
|
751
820
|
this.syncPredicates,
|
|
752
821
|
this.amplifyConfig,
|
|
753
|
-
this.authModeStrategy
|
|
822
|
+
this.authModeStrategy,
|
|
823
|
+
this.amplifyContext
|
|
754
824
|
);
|
|
755
825
|
|
|
756
826
|
// tslint:disable-next-line:max-line-length
|
|
@@ -796,7 +866,10 @@ class DataStore {
|
|
|
796
866
|
query: {
|
|
797
867
|
<T extends PersistentModel>(
|
|
798
868
|
modelConstructor: PersistentModelConstructor<T>,
|
|
799
|
-
|
|
869
|
+
identifier: IdentifierFieldOrIdentifierObject<
|
|
870
|
+
T,
|
|
871
|
+
PersistentModelMetaData<T>
|
|
872
|
+
>
|
|
800
873
|
): Promise<T | undefined>;
|
|
801
874
|
<T extends PersistentModel>(
|
|
802
875
|
modelConstructor: PersistentModelConstructor<T>,
|
|
@@ -805,7 +878,10 @@ class DataStore {
|
|
|
805
878
|
): Promise<T[]>;
|
|
806
879
|
} = async <T extends PersistentModel>(
|
|
807
880
|
modelConstructor: PersistentModelConstructor<T>,
|
|
808
|
-
|
|
881
|
+
identifierOrCriteria?:
|
|
882
|
+
| IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
|
|
883
|
+
| ProducerModelPredicate<T>
|
|
884
|
+
| typeof PredicateAll,
|
|
809
885
|
paginationProducer?: ProducerPaginationInput<T>
|
|
810
886
|
): Promise<T | T[] | undefined> => {
|
|
811
887
|
await this.start();
|
|
@@ -819,28 +895,37 @@ class DataStore {
|
|
|
819
895
|
throw new Error(msg);
|
|
820
896
|
}
|
|
821
897
|
|
|
822
|
-
if (typeof
|
|
898
|
+
if (typeof identifierOrCriteria === 'string') {
|
|
823
899
|
if (paginationProducer !== undefined) {
|
|
824
900
|
logger.warn('Pagination is ignored when querying by id');
|
|
825
901
|
}
|
|
826
902
|
}
|
|
827
903
|
|
|
828
904
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
905
|
+
const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
|
|
906
|
+
|
|
829
907
|
let predicate: ModelPredicate<T>;
|
|
830
908
|
|
|
831
|
-
if (isQueryOne(
|
|
832
|
-
predicate = ModelPredicateCreator.
|
|
909
|
+
if (isQueryOne(identifierOrCriteria)) {
|
|
910
|
+
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
833
911
|
modelDefinition,
|
|
834
|
-
|
|
912
|
+
keyFields[0],
|
|
913
|
+
identifierOrCriteria
|
|
835
914
|
);
|
|
836
915
|
} else {
|
|
837
|
-
|
|
916
|
+
// Object is being queried using object literal syntax
|
|
917
|
+
if (isIdentifierObject(<T>identifierOrCriteria, modelDefinition)) {
|
|
918
|
+
predicate = ModelPredicateCreator.createForPk<T>(
|
|
919
|
+
modelDefinition,
|
|
920
|
+
<T>identifierOrCriteria
|
|
921
|
+
);
|
|
922
|
+
} else if (isPredicatesAll(identifierOrCriteria)) {
|
|
838
923
|
// Predicates.ALL means "all records", so no predicate (undefined)
|
|
839
924
|
predicate = undefined;
|
|
840
925
|
} else {
|
|
841
926
|
predicate = ModelPredicateCreator.createFromExisting(
|
|
842
927
|
modelDefinition,
|
|
843
|
-
|
|
928
|
+
<any>identifierOrCriteria
|
|
844
929
|
);
|
|
845
930
|
}
|
|
846
931
|
}
|
|
@@ -870,7 +955,13 @@ class DataStore {
|
|
|
870
955
|
pagination
|
|
871
956
|
);
|
|
872
957
|
|
|
873
|
-
|
|
958
|
+
const isSingleFieldIdentifier = keyFields.length === 1;
|
|
959
|
+
const returnOne =
|
|
960
|
+
isSingleFieldIdentifier &&
|
|
961
|
+
(isQueryOne(identifierOrCriteria) ||
|
|
962
|
+
isIdentifierObject(identifierOrCriteria, modelDefinition));
|
|
963
|
+
|
|
964
|
+
return returnOne ? result[0] : result;
|
|
874
965
|
};
|
|
875
966
|
|
|
876
967
|
save = async <T extends PersistentModel>(
|
|
@@ -883,7 +974,7 @@ class DataStore {
|
|
|
883
974
|
// Allows us to only include changed fields for updates
|
|
884
975
|
const patchesTuple = modelPatchesMap.get(model);
|
|
885
976
|
|
|
886
|
-
const modelConstructor: PersistentModelConstructor<T> = model
|
|
977
|
+
const modelConstructor: PersistentModelConstructor<T> | undefined = model
|
|
887
978
|
? <PersistentModelConstructor<T>>model.constructor
|
|
888
979
|
: undefined;
|
|
889
980
|
|
|
@@ -898,15 +989,15 @@ class DataStore {
|
|
|
898
989
|
|
|
899
990
|
const producedCondition = ModelPredicateCreator.createFromExisting(
|
|
900
991
|
modelDefinition,
|
|
901
|
-
condition
|
|
992
|
+
condition!
|
|
902
993
|
);
|
|
903
994
|
|
|
904
995
|
const [savedModel] = await this.storage.runExclusive(async s => {
|
|
905
996
|
await s.save(model, producedCondition, undefined, patchesTuple);
|
|
906
997
|
|
|
907
|
-
return s.query(
|
|
998
|
+
return s.query<T>(
|
|
908
999
|
modelConstructor,
|
|
909
|
-
ModelPredicateCreator.
|
|
1000
|
+
ModelPredicateCreator.createForPk(modelDefinition, model)
|
|
910
1001
|
);
|
|
911
1002
|
});
|
|
912
1003
|
|
|
@@ -946,22 +1037,28 @@ class DataStore {
|
|
|
946
1037
|
};
|
|
947
1038
|
|
|
948
1039
|
delete: {
|
|
949
|
-
<T extends PersistentModel>(
|
|
950
|
-
model: T,
|
|
951
|
-
condition?: ProducerModelPredicate<T>
|
|
952
|
-
): Promise<T>;
|
|
953
1040
|
<T extends PersistentModel>(
|
|
954
1041
|
modelConstructor: PersistentModelConstructor<T>,
|
|
955
|
-
|
|
1042
|
+
identifier: IdentifierFieldOrIdentifierObject<
|
|
1043
|
+
T,
|
|
1044
|
+
PersistentModelMetaData<T>
|
|
1045
|
+
>
|
|
956
1046
|
): Promise<T[]>;
|
|
957
1047
|
<T extends PersistentModel>(
|
|
958
1048
|
modelConstructor: PersistentModelConstructor<T>,
|
|
959
1049
|
condition: ProducerModelPredicate<T> | typeof PredicateAll
|
|
960
1050
|
): Promise<T[]>;
|
|
1051
|
+
<T extends PersistentModel>(
|
|
1052
|
+
model: T,
|
|
1053
|
+
condition?: ProducerModelPredicate<T>
|
|
1054
|
+
): Promise<T>;
|
|
961
1055
|
} = async <T extends PersistentModel>(
|
|
962
1056
|
modelOrConstructor: T | PersistentModelConstructor<T>,
|
|
963
|
-
|
|
964
|
-
|
|
1057
|
+
identifierOrCriteria?:
|
|
1058
|
+
| IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
|
|
1059
|
+
| ProducerModelPredicate<T>
|
|
1060
|
+
| typeof PredicateAll
|
|
1061
|
+
): Promise<T | T[]> => {
|
|
965
1062
|
await this.start();
|
|
966
1063
|
|
|
967
1064
|
let condition: ModelPredicate<T>;
|
|
@@ -973,31 +1070,43 @@ class DataStore {
|
|
|
973
1070
|
throw new Error(msg);
|
|
974
1071
|
}
|
|
975
1072
|
|
|
976
|
-
if (isValidModelConstructor(modelOrConstructor)) {
|
|
1073
|
+
if (isValidModelConstructor<T>(modelOrConstructor)) {
|
|
977
1074
|
const modelConstructor = modelOrConstructor;
|
|
978
1075
|
|
|
979
|
-
if (!
|
|
1076
|
+
if (!identifierOrCriteria) {
|
|
980
1077
|
const msg =
|
|
981
1078
|
'Id to delete or criteria required. Do you want to delete all? Pass Predicates.ALL';
|
|
982
|
-
logger.error(msg, {
|
|
1079
|
+
logger.error(msg, { identifierOrCriteria });
|
|
983
1080
|
|
|
984
1081
|
throw new Error(msg);
|
|
985
1082
|
}
|
|
986
1083
|
|
|
987
|
-
|
|
988
|
-
|
|
1084
|
+
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1085
|
+
|
|
1086
|
+
if (typeof identifierOrCriteria === 'string') {
|
|
1087
|
+
const [keyField] = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1088
|
+
|
|
1089
|
+
condition = ModelPredicateCreator.createForSingleField<T>(
|
|
989
1090
|
getModelDefinition(modelConstructor),
|
|
990
|
-
|
|
1091
|
+
keyField,
|
|
1092
|
+
identifierOrCriteria
|
|
991
1093
|
);
|
|
992
1094
|
} else {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1095
|
+
if (isIdentifierObject(identifierOrCriteria, modelDefinition)) {
|
|
1096
|
+
condition = ModelPredicateCreator.createForPk<T>(
|
|
1097
|
+
modelDefinition,
|
|
1098
|
+
<T>identifierOrCriteria
|
|
1099
|
+
);
|
|
1100
|
+
} else {
|
|
1101
|
+
condition = ModelPredicateCreator.createFromExisting(
|
|
1102
|
+
modelDefinition,
|
|
1103
|
+
/**
|
|
1104
|
+
* idOrCriteria is always a ProducerModelPredicate<T>, never a symbol.
|
|
1105
|
+
* The symbol is used only for typing purposes. e.g. see Predicates.ALL
|
|
1106
|
+
*/
|
|
1107
|
+
identifierOrCriteria as ProducerModelPredicate<T>
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1001
1110
|
|
|
1002
1111
|
if (!condition || !ModelPredicateCreator.isValidPredicate(condition)) {
|
|
1003
1112
|
const msg =
|
|
@@ -1025,22 +1134,24 @@ class DataStore {
|
|
|
1025
1134
|
|
|
1026
1135
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1027
1136
|
|
|
1028
|
-
const
|
|
1137
|
+
const pkPredicate = ModelPredicateCreator.createForPk<T>(
|
|
1029
1138
|
modelDefinition,
|
|
1030
|
-
model
|
|
1139
|
+
model
|
|
1031
1140
|
);
|
|
1032
1141
|
|
|
1033
|
-
if (
|
|
1034
|
-
if (typeof
|
|
1142
|
+
if (identifierOrCriteria) {
|
|
1143
|
+
if (typeof identifierOrCriteria !== 'function') {
|
|
1035
1144
|
const msg = 'Invalid criteria';
|
|
1036
|
-
logger.error(msg, {
|
|
1145
|
+
logger.error(msg, { identifierOrCriteria });
|
|
1037
1146
|
|
|
1038
1147
|
throw new Error(msg);
|
|
1039
1148
|
}
|
|
1040
1149
|
|
|
1041
|
-
condition =
|
|
1150
|
+
condition = (<ProducerModelPredicate<T>>identifierOrCriteria)(
|
|
1151
|
+
pkPredicate
|
|
1152
|
+
);
|
|
1042
1153
|
} else {
|
|
1043
|
-
condition =
|
|
1154
|
+
condition = pkPredicate;
|
|
1044
1155
|
}
|
|
1045
1156
|
|
|
1046
1157
|
const [[deleted]] = await this.storage.delete(model, condition);
|
|
@@ -1052,20 +1163,28 @@ class DataStore {
|
|
|
1052
1163
|
observe: {
|
|
1053
1164
|
(): Observable<SubscriptionMessage<PersistentModel>>;
|
|
1054
1165
|
|
|
1055
|
-
<T extends PersistentModel>(
|
|
1166
|
+
<T extends PersistentModel>(
|
|
1167
|
+
modelConstructor: PersistentModelConstructor<T>,
|
|
1168
|
+
identifier: string
|
|
1169
|
+
): Observable<SubscriptionMessage<T>>;
|
|
1056
1170
|
|
|
1057
1171
|
<T extends PersistentModel>(
|
|
1058
1172
|
modelConstructor: PersistentModelConstructor<T>,
|
|
1059
|
-
criteria?:
|
|
1173
|
+
criteria?: ProducerModelPredicate<T> | typeof PredicateAll
|
|
1060
1174
|
): Observable<SubscriptionMessage<T>>;
|
|
1061
|
-
|
|
1175
|
+
|
|
1176
|
+
<T extends PersistentModel>(model: T): Observable<SubscriptionMessage<T>>;
|
|
1177
|
+
} = <T extends PersistentModel>(
|
|
1062
1178
|
modelOrConstructor?: T | PersistentModelConstructor<T>,
|
|
1063
|
-
|
|
1179
|
+
identifierOrCriteria?:
|
|
1180
|
+
| string
|
|
1181
|
+
| ProducerModelPredicate<T>
|
|
1182
|
+
| typeof PredicateAll
|
|
1064
1183
|
): Observable<SubscriptionMessage<T>> => {
|
|
1065
1184
|
let predicate: ModelPredicate<T>;
|
|
1066
1185
|
|
|
1067
|
-
const modelConstructor: PersistentModelConstructor<T> =
|
|
1068
|
-
modelOrConstructor && isValidModelConstructor(modelOrConstructor)
|
|
1186
|
+
const modelConstructor: PersistentModelConstructor<T> | undefined =
|
|
1187
|
+
modelOrConstructor && isValidModelConstructor<T>(modelOrConstructor)
|
|
1069
1188
|
? modelOrConstructor
|
|
1070
1189
|
: undefined;
|
|
1071
1190
|
|
|
@@ -1075,10 +1194,10 @@ class DataStore {
|
|
|
1075
1194
|
model && (<Object>Object.getPrototypeOf(model)).constructor;
|
|
1076
1195
|
|
|
1077
1196
|
if (isValidModelConstructor<T>(modelConstructor)) {
|
|
1078
|
-
if (
|
|
1197
|
+
if (identifierOrCriteria) {
|
|
1079
1198
|
logger.warn('idOrCriteria is ignored when using a model instance', {
|
|
1080
1199
|
model,
|
|
1081
|
-
|
|
1200
|
+
identifierOrCriteria,
|
|
1082
1201
|
});
|
|
1083
1202
|
}
|
|
1084
1203
|
|
|
@@ -1092,9 +1211,9 @@ class DataStore {
|
|
|
1092
1211
|
}
|
|
1093
1212
|
}
|
|
1094
1213
|
|
|
1095
|
-
if (
|
|
1214
|
+
if (identifierOrCriteria !== undefined && modelConstructor === undefined) {
|
|
1096
1215
|
const msg = 'Cannot provide criteria without a modelConstructor';
|
|
1097
|
-
logger.error(msg,
|
|
1216
|
+
logger.error(msg, identifierOrCriteria);
|
|
1098
1217
|
throw new Error(msg);
|
|
1099
1218
|
}
|
|
1100
1219
|
|
|
@@ -1105,18 +1224,26 @@ class DataStore {
|
|
|
1105
1224
|
throw new Error(msg);
|
|
1106
1225
|
}
|
|
1107
1226
|
|
|
1108
|
-
if (typeof
|
|
1109
|
-
|
|
1227
|
+
if (typeof identifierOrCriteria === 'string') {
|
|
1228
|
+
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1229
|
+
const [keyField] = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1230
|
+
|
|
1231
|
+
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
1110
1232
|
getModelDefinition(modelConstructor),
|
|
1111
|
-
|
|
1233
|
+
keyField,
|
|
1234
|
+
identifierOrCriteria
|
|
1112
1235
|
);
|
|
1113
1236
|
} else {
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1237
|
+
if (isPredicatesAll(identifierOrCriteria)) {
|
|
1238
|
+
predicate = undefined;
|
|
1239
|
+
} else {
|
|
1240
|
+
predicate =
|
|
1241
|
+
modelConstructor &&
|
|
1242
|
+
ModelPredicateCreator.createFromExisting<T>(
|
|
1243
|
+
getModelDefinition(modelConstructor),
|
|
1244
|
+
identifierOrCriteria
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1120
1247
|
}
|
|
1121
1248
|
|
|
1122
1249
|
return new Observable<SubscriptionMessage<T>>(observer => {
|
|
@@ -1125,10 +1252,37 @@ class DataStore {
|
|
|
1125
1252
|
(async () => {
|
|
1126
1253
|
await this.start();
|
|
1127
1254
|
|
|
1255
|
+
// Filter the events returned by Storage according to namespace,
|
|
1256
|
+
// append original element data, and subscribe to the observable
|
|
1128
1257
|
handle = this.storage
|
|
1129
1258
|
.observe(modelConstructor, predicate)
|
|
1130
1259
|
.filter(({ model }) => namespaceResolver(model) === USER)
|
|
1131
|
-
.subscribe(
|
|
1260
|
+
.subscribe({
|
|
1261
|
+
next: async item => {
|
|
1262
|
+
// the `element` doesn't necessarily contain all item details or
|
|
1263
|
+
// have related records attached consistently with that of a query()
|
|
1264
|
+
// result item. for consistency, we attach them here.
|
|
1265
|
+
|
|
1266
|
+
let message = item;
|
|
1267
|
+
|
|
1268
|
+
// as lnog as we're not dealing with a DELETE, we need to fetch a fresh
|
|
1269
|
+
// item from storage to ensure it's fully populated.
|
|
1270
|
+
if (item.opType !== 'DELETE') {
|
|
1271
|
+
const freshElement = await this.query(
|
|
1272
|
+
item.model,
|
|
1273
|
+
item.element.id
|
|
1274
|
+
);
|
|
1275
|
+
message = {
|
|
1276
|
+
...message,
|
|
1277
|
+
element: freshElement as T,
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
observer.next(message as SubscriptionMessage<T>);
|
|
1282
|
+
},
|
|
1283
|
+
error: err => observer.error(err),
|
|
1284
|
+
complete: () => observer.complete(),
|
|
1285
|
+
});
|
|
1132
1286
|
})();
|
|
1133
1287
|
|
|
1134
1288
|
return () => {
|
|
@@ -1145,7 +1299,7 @@ class DataStore {
|
|
|
1145
1299
|
criteria?: ProducerModelPredicate<T> | typeof PredicateAll,
|
|
1146
1300
|
paginationProducer?: ObserveQueryOptions<T>
|
|
1147
1301
|
): Observable<DataStoreSnapshot<T>>;
|
|
1148
|
-
} = <T extends PersistentModel
|
|
1302
|
+
} = <T extends PersistentModel>(
|
|
1149
1303
|
model: PersistentModelConstructor<T>,
|
|
1150
1304
|
criteria?: ProducerModelPredicate<T> | typeof PredicateAll,
|
|
1151
1305
|
options?: ObserveQueryOptions<T>
|
|
@@ -1155,7 +1309,18 @@ class DataStore {
|
|
|
1155
1309
|
const itemsChanged = new Map<string, T>();
|
|
1156
1310
|
let deletedItemIds: string[] = [];
|
|
1157
1311
|
let handle: ZenObservable.Subscription;
|
|
1158
|
-
|
|
1312
|
+
let predicate: ModelPredicate<T>;
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* As the name suggests, this geneates a snapshot in the form of
|
|
1316
|
+
* `{items: T[], isSynced: boolean}`
|
|
1317
|
+
* and sends it to the observer.
|
|
1318
|
+
*
|
|
1319
|
+
* SIDE EFFECT: The underlying generation and emission methods may touch:
|
|
1320
|
+
* `items`, `itemsChanged`, and `deletedItemIds`.
|
|
1321
|
+
*
|
|
1322
|
+
* Refer to `generateSnapshot` and `emitSnapshot` for more details.
|
|
1323
|
+
*/
|
|
1159
1324
|
const generateAndEmitSnapshot = (): void => {
|
|
1160
1325
|
const snapshot = generateSnapshot();
|
|
1161
1326
|
emitSnapshot(snapshot);
|
|
@@ -1172,6 +1337,31 @@ class DataStore {
|
|
|
1172
1337
|
const { sort } = options || {};
|
|
1173
1338
|
const sortOptions = sort ? { sort } : undefined;
|
|
1174
1339
|
|
|
1340
|
+
const modelDefinition = getModelDefinition(model);
|
|
1341
|
+
const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1342
|
+
|
|
1343
|
+
if (isQueryOne(criteria)) {
|
|
1344
|
+
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
1345
|
+
modelDefinition,
|
|
1346
|
+
keyFields[0],
|
|
1347
|
+
criteria
|
|
1348
|
+
);
|
|
1349
|
+
} else {
|
|
1350
|
+
if (isPredicatesAll(criteria)) {
|
|
1351
|
+
// Predicates.ALL means "all records", so no predicate (undefined)
|
|
1352
|
+
predicate = undefined;
|
|
1353
|
+
} else {
|
|
1354
|
+
predicate = ModelPredicateCreator.createFromExisting(
|
|
1355
|
+
modelDefinition,
|
|
1356
|
+
criteria
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
const { predicates, type: predicateGroupType } =
|
|
1362
|
+
ModelPredicateCreator.getPredicates(predicate, false) || {};
|
|
1363
|
+
const hasPredicate = !!predicates;
|
|
1364
|
+
|
|
1175
1365
|
(async () => {
|
|
1176
1366
|
try {
|
|
1177
1367
|
// first, query and return any locally-available records
|
|
@@ -1179,34 +1369,54 @@ class DataStore {
|
|
|
1179
1369
|
items.set(item.id, item)
|
|
1180
1370
|
);
|
|
1181
1371
|
|
|
1182
|
-
//
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1372
|
+
// Observe the model and send a stream of updates (debounced).
|
|
1373
|
+
// We need to post-filter results instead of passing criteria through
|
|
1374
|
+
// to have visibility into items that move from in-set to out-of-set.
|
|
1375
|
+
// We need to explicitly remove those items from the existing snapshot.
|
|
1376
|
+
handle = this.observe(model).subscribe(
|
|
1377
|
+
({ element, model, opType }) => {
|
|
1378
|
+
if (
|
|
1379
|
+
hasPredicate &&
|
|
1380
|
+
!validatePredicate(element, predicateGroupType, predicates)
|
|
1381
|
+
) {
|
|
1382
|
+
if (
|
|
1383
|
+
opType === 'UPDATE' &&
|
|
1384
|
+
(items.has(element.id) || itemsChanged.has(element.id))
|
|
1385
|
+
) {
|
|
1386
|
+
// tracking as a "deleted item" will include the item in
|
|
1387
|
+
// page limit calculations and ensure it is removed from the
|
|
1388
|
+
// final items collection, regardless of which collection(s)
|
|
1389
|
+
// it is currently in. (I mean, it could be in both, right!?)
|
|
1390
|
+
deletedItemIds.push(element.id);
|
|
1391
|
+
} else {
|
|
1392
|
+
// ignore updates for irrelevant/filtered items.
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1197
1396
|
|
|
1198
|
-
|
|
1397
|
+
// Flag items which have been recently deleted
|
|
1398
|
+
// NOTE: Merging of separate operations to the same model instance is handled upstream
|
|
1399
|
+
// in the `mergePage` method within src/sync/merger.ts. The final state of a model instance
|
|
1400
|
+
// depends on the LATEST record (for a given id).
|
|
1401
|
+
if (opType === 'DELETE') {
|
|
1402
|
+
deletedItemIds.push(element.id);
|
|
1403
|
+
} else {
|
|
1404
|
+
itemsChanged.set(element.id, element);
|
|
1405
|
+
}
|
|
1199
1406
|
|
|
1200
|
-
|
|
1201
|
-
itemsChanged.size - deletedItemIds.length >= this.syncPageSize;
|
|
1407
|
+
const isSynced = this.sync?.getModelSyncedStatus(model) ?? false;
|
|
1202
1408
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
}
|
|
1409
|
+
const limit =
|
|
1410
|
+
itemsChanged.size - deletedItemIds.length >= this.syncPageSize;
|
|
1206
1411
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1412
|
+
if (limit || isSynced) {
|
|
1413
|
+
limitTimerRace.resolve();
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// kicks off every subsequent race as results sync down
|
|
1417
|
+
limitTimerRace.start();
|
|
1418
|
+
}
|
|
1419
|
+
);
|
|
1210
1420
|
|
|
1211
1421
|
// returns a set of initial/locally-available results
|
|
1212
1422
|
generateAndEmitSnapshot();
|
|
@@ -1215,7 +1425,12 @@ class DataStore {
|
|
|
1215
1425
|
}
|
|
1216
1426
|
})();
|
|
1217
1427
|
|
|
1218
|
-
|
|
1428
|
+
/**
|
|
1429
|
+
* Combines the `items`, `itemsChanged`, and `deletedItemIds` collections into
|
|
1430
|
+
* a snapshot in the form of `{ items: T[], isSynced: boolean}`.
|
|
1431
|
+
*
|
|
1432
|
+
* SIDE EFFECT: The shared `items` collection is recreated.
|
|
1433
|
+
*/
|
|
1219
1434
|
const generateSnapshot = (): DataStoreSnapshot<T> => {
|
|
1220
1435
|
const isSynced = this.sync?.getModelSyncedStatus(model) ?? false;
|
|
1221
1436
|
const itemsArray = [
|
|
@@ -1239,6 +1454,14 @@ class DataStore {
|
|
|
1239
1454
|
};
|
|
1240
1455
|
};
|
|
1241
1456
|
|
|
1457
|
+
/**
|
|
1458
|
+
* Emits the list of items to the observer.
|
|
1459
|
+
*
|
|
1460
|
+
* SIDE EFFECT: `itemsChanged` and `deletedItemIds` are cleared to prepare
|
|
1461
|
+
* for the next snapshot.
|
|
1462
|
+
*
|
|
1463
|
+
* @param snapshot The generated items data to emit.
|
|
1464
|
+
*/
|
|
1242
1465
|
const emitSnapshot = (snapshot: DataStoreSnapshot<T>): void => {
|
|
1243
1466
|
// send the generated snapshot to the primary subscription
|
|
1244
1467
|
observer.next(snapshot);
|
|
@@ -1248,6 +1471,12 @@ class DataStore {
|
|
|
1248
1471
|
deletedItemIds = [];
|
|
1249
1472
|
};
|
|
1250
1473
|
|
|
1474
|
+
/**
|
|
1475
|
+
* Sorts an `Array` of `T` according to the sort instructions given in the
|
|
1476
|
+
* original `observeQuery()` call.
|
|
1477
|
+
*
|
|
1478
|
+
* @param itemsToSort A array of model type.
|
|
1479
|
+
*/
|
|
1251
1480
|
const sortItems = (itemsToSort: T[]): void => {
|
|
1252
1481
|
const modelDefinition = getModelDefinition(model);
|
|
1253
1482
|
const pagination = this.processPagination(modelDefinition, options);
|
|
@@ -1262,7 +1491,14 @@ class DataStore {
|
|
|
1262
1491
|
}
|
|
1263
1492
|
};
|
|
1264
1493
|
|
|
1265
|
-
|
|
1494
|
+
/**
|
|
1495
|
+
* Force one last snapshot when the model is fully synced.
|
|
1496
|
+
*
|
|
1497
|
+
* This reduces latency for that last snapshot, which will otherwise
|
|
1498
|
+
* wait for the configured timeout.
|
|
1499
|
+
*
|
|
1500
|
+
* @param payload The payload from the Hub event.
|
|
1501
|
+
*/
|
|
1266
1502
|
const hubCallback = ({ payload }): void => {
|
|
1267
1503
|
const { event, data } = payload;
|
|
1268
1504
|
if (
|
|
@@ -1284,6 +1520,10 @@ class DataStore {
|
|
|
1284
1520
|
};
|
|
1285
1521
|
|
|
1286
1522
|
configure = (config: DataStoreConfig = {}) => {
|
|
1523
|
+
this.amplifyContext.Auth = this.Auth;
|
|
1524
|
+
this.amplifyContext.API = this.API;
|
|
1525
|
+
this.amplifyContext.Cache = this.Cache;
|
|
1526
|
+
|
|
1287
1527
|
const {
|
|
1288
1528
|
DataStore: configDataStore,
|
|
1289
1529
|
authModeStrategyType: configAuthModeStrategyType,
|
|
@@ -1313,7 +1553,7 @@ class DataStore {
|
|
|
1313
1553
|
|
|
1314
1554
|
switch (authModeStrategyType) {
|
|
1315
1555
|
case AuthModeStrategyType.MULTI_AUTH:
|
|
1316
|
-
this.authModeStrategy = multiAuthStrategy;
|
|
1556
|
+
this.authModeStrategy = multiAuthStrategy(this.amplifyContext);
|
|
1317
1557
|
break;
|
|
1318
1558
|
case AuthModeStrategyType.DEFAULT:
|
|
1319
1559
|
this.authModeStrategy = defaultAuthStrategy;
|
|
@@ -1329,12 +1569,13 @@ class DataStore {
|
|
|
1329
1569
|
|
|
1330
1570
|
this.syncExpressions =
|
|
1331
1571
|
(configDataStore && configDataStore.syncExpressions) ||
|
|
1332
|
-
|
|
1333
|
-
|
|
1572
|
+
configSyncExpressions ||
|
|
1573
|
+
this.syncExpressions;
|
|
1334
1574
|
|
|
1335
1575
|
this.maxRecordsToSync =
|
|
1336
1576
|
(configDataStore && configDataStore.maxRecordsToSync) ||
|
|
1337
1577
|
configMaxRecordsToSync ||
|
|
1578
|
+
this.maxRecordsToSync ||
|
|
1338
1579
|
10000;
|
|
1339
1580
|
|
|
1340
1581
|
// store on config object, so that Sync, Subscription, and Mutation processors can have access
|
|
@@ -1343,6 +1584,7 @@ class DataStore {
|
|
|
1343
1584
|
this.syncPageSize =
|
|
1344
1585
|
(configDataStore && configDataStore.syncPageSize) ||
|
|
1345
1586
|
configSyncPageSize ||
|
|
1587
|
+
this.syncPageSize ||
|
|
1346
1588
|
1000;
|
|
1347
1589
|
|
|
1348
1590
|
// store on config object, so that Sync, Subscription, and Mutation processors can have access
|
|
@@ -1350,22 +1592,32 @@ class DataStore {
|
|
|
1350
1592
|
|
|
1351
1593
|
this.fullSyncInterval =
|
|
1352
1594
|
(configDataStore && configDataStore.fullSyncInterval) ||
|
|
1353
|
-
this.fullSyncInterval ||
|
|
1354
1595
|
configFullSyncInterval ||
|
|
1596
|
+
this.fullSyncInterval ||
|
|
1355
1597
|
24 * 60; // 1 day
|
|
1356
1598
|
|
|
1357
1599
|
this.storageAdapter =
|
|
1358
1600
|
(configDataStore && configDataStore.storageAdapter) ||
|
|
1359
|
-
this.storageAdapter ||
|
|
1360
1601
|
configStorageAdapter ||
|
|
1602
|
+
this.storageAdapter ||
|
|
1361
1603
|
undefined;
|
|
1362
1604
|
|
|
1363
|
-
this.sessionId = this.retrieveSessionId()
|
|
1605
|
+
this.sessionId = this.retrieveSessionId()!;
|
|
1364
1606
|
};
|
|
1365
1607
|
|
|
1366
1608
|
clear = async function clear() {
|
|
1609
|
+
checkSchemaInitialized();
|
|
1367
1610
|
if (this.storage === undefined) {
|
|
1368
|
-
|
|
1611
|
+
// connect to storage so that it can be cleared without fully starting DataStore
|
|
1612
|
+
this.storage = new Storage(
|
|
1613
|
+
schema,
|
|
1614
|
+
namespaceResolver,
|
|
1615
|
+
getModelConstructorByModelName,
|
|
1616
|
+
modelInstanceCreator,
|
|
1617
|
+
this.storageAdapter,
|
|
1618
|
+
this.sessionId
|
|
1619
|
+
);
|
|
1620
|
+
await this.storage.init();
|
|
1369
1621
|
}
|
|
1370
1622
|
|
|
1371
1623
|
if (syncSubscription && !syncSubscription.closed) {
|
|
@@ -1384,7 +1636,7 @@ class DataStore {
|
|
|
1384
1636
|
this.syncPredicates = new WeakMap<SchemaModel, ModelPredicate<any>>();
|
|
1385
1637
|
};
|
|
1386
1638
|
|
|
1387
|
-
stop = async function stop() {
|
|
1639
|
+
stop = async function stop(this: InstanceType<typeof DataStore>) {
|
|
1388
1640
|
if (this.initialized !== undefined) {
|
|
1389
1641
|
await this.start();
|
|
1390
1642
|
}
|
|
@@ -1548,9 +1800,9 @@ class DataStore {
|
|
|
1548
1800
|
|
|
1549
1801
|
return `${sessionId}-${appSyncId}`;
|
|
1550
1802
|
}
|
|
1551
|
-
} catch {
|
|
1552
|
-
|
|
1553
|
-
|
|
1803
|
+
} catch {}
|
|
1804
|
+
|
|
1805
|
+
return undefined;
|
|
1554
1806
|
}
|
|
1555
1807
|
}
|
|
1556
1808
|
|