@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.
Files changed (137) hide show
  1. package/CHANGELOG.md +153 -15
  2. package/README.md +154 -0
  3. package/dist/aws-amplify-datastore.js +4638 -2685
  4. package/dist/aws-amplify-datastore.js.map +1 -1
  5. package/dist/aws-amplify-datastore.min.js +25 -95
  6. package/dist/aws-amplify-datastore.min.js.map +1 -1
  7. package/lib/authModeStrategies/multiAuthStrategy.d.ts +2 -2
  8. package/lib/authModeStrategies/multiAuthStrategy.js +32 -26
  9. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  10. package/lib/datastore/datastore.d.ts +17 -16
  11. package/lib/datastore/datastore.js +249 -78
  12. package/lib/datastore/datastore.js.map +1 -1
  13. package/lib/index.d.ts +3 -19
  14. package/lib/predicates/index.d.ts +3 -2
  15. package/lib/predicates/index.js +12 -2
  16. package/lib/predicates/index.js.map +1 -1
  17. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +6 -2
  18. package/lib/storage/adapter/AsyncStorageAdapter.js +140 -66
  19. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  20. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +4 -4
  21. package/lib/storage/adapter/AsyncStorageDatabase.js +57 -27
  22. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  23. package/lib/storage/adapter/InMemoryStore.js +2 -2
  24. package/lib/storage/adapter/InMemoryStore.js.map +1 -1
  25. package/lib/storage/adapter/IndexedDBAdapter.d.ts +7 -2
  26. package/lib/storage/adapter/IndexedDBAdapter.js +454 -252
  27. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  28. package/lib/storage/adapter/index.d.ts +1 -1
  29. package/lib/storage/storage.d.ts +3 -3
  30. package/lib/storage/storage.js +106 -28
  31. package/lib/storage/storage.js.map +1 -1
  32. package/lib/sync/index.d.ts +23 -7
  33. package/lib/sync/index.js +18 -17
  34. package/lib/sync/index.js.map +1 -1
  35. package/lib/sync/merger.d.ts +3 -3
  36. package/lib/sync/merger.js +8 -6
  37. package/lib/sync/merger.js.map +1 -1
  38. package/lib/sync/outbox.d.ts +2 -2
  39. package/lib/sync/outbox.js +12 -9
  40. package/lib/sync/outbox.js.map +1 -1
  41. package/lib/sync/processors/errorMaps.d.ts +17 -0
  42. package/lib/sync/processors/errorMaps.js +125 -0
  43. package/lib/sync/processors/errorMaps.js.map +1 -0
  44. package/lib/sync/processors/mutation.d.ts +22 -4
  45. package/lib/sync/processors/mutation.js +119 -51
  46. package/lib/sync/processors/mutation.js.map +1 -1
  47. package/lib/sync/processors/subscription.d.ts +4 -2
  48. package/lib/sync/processors/subscription.js +76 -41
  49. package/lib/sync/processors/subscription.js.map +1 -1
  50. package/lib/sync/processors/sync.d.ts +4 -2
  51. package/lib/sync/processors/sync.js +62 -27
  52. package/lib/sync/processors/sync.js.map +1 -1
  53. package/lib/sync/utils.d.ts +3 -2
  54. package/lib/sync/utils.js +58 -7
  55. package/lib/sync/utils.js.map +1 -1
  56. package/lib/types.d.ts +90 -34
  57. package/lib/types.js +31 -2
  58. package/lib/types.js.map +1 -1
  59. package/lib/util.d.ts +44 -33
  60. package/lib/util.js +210 -57
  61. package/lib/util.js.map +1 -1
  62. package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +2 -2
  63. package/lib-esm/authModeStrategies/multiAuthStrategy.js +32 -26
  64. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  65. package/lib-esm/datastore/datastore.d.ts +17 -16
  66. package/lib-esm/datastore/datastore.js +251 -80
  67. package/lib-esm/datastore/datastore.js.map +1 -1
  68. package/lib-esm/index.d.ts +3 -19
  69. package/lib-esm/predicates/index.d.ts +3 -2
  70. package/lib-esm/predicates/index.js +13 -3
  71. package/lib-esm/predicates/index.js.map +1 -1
  72. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +6 -2
  73. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +140 -66
  74. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  75. package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +4 -4
  76. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +57 -27
  77. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  78. package/lib-esm/storage/adapter/InMemoryStore.js +2 -2
  79. package/lib-esm/storage/adapter/InMemoryStore.js.map +1 -1
  80. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +7 -2
  81. package/lib-esm/storage/adapter/IndexedDBAdapter.js +454 -252
  82. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  83. package/lib-esm/storage/adapter/index.d.ts +1 -1
  84. package/lib-esm/storage/storage.d.ts +3 -3
  85. package/lib-esm/storage/storage.js +106 -28
  86. package/lib-esm/storage/storage.js.map +1 -1
  87. package/lib-esm/sync/index.d.ts +23 -7
  88. package/lib-esm/sync/index.js +20 -19
  89. package/lib-esm/sync/index.js.map +1 -1
  90. package/lib-esm/sync/merger.d.ts +3 -3
  91. package/lib-esm/sync/merger.js +8 -6
  92. package/lib-esm/sync/merger.js.map +1 -1
  93. package/lib-esm/sync/outbox.d.ts +2 -2
  94. package/lib-esm/sync/outbox.js +13 -10
  95. package/lib-esm/sync/outbox.js.map +1 -1
  96. package/lib-esm/sync/processors/errorMaps.d.ts +17 -0
  97. package/lib-esm/sync/processors/errorMaps.js +119 -0
  98. package/lib-esm/sync/processors/errorMaps.js.map +1 -0
  99. package/lib-esm/sync/processors/mutation.d.ts +22 -4
  100. package/lib-esm/sync/processors/mutation.js +122 -54
  101. package/lib-esm/sync/processors/mutation.js.map +1 -1
  102. package/lib-esm/sync/processors/subscription.d.ts +4 -2
  103. package/lib-esm/sync/processors/subscription.js +77 -42
  104. package/lib-esm/sync/processors/subscription.js.map +1 -1
  105. package/lib-esm/sync/processors/sync.d.ts +4 -2
  106. package/lib-esm/sync/processors/sync.js +62 -27
  107. package/lib-esm/sync/processors/sync.js.map +1 -1
  108. package/lib-esm/sync/utils.d.ts +3 -2
  109. package/lib-esm/sync/utils.js +58 -8
  110. package/lib-esm/sync/utils.js.map +1 -1
  111. package/lib-esm/types.d.ts +90 -34
  112. package/lib-esm/types.js +29 -3
  113. package/lib-esm/types.js.map +1 -1
  114. package/lib-esm/util.d.ts +44 -33
  115. package/lib-esm/util.js +199 -54
  116. package/lib-esm/util.js.map +1 -1
  117. package/package.json +10 -9
  118. package/src/authModeStrategies/multiAuthStrategy.ts +24 -21
  119. package/src/datastore/datastore.ts +395 -143
  120. package/src/predicates/index.ts +32 -10
  121. package/src/storage/adapter/AsyncStorageAdapter.ts +161 -61
  122. package/src/storage/adapter/AsyncStorageDatabase.ts +62 -25
  123. package/src/storage/adapter/InMemoryStore.ts +2 -2
  124. package/src/storage/adapter/IndexedDBAdapter.ts +345 -101
  125. package/src/storage/adapter/index.ts +1 -1
  126. package/src/storage/storage.ts +85 -24
  127. package/src/sync/index.ts +74 -58
  128. package/src/sync/merger.ts +16 -4
  129. package/src/sync/outbox.ts +22 -8
  130. package/src/sync/processors/errorMaps.ts +93 -0
  131. package/src/sync/processors/mutation.ts +143 -84
  132. package/src/sync/processors/subscription.ts +67 -36
  133. package/src/sync/processors/sync.ts +37 -12
  134. package/src/sync/utils.ts +67 -16
  135. package/src/types.ts +252 -50
  136. package/src/util.ts +241 -42
  137. 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
