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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/CHANGELOG.md +144 -17
  2. package/README.md +154 -0
  3. package/dist/aws-amplify-datastore.js +3344 -1405
  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 +250 -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 +460 -253
  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 +54 -7
  55. package/lib/sync/utils.js.map +1 -1
  56. package/lib/types.d.ts +85 -33
  57. package/lib/types.js +31 -2
  58. package/lib/types.js.map +1 -1
  59. package/lib/util.d.ts +43 -33
  60. package/lib/util.js +161 -21
  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 +252 -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 +460 -253
  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 +54 -8
  110. package/lib-esm/sync/utils.js.map +1 -1
  111. package/lib-esm/types.d.ts +85 -33
  112. package/lib-esm/types.js +29 -3
  113. package/lib-esm/types.js.map +1 -1
  114. package/lib-esm/util.d.ts +43 -33
  115. package/lib-esm/util.js +151 -18
  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 +396 -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 +355 -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 +63 -15
  135. package/src/types.ts +242 -49
  136. package/src/util.ts +212 -35
  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,7 +142,11 @@ function getScalarFields(
138
142
  return result;
139
143
  }
140
144
 
141
- function getConnectionFields(modelDefinition: SchemaModel): string[] {
145
+ // Used for generating the selection set for queries and mutations
146
+ function getConnectionFields(
147
+ modelDefinition: SchemaModel,
148
+ namespace: SchemaNamespace
149
+ ): string[] {
142
150
  const result = [];
143
151
 
144
152
  Object.values(modelDefinition.fields)
@@ -153,7 +161,23 @@ 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
+ // keyFields are fields of the connected model
173
+ const keyFields = relations[connectedModelName].indexes;
174
+
175
+ // We rely on `_deleted` when we process the sync query (e.g. in batchSave in the adapters)
176
+ result.push(`${name} { ${keyFields} _deleted }`);
177
+ } else {
178
+ // backwards-compatability for schema generated prior to custom primary key support
179
+ result.push(`${name} { id _deleted }`);
180
+ }
157
181
  }
158
182
  break;
159
183
  default:
@@ -412,10 +436,13 @@ export function createMutationInstanceFromModelOperation<
412
436
  return v;
413
437
  };
414
438
 
439
+ const modelId = getIdentifierValue(modelDefinition, element);
440
+ const optionalId = OpType.INSERT && id ? { id } : {};
441
+
415
442
  const mutationEvent = modelInstanceCreator(MutationEventConstructor, {
416
- ...(id ? { id } : {}),
443
+ ...optionalId,
417
444
  data: JSON.stringify(element, replacer),
418
- modelId: element.id,
445
+ modelId,
419
446
  model: model.name,
420
447
  operation,
421
448
  condition: JSON.stringify(condition),
@@ -425,7 +452,8 @@ export function createMutationInstanceFromModelOperation<
425
452
  }
426
453
 
427
454
  export function predicateToGraphQLCondition(
428
- predicate: PredicatesGroup<any>
455
+ predicate: PredicatesGroup<any>,
456
+ modelDefinition: SchemaModel
429
457
  ): GraphQLCondition {
430
458
  const result = {};
431
459
 
@@ -433,17 +461,27 @@ export function predicateToGraphQLCondition(
433
461
  return result;
434
462
  }
435
463
 
464
+ const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
465
+
436
466
  predicate.predicates.forEach(p => {
437
467
  if (isPredicateObj(p)) {
438
468
  const { field, operator, operand } = p;
439
469
 
440
- if (field === 'id') {
470
+ // This is compatible with how the GQL Transform currently generates the Condition Input,
471
+ // i.e. any PK and SK fields are omitted and can't be used as conditions.
472
+ // However, I think this limits usability.
473
+ // What if we want to delete all records where SK > some value
474
+ // Or all records where PK = some value but SKs are different values
475
+
476
+ // TODO: if the Transform gets updated ^ we'll need to modify this logic to only omit
477
+ // key fields from the predicate/condition when ALL of the keyFields are present and using `eq` operators
478
+ if (keyFields.includes(field as string)) {
441
479
  return;
442
480
  }
443
481
 
444
482
  result[field] = { [operator]: operand };
445
483
  } else {
446
- result[p.type] = predicateToGraphQLCondition(p);
484
+ result[p.type] = predicateToGraphQLCondition(p, modelDefinition);
447
485
  }
448
486
  });
449
487
 
@@ -515,11 +553,9 @@ export async function getModelAuthModes({
515
553
  defaultAuthMode: GRAPHQL_AUTH_MODE;
516
554
  modelName: string;
517
555
  schema: InternalSchema;
518
- }): Promise<
519
- {
520
- [key in ModelOperation]: GRAPHQL_AUTH_MODE[];
521
- }
522
- > {
556
+ }): Promise<{
557
+ [key in ModelOperation]: GRAPHQL_AUTH_MODE[];
558
+ }> {
523
559
  const operations = Object.values(ModelOperation);
524
560
 
525
561
  const modelAuthModes: {
@@ -612,3 +648,15 @@ export async function getTokenForCustomAuth(
612
648
  }
613
649
  }
614
650
  }
651
+
652
+ // Util that takes a modelDefinition and model and returns either the id value(s) or the custom primary key value(s)
653
+ export function getIdentifierValue(
654
+ modelDefinition: SchemaModel,
655
+ model: ModelInstanceMetadata | PersistentModel
656
+ ): string {
657
+ const pkFieldNames = extractPrimaryKeyFieldNames(modelDefinition);
658
+
659
+ const idOrPk = pkFieldNames.map(f => model[f]).join('-');
660
+
661
+ return idOrPk;
662
+ }