@aws-amplify/datastore 3.12.12 → 3.12.13-custom-pk.1

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 (105) hide show
  1. package/dist/aws-amplify-datastore.js +1854 -965
  2. package/dist/aws-amplify-datastore.js.map +1 -1
  3. package/dist/aws-amplify-datastore.min.js +7 -7
  4. package/dist/aws-amplify-datastore.min.js.map +1 -1
  5. package/lib/datastore/datastore.d.ts +13 -16
  6. package/lib/datastore/datastore.js +130 -63
  7. package/lib/datastore/datastore.js.map +1 -1
  8. package/lib/index.d.ts +3 -19
  9. package/lib/predicates/index.d.ts +3 -2
  10. package/lib/predicates/index.js +12 -2
  11. package/lib/predicates/index.js.map +1 -1
  12. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
  13. package/lib/storage/adapter/AsyncStorageAdapter.js +354 -203
  14. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  15. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
  16. package/lib/storage/adapter/AsyncStorageDatabase.js +65 -28
  17. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  18. package/lib/storage/adapter/IndexedDBAdapter.d.ts +5 -4
  19. package/lib/storage/adapter/IndexedDBAdapter.js +389 -267
  20. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  21. package/lib/storage/adapter/index.d.ts +1 -1
  22. package/lib/storage/storage.d.ts +1 -1
  23. package/lib/storage/storage.js +92 -27
  24. package/lib/storage/storage.js.map +1 -1
  25. package/lib/sync/index.d.ts +21 -4
  26. package/lib/sync/index.js +13 -11
  27. package/lib/sync/index.js.map +1 -1
  28. package/lib/sync/merger.d.ts +3 -3
  29. package/lib/sync/merger.js +7 -6
  30. package/lib/sync/merger.js.map +1 -1
  31. package/lib/sync/outbox.d.ts +2 -2
  32. package/lib/sync/outbox.js +11 -9
  33. package/lib/sync/outbox.js.map +1 -1
  34. package/lib/sync/processors/mutation.js +60 -42
  35. package/lib/sync/processors/mutation.js.map +1 -1
  36. package/lib/sync/processors/subscription.js.map +1 -1
  37. package/lib/sync/processors/sync.js.map +1 -1
  38. package/lib/sync/utils.d.ts +3 -2
  39. package/lib/sync/utils.js +61 -8
  40. package/lib/sync/utils.js.map +1 -1
  41. package/lib/types.d.ts +64 -25
  42. package/lib/types.js +10 -1
  43. package/lib/types.js.map +1 -1
  44. package/lib/util.d.ts +56 -24
  45. package/lib/util.js +334 -170
  46. package/lib/util.js.map +1 -1
  47. package/lib-esm/datastore/datastore.d.ts +13 -16
  48. package/lib-esm/datastore/datastore.js +132 -65
  49. package/lib-esm/datastore/datastore.js.map +1 -1
  50. package/lib-esm/index.d.ts +3 -19
  51. package/lib-esm/predicates/index.d.ts +3 -2
  52. package/lib-esm/predicates/index.js +13 -3
  53. package/lib-esm/predicates/index.js.map +1 -1
  54. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
  55. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +355 -204
  56. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  57. package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
  58. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +66 -29
  59. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  60. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +5 -4
  61. package/lib-esm/storage/adapter/IndexedDBAdapter.js +390 -268
  62. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  63. package/lib-esm/storage/adapter/index.d.ts +1 -1
  64. package/lib-esm/storage/storage.d.ts +1 -1
  65. package/lib-esm/storage/storage.js +92 -27
  66. package/lib-esm/storage/storage.js.map +1 -1
  67. package/lib-esm/sync/index.d.ts +21 -4
  68. package/lib-esm/sync/index.js +15 -13
  69. package/lib-esm/sync/index.js.map +1 -1
  70. package/lib-esm/sync/merger.d.ts +3 -3
  71. package/lib-esm/sync/merger.js +7 -6
  72. package/lib-esm/sync/merger.js.map +1 -1
  73. package/lib-esm/sync/outbox.d.ts +2 -2
  74. package/lib-esm/sync/outbox.js +12 -10
  75. package/lib-esm/sync/outbox.js.map +1 -1
  76. package/lib-esm/sync/processors/mutation.js +61 -43
  77. package/lib-esm/sync/processors/mutation.js.map +1 -1
  78. package/lib-esm/sync/processors/subscription.js.map +1 -1
  79. package/lib-esm/sync/processors/sync.js.map +1 -1
  80. package/lib-esm/sync/utils.d.ts +3 -2
  81. package/lib-esm/sync/utils.js +62 -10
  82. package/lib-esm/sync/utils.js.map +1 -1
  83. package/lib-esm/types.d.ts +64 -25
  84. package/lib-esm/types.js +9 -2
  85. package/lib-esm/types.js.map +1 -1
  86. package/lib-esm/util.d.ts +56 -24
  87. package/lib-esm/util.js +334 -170
  88. package/lib-esm/util.js.map +1 -1
  89. package/package.json +7 -7
  90. package/src/datastore/datastore.ts +253 -113
  91. package/src/predicates/index.ts +32 -10
  92. package/src/storage/adapter/AsyncStorageAdapter.ts +309 -93
  93. package/src/storage/adapter/AsyncStorageDatabase.ts +74 -26
  94. package/src/storage/adapter/IndexedDBAdapter.ts +319 -136
  95. package/src/storage/adapter/index.ts +1 -1
  96. package/src/storage/storage.ts +68 -21
  97. package/src/sync/index.ts +41 -26
  98. package/src/sync/merger.ts +14 -4
  99. package/src/sync/outbox.ts +21 -8
  100. package/src/sync/processors/mutation.ts +49 -45
  101. package/src/sync/processors/subscription.ts +0 -1
  102. package/src/sync/processors/sync.ts +1 -3
  103. package/src/sync/utils.ts +69 -12
  104. package/src/types.ts +181 -29
  105. package/src/util.ts +415 -176