- constructor(init: ModelInit<Setting>);
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
- ModelInit<PersistentModel & Partial<ModelInstanceMetadata>>
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: ModelInit<T> & Partial<ModelInstanceMetadata>
286
+ init: Partial<T>
255
287
  ): T {
256
288
  instancesMetadata.add(init);
257
289
 
258
- return <T>new modelConstructor(init);
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
- instancesMetadata.has(init)
446
+ isInternallyInitialized
412
447
  ? <ModelInstanceMetadata>(<unknown>init)
413
448
  : <ModelInstanceMetadata>{};
414
- const {
415
- id: _id,
416
- _version,
417
- _lastChangedAt,
418
- _deleted,
419
- } = modelInstanceMetadata;
420
-
421
- // instancesIds are set by modelInstanceCreator, it is accessible only internally
422
- const isInternal = _id !== null && _id !== undefined;
423
-
424
- const id = isInternal
425
- ? _id
426
- : modelDefinition.syncable
427
- ? uuid4()
428
- : ulid();
429
-
430
- if (!isInternal) {
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
- draft.id = id;
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>>(draft as unknown));
460
- draft.id = source.id;
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
- if (patches.length) {
472
- modelPatchesMap.set(model, [patches, source]);
473
- checkReadOnlyPropertyOnUpdate(patches, modelDefinition);
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>(typeDefinition: SchemaNonModel) => {
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: Promise<void>;
754
+ private initialized?: Promise<void>;
691
755
  private initReject: Function;
692
756
  private initResolve: Function;
693
757
  private maxRecordsToSync: number;
694
- private storage: Storage;
695
- private sync: SyncEngine;
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
- id: string
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
- idOrCriteria?: string | ProducerModelPredicate<T> | typeof PredicateAll,
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 idOrCriteria === 'string') {
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(idOrCriteria)) {
832
- predicate = ModelPredicateCreator.createForId<T>(
909
+ if (isQueryOne(identifierOrCriteria)) {
910
+ predicate = ModelPredicateCreator.createForSingleField<T>(
833
911
  modelDefinition,
834
- idOrCriteria
912
+ keyFields[0],
913
+ identifierOrCriteria
835
914
  );
836
915
  } else {
837
- if (isPredicatesAll(idOrCriteria)) {
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
- idOrCriteria
928
+ <any>identifierOrCriteria
844
929
  );
845
930
  }
846
931
  }
@@ -870,7 +955,13 @@ class DataStore {
870
955
  pagination
871
956
  );
872
957
 
873
- return isQueryOne(idOrCriteria) ? result[0] : result;
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.createForId(modelDefinition, model.id)
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
- id: string
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
- idOrCriteria?: string | ProducerModelPredicate<T> | typeof PredicateAll
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 (!idOrCriteria) {
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, { idOrCriteria });
1079
+ logger.error(msg, { identifierOrCriteria });
983
1080
 
984
1081
  throw new Error(msg);
985
1082
  }
986
1083
 
987
- if (typeof idOrCriteria === 'string') {
988
- condition = ModelPredicateCreator.createForId<T>(
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
- idOrCriteria
1091
+ keyField,
1092
+ identifierOrCriteria
991
1093
  );
992
1094
  } else {
993
- condition = ModelPredicateCreator.createFromExisting(
994
- getModelDefinition(modelConstructor),
995
- /**
996
- * idOrCriteria is always a ProducerModelPredicate<T>, never a symbol.
997
- * The symbol is used only for typing purposes. e.g. see Predicates.ALL
998
- */
999
- idOrCriteria as ProducerModelPredicate<T>
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 idPredicate = ModelPredicateCreator.createForId<T>(
1137
+ const pkPredicate = ModelPredicateCreator.createForPk<T>(
1029
1138
  modelDefinition,
1030
- model.id
1139
+ model
1031
1140
  );
1032
1141
 
1033
- if (idOrCriteria) {
1034
- if (typeof idOrCriteria !== 'function') {
1142
+ if (identifierOrCriteria) {
1143
+ if (typeof identifierOrCriteria !== 'function') {
1035
1144
  const msg = 'Invalid criteria';
1036
- logger.error(msg, { idOrCriteria });
1145
+ logger.error(msg, { identifierOrCriteria });
1037
1146
 
1038
1147
  throw new Error(msg);
1039
1148
  }
1040
1149
 
1041
- condition = idOrCriteria(idPredicate);
1150
+ condition = (<ProducerModelPredicate<T>>identifierOrCriteria)(
1151
+ pkPredicate
1152
+ );
1042
1153
  } else {
1043
- condition = idPredicate;
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>(model: T): Observable<SubscriptionMessage<T>>;
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?: string | ProducerModelPredicate<T>
1173
+ criteria?: ProducerModelPredicate<T> | typeof PredicateAll
1060
1174
  ): Observable<SubscriptionMessage<T>>;
1061
- } = <T extends PersistentModel = PersistentModel>(
1175
+
1176
+ <T extends PersistentModel>(model: T): Observable<SubscriptionMessage<T>>;
1177
+ } = <T extends PersistentModel>(
1062
1178
  modelOrConstructor?: T | PersistentModelConstructor<T>,
1063
- idOrCriteria?: string | ProducerModelPredicate<T>
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 (idOrCriteria) {
1197
+ if (identifierOrCriteria) {
1079
1198
  logger.warn('idOrCriteria is ignored when using a model instance', {
1080
1199
  model,
1081
- idOrCriteria,
1200
+ identifierOrCriteria,
1082
1201
  });
1083
1202
  }
1084
1203
 
@@ -1092,9 +1211,9 @@ class DataStore {
1092
1211
  }
1093
1212
  }
1094
1213
 
1095
- if (idOrCriteria !== undefined && modelConstructor === undefined) {
1214
+ if (identifierOrCriteria !== undefined && modelConstructor === undefined) {
1096
1215
  const msg = 'Cannot provide criteria without a modelConstructor';
1097
- logger.error(msg, idOrCriteria);
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 idOrCriteria === 'string') {
1109
- predicate = ModelPredicateCreator.createForId<T>(
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
- idOrCriteria
1233
+ keyField,
1234
+ identifierOrCriteria
1112
1235
  );
1113
1236
  } else {
1114
- predicate =
1115
- modelConstructor &&
1116
- ModelPredicateCreator.createFromExisting<T>(
1117
- getModelDefinition(modelConstructor),
1118
- idOrCriteria
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(observer);
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 = 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
- // observe the model and send a stream of updates (debounced)
1183
- handle = this.observe(
1184
- model,
1185
- // @ts-ignore TODO: fix this TSlint error
1186
- criteria
1187
- ).subscribe(({ element, model, opType }) => {
1188
- // Flag items which have been recently deleted
1189
- // NOTE: Merging of separate operations to the same model instance is handled upstream
1190
- // in the `mergePage` method within src/sync/merger.ts. The final state of a model instance
1191
- // depends on the LATEST record (for a given id).
1192
- if (opType === 'DELETE') {
1193
- deletedItemIds.push(element.id);
1194
- } else {
1195
- itemsChanged.set(element.id, element);
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
- const isSynced = this.sync?.getModelSyncedStatus(model) ?? false;
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
- const limit =
1201
- itemsChanged.size - deletedItemIds.length >= this.syncPageSize;
1407
+ const isSynced = this.sync?.getModelSyncedStatus(model) ?? false;
1202
1408
 
1203
- if (limit || isSynced) {
1204
- limitTimerRace.resolve();
1205
- }
1409
+ const limit =
1410
+ itemsChanged.size - deletedItemIds.length >= this.syncPageSize;
1206
1411
 
1207
- // kicks off every subsequent race as results sync down
1208
- limitTimerRace.start();
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
- // TODO: abstract this function into a util file to be able to write better unit tests
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
- // send one last snapshot when the model is fully synced
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
- this.syncExpressions ||
1333
- configSyncExpressions;
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
- return;
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
- return undefined;
1553
- }
1803
+ } catch {}
1804
+
1805
+ return undefined;
1554
1806
  }
1555
1807
  }
1556
1808