@aws-amplify/datastore 4.0.12 → 4.0.13-push-notification-dryrun.43

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 (111) hide show
  1. package/lib/datastore/datastore.d.ts +29 -3
  2. package/lib/datastore/datastore.js +308 -147
  3. package/lib/datastore/datastore.js.map +1 -1
  4. package/lib/predicates/index.d.ts +77 -7
  5. package/lib/predicates/index.js +142 -122
  6. package/lib/predicates/index.js.map +1 -1
  7. package/lib/predicates/next.d.ts +51 -10
  8. package/lib/predicates/next.js +111 -91
  9. package/lib/predicates/next.js.map +1 -1
  10. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +28 -30
  11. package/lib/storage/adapter/AsyncStorageAdapter.js +135 -532
  12. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  13. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  14. package/lib/storage/adapter/IndexedDBAdapter.d.ts +28 -29
  15. package/lib/storage/adapter/IndexedDBAdapter.js +490 -885
  16. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  17. package/lib/storage/adapter/StorageAdapterBase.d.ts +134 -0
  18. package/lib/storage/adapter/StorageAdapterBase.js +439 -0
  19. package/lib/storage/adapter/StorageAdapterBase.js.map +1 -0
  20. package/lib/storage/relationship.d.ts +9 -0
  21. package/lib/storage/relationship.js +9 -0
  22. package/lib/storage/relationship.js.map +1 -1
  23. package/lib/storage/storage.d.ts +1 -1
  24. package/lib/storage/storage.js +4 -3
  25. package/lib/storage/storage.js.map +1 -1
  26. package/lib/sync/index.d.ts +15 -1
  27. package/lib/sync/index.js +80 -13
  28. package/lib/sync/index.js.map +1 -1
  29. package/lib/sync/outbox.js +14 -7
  30. package/lib/sync/outbox.js.map +1 -1
  31. package/lib/sync/processors/mutation.d.ts +10 -1
  32. package/lib/sync/processors/mutation.js +33 -12
  33. package/lib/sync/processors/mutation.js.map +1 -1
  34. package/lib/sync/processors/subscription.d.ts +7 -1
  35. package/lib/sync/processors/subscription.js +196 -135
  36. package/lib/sync/processors/subscription.js.map +1 -1
  37. package/lib/sync/processors/sync.d.ts +1 -1
  38. package/lib/sync/processors/sync.js.map +1 -1
  39. package/lib/sync/utils.d.ts +66 -2
  40. package/lib/sync/utils.js +264 -16
  41. package/lib/sync/utils.js.map +1 -1
  42. package/lib/types.d.ts +9 -1
  43. package/lib/types.js.map +1 -1
  44. package/lib/util.d.ts +16 -0
  45. package/lib/util.js +31 -2
  46. package/lib/util.js.map +1 -1
  47. package/lib-esm/datastore/datastore.d.ts +29 -3
  48. package/lib-esm/datastore/datastore.js +310 -149
  49. package/lib-esm/datastore/datastore.js.map +1 -1
  50. package/lib-esm/predicates/index.d.ts +77 -7
  51. package/lib-esm/predicates/index.js +143 -123
  52. package/lib-esm/predicates/index.js.map +1 -1
  53. package/lib-esm/predicates/next.d.ts +51 -10
  54. package/lib-esm/predicates/next.js +111 -91
  55. package/lib-esm/predicates/next.js.map +1 -1
  56. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +28 -30
  57. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +138 -535
  58. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  59. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  60. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +28 -29
  61. package/lib-esm/storage/adapter/IndexedDBAdapter.js +489 -884
  62. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  63. package/lib-esm/storage/adapter/StorageAdapterBase.d.ts +134 -0
  64. package/lib-esm/storage/adapter/StorageAdapterBase.js +437 -0
  65. package/lib-esm/storage/adapter/StorageAdapterBase.js.map +1 -0
  66. package/lib-esm/storage/relationship.d.ts +9 -0
  67. package/lib-esm/storage/relationship.js +9 -0
  68. package/lib-esm/storage/relationship.js.map +1 -1
  69. package/lib-esm/storage/storage.d.ts +1 -1
  70. package/lib-esm/storage/storage.js +4 -3
  71. package/lib-esm/storage/storage.js.map +1 -1
  72. package/lib-esm/sync/index.d.ts +15 -1
  73. package/lib-esm/sync/index.js +82 -15
  74. package/lib-esm/sync/index.js.map +1 -1
  75. package/lib-esm/sync/outbox.js +14 -7
  76. package/lib-esm/sync/outbox.js.map +1 -1
  77. package/lib-esm/sync/processors/mutation.d.ts +10 -1
  78. package/lib-esm/sync/processors/mutation.js +33 -12
  79. package/lib-esm/sync/processors/mutation.js.map +1 -1
  80. package/lib-esm/sync/processors/subscription.d.ts +7 -1
  81. package/lib-esm/sync/processors/subscription.js +197 -136
  82. package/lib-esm/sync/processors/subscription.js.map +1 -1
  83. package/lib-esm/sync/processors/sync.d.ts +1 -1
  84. package/lib-esm/sync/processors/sync.js.map +1 -1
  85. package/lib-esm/sync/utils.d.ts +66 -2
  86. package/lib-esm/sync/utils.js +261 -18
  87. package/lib-esm/sync/utils.js.map +1 -1
  88. package/lib-esm/types.d.ts +9 -1
  89. package/lib-esm/types.js.map +1 -1
  90. package/lib-esm/util.d.ts +16 -0
  91. package/lib-esm/util.js +32 -3
  92. package/lib-esm/util.js.map +1 -1
  93. package/package.json +12 -11
  94. package/src/datastore/datastore.ts +288 -159
  95. package/src/predicates/index.ts +145 -175
  96. package/src/predicates/next.ts +114 -81
  97. package/src/storage/adapter/AsyncStorageAdapter.ts +97 -563
  98. package/src/storage/adapter/AsyncStorageDatabase.ts +2 -2
  99. package/src/storage/adapter/IndexedDBAdapter.ts +318 -770
  100. package/src/storage/adapter/StorageAdapterBase.ts +545 -0
  101. package/src/storage/relationship.ts +9 -0
  102. package/src/storage/storage.ts +12 -9
  103. package/src/sync/index.ts +108 -20
  104. package/src/sync/outbox.ts +17 -11
  105. package/src/sync/processors/mutation.ts +35 -4
  106. package/src/sync/processors/subscription.ts +124 -10
  107. package/src/sync/processors/sync.ts +4 -1
  108. package/src/sync/utils.ts +285 -15
  109. package/src/types.ts +15 -2
  110. package/src/util.ts +40 -1
  111. package/CHANGELOG.md +0 -904