@@ -29,6 +29,7 @@ import {
29
29
  GraphQLScalarType,
30
30
  InternalSchema,
31
31
  isGraphQLScalarType,
32
+ isSchemaModelWithAttributes,
32
33
  ModelFieldType,
33
34
  ModelInit,
34
35
  ModelInstanceMetadata,
@@ -57,10 +58,16 @@ import {
57
58
  isNonModelFieldType,
58
59
  isModelFieldType,
59
60
  ObserveQueryOptions,
61
+ ManagedIdentifier,
62
+ PersistentModelMetaData,
63
+ IdentifierFieldOrIdentifierObject,
64
+ __modelMeta__,
65
+ isIdentifierObject,
60
66
  AmplifyContext,
61
67
  } from '../types';
62
68
  import {
63
69
  DATASTORE,
70
+ errorMessages,
64
71
  establishRelationAndKeys,
65
72
  exhaustiveCheck,
66
73
  isModelConstructor,
@@ -73,9 +80,14 @@ import {
73
80
  registerNonModelClass,
74
81
  sortCompareFunction,
75
82
  DeferredCallbackResolver,
83
+ extractPrimaryKeyFieldNames,
84
+ extractPrimaryKeysAndValues,
85
+ isIdManaged,
86
+ isIdOptionallyManaged,
76
87
  validatePredicate,
77
88
  mergePatches,
78
89
  } from '../util';
90
+ import { getIdentifierValue } from '../sync/utils';
79
91
 
80
92
  setAutoFreeze(true);
81
93
  enablePatches();
@@ -85,11 +97,16 @@ const logger = new Logger('DataStore');
85
97
  const ulid = monotonicUlidFactory(Date.now());
86
98
  const { isNode } = JS.browserOrNode();
87
99
 
100
+ type SettingMetaData = {
101
+ identifier: ManagedIdentifier<Setting, 'id'>;
102
+ readOnlyFields: never;
103
+ };
88
104
  declare class Setting {
89
- constructor(init: ModelInit<Setting>);
105
+ public readonly [__modelMeta__]: SettingMetaData;
106
+ constructor(init: ModelInit<Setting, SettingMetaData>);
90
107
  static copyOf(
91
108
  src: Setting,
92
- mutator: (draft: MutableModel<Setting>) => void | Setting
109
+ mutator: (draft: MutableModel<Setting, SettingMetaData>) => void | Setting
93
110
  ): Setting;
94
111
  public readonly id: string;
95
112
  public readonly key: string;
@@ -266,16 +283,15 @@ const createTypeClasses: (
266
283
 
267
284
  export declare type ModelInstanceCreator = typeof modelInstanceCreator;
268
285
 
269
- const instancesMetadata = new WeakSet<
270
- ModelInit<PersistentModel & Partial<ModelInstanceMetadata>>
271
- >();
272
- function modelInstanceCreator<T extends PersistentModel = PersistentModel>(
286
+ const instancesMetadata = new WeakSet<ModelInit<unknown, unknown>>();
287
+
288
+ function modelInstanceCreator<T extends PersistentModel>(
273
289
  modelConstructor: PersistentModelConstructor<T>,
274
- init: ModelInit<T> & Partial<ModelInstanceMetadata>
290
+ init: Partial<T>
275
291
  ): T {
276
292
  instancesMetadata.add(init);
277
293
 
278
- return <T>new modelConstructor(init);
294
+ return new modelConstructor(<ModelInit<T, PersistentModelMetaData<T>>>init);
279
295
  }
280
296
 
281
297
  const validateModelFields =
@@ -293,6 +309,14 @@ const validateModelFields =
293
309
  throw new Error(`Field ${name} is required`);
294
310
  }
295
311
 
312
+ if (isSchemaModelWithAttributes(modelDefinition) && !isIdManaged(modelDefinition)) {
313
+ const keys = extractPrimaryKeyFieldNames(modelDefinition);
314
+ if (keys.includes(k) && v === '') {
315
+ logger.error(errorMessages.idEmptyString, { k, value: v });
316
+ throw new Error(errorMessages.idEmptyString);
317
+ }
318
+ }
319
+
296
320
  if (isGraphQLScalarType(type)) {
297
321
  const jsType = GraphQLScalarType.getJSType(type);
298
322
  const validateScalar = GraphQLScalarType.getValidationFunction(type);
@@ -403,7 +427,7 @@ const castInstanceType = (
403
427
  return v;
404
428
  };
405
429
 
406
- const initializeInstance = <T>(
430
+ const initializeInstance = <T extends PersistentModel>(
407
431
  init: ModelInit<T>,
408
432
  modelDefinition: SchemaModel | SchemaNonModel,
409
433
  draft: Draft<T & ModelInstanceMetadata>
@@ -427,31 +451,39 @@ const createModelClass = <T extends PersistentModel>(
427
451
  (draft: Draft<T & ModelInstanceMetadata>) => {
428
452
  initializeInstance(init, modelDefinition, draft);
429
453
 
454
+ // model is initialized inside a DataStore component (e.g. by Sync Engine, Storage Engine, etc.)
455
+ const isInternallyInitialized = instancesMetadata.has(init);
456
+
430
457
  const modelInstanceMetadata: ModelInstanceMetadata =
431
- instancesMetadata.has(init)
458
+ isInternallyInitialized
432
459
  ? <ModelInstanceMetadata>(<unknown>init)
433
460
  : <ModelInstanceMetadata>{};
434
- const {
435
- id: _id,
436
- _version,
437
- _lastChangedAt,
438
- _deleted,
439
- } = modelInstanceMetadata;
440
-
441
- // instancesIds are set by modelInstanceCreator, it is accessible only internally
442
- const isInternal = _id !== null && _id !== undefined;
443
-
444
- const id = isInternal
445
- ? _id
446
- : modelDefinition.syncable
447
- ? uuid4()
448
- : ulid();
449
-
450
- if (!isInternal) {
461
+
462
+ type ModelWithIDIdentifier = { id: string };
463
+
464
+ const { id: _id } =
465
+ modelInstanceMetadata as unknown as ModelWithIDIdentifier;
466
+
467
+ if (isIdManaged(modelDefinition)) {
468
+ const isInternalModel = _id !== null && _id !== undefined;
469
+
470
+ const id = isInternalModel
471
+ ? _id
472
+ : modelDefinition.syncable
473
+ ? uuid4()
474
+ : ulid();
475
+
476
+ (<ModelWithIDIdentifier>(<unknown>draft)).id = id;
477
+ } else if (isIdOptionallyManaged(modelDefinition)) {
478
+ // only auto-populate if the id was not provided
479
+ (<ModelWithIDIdentifier>(<unknown>draft)).id = draft.id || uuid4();
480
+ }
481
+
482
+ if (!isInternallyInitialized) {
451
483
  checkReadOnlyPropertyOnCreate(draft, modelDefinition);
452
484
  }
453
485
 
454
- draft.id = id;
486
+ const { _version, _lastChangedAt, _deleted } = modelInstanceMetadata;
455
487
 
456
488
  if (modelDefinition.syncable) {
457
489
  draft._version = _version;
@@ -476,8 +508,12 @@ const createModelClass = <T extends PersistentModel>(
476
508
  const model = produce(
477
509
  source,
478
510
  draft => {
479
- fn(<MutableModel<T>>(draft as unknown));
480
- draft.id = source.id;
511
+ fn(<MutableModel<T>>draft);
512
+
513
+ const keyNames = extractPrimaryKeyFieldNames(modelDefinition);
514
+ // Keys are immutable
515
+ keyNames.forEach(key => ((draft as Object)[key] = source[key]));
516
+
481
517
  const modelValidator = validateModelFields(modelDefinition);
482
518
  Object.entries(draft).forEach(([k, v]) => {
483
519
  const parsedValue = castInstanceType(modelDefinition, k, v);
@@ -489,6 +525,7 @@ const createModelClass = <T extends PersistentModel>(
489
525
  );
490
526
 
491
527
  const hasExistingPatches = modelPatchesMap.has(source);
528
+
492
529
  if (patches.length || hasExistingPatches) {
493
530
  if (hasExistingPatches) {
494
531
  const [existingPatches, existingSource] = modelPatchesMap.get(source);
@@ -516,6 +553,7 @@ const createModelClass = <T extends PersistentModel>(
516
553
  }
517
554
 
518
555
  const instance = modelInstanceCreator(clazz, json);
556
+
519
557
  const modelValidator = validateModelFields(modelDefinition);
520
558
 
521
559
  Object.entries(instance).forEach(([k, v]) => {
@@ -563,7 +601,9 @@ const checkReadOnlyPropertyOnUpdate = (
563
601
  });
564
602
  };
565
603
 
566
- const createNonModelClass = <T>(typeDefinition: SchemaNonModel) => {
604
+ const createNonModelClass = <T extends PersistentModel>(
605
+ typeDefinition: SchemaNonModel
606
+ ) => {
567
607
  const clazz = <NonModelTypeConstructor<T>>(<unknown>class Model {
568
608
  constructor(init: ModelInit<T>) {
569
609
  const instance = produce(
@@ -647,7 +687,6 @@ async function checkSchemaVersion(
647
687
  const [schemaVersionSetting] = await s.query(
648
688
  Setting,
649
689
  ModelPredicateCreator.createFromExisting(modelDefinition, c =>
650
- // @ts-ignore Argument of type '"eq"' is not assignable to parameter of type 'never'.
651
690
  c.key('eq', SETTING_SCHEMA_VERSION)
652
691
  ),
653
692
  { page: 0, limit: 1 }
@@ -724,12 +763,12 @@ class DataStore {
724
763
  private conflictHandler: ConflictHandler;
725
764
  private errorHandler: (error: SyncError<PersistentModel>) => void;
726
765
  private fullSyncInterval: number;
727
- private initialized: Promise<void>;
766
+ private initialized?: Promise<void>;
728
767
  private initReject: Function;
729
768
  private initResolve: Function;
730
769
  private maxRecordsToSync: number;
731
- private storage: Storage;
732
- private sync: SyncEngine;
770
+ private storage?: Storage;
771
+ private sync?: SyncEngine;
733
772
  private syncPageSize: number;
734
773
  private syncExpressions: SyncExpression[];
735
774
  private syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>> =
@@ -839,7 +878,10 @@ class DataStore {
839
878
  query: {
840
879
  <T extends PersistentModel>(
841
880
  modelConstructor: PersistentModelConstructor<T>,
842
- id: string
881
+ identifier: IdentifierFieldOrIdentifierObject<
882
+ T,
883
+ PersistentModelMetaData<T>
884
+ >
843
885
  ): Promise<T | undefined>;
844
886
  <T extends PersistentModel>(
845
887
  modelConstructor: PersistentModelConstructor<T>,
@@ -848,7 +890,10 @@ class DataStore {
848
890
  ): Promise<T[]>;
849
891
  } = async <T extends PersistentModel>(
850
892
  modelConstructor: PersistentModelConstructor<T>,
851
- idOrCriteria?: string | ProducerModelPredicate<T> | typeof PredicateAll,
893
+ identifierOrCriteria?:
894
+ | IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
895
+ | ProducerModelPredicate<T>
896
+ | typeof PredicateAll,
852
897
  paginationProducer?: ProducerPaginationInput<T>
853
898
  ): Promise<T | T[] | undefined> => {
854
899
  await this.start();
@@ -862,28 +907,44 @@ class DataStore {
862
907
  throw new Error(msg);
863
908
  }
864
909
 
865
- if (typeof idOrCriteria === 'string') {
910
+ if (typeof identifierOrCriteria === 'string') {
866
911
  if (paginationProducer !== undefined) {
867
912
  logger.warn('Pagination is ignored when querying by id');
868
913
  }
869
914
  }
870
915
 
871
916
  const modelDefinition = getModelDefinition(modelConstructor);
917
+ const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
918
+
872
919
  let predicate: ModelPredicate<T>;
873
920
 
874
- if (isQueryOne(idOrCriteria)) {
875
- predicate = ModelPredicateCreator.createForId<T>(
921
+ if (isQueryOne(identifierOrCriteria)) {
922
+ if (keyFields.length > 1) {
923
+ const msg = errorMessages.queryByPkWithCompositeKeyPresent;
924
+ logger.error(msg, { keyFields });
925
+
926
+ throw new Error(msg);
927
+ }
928
+
929
+ predicate = ModelPredicateCreator.createForSingleField<T>(
876
930
  modelDefinition,
877
- idOrCriteria
931
+ keyFields[0],
932
+ identifierOrCriteria
878
933
  );
879
934
  } else {
880
- if (isPredicatesAll(idOrCriteria)) {
935
+ // Object is being queried using object literal syntax
936
+ if (isIdentifierObject(<T>identifierOrCriteria, modelDefinition)) {
937
+ predicate = ModelPredicateCreator.createForPk<T>(
938
+ modelDefinition,
939
+ <T>identifierOrCriteria
940
+ );
941
+ } else if (isPredicatesAll(identifierOrCriteria)) {
881
942
  // Predicates.ALL means "all records", so no predicate (undefined)
882
943
  predicate = undefined;
883
944
  } else {
884
945
  predicate = ModelPredicateCreator.createFromExisting(
885
946
  modelDefinition,
886
- idOrCriteria
947
+ <any>identifierOrCriteria
887
948
  );
888
949
  }
889
950
  }
@@ -913,7 +974,11 @@ class DataStore {
913
974
  pagination
914
975
  );
915
976
 
916
- return isQueryOne(idOrCriteria) ? result[0] : result;
977
+ const returnOne =
978
+ isQueryOne(identifierOrCriteria) ||
979
+ isIdentifierObject(identifierOrCriteria, modelDefinition);
980
+
981
+ return returnOne ? result[0] : result;
917
982
  };
918
983
 
919
984
  save = async <T extends PersistentModel>(
@@ -926,7 +991,7 @@ class DataStore {
926
991
  // Allows us to only include changed fields for updates
927
992
  const patchesTuple = modelPatchesMap.get(model);
928
993
 
929
- const modelConstructor: PersistentModelConstructor<T> = model
994
+ const modelConstructor: PersistentModelConstructor<T> | undefined = model
930
995
  ? <PersistentModelConstructor<T>>model.constructor
931
996
  : undefined;
932
997
 
@@ -941,15 +1006,15 @@ class DataStore {
941
1006
 
942
1007
  const producedCondition = ModelPredicateCreator.createFromExisting(
943
1008
  modelDefinition,
944
- condition
1009
+ condition!
945
1010
  );
946
1011
 
947
1012
  const [savedModel] = await this.storage.runExclusive(async s => {
948
1013
  await s.save(model, producedCondition, undefined, patchesTuple);
949
1014
 
950
- return s.query(
1015
+ return s.query<T>(
951
1016
  modelConstructor,
952
- ModelPredicateCreator.createForId(modelDefinition, model.id)
1017
+ ModelPredicateCreator.createForPk(modelDefinition, model)
953
1018
  );
954
1019
  });
955
1020
 
@@ -989,22 +1054,28 @@ class DataStore {
989
1054
  };
990
1055
 
991
1056
  delete: {
992
- <T extends PersistentModel>(
993
- model: T,
994
- condition?: ProducerModelPredicate<T>
995
- ): Promise<T>;
996
1057
  <T extends PersistentModel>(
997
1058
  modelConstructor: PersistentModelConstructor<T>,
998
- id: string
1059
+ identifier: IdentifierFieldOrIdentifierObject<
1060
+ T,
1061
+ PersistentModelMetaData<T>
1062
+ >
999
1063
  ): Promise<T[]>;
1000
1064
  <T extends PersistentModel>(
1001
1065
  modelConstructor: PersistentModelConstructor<T>,
1002
1066
  condition: ProducerModelPredicate<T> | typeof PredicateAll
1003
1067
  ): Promise<T[]>;
1068
+ <T extends PersistentModel>(
1069
+ model: T,
1070
+ condition?: ProducerModelPredicate<T>
1071
+ ): Promise<T>;
1004
1072
  } = async <T extends PersistentModel>(
1005
1073
  modelOrConstructor: T | PersistentModelConstructor<T>,
1006
- idOrCriteria?: string | ProducerModelPredicate<T> | typeof PredicateAll
1007
- ) => {
1074
+ identifierOrCriteria?:
1075
+ | IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
1076
+ | ProducerModelPredicate<T>
1077
+ | typeof PredicateAll
1078
+ ): Promise<T | T[]> => {
1008
1079
  await this.start();
1009
1080
 
1010
1081
  let condition: ModelPredicate<T>;
@@ -1016,31 +1087,50 @@ class DataStore {
1016
1087
  throw new Error(msg);
1017
1088
  }
1018
1089
 
1019
- if (isValidModelConstructor(modelOrConstructor)) {
1090
+ if (isValidModelConstructor<T>(modelOrConstructor)) {
1020
1091
  const modelConstructor = modelOrConstructor;
1021
1092
 
1022
- if (!idOrCriteria) {
1093
+ if (!identifierOrCriteria) {
1023
1094
  const msg =
1024
1095
  'Id to delete or criteria required. Do you want to delete all? Pass Predicates.ALL';
1025
- logger.error(msg, { idOrCriteria });
1096
+ logger.error(msg, { identifierOrCriteria });
1026
1097
 
1027
1098
  throw new Error(msg);
1028
1099
  }
1029
1100
 
1030
- if (typeof idOrCriteria === 'string') {
1031
- condition = ModelPredicateCreator.createForId<T>(
1101
+ const modelDefinition = getModelDefinition(modelConstructor);
1102
+
1103
+ if (typeof identifierOrCriteria === 'string') {
1104
+ const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
1105
+
1106
+ if (keyFields.length > 1) {
1107
+ const msg = errorMessages.deleteByPkWithCompositeKeyPresent;
1108
+ logger.error(msg, { keyFields });
1109
+
1110
+ throw new Error(msg);
1111
+ }
1112
+
1113
+ condition = ModelPredicateCreator.createForSingleField<T>(
1032
1114
  getModelDefinition(modelConstructor),
1033
- idOrCriteria
1115
+ keyFields[0],
1116
+ identifierOrCriteria
1034
1117
  );
1035
1118
  } else {
1036
- condition = ModelPredicateCreator.createFromExisting(
1037
- getModelDefinition(modelConstructor),
1038
- /**
1039
- * idOrCriteria is always a ProducerModelPredicate<T>, never a symbol.
1040
- * The symbol is used only for typing purposes. e.g. see Predicates.ALL
1041
- */
1042
- idOrCriteria as ProducerModelPredicate<T>
1043
- );
1119
+ if (isIdentifierObject(identifierOrCriteria, modelDefinition)) {
1120
+ condition = ModelPredicateCreator.createForPk<T>(
1121
+ modelDefinition,
1122
+ <T>identifierOrCriteria
1123
+ );
1124
+ } else {
1125
+ condition = ModelPredicateCreator.createFromExisting(
1126
+ modelDefinition,
1127
+ /**
1128
+ * idOrCriteria is always a ProducerModelPredicate<T>, never a symbol.
1129
+ * The symbol is used only for typing purposes. e.g. see Predicates.ALL
1130
+ */
1131
+ identifierOrCriteria as ProducerModelPredicate<T>
1132
+ );
1133
+ }
1044
1134
 
1045
1135
  if (!condition || !ModelPredicateCreator.isValidPredicate(condition)) {
1046
1136
  const msg =
@@ -1068,22 +1158,24 @@ class DataStore {
1068
1158
 
1069
1159
  const modelDefinition = getModelDefinition(modelConstructor);
1070
1160
 
1071
- const idPredicate = ModelPredicateCreator.createForId<T>(
1161
+ const pkPredicate = ModelPredicateCreator.createForPk<T>(
1072
1162
  modelDefinition,
1073
- model.id
1163
+ model
1074
1164
  );
1075
1165
 
1076
- if (idOrCriteria) {
1077
- if (typeof idOrCriteria !== 'function') {
1166
+ if (identifierOrCriteria) {
1167
+ if (typeof identifierOrCriteria !== 'function') {
1078
1168
  const msg = 'Invalid criteria';
1079
- logger.error(msg, { idOrCriteria });
1169
+ logger.error(msg, { identifierOrCriteria });
1080
1170
 
1081
1171
  throw new Error(msg);
1082
1172
  }
1083
1173
 
1084
- condition = idOrCriteria(idPredicate);
1174
+ condition = (<ProducerModelPredicate<T>>identifierOrCriteria)(
1175
+ pkPredicate
1176
+ );
1085
1177
  } else {
1086
- condition = idPredicate;
1178
+ condition = pkPredicate;
1087
1179
  }
1088
1180
 
1089
1181
  const [[deleted]] = await this.storage.delete(model, condition);
@@ -1095,20 +1187,28 @@ class DataStore {
1095
1187
  observe: {
1096
1188
  (): Observable<SubscriptionMessage<PersistentModel>>;
1097
1189
 
1098
- <T extends PersistentModel>(model: T): Observable<SubscriptionMessage<T>>;
1190
+ <T extends PersistentModel>(
1191
+ modelConstructor: PersistentModelConstructor<T>,
1192
+ identifier: string
1193
+ ): Observable<SubscriptionMessage<T>>;
1099
1194
 
1100
1195
  <T extends PersistentModel>(
1101
1196
  modelConstructor: PersistentModelConstructor<T>,
1102
- criteria?: string | ProducerModelPredicate<T>
1197
+ criteria?: ProducerModelPredicate<T> | typeof PredicateAll
1103
1198
  ): Observable<SubscriptionMessage<T>>;
1104
- } = <T extends PersistentModel = PersistentModel>(
1199
+
1200
+ <T extends PersistentModel>(model: T): Observable<SubscriptionMessage<T>>;
1201
+ } = <T extends PersistentModel>(
1105
1202
  modelOrConstructor?: T | PersistentModelConstructor<T>,
1106
- idOrCriteria?: string | ProducerModelPredicate<T>
1203
+ identifierOrCriteria?:
1204
+ | string
1205
+ | ProducerModelPredicate<T>
1206
+ | typeof PredicateAll
1107
1207
  ): Observable<SubscriptionMessage<T>> => {
1108
1208
  let predicate: ModelPredicate<T>;
1109
1209
 
1110
- const modelConstructor: PersistentModelConstructor<T> =
1111
- modelOrConstructor && isValidModelConstructor(modelOrConstructor)
1210
+ const modelConstructor: PersistentModelConstructor<T> | undefined =
1211
+ modelOrConstructor && isValidModelConstructor<T>(modelOrConstructor)
1112
1212
  ? modelOrConstructor
1113
1213
  : undefined;
1114
1214
 
@@ -1118,10 +1218,10 @@ class DataStore {
1118
1218
  model && (<Object>Object.getPrototypeOf(model)).constructor;
1119
1219
 
1120
1220
  if (isValidModelConstructor<T>(modelConstructor)) {
1121
- if (idOrCriteria) {
1221
+ if (identifierOrCriteria) {
1122
1222
  logger.warn('idOrCriteria is ignored when using a model instance', {
1123
1223
  model,
1124
- idOrCriteria,
1224
+ identifierOrCriteria,
1125
1225
  });
1126
1226
  }
1127
1227
 
@@ -1135,9 +1235,24 @@ class DataStore {
1135
1235
  }
1136
1236
  }
1137
1237
 
1138
- if (idOrCriteria !== undefined && modelConstructor === undefined) {
1238
+ // observe should not accept object literal syntax
1239
+ if (
1240
+ identifierOrCriteria &&
1241
+ modelConstructor &&
1242
+ isIdentifierObject(
1243
+ identifierOrCriteria,
1244
+ getModelDefinition(modelConstructor)
1245
+ )
1246
+ ) {
1247
+ const msg = errorMessages.observeWithObjectLiteral;
1248
+ logger.error(msg, { objectLiteral: identifierOrCriteria });
1249
+
1250
+ throw new Error(msg);
1251
+ }
1252
+
1253
+ if (identifierOrCriteria !== undefined && modelConstructor === undefined) {
1139
1254
  const msg = 'Cannot provide criteria without a modelConstructor';
1140
- logger.error(msg, idOrCriteria);
1255
+ logger.error(msg, identifierOrCriteria);
1141
1256
  throw new Error(msg);
1142
1257
  }
1143
1258
 
@@ -1148,18 +1263,26 @@ class DataStore {
1148
1263
  throw new Error(msg);
1149
1264
  }
1150
1265
 
1151
- if (typeof idOrCriteria === 'string') {
1152
- predicate = ModelPredicateCreator.createForId<T>(
1266
+ if (typeof identifierOrCriteria === 'string') {
1267
+ const modelDefinition = getModelDefinition(modelConstructor);
1268
+ const [keyField] = extractPrimaryKeyFieldNames(modelDefinition);
1269
+
1270
+ predicate = ModelPredicateCreator.createForSingleField<T>(
1153
1271
  getModelDefinition(modelConstructor),
1154
- idOrCriteria
1272
+ keyField,
1273
+ identifierOrCriteria
1155
1274
  );
1156
1275
  } else {
1157
- predicate =
1158
- modelConstructor &&
1159
- ModelPredicateCreator.createFromExisting<T>(
1160
- getModelDefinition(modelConstructor),
1161
- idOrCriteria
1162
- );
1276
+ if (isPredicatesAll(identifierOrCriteria)) {
1277
+ predicate = undefined;
1278
+ } else {
1279
+ predicate =
1280
+ modelConstructor &&
1281
+ ModelPredicateCreator.createFromExisting<T>(
1282
+ getModelDefinition(modelConstructor),
1283
+ identifierOrCriteria
1284
+ );
1285
+ }
1163
1286
  }
1164
1287
 
1165
1288
  return new Observable<SubscriptionMessage<T>>(observer => {
@@ -1181,12 +1304,18 @@ class DataStore {
1181
1304
 
1182
1305
  let message = item;
1183
1306
 
1184
- // as lnog as we're not dealing with a DELETE, we need to fetch a fresh
1307
+ // as long as we're not dealing with a DELETE, we need to fetch a fresh
1185
1308
  // item from storage to ensure it's fully populated.
1186
1309
  if (item.opType !== 'DELETE') {
1310
+ const modelDefinition = getModelDefinition(item.model);
1311
+ const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
1312
+ const primaryKeysAndValues = extractPrimaryKeysAndValues(
1313
+ item.element,
1314
+ keyFields
1315
+ );
1187
1316
  const freshElement = await this.query(
1188
1317
  item.model,
1189
- item.element.id
1318
+ primaryKeysAndValues
1190
1319
  );
1191
1320
  message = {
1192
1321
  ...message,
@@ -1215,7 +1344,7 @@ class DataStore {
1215
1344
  criteria?: ProducerModelPredicate<T> | typeof PredicateAll,
1216
1345
  paginationProducer?: ObserveQueryOptions<T>
1217
1346
  ): Observable<DataStoreSnapshot<T>>;
1218
- } = <T extends PersistentModel = PersistentModel>(
1347
+ } = <T extends PersistentModel>(
1219
1348
  model: PersistentModelConstructor<T>,
1220
1349
  criteria?: ProducerModelPredicate<T> | typeof PredicateAll,
1221
1350
  options?: ObserveQueryOptions<T>
@@ -1254,9 +1383,12 @@ class DataStore {
1254
1383
  const sortOptions = sort ? { sort } : undefined;
1255
1384
 
1256
1385
  const modelDefinition = getModelDefinition(model);
1386
+ const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
1387
+
1257
1388
  if (isQueryOne(criteria)) {
1258
- predicate = ModelPredicateCreator.createForId<T>(
1389
+ predicate = ModelPredicateCreator.createForSingleField<T>(
1259
1390
  modelDefinition,
1391
+ keyFields[0],
1260
1392
  criteria
1261
1393
  );
1262
1394
  } else {
@@ -1278,9 +1410,11 @@ class DataStore {
1278
1410
  (async () => {
1279
1411
  try {
1280
1412
  // first, query and return any locally-available records
1281
- (await this.query(model, criteria, sortOptions)).forEach(item =>
1282
- items.set(item.id, item)
1283
- );
1413
+ (await this.query(model, criteria, sortOptions)).forEach(item => {
1414
+ const itemModelDefinition = getModelDefinition(model);
1415
+ const idOrPk = getIdentifierValue(itemModelDefinition, item);
1416
+ items.set(idOrPk, item);
1417
+ });
1284
1418
 
1285
1419
  // Observe the model and send a stream of updates (debounced).
1286
1420
  // We need to post-filter results instead of passing criteria through
@@ -1288,19 +1422,21 @@ class DataStore {
1288
1422
  // We need to explicitly remove those items from the existing snapshot.
1289
1423
  handle = this.observe(model).subscribe(
1290
1424
  ({ element, model, opType }) => {
1425
+ const itemModelDefinition = getModelDefinition(model);
1426
+ const idOrPk = getIdentifierValue(itemModelDefinition, element);
1291
1427
  if (
1292
1428
  hasPredicate &&
1293
1429
  !validatePredicate(element, predicateGroupType, predicates)
1294
1430
  ) {
1295
1431
  if (
1296
1432
  opType === 'UPDATE' &&
1297
- (items.has(element.id) || itemsChanged.has(element.id))
1433
+ (items.has(idOrPk) || itemsChanged.has(idOrPk))
1298
1434
  ) {
1299
1435
  // tracking as a "deleted item" will include the item in
1300
1436
  // page limit calculations and ensure it is removed from the
1301
1437
  // final items collection, regardless of which collection(s)
1302
1438
  // it is currently in. (I mean, it could be in both, right!?)
1303
- deletedItemIds.push(element.id);
1439
+ deletedItemIds.push(idOrPk);
1304
1440
  } else {
1305
1441
  // ignore updates for irrelevant/filtered items.
1306
1442
  return;
@@ -1312,9 +1448,9 @@ class DataStore {
1312
1448
  // in the `mergePage` method within src/sync/merger.ts. The final state of a model instance
1313
1449
  // depends on the LATEST record (for a given id).
1314
1450
  if (opType === 'DELETE') {
1315
- deletedItemIds.push(element.id);
1451
+ deletedItemIds.push(idOrPk);
1316
1452
  } else {
1317
- itemsChanged.set(element.id, element);
1453
+ itemsChanged.set(idOrPk, element);
1318
1454
  }
1319
1455
 
1320
1456
  const isSynced = this.sync?.getModelSyncedStatus(model) ?? false;
@@ -1356,10 +1492,14 @@ class DataStore {
1356
1492
  }
1357
1493
 
1358
1494
  items.clear();
1359
- itemsArray.forEach(item => items.set(item.id, item));
1495
+ itemsArray.forEach(item => {
1496
+ const itemModelDefinition = getModelDefinition(model);
1497
+ const idOrPk = getIdentifierValue(itemModelDefinition, item);
1498
+ items.set(idOrPk, item);
1499
+ });
1360
1500
 
1361
1501
  // remove deleted items from the final result set
1362
- deletedItemIds.forEach(id => items.delete(id));
1502
+ deletedItemIds.forEach(idOrPk => items.delete(idOrPk));
1363
1503
 
1364
1504
  return {
1365
1505
  items: Array.from(items.values()),
@@ -1515,7 +1655,7 @@ class DataStore {
1515
1655
  this.storageAdapter ||
1516
1656
  undefined;
1517
1657
 
1518
- this.sessionId = this.retrieveSessionId();
1658
+ this.sessionId = this.retrieveSessionId()!;
1519
1659
  };
1520
1660
 
1521
1661
  clear = async function clear() {
@@ -1549,7 +1689,7 @@ class DataStore {
1549
1689
  this.syncPredicates = new WeakMap<SchemaModel, ModelPredicate<any>>();
1550
1690
  };
1551
1691
 
1552
- stop = async function stop() {
1692
+ stop = async function stop(this: InstanceType<typeof DataStore>) {
1553
1693
  if (this.initialized !== undefined) {
1554
1694
  await this.start();
1555
1695
  }
@@ -1713,9 +1853,9 @@ class DataStore {
1713
1853
 
1714
1854
  return `${sessionId}-${appSyncId}`;
1715
1855
  }
1716
- } catch {
1717
- return undefined;
1718
- }
1856
+ } catch {}
1857
+
1858
+ return undefined;
1719
1859
  }
1720
1860
  }
1721
1861