@aws-amplify/datastore 3.7.3 → 3.7.4-custom-pk.86

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 +144 -17
  2. package/README.md +154 -0
  3. package/dist/aws-amplify-datastore.js +3740 -1599
  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 +291 -83
  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 +361 -193
  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 +59 -28
  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 +48 -33
  60. package/lib/util.js +219 -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 +293 -85
  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 +361 -193
  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 +60 -29
  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 +48 -33
  115. package/lib-esm/util.js +207 -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 +448 -148
  120. package/src/predicates/index.ts +32 -10
  121. package/src/storage/adapter/AsyncStorageAdapter.ts +305 -78
  122. package/src/storage/adapter/AsyncStorageDatabase.ts +65 -26
  123. package/src/storage/adapter/InMemoryStore.ts +2 -2
  124. package/src/storage/adapter/IndexedDBAdapter.ts +344 -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 +256 -42
  137. package/ssr/package.json +1 -1
@@ -8,6 +8,9 @@ import {
8
8
  PredicatesGroup,
9
9
  GraphQLFilter,
10
10
  AuthModeStrategy,
11
+ ErrorHandler,
12
+ ProcessName,
13
+ AmplifyContext,
11
14
  } from '../../types';
12
15
  import {
13
16
  buildGraphQLOperation,
@@ -17,6 +20,7 @@ import {
17
20
  predicateToGraphQLFilter,
18
21
  getTokenForCustomAuth,
19
22
  } from '../utils';
23
+ import { USER_AGENT_SUFFIX_DATASTORE } from '../../util';
20
24
  import {
21
25
  jitteredExponentialRetry,
22
26
  ConsoleLogger as Logger,
@@ -24,7 +28,7 @@ import {
24
28
  NonRetryableError,
25
29
  } from '@aws-amplify/core';
26
30
  import { ModelPredicateCreator } from '../../predicates';
27
-
31
+ import { getSyncErrorType } from './errorMaps';
28
32
  const opResultDefaults = {
29
33
  items: [],
30
34
  nextToken: null,
@@ -40,8 +44,11 @@ class SyncProcessor {
40
44
  private readonly schema: InternalSchema,
41
45
  private readonly syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>>,
42
46
  private readonly amplifyConfig: Record<string, any> = {},
43
- private readonly authModeStrategy: AuthModeStrategy
47
+ private readonly authModeStrategy: AuthModeStrategy,
48
+ private readonly errorHandler: ErrorHandler,
49
+ private readonly amplifyContext: AmplifyContext
44
50
  ) {
51
+ amplifyContext.API = amplifyContext.API || API;
45
52
  this.generateQueries();
46
53
  }
47
54
 
@@ -65,10 +72,11 @@ class SyncProcessor {
65
72
  if (!this.syncPredicates) {
66
73
  return null;
67
74
  }
68
- const predicatesGroup: PredicatesGroup<any> = ModelPredicateCreator.getPredicates(
69
- this.syncPredicates.get(model),
70
- false
71
- );
75
+ const predicatesGroup: PredicatesGroup<any> =
76
+ ModelPredicateCreator.getPredicates(
77
+ this.syncPredicates.get(model),
78
+ false
79
+ );
72
80
 
73
81
  if (!predicatesGroup) {
74
82
  return null;
@@ -77,9 +85,7 @@ class SyncProcessor {
77
85
  return predicateToGraphQLFilter(predicatesGroup);
78
86
  }
79
87
 
80
- private async retrievePage<
81
- T extends ModelInstanceMetadata = ModelInstanceMetadata
82
- >(
88
+ private async retrievePage<T extends ModelInstanceMetadata>(
83
89
  modelDefinition: SchemaModel,
84
90
  lastSync: number,
85
91
  nextToken: string,
@@ -202,11 +208,12 @@ class SyncProcessor {
202
208
  this.amplifyConfig
203
209
  );
204
210
 
205
- return await API.graphql({
211
+ return await this.amplifyContext.API.graphql({
206
212
  query,
207
213
  variables,
208
214
  authMode,
209
215
  authToken,
216
+ userAgentSuffix: USER_AGENT_SUFFIX_DATASTORE,
210
217
  });
211
218
  } catch (error) {
212
219
  // Catch client-side (GraphQLAuthError) & 401/403 errors here so that we don't continue to retry
@@ -222,15 +229,33 @@ class SyncProcessor {
222
229
  error.data[opName] &&
223
230
  error.data[opName].items
224
231
  );
225
-
226
232
  if (this.partialDataFeatureFlagEnabled()) {
227
233
  if (hasItems) {
228
234
  const result = error;
229
235
  result.data[opName].items = result.data[opName].items.filter(
230
236
  item => item !== null
231
237
  );
232
-
233
238
  if (error.errors) {
239
+ await Promise.all(
240
+ error.errors.map(async err => {
241
+ try {
242
+ await this.errorHandler({
243
+ recoverySuggestion:
244
+ 'Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues',
245
+ localModel: null,
246
+ message: err.message,
247
+ model: modelDefinition.name,
248
+ operation: opName,
249
+ errorType: getSyncErrorType(err),
250
+ process: ProcessName.sync,
251
+ remoteModel: null,
252
+ cause: err,
253
+ });
254
+ } catch (e) {
255
+ logger.error('Sync error handler failed with:', e);
256
+ }
257
+ })
258
+ );
234
259
  Hub.dispatch('datastore', {
235
260
  event: 'syncQueriesPartialSyncError',
236
261
  data: {
package/src/sync/utils.ts CHANGED
@@ -27,7 +27,11 @@ import {
27
27
  InternalSchema,
28
28
  AuthModeStrategy,
29
29
  } from '../types';
30
- import { exhaustiveCheck } from '../util';
30
+ import {
31
+ exhaustiveCheck,
32
+ extractPrimaryKeyFieldNames,
33
+ establishRelationAndKeys,
34
+ } from '../util';
31
35
  import { MutationEvent } from './';
32
36
 
33
37
  const logger = new Logger('DataStore');
@@ -47,7 +51,7 @@ export enum TransformerMutationType {
47
51
  GET = 'Get',
48
52
  }
49
53
 
50
- const dummyMetadata: Omit<ModelInstanceMetadata, 'id'> = {
54
+ const dummyMetadata: ModelInstanceMetadata = {
51
55
  _version: undefined,
52
56
  _lastChangedAt: undefined,
53
57
  _deleted: undefined,
@@ -79,7 +83,7 @@ export function generateSelectionSet(
79
83
  if (isSchemaModel(modelDefinition)) {
80
84
  scalarAndMetadataFields = scalarAndMetadataFields
81
85
  .concat(getMetadataFields())
82
- .concat(getConnectionFields(modelDefinition));
86
+ .concat(getConnectionFields(modelDefinition, namespace));
83
87
  }
84
88
 
85
89
  const result = scalarAndMetadataFields.join('\n');
@@ -138,8 +142,12 @@ function getScalarFields(
138
142
  return result;
139
143
  }
140
144
 
141
- function getConnectionFields(modelDefinition: SchemaModel): string[] {
142
- const result = [];
145
+ // Used for generating the selection set for queries and mutations
146
+ function getConnectionFields(
147
+ modelDefinition: SchemaModel,
148
+ namespace: SchemaNamespace
149
+ ): string[] {
150
+ const result: string[] = [];
143
151
 
144
152
  Object.values(modelDefinition.fields)
145
153
  .filter(({ association }) => association && Object.keys(association).length)
@@ -153,7 +161,26 @@ function getConnectionFields(modelDefinition: SchemaModel): string[] {
153
161
  break;
154
162
  case 'BELONGS_TO':
155
163
  if (isTargetNameAssociation(association)) {
156
- result.push(`${name} { id _deleted }`);
164
+ // New codegen (CPK)
165
+ if (association.targetNames && association.targetNames.length > 0) {
166
+ // Need to retrieve relations in order to get connected model keys
167
+ const [relations] = establishRelationAndKeys(namespace);
168
+
169
+ const connectedModelName =
170
+ modelDefinition.fields[name].type['model'];
171
+
172
+ const byPkIndex = relations[connectedModelName].indexes.find(
173
+ ([name]) => name === 'byPk'
174
+ );
175
+ const keyFields = byPkIndex && byPkIndex[1];
176
+ const keyFieldSelectionSet = keyFields?.join(' ');
177
+
178
+ // We rely on `_deleted` when we process the sync query (e.g. in batchSave in the adapters)
179
+ result.push(`${name} { ${keyFieldSelectionSet} _deleted }`);
180
+ } else {
181
+ // backwards-compatability for schema generated prior to custom primary key support
182
+ result.push(`${name} { id _deleted }`);
183
+ }
157
184
  }
158
185
  break;
159
186
  default:
@@ -412,10 +439,13 @@ export function createMutationInstanceFromModelOperation<
412
439
  return v;
413
440
  };
414
441
 
442
+ const modelId = getIdentifierValue(modelDefinition, element);
443
+ const optionalId = OpType.INSERT && id ? { id } : {};
444
+
415
445
  const mutationEvent = modelInstanceCreator(MutationEventConstructor, {
416
- ...(id ? { id } : {}),
446
+ ...optionalId,
417
447
  data: JSON.stringify(element, replacer),
418
- modelId: element.id,
448
+ modelId,
419
449
  model: model.name,
420
450
  operation,
421
451
  condition: JSON.stringify(condition),
@@ -425,7 +455,8 @@ export function createMutationInstanceFromModelOperation<
425
455
  }
426
456
 
427
457
  export function predicateToGraphQLCondition(
428
- predicate: PredicatesGroup<any>
458
+ predicate: PredicatesGroup<any>,
459
+ modelDefinition: SchemaModel
429
460
  ): GraphQLCondition {
430
461
  const result = {};
431
462
 
@@ -433,17 +464,27 @@ export function predicateToGraphQLCondition(
433
464
  return result;
434
465
  }
435
466
 
467
+ const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
468
+
436
469
  predicate.predicates.forEach(p => {
437
470
  if (isPredicateObj(p)) {
438
471
  const { field, operator, operand } = p;
439
472
 
440
- if (field === 'id') {
473
+ // This is compatible with how the GQL Transform currently generates the Condition Input,
474
+ // i.e. any PK and SK fields are omitted and can't be used as conditions.
475
+ // However, I think this limits usability.
476
+ // What if we want to delete all records where SK > some value
477
+ // Or all records where PK = some value but SKs are different values
478
+
479
+ // TODO: if the Transform gets updated ^ we'll need to modify this logic to only omit
480
+ // key fields from the predicate/condition when ALL of the keyFields are present and using `eq` operators
481
+ if (keyFields.includes(field as string)) {
441
482
  return;
442
483
  }
443
484
 
444
485
  result[field] = { [operator]: operand };
445
486
  } else {
446
- result[p.type] = predicateToGraphQLCondition(p);
487
+ result[p.type] = predicateToGraphQLCondition(p, modelDefinition);
447
488
  }
448
489
  });
449
490
 
@@ -515,11 +556,9 @@ export async function getModelAuthModes({
515
556
  defaultAuthMode: GRAPHQL_AUTH_MODE;
516
557
  modelName: string;
517
558
  schema: InternalSchema;
518
- }): Promise<
519
- {
520
- [key in ModelOperation]: GRAPHQL_AUTH_MODE[];
521
- }
522
- > {
559
+ }): Promise<{
560
+ [key in ModelOperation]: GRAPHQL_AUTH_MODE[];
561
+ }> {
523
562
  const operations = Object.values(ModelOperation);
524
563
 
525
564
  const modelAuthModes: {
@@ -612,3 +651,15 @@ export async function getTokenForCustomAuth(
612
651
  }
613
652
  }
614
653
  }
654
+
655
+ // Util that takes a modelDefinition and model and returns either the id value(s) or the custom primary key value(s)
656
+ export function getIdentifierValue(
657
+ modelDefinition: SchemaModel,
658
+ model: ModelInstanceMetadata | PersistentModel
659
+ ): string {
660
+ const pkFieldNames = extractPrimaryKeyFieldNames(modelDefinition);
661
+
662
+ const idOrPk = pkFieldNames.map(f => model[f]).join('-');
663
+
664
+ return idOrPk;
665
+ }