@@ -0,0 +1,545 @@
1
+ import { ConsoleLogger as Logger } from '@aws-amplify/core';
2
+ import { Adapter } from './index';
3
+ import { ModelInstanceCreator } from '../../datastore/datastore';
4
+ import { ModelPredicateCreator } from '../../predicates';
5
+ import {
6
+ InternalSchema,
7
+ isPredicateObj,
8
+ ModelInstanceMetadata,
9
+ ModelPredicate,
10
+ NamespaceResolver,
11
+ OpType,
12
+ PaginationInput,
13
+ PersistentModel,
14
+ PersistentModelConstructor,
15
+ PredicateObject,
16
+ PredicatesGroup,
17
+ QueryOne,
18
+ } from '../../types';
19
+ import {
20
+ NAMESPACES,
21
+ getStorename,
22
+ getIndexKeys,
23
+ extractPrimaryKeyValues,
24
+ traverseModel,
25
+ validatePredicate,
26
+ isModelConstructor,
27
+ extractPrimaryKeyFieldNames,
28
+ } from '../../util';
29
+ import type { IDBPDatabase, IDBPObjectStore } from 'idb';
30
+ import type AsyncStorageDatabase from './AsyncStorageDatabase';
31
+ import { ModelRelationship } from '../relationship';
32
+
33
+ const logger = new Logger('DataStore');
34
+ const DB_NAME = 'amplify-datastore';
35
+
36
+ export abstract class StorageAdapterBase implements Adapter {
37
+ // Non-null assertions (bang operators) added to most properties to make TS happy.
38
+ // For now, we can be reasonably sure they're available when they're needed, because
39
+ // the adapter is not used directly outside the library boundary.
40
+ protected schema!: InternalSchema;
41
+ protected namespaceResolver!: NamespaceResolver;
42
+ protected modelInstanceCreator!: ModelInstanceCreator;
43
+ protected getModelConstructorByModelName!: (
44
+ namsespaceName: NAMESPACES,
45
+ modelName: string
46
+ ) => PersistentModelConstructor<any>;
47
+ protected initPromise!: Promise<void>;
48
+ protected resolve!: (value?: any) => void;
49
+ protected reject!: (value?: any) => void;
50
+ protected dbName: string = DB_NAME;
51
+ protected abstract db: IDBPDatabase | AsyncStorageDatabase;
52
+
53
+ protected abstract preSetUpChecks(): Promise<void>;
54
+ protected abstract preOpCheck(): Promise<void>;
55
+ protected abstract initDb(): Promise<IDBPDatabase | AsyncStorageDatabase>;
56
+
57
+ /**
58
+ * Initializes local DB
59
+ *
60
+ * @param theSchema
61
+ * @param namespaceResolver
62
+ * @param modelInstanceCreator
63
+ * @param getModelConstructorByModelName
64
+ * @param sessionId
65
+ */
66
+ public async setUp(
67
+ theSchema: InternalSchema,
68
+ namespaceResolver: NamespaceResolver,
69
+ modelInstanceCreator: ModelInstanceCreator,
70
+ getModelConstructorByModelName: (
71
+ namsespaceName: NAMESPACES,
72
+ modelName: string
73
+ ) => PersistentModelConstructor<any>,
74
+ sessionId?: string
75
+ ): Promise<void> {
76
+ await this.preSetUpChecks();
77
+
78
+ if (!this.initPromise) {
79
+ this.initPromise = new Promise((res, rej) => {
80
+ this.resolve = res;
81
+ this.reject = rej;
82
+ });
83
+ } else {
84
+ await this.initPromise;
85
+ return;
86
+ }
87
+ if (sessionId) {
88
+ this.dbName = `${DB_NAME}-${sessionId}`;
89
+ }
90
+ this.schema = theSchema;
91
+ this.namespaceResolver = namespaceResolver;
92
+ this.modelInstanceCreator = modelInstanceCreator;
93
+ this.getModelConstructorByModelName = getModelConstructorByModelName;
94
+
95
+ try {
96
+ if (!this.db) {
97
+ this.db = await this.initDb();
98
+ this.resolve();
99
+ }
100
+ } catch (error) {
101
+ this.reject(error);
102
+ }
103
+ }
104
+
105
+ /*
106
+ * Abstract Methods for Adapter interface
107
+ * Not enough implementation similarities between the adapters
108
+ * to consolidate in the base class
109
+ */
110
+ public abstract clear(): Promise<void>;
111
+
112
+ public abstract save<T extends PersistentModel>(
113
+ model: T,
114
+ condition?: ModelPredicate<T>
115
+ );
116
+
117
+ public abstract query<T extends PersistentModel>(
118
+ modelConstructor: PersistentModelConstructor<T>,
119
+ predicate?: ModelPredicate<T>,
120
+ pagination?: PaginationInput<T>
121
+ ): Promise<T[]>;
122
+
123
+ public abstract queryOne<T extends PersistentModel>(
124
+ modelConstructor: PersistentModelConstructor<T>,
125
+ firstOrLast: QueryOne
126
+ ): Promise<T | undefined>;
127
+
128
+ public abstract batchSave<T extends PersistentModel>(
129
+ modelConstructor: PersistentModelConstructor<any>,
130
+ items: ModelInstanceMetadata[]
131
+ ): Promise<[T, OpType][]>;
132
+
133
+ /**
134
+ * @param modelConstructor
135
+ * @returns local DB table name
136
+ */
137
+ protected getStorenameForModel(
138
+ modelConstructor: PersistentModelConstructor<any>
139
+ ): string {
140
+ const namespace = this.namespaceResolver(modelConstructor);
141
+ const { name: modelName } = modelConstructor;
142
+
143
+ return getStorename(namespace, modelName);
144
+ }
145
+
146
+ /**
147
+ *
148
+ * @param model - instantiated model record
149
+ * @returns the record's primary key values
150
+ */
151
+ protected getIndexKeyValuesFromModel<T extends PersistentModel>(
152
+ model: T
153
+ ): string[] {
154
+ const modelConstructor = Object.getPrototypeOf(model)
155
+ .constructor as PersistentModelConstructor<T>;
156
+ const namespaceName = this.namespaceResolver(modelConstructor);
157
+
158
+ const keys = getIndexKeys(
159
+ this.schema.namespaces[namespaceName],
160
+ modelConstructor.name
161
+ );
162
+
163
+ return extractPrimaryKeyValues(model, keys);
164
+ }
165
+
166
+ /**
167
+ * Common metadata for `save` operation
168
+ * used by individual storage adapters
169
+ *
170
+ * @param model
171
+ */
172
+ protected saveMetadata<T extends PersistentModel>(
173
+ model: T
174
+ ): {
175
+ storeName: string;
176
+ set: Set<string>;
177
+ connectionStoreNames;
178
+ modelKeyValues: string[];
179
+ } {
180
+ const modelConstructor = Object.getPrototypeOf(model)
181
+ .constructor as PersistentModelConstructor<T>;
182
+ const storeName = this.getStorenameForModel(modelConstructor);
183
+ const namespaceName = this.namespaceResolver(modelConstructor);
184
+
185
+ const connectedModels = traverseModel(
186
+ modelConstructor.name,
187
+ model,
188
+ this.schema.namespaces[namespaceName],
189
+ this.modelInstanceCreator,
190
+ this.getModelConstructorByModelName!
191
+ );
192
+
193
+ const set = new Set<string>();
194
+ const connectionStoreNames = Object.values(connectedModels).map(
195
+ ({ modelName, item, instance }) => {
196
+ const storeName = getStorename(namespaceName, modelName);
197
+ set.add(storeName);
198
+ const keys = getIndexKeys(
199
+ this.schema.namespaces[namespaceName],
200
+ modelName
201
+ );
202
+ return { storeName, item, instance, keys };
203
+ }
204
+ );
205
+
206
+ const modelKeyValues = this.getIndexKeyValuesFromModel(model);
207
+
208
+ return { storeName, set, connectionStoreNames, modelKeyValues };
209
+ }
210
+
211
+ /**
212
+ * Enforces conditional save. Throws if condition is not met.
213
+ * used by individual storage adapters
214
+ *
215
+ * @param model
216
+ */
217
+ protected validateSaveCondition<T extends PersistentModel>(
218
+ condition?: ModelPredicate<T>,
219
+ fromDB?: unknown
220
+ ): void {
221
+ if (!(condition && fromDB)) {
222
+ return;
223
+ }
224
+
225
+ const predicates = ModelPredicateCreator.getPredicates(condition);
226
+ const { predicates: predicateObjs, type } = predicates!;
227
+
228
+ const isValid = validatePredicate(fromDB, type, predicateObjs);
229
+
230
+ if (!isValid) {
231
+ const msg = 'Conditional update failed';
232
+ logger.error(msg, { model: fromDB, condition: predicateObjs });
233
+
234
+ throw new Error(msg);
235
+ }
236
+ }
237
+
238
+ protected abstract _get<T>(
239
+ storeOrStoreName: IDBPObjectStore | string,
240
+ keyArr: string[]
241
+ ): Promise<T>;
242
+
243
+ /**
244
+ * Instantiate models from POJO records returned from the database
245
+ *
246
+ * @param namespaceName - string model namespace
247
+ * @param srcModelName - string model name
248
+ * @param records - array of uninstantiated records
249
+ * @returns
250
+ */
251
+ protected async load<T>(
252
+ namespaceName: NAMESPACES,
253
+ srcModelName: string,
254
+ records: T[]
255
+ ): Promise<T[]> {
256
+ const namespace = this.schema.namespaces[namespaceName];
257
+ const relations = namespace.relationships![srcModelName].relationTypes;
258
+ const connectionStoreNames = relations.map(({ modelName }) => {
259
+ return getStorename(namespaceName, modelName);
260
+ });
261
+ const modelConstructor = this.getModelConstructorByModelName!(
262
+ namespaceName,
263
+ srcModelName
264
+ );
265
+
266
+ if (connectionStoreNames.length === 0) {
267
+ return records.map(record =>
268
+ this.modelInstanceCreator(modelConstructor, record)
269
+ );
270
+ }
271
+
272
+ return records.map(record =>
273
+ this.modelInstanceCreator(modelConstructor, record)
274
+ );
275
+ }
276
+
277
+ /**
278
+ * Extracts operands from a predicate group into an array of key values
279
+ * Used in the query method
280
+ *
281
+ * @param predicates - predicate group
282
+ * @param keyPath - string array of key names ['id', 'sortKey']
283
+ * @returns string[] of key values
284
+ *
285
+ * @example
286
+ * ```js
287
+ * { and:[{ id: { eq: 'abc' }}, { sortKey: { eq: 'def' }}] }
288
+ * ```
289
+ * Becomes
290
+ * ```
291
+ * ['abc', 'def']
292
+ * ```
293
+ */
294
+ private keyValueFromPredicate<T extends PersistentModel>(
295
+ predicates: PredicatesGroup<T>,
296
+ keyPath: string[]
297
+ ): string[] | undefined {
298
+ const { predicates: predicateObjs } = predicates;
299
+
300
+ if (predicateObjs.length !== keyPath.length) {
301
+ return;
302
+ }
303
+
304
+ const keyValues = [] as any[];
305
+
306
+ for (const key of keyPath) {
307
+ const predicateObj = predicateObjs.find(
308
+ p =>
309
+ // it's a relevant predicate object only if it's an equality
310
+ // operation for a key field from the key:
311
+ isPredicateObj(p) &&
312
+ p.field === key &&
313
+ p.operator === 'eq' &&
314
+ p.operand !== null &&
315
+ p.operand !== undefined
316
+ ) as PredicateObject<T>;
317
+
318
+ predicateObj && keyValues.push(predicateObj.operand);
319
+ }
320
+
321
+ return keyValues.length === keyPath.length ? keyValues : undefined;
322
+ }
323
+
324
+ /**
325
+ * Common metadata for `query` operation
326
+ * used by individual storage adapters
327
+ *
328
+ * @param modelConstructor
329
+ * @param predicate
330
+ * @param pagination
331
+ */
332
+ protected queryMetadata<T extends PersistentModel>(
333
+ modelConstructor: PersistentModelConstructor<T>,
334
+ predicate?: ModelPredicate<T>,
335
+ pagination?: PaginationInput<T>
336
+ ) {
337
+ const storeName = this.getStorenameForModel(modelConstructor);
338
+ const namespaceName = this.namespaceResolver(
339
+ modelConstructor
340
+ ) as NAMESPACES;
341
+
342
+ const predicates =
343
+ predicate && ModelPredicateCreator.getPredicates(predicate);
344
+ const keyPath = getIndexKeys(
345
+ this.schema.namespaces[namespaceName],
346
+ modelConstructor.name
347
+ );
348
+ const queryByKey =
349
+ predicates && this.keyValueFromPredicate(predicates, keyPath);
350
+
351
+ const hasSort = pagination && pagination.sort;
352
+ const hasPagination = pagination && pagination.limit;
353
+
354
+ return {
355
+ storeName,
356
+ namespaceName,
357
+ queryByKey,
358
+ predicates,
359
+ hasSort,
360
+ hasPagination,
361
+ };
362
+ }
363
+
364
+ /**
365
+ * Delete record
366
+ * Cascades to related records (for Has One and Has Many relationships)
367
+ *
368
+ * @param modelOrModelConstructor
369
+ * @param condition
370
+ * @returns
371
+ */
372
+ public async delete<T extends PersistentModel>(
373
+ modelOrModelConstructor: T | PersistentModelConstructor<T>,
374
+ condition?: ModelPredicate<T>
375
+ ): Promise<[T[], T[]]> {
376
+ await this.preOpCheck();
377
+
378
+ const deleteQueue: { storeName: string; items: T[] }[] = [];
379
+
380
+ if (isModelConstructor(modelOrModelConstructor)) {
381
+ const modelConstructor =
382
+ modelOrModelConstructor as PersistentModelConstructor<T>;
383
+ const namespace = this.namespaceResolver(modelConstructor) as NAMESPACES;
384
+ const models = await this.query(modelConstructor, condition);
385
+
386
+ if (condition !== undefined) {
387
+ await this.deleteTraverse(
388
+ models,
389
+ modelConstructor,
390
+ namespace,
391
+ deleteQueue
392
+ );
393
+
394
+ await this.deleteItem(deleteQueue);
395
+
396
+ const deletedModels = deleteQueue.reduce(
397
+ (acc, { items }) => acc.concat(items),
398
+ <T[]>[]
399
+ );
400
+
401
+ return [models, deletedModels];
402
+ } else {
403
+ await this.deleteTraverse(
404
+ models,
405
+ modelConstructor,
406
+ namespace,
407
+ deleteQueue
408
+ );
409
+
410
+ await this.deleteItem(deleteQueue);
411
+
412
+ const deletedModels = deleteQueue.reduce(
413
+ (acc, { items }) => acc.concat(items),
414
+ <T[]>[]
415
+ );
416
+
417
+ return [models, deletedModels];
418
+ }
419
+ } else {
420
+ const model = modelOrModelConstructor as T;
421
+
422
+ const modelConstructor = Object.getPrototypeOf(model)
423
+ .constructor as PersistentModelConstructor<T>;
424
+
425
+ const namespaceName = this.namespaceResolver(
426
+ modelConstructor
427
+ ) as NAMESPACES;
428
+
429
+ const storeName = this.getStorenameForModel(modelConstructor);
430
+
431
+ if (condition) {
432
+ const keyValues = this.getIndexKeyValuesFromModel(model);
433
+ const fromDB = await this._get(storeName, keyValues);
434
+
435
+ if (fromDB === undefined) {
436
+ const msg = 'Model instance not found in storage';
437
+ logger.warn(msg, { model });
438
+
439
+ return [[model], []];
440
+ }
441
+
442
+ const predicates = ModelPredicateCreator.getPredicates(condition);
443
+ const { predicates: predicateObjs, type } =
444
+ predicates as PredicatesGroup<T>;
445
+
446
+ const isValid = validatePredicate(fromDB as T, type, predicateObjs);
447
+ if (!isValid) {
448
+ const msg = 'Conditional update failed';
449
+ logger.error(msg, { model: fromDB, condition: predicateObjs });
450
+
451
+ throw new Error(msg);
452
+ }
453
+
454
+ await this.deleteTraverse(
455
+ [model],
456
+ modelConstructor,
457
+ namespaceName,
458
+ deleteQueue
459
+ );
460
+ } else {
461
+ await this.deleteTraverse(
462
+ [model],
463
+ modelConstructor,
464
+ namespaceName,
465
+ deleteQueue
466
+ );
467
+ }
468
+ await this.deleteItem(deleteQueue);
469
+
470
+ const deletedModels = deleteQueue.reduce(
471
+ (acc, { items }) => acc.concat(items),
472
+ <T[]>[]
473
+ );
474
+
475
+ return [[model], deletedModels];
476
+ }
477
+ }
478
+
479
+ protected abstract deleteItem<T extends PersistentModel>(
480
+ deleteQueue?: {
481
+ storeName: string;
482
+ items: T[] | IDBValidKey[];
483
+ }[]
484
+ );
485
+
486
+ /**
487
+ * Recursively traverse relationship graph and add
488
+ * all Has One and Has Many relations to `deleteQueue` param
489
+ *
490
+ * Actual deletion of records added to `deleteQueue` occurs in the `delete` method
491
+ *
492
+ * @param models
493
+ * @param modelConstructor
494
+ * @param namespace
495
+ * @param deleteQueue
496
+ */
497
+ private async deleteTraverse<T extends PersistentModel>(
498
+ models: T[],
499
+ modelConstructor: PersistentModelConstructor<T>,
500
+ namespace: NAMESPACES,
501
+ deleteQueue: { storeName: string; items: T[] }[]
502
+ ): Promise<void> {
503
+ const cascadingRelationTypes = ['HAS_ONE', 'HAS_MANY'];
504
+
505
+ for await (const model of models) {
506
+ const modelDefinition =
507
+ this.schema.namespaces[namespace].models[modelConstructor.name];
508
+
509
+ const modelMeta = {
510
+ builder: modelConstructor,
511
+ schema: modelDefinition,
512
+ pkField: extractPrimaryKeyFieldNames(modelDefinition),
513
+ };
514
+
515
+ const relationships = ModelRelationship.allFrom(modelMeta).filter(r =>
516
+ cascadingRelationTypes.includes(r.type)
517
+ );
518
+
519
+ for await (const r of relationships) {
520
+ const queryObject = r.createRemoteQueryObject(model);
521
+ if (queryObject !== null) {
522
+ const relatedRecords = await this.query(
523
+ r.remoteModelConstructor,
524
+ ModelPredicateCreator.createFromFlatEqualities(
525
+ r.remoteDefinition!,
526
+ queryObject
527
+ )
528
+ );
529
+
530
+ await this.deleteTraverse(
531
+ relatedRecords,
532
+ r.remoteModelConstructor,
533
+ namespace,
534
+ deleteQueue
535
+ );
536
+ }
537
+ }
538
+ }
539
+
540
+ deleteQueue.push({
541
+ storeName: getStorename(namespace, modelConstructor.name),
542
+ items: models,
543
+ });
544
+ }
545
+ }
@@ -173,6 +173,15 @@ export class ModelRelationship<T> {
173
173
  }
174
174
  }
175
175
 
176
+ /**
177
+ * The `remote` model's associated field's `assocation` metadata, if
178
+ * present.
179
+ *
180
+ * This is used when determining if the remote model's associated field
181
+ * specifies which FK fields to use. If this value is `undefined`, the
182
+ * name of the remote field (`this.localAssociatedWith`) *is* the remote
183
+ * key field.
184
+ */
176
185
  private get explicitRemoteAssociation() {
177
186
  if (this.localAssociatedWith) {
178
187
  if (this.localAssociatedWith.length === 1) {
@@ -60,7 +60,7 @@ class StorageClass implements StorageFacade {
60
60
  private readonly sessionId?: string
61
61
  ) {
62
62
  this.adapter = this.adapter || getDefaultAdapter();
63
- this.pushStream = new PushStream() as any;
63
+ this.pushStream = new PushStream();
64
64
  }
65
65
 
66
66
  static getNamespace() {
@@ -123,7 +123,10 @@ class StorageClass implements StorageFacade {
123
123
  let updateMutationInput;
124
124
  // don't attempt to calc mutation input when storage.save
125
125
  // is called by Merger, i.e., when processing an AppSync response
126
- if (opType === OpType.UPDATE && !syncResponse) {
126
+ if (
127
+ (opType === OpType.UPDATE || opType === OpType.INSERT) &&
128
+ !syncResponse
129
+ ) {
127
130
  //
128
131
  // TODO: LOOK!!!
129
132
  // the `model` used here is in effect regardless of what model
@@ -136,7 +139,7 @@ class StorageClass implements StorageFacade {
136
139
  // depends on this remaining as-is.
137
140
  //
138
141
 
139
- updateMutationInput = this.getUpdateMutationInput(
142
+ updateMutationInput = this.getChangedFieldsInput(
140
143
  model,
141
144
  savedElement,
142
145
  patchesTuple
@@ -154,7 +157,7 @@ class StorageClass implements StorageFacade {
154
157
  .constructor as PersistentModelConstructor<T>;
155
158
 
156
159
  this.pushStream.next({
157
- model: modelConstructor as any,
160
+ model: modelConstructor,
158
161
  opType,
159
162
  element,
160
163
  mutator,
@@ -234,7 +237,7 @@ class StorageClass implements StorageFacade {
234
237
  }
235
238
 
236
239
  this.pushStream.next({
237
- model: modelConstructor as any,
240
+ model: modelConstructor,
238
241
  opType: OpType.DELETE,
239
242
  element: model,
240
243
  mutator,
@@ -340,11 +343,11 @@ class StorageClass implements StorageFacade {
340
343
  });
341
344
  });
342
345
 
343
- return result as any;
346
+ return result;
344
347
  }
345
348
 
346
349
  // returns null if no user fields were changed (determined by value comparison)
347
- private getUpdateMutationInput<T extends PersistentModel>(
350
+ private getChangedFieldsInput<T extends PersistentModel>(
348
351
  model: T,
349
352
  originalElement: T,
350
353
  patchesTuple?: [Patch[], PersistentModel]
@@ -510,11 +513,11 @@ class ExclusiveStorage implements StorageFacade {
510
513
  if (isModelConstructor(modelOrModelConstructor)) {
511
514
  const modelConstructor = modelOrModelConstructor;
512
515
 
513
- return storage.delete(modelConstructor as any, condition, mutator);
516
+ return storage.delete(modelConstructor, condition, mutator);
514
517
  } else {
515
518
  const model = modelOrModelConstructor;
516
519
 
517
- return storage.delete(model as any, condition, mutator);
520
+ return storage.delete(model, condition, mutator);
518
521
  }
519
522
  });
520
523
  }