@aws-amplify/datastore 3.14.5-unstable.4 → 3.14.5

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 (178) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build.js +5 -0
  3. package/dist/aws-amplify-datastore.js +92853 -0
  4. package/dist/aws-amplify-datastore.js.map +1 -0
  5. package/dist/aws-amplify-datastore.min.js +65 -0
  6. package/dist/aws-amplify-datastore.min.js.map +1 -0
  7. package/index.js +7 -0
  8. package/lib/authModeStrategies/multiAuthStrategy.js +64 -6
  9. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  10. package/lib/datastore/datastore.js +297 -703
  11. package/lib/datastore/datastore.js.map +1 -1
  12. package/lib/index.js +4 -6
  13. package/lib/index.js.map +1 -1
  14. package/lib/predicates/index.js +6 -127
  15. package/lib/predicates/index.js.map +1 -1
  16. package/lib/predicates/sort.js +4 -10
  17. package/lib/predicates/sort.js.map +1 -1
  18. package/lib/storage/adapter/AsyncStorageAdapter.js +381 -138
  19. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  20. package/lib/storage/adapter/AsyncStorageDatabase.js +98 -37
  21. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  22. package/lib/storage/adapter/InMemoryStore.js +67 -16
  23. package/lib/storage/adapter/InMemoryStore.js.map +1 -1
  24. package/lib/storage/adapter/InMemoryStore.native.js +4 -2
  25. package/lib/storage/adapter/InMemoryStore.native.js.map +1 -1
  26. package/lib/storage/adapter/IndexedDBAdapter.js +420 -272
  27. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  28. package/lib/storage/adapter/getDefaultAdapter/index.js +5 -3
  29. package/lib/storage/adapter/getDefaultAdapter/index.js.map +1 -1
  30. package/lib/storage/adapter/getDefaultAdapter/index.native.js +4 -2
  31. package/lib/storage/adapter/getDefaultAdapter/index.native.js.map +1 -1
  32. package/lib/storage/storage.js +143 -72
  33. package/lib/storage/storage.js.map +1 -1
  34. package/lib/sync/datastoreConnectivity.js +55 -6
  35. package/lib/sync/datastoreConnectivity.js.map +1 -1
  36. package/lib/sync/datastoreReachability/index.native.js +4 -2
  37. package/lib/sync/datastoreReachability/index.native.js.map +1 -1
  38. package/lib/sync/index.js +124 -49
  39. package/lib/sync/index.js.map +1 -1
  40. package/lib/sync/merger.js +74 -8
  41. package/lib/sync/merger.js.map +1 -1
  42. package/lib/sync/outbox.js +97 -24
  43. package/lib/sync/outbox.js.map +1 -1
  44. package/lib/sync/processors/errorMaps.js +35 -5
  45. package/lib/sync/processors/errorMaps.js.map +1 -1
  46. package/lib/sync/processors/mutation.js +131 -47
  47. package/lib/sync/processors/mutation.js.map +1 -1
  48. package/lib/sync/processors/subscription.js +102 -29
  49. package/lib/sync/processors/subscription.js.map +1 -1
  50. package/lib/sync/processors/sync.js +102 -26
  51. package/lib/sync/processors/sync.js.map +1 -1
  52. package/lib/sync/utils.js +103 -40
  53. package/lib/sync/utils.js.map +1 -1
  54. package/lib/types.js +39 -9
  55. package/lib/types.js.map +1 -1
  56. package/lib/util.js +188 -192
  57. package/lib/util.js.map +1 -1
  58. package/lib-esm/authModeStrategies/multiAuthStrategy.js +57 -2
  59. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  60. package/lib-esm/datastore/datastore.d.ts +8 -59
  61. package/lib-esm/datastore/datastore.js +234 -642
  62. package/lib-esm/datastore/datastore.js.map +1 -1
  63. package/lib-esm/index.d.ts +2 -3
  64. package/lib-esm/index.js +1 -2
  65. package/lib-esm/index.js.map +1 -1
  66. package/lib-esm/predicates/index.d.ts +2 -16
  67. package/lib-esm/predicates/index.js +7 -128
  68. package/lib-esm/predicates/index.js.map +1 -1
  69. package/lib-esm/predicates/sort.js +4 -10
  70. package/lib-esm/predicates/sort.js.map +1 -1
  71. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +1 -2
  72. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +349 -109
  73. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  74. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +68 -7
  75. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  76. package/lib-esm/storage/adapter/InMemoryStore.d.ts +1 -1
  77. package/lib-esm/storage/adapter/InMemoryStore.js +52 -1
  78. package/lib-esm/storage/adapter/InMemoryStore.js.map +1 -1
  79. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +2 -4
  80. package/lib-esm/storage/adapter/IndexedDBAdapter.js +368 -227
  81. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  82. package/lib-esm/storage/adapter/getDefaultAdapter/index.js.map +1 -1
  83. package/lib-esm/storage/storage.d.ts +6 -7
  84. package/lib-esm/storage/storage.js +101 -33
  85. package/lib-esm/storage/storage.js.map +1 -1
  86. package/lib-esm/sync/datastoreConnectivity.js +47 -1
  87. package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
  88. package/lib-esm/sync/index.js +76 -4
  89. package/lib-esm/sync/index.js.map +1 -1
  90. package/lib-esm/sync/merger.js +67 -1
  91. package/lib-esm/sync/merger.js.map +1 -1
  92. package/lib-esm/sync/outbox.js +74 -1
  93. package/lib-esm/sync/outbox.js.map +1 -1
  94. package/lib-esm/sync/processors/errorMaps.js +32 -2
  95. package/lib-esm/sync/processors/errorMaps.js.map +1 -1
  96. package/lib-esm/sync/processors/mutation.js +93 -12
  97. package/lib-esm/sync/processors/mutation.js.map +1 -1
  98. package/lib-esm/sync/processors/subscription.js +69 -6
  99. package/lib-esm/sync/processors/subscription.js.map +1 -1
  100. package/lib-esm/sync/processors/sync.js +75 -2
  101. package/lib-esm/sync/processors/sync.js.map +1 -1
  102. package/lib-esm/sync/utils.d.ts +1 -1
  103. package/lib-esm/sync/utils.js +95 -32
  104. package/lib-esm/sync/utils.js.map +1 -1
  105. package/lib-esm/types.d.ts +10 -63
  106. package/lib-esm/types.js +38 -7
  107. package/lib-esm/types.js.map +1 -1
  108. package/lib-esm/util.d.ts +6 -39
  109. package/lib-esm/util.js +171 -171
  110. package/lib-esm/util.js.map +1 -1
  111. package/package.json +14 -21
  112. package/src/authModeStrategies/multiAuthStrategy.ts +2 -2
  113. package/src/datastore/datastore.ts +206 -699
  114. package/src/index.ts +0 -4
  115. package/src/predicates/index.ts +17 -143
  116. package/src/predicates/sort.ts +2 -8
  117. package/src/storage/adapter/AsyncStorageAdapter.ts +178 -56
  118. package/src/storage/adapter/AsyncStorageDatabase.ts +15 -16
  119. package/src/storage/adapter/InMemoryStore.ts +2 -5
  120. package/src/storage/adapter/IndexedDBAdapter.ts +191 -166
  121. package/src/storage/adapter/getDefaultAdapter/index.ts +2 -2
  122. package/src/storage/storage.ts +37 -56
  123. package/src/sync/datastoreConnectivity.ts +4 -4
  124. package/src/sync/index.ts +28 -22
  125. package/src/sync/merger.ts +1 -1
  126. package/src/sync/outbox.ts +6 -6
  127. package/src/sync/processors/errorMaps.ts +1 -1
  128. package/src/sync/processors/mutation.ts +19 -23
  129. package/src/sync/processors/subscription.ts +16 -20
  130. package/src/sync/processors/sync.ts +17 -17
  131. package/src/sync/utils.ts +48 -42
  132. package/src/types.ts +16 -128
  133. package/src/util.ts +150 -108
  134. package/webpack.config.dev.js +6 -0
  135. package/lib/authModeStrategies/defaultAuthStrategy.d.ts +0 -2
  136. package/lib/authModeStrategies/index.d.ts +0 -2
  137. package/lib/authModeStrategies/multiAuthStrategy.d.ts +0 -13
  138. package/lib/datastore/datastore.d.ts +0 -207
  139. package/lib/index.d.ts +0 -16
  140. package/lib/predicates/index.d.ts +0 -30
  141. package/lib/predicates/next.d.ts +0 -301
  142. package/lib/predicates/next.js +0 -816
  143. package/lib/predicates/next.js.map +0 -1
  144. package/lib/predicates/sort.d.ts +0 -8
  145. package/lib/ssr/index.d.ts +0 -3
  146. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +0 -42
  147. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +0 -39
  148. package/lib/storage/adapter/InMemoryStore.d.ts +0 -11
  149. package/lib/storage/adapter/InMemoryStore.native.d.ts +0 -1
  150. package/lib/storage/adapter/IndexedDBAdapter.d.ts +0 -61
  151. package/lib/storage/adapter/getDefaultAdapter/index.d.ts +0 -3
  152. package/lib/storage/adapter/getDefaultAdapter/index.native.d.ts +0 -3
  153. package/lib/storage/adapter/index.d.ts +0 -9
  154. package/lib/storage/relationship.d.ts +0 -140
  155. package/lib/storage/relationship.js +0 -335
  156. package/lib/storage/relationship.js.map +0 -1
  157. package/lib/storage/storage.d.ts +0 -50
  158. package/lib/sync/datastoreConnectivity.d.ts +0 -16
  159. package/lib/sync/datastoreReachability/index.d.ts +0 -3
  160. package/lib/sync/datastoreReachability/index.native.d.ts +0 -3
  161. package/lib/sync/index.d.ts +0 -89
  162. package/lib/sync/merger.d.ts +0 -17
  163. package/lib/sync/outbox.d.ts +0 -27
  164. package/lib/sync/processors/errorMaps.d.ts +0 -17
  165. package/lib/sync/processors/mutation.d.ts +0 -58
  166. package/lib/sync/processors/subscription.d.ts +0 -33
  167. package/lib/sync/processors/sync.d.ts +0 -28
  168. package/lib/sync/utils.d.ts +0 -42
  169. package/lib/types.d.ts +0 -554
  170. package/lib/util.d.ts +0 -189
  171. package/lib-esm/predicates/next.d.ts +0 -301
  172. package/lib-esm/predicates/next.js +0 -812
  173. package/lib-esm/predicates/next.js.map +0 -1
  174. package/lib-esm/storage/relationship.d.ts +0 -140
  175. package/lib-esm/storage/relationship.js +0 -333
  176. package/lib-esm/storage/relationship.js.map +0 -1
  177. package/src/predicates/next.ts +0 -967
  178. package/src/storage/relationship.ts +0 -272
@@ -1,11 +1,13 @@
1
1
  import { ConsoleLogger as Logger } from '@aws-amplify/core';
2
2
  import * as idb from 'idb';
3
3
  import { ModelInstanceCreator } from '../../datastore/datastore';
4
- import { ModelPredicateCreator } from '../../predicates';
4
+ import {
5
+ ModelPredicateCreator,
6
+ ModelSortPredicateCreator,
7
+ } from '../../predicates';
5
8
  import {
6
9
  InternalSchema,
7
10
  isPredicateObj,
8
- isPredicateGroup,
9
11
  ModelInstanceMetadata,
10
12
  ModelPredicate,
11
13
  NamespaceResolver,
@@ -19,14 +21,14 @@ import {
19
21
  RelationType,
20
22
  } from '../../types';
21
23
  import {
24
+ exhaustiveCheck,
22
25
  getIndex,
23
26
  getIndexFromAssociation,
24
27
  isModelConstructor,
25
28
  isPrivateMode,
26
29
  traverseModel,
27
30
  validatePredicate,
28
- inMemoryPagination,
29
- NAMESPACES,
31
+ sortCompareFunction,
30
32
  keysEqual,
31
33
  getStorename,
32
34
  getIndexKeys,
@@ -39,17 +41,17 @@ const logger = new Logger('DataStore');
39
41
 
40
42
  const DB_NAME = 'amplify-datastore';
41
43
  class IndexedDBAdapter implements Adapter {
42
- private schema!: InternalSchema;
43
- private namespaceResolver!: NamespaceResolver;
44
- private modelInstanceCreator!: ModelInstanceCreator;
45
- private getModelConstructorByModelName?: (
46
- namsespaceName: NAMESPACES,
44
+ private schema: InternalSchema;
45
+ private namespaceResolver: NamespaceResolver;
46
+ private modelInstanceCreator: ModelInstanceCreator;
47
+ private getModelConstructorByModelName: (
48
+ namsespaceName: string,
47
49
  modelName: string
48
50
  ) => PersistentModelConstructor<any>;
49
- private db!: idb.IDBPDatabase;
50
- private initPromise!: Promise<void>;
51
- private resolve!: (value?: any) => void;
52
- private reject!: (value?: any) => void;
51
+ private db: idb.IDBPDatabase;
52
+ private initPromise: Promise<void>;
53
+ private resolve: (value?: any) => void;
54
+ private reject: (value?: any) => void;
53
55
  private dbName: string = DB_NAME;
54
56
  private safariCompatabilityMode: boolean = false;
55
57
 
@@ -123,7 +125,7 @@ class IndexedDBAdapter implements Adapter {
123
125
  namespaceResolver: NamespaceResolver,
124
126
  modelInstanceCreator: ModelInstanceCreator,
125
127
  getModelConstructorByModelName: (
126
- namsespaceName: NAMESPACES,
128
+ namsespaceName: string,
127
129
  modelName: string
128
130
  ) => PersistentModelConstructor<any>,
129
131
  sessionId?: string
@@ -283,7 +285,7 @@ class IndexedDBAdapter implements Adapter {
283
285
  model,
284
286
  this.schema.namespaces[namespaceName],
285
287
  this.modelInstanceCreator,
286
- this.getModelConstructorByModelName!
288
+ this.getModelConstructorByModelName
287
289
  );
288
290
 
289
291
  const set = new Set<string>();
@@ -311,13 +313,9 @@ class IndexedDBAdapter implements Adapter {
311
313
 
312
314
  if (condition && fromDB) {
313
315
  const predicates = ModelPredicateCreator.getPredicates(condition);
314
- const { predicates: predicateObjs, type } = predicates || {};
316
+ const { predicates: predicateObjs, type } = predicates;
315
317
 
316
- const isValid = validatePredicate(
317
- fromDB as any,
318
- type as any,
319
- predicateObjs as any
320
- );
318
+ const isValid = validatePredicate(fromDB, type, predicateObjs);
321
319
 
322
320
  if (!isValid) {
323
321
  const msg = 'Conditional update failed';
@@ -328,6 +326,7 @@ class IndexedDBAdapter implements Adapter {
328
326
  }
329
327
 
330
328
  const result: [T, OpType.INSERT | OpType.UPDATE][] = [];
329
+
331
330
  for await (const resItem of connectionStoreNames) {
332
331
  const { storeName, item, instance, keys } = resItem;
333
332
  const store = tx.objectStore(storeName);
@@ -352,6 +351,7 @@ class IndexedDBAdapter implements Adapter {
352
351
  .index('byPk')
353
352
  .getKey(this.canonicalKeyPath(itemKeyValues));
354
353
  await store.put(item, key);
354
+
355
355
  result.push([instance, opType]);
356
356
  }
357
357
  }
@@ -362,16 +362,16 @@ class IndexedDBAdapter implements Adapter {
362
362
  }
363
363
 
364
364
  private async load<T>(
365
- namespaceName: NAMESPACES,
365
+ namespaceName: string,
366
366
  srcModelName: string,
367
367
  records: T[]
368
368
  ): Promise<T[]> {
369
369
  const namespace = this.schema.namespaces[namespaceName];
370
- const relations = namespace.relationships![srcModelName].relationTypes;
370
+ const relations = namespace.relationships[srcModelName].relationTypes;
371
371
  const connectionStoreNames = relations.map(({ modelName }) => {
372
372
  return getStorename(namespaceName, modelName);
373
373
  });
374
- const modelConstructor = this.getModelConstructorByModelName!(
374
+ const modelConstructor = this.getModelConstructorByModelName(
375
375
  namespaceName,
376
376
  srcModelName
377
377
  );
@@ -382,6 +382,116 @@ class IndexedDBAdapter implements Adapter {
382
382
  );
383
383
  }
384
384
 
385
+ const tx = this.db.transaction([...connectionStoreNames], 'readonly');
386
+
387
+ for await (const relation of relations) {
388
+ // target name, metadata, set by init
389
+ const { fieldName, modelName, targetName, targetNames } = relation;
390
+ const storeName = getStorename(namespaceName, modelName);
391
+ const store = tx.objectStore(storeName);
392
+ const modelConstructor = this.getModelConstructorByModelName(
393
+ namespaceName,
394
+ modelName
395
+ );
396
+
397
+ switch (relation.relationType) {
398
+ case 'HAS_ONE':
399
+ for await (const recordItem of records) {
400
+ // POST CPK codegen changes:
401
+ if (targetNames?.length) {
402
+ let getByFields = [];
403
+ let allPresent;
404
+ // iterate through all targetnames to make sure they are all present in the recordItem
405
+ allPresent = targetNames.every(targetName => {
406
+ return recordItem[targetName] != null;
407
+ });
408
+
409
+ if (!allPresent) {
410
+ break;
411
+ }
412
+
413
+ getByFields = targetNames as any;
414
+
415
+ // keys are the key values
416
+ const keys = getByFields.map(
417
+ getByField => recordItem[getByField]
418
+ );
419
+
420
+ const connectionRecord = await this._get(store, keys);
421
+
422
+ recordItem[fieldName] =
423
+ connectionRecord &&
424
+ this.modelInstanceCreator(modelConstructor, connectionRecord);
425
+ } else {
426
+ // If single target name, using old codegen
427
+ const getByfield = recordItem[targetName]
428
+ ? targetName
429
+ : fieldName;
430
+
431
+ // We break here, because the recordItem does not have 'team', the `getByField`
432
+ // extract the keys on the related model.
433
+ if (!recordItem[getByfield]) break;
434
+
435
+ const key = [recordItem[getByfield]];
436
+
437
+ const connectionRecord = await this._get(store, key);
438
+
439
+ recordItem[fieldName] =
440
+ connectionRecord &&
441
+ this.modelInstanceCreator(modelConstructor, connectionRecord);
442
+ }
443
+ }
444
+ break;
445
+ case 'BELONGS_TO':
446
+ for await (const recordItem of records) {
447
+ // POST CPK codegen changes:
448
+ if (targetNames?.length) {
449
+ let allPresent;
450
+ // iterate through all targetnames to make sure they are all present in the recordItem
451
+ allPresent = targetNames.every(targetName => {
452
+ return recordItem[targetName] != null;
453
+ });
454
+
455
+ // If not present, there is not yet a connected record
456
+ if (!allPresent) {
457
+ break;
458
+ }
459
+
460
+ const keys = targetNames
461
+ .filter(targetName => recordItem[targetName] ?? false)
462
+ .map(targetName => recordItem[targetName]);
463
+
464
+ // Retrieve the connected record
465
+ const connectionRecord = await this._get(store, keys);
466
+
467
+ recordItem[fieldName] =
468
+ connectionRecord &&
469
+ this.modelInstanceCreator(modelConstructor, connectionRecord);
470
+
471
+ targetNames?.map(targetName => {
472
+ delete recordItem[targetName];
473
+ });
474
+ } else if (recordItem[targetName]) {
475
+ const key = [recordItem[targetName]];
476
+
477
+ const connectionRecord = await this._get(store, key);
478
+
479
+ recordItem[fieldName] =
480
+ connectionRecord &&
481
+ this.modelInstanceCreator(modelConstructor, connectionRecord);
482
+ delete recordItem[targetName];
483
+ }
484
+ }
485
+ break;
486
+ case 'HAS_MANY':
487
+ // TODO: Lazy loading
488
+ break;
489
+ default:
490
+ exhaustiveCheck(relation.relationType);
491
+ break;
492
+ }
493
+ }
494
+
385
495
  return records.map(record =>
386
496
  this.modelInstanceCreator(modelConstructor, record)
387
497
  );
@@ -394,9 +504,7 @@ class IndexedDBAdapter implements Adapter {
394
504
  ): Promise<T[]> {
395
505
  await this.checkPrivate();
396
506
  const storeName = this.getStorenameForModel(modelConstructor);
397
- const namespaceName = this.namespaceResolver(
398
- modelConstructor
399
- ) as NAMESPACES;
507
+ const namespaceName = this.namespaceResolver(modelConstructor);
400
508
 
401
509
  const predicates =
402
510
  predicate && ModelPredicateCreator.getPredicates(predicate);
@@ -410,7 +518,7 @@ class IndexedDBAdapter implements Adapter {
410
518
  const hasSort = pagination && pagination.sort;
411
519
  const hasPagination = pagination && pagination.limit;
412
520
 
413
- const records: T[] = (await (async () => {
521
+ const records: T[] = await (async () => {
414
522
  if (queryByKey) {
415
523
  const record = await this.getByKey(storeName, queryByKey);
416
524
  return record ? [record] : [];
@@ -431,7 +539,7 @@ class IndexedDBAdapter implements Adapter {
431
539
  }
432
540
 
433
541
  return this.getAll(storeName);
434
- })()) as T[];
542
+ })();
435
543
 
436
544
  return await this.load(namespaceName, modelConstructor.name, records);
437
545
  }
@@ -440,7 +548,8 @@ class IndexedDBAdapter implements Adapter {
440
548
  storeName: string,
441
549
  keyValue: string[]
442
550
  ): Promise<T> {
443
- return <T>await this._get(storeName, keyValue);
551
+ const record = <T>await this._get(storeName, keyValue);
552
+ return record;
444
553
  }
445
554
 
446
555
  private async getAll<T extends PersistentModel>(
@@ -459,7 +568,7 @@ class IndexedDBAdapter implements Adapter {
459
568
  return;
460
569
  }
461
570
 
462
- const keyValues = [] as any[];
571
+ const keyValues = [];
463
572
 
464
573
  for (const key of keyPath) {
465
574
  const predicateObj = predicateObjs.find(
@@ -472,116 +581,17 @@ class IndexedDBAdapter implements Adapter {
472
581
  return keyValues.length === keyPath.length ? keyValues : undefined;
473
582
  }
474
583
 
475
- private matchingIndex(
476
- storeName: string,
477
- fieldName: string,
478
- transaction: idb.IDBPTransaction<unknown, [string]>
479
- ) {
480
- const store = transaction.objectStore(storeName);
481
- for (const name of store.indexNames) {
482
- const idx = store.index(name);
483
- if (idx.keyPath === fieldName) {
484
- return idx;
485
- }
486
- }
487
- }
488
-
489
584
  private async filterOnPredicate<T extends PersistentModel>(
490
585
  storeName: string,
491
586
  predicates: PredicatesGroup<T>
492
587
  ) {
493
- let { predicates: predicateObjs, type } = predicates;
494
-
495
- // the predicate objects we care about tend to be nested at least
496
- // one level down: `{and: {or: {and: { <the predicates we want> }}}}`
497
- // so, we unpack and/or groups until we find a group with more than 1
498
- // child OR a child that is not a group (and is therefore a predicate "object").
499
- while (predicateObjs.length === 1 && isPredicateGroup(predicateObjs[0])) {
500
- type = (predicateObjs[0] as PredicatesGroup<T>).type;
501
- predicateObjs = (predicateObjs[0] as PredicatesGroup<T>).predicates;
502
- }
588
+ const { predicates: predicateObjs, type } = predicates;
503
589
 
504
- // where we'll accumulate candidate results, which will be filtered at the end.
505
- let candidateResults: T[];
506
-
507
- // AFAIK, this will always be a homogenous group of predicate objects at this point.
508
- // but, if that ever changes, this pulls out just the predicates from the list that
509
- // are field-level predicate objects we can potentially smash against an index.
510
- const fieldPredicates = predicateObjs.filter(p =>
511
- isPredicateObj(p)
512
- ) as PredicateObject<T>[];
513
-
514
- // several sub-queries could occur here. explicitly start a txn here to avoid
515
- // opening/closing multiple txns.
516
- const txn = this.db.transaction(storeName);
517
-
518
- // our potential indexes or lacks thereof.
519
- const predicateIndexes = fieldPredicates.map(p => {
520
- return {
521
- predicate: p,
522
- index: this.matchingIndex(storeName, String(p.field), txn),
523
- };
524
- });
525
-
526
- // Explicitly wait for txns from index queries to complete before proceding.
527
- // This helps ensure IndexedDB is in a stable, ready state. Else, subseqeuent
528
- // qeuries can sometimes appear to deadlock (at least in FakeIndexedDB).
529
- await txn.done;
530
-
531
- // semi-naive implementation:
532
- if (type === 'and') {
533
- // each condition must be satsified, we can form a base set with any
534
- // ONE of those conditions and then filter.
535
- const actualPredicateIndexes = predicateIndexes.filter(
536
- i => i.index && i.predicate.operator === 'eq'
537
- );
538
-
539
- if (actualPredicateIndexes.length > 0) {
540
- const predicateIndex = actualPredicateIndexes[0];
541
- candidateResults = <T[]>(
542
- await predicateIndex.index!.getAll(predicateIndex.predicate.operand)
543
- );
544
- } else {
545
- // no usable indexes
546
- candidateResults = <T[]>await this.getAll(storeName);
547
- }
548
- } else if (type === 'or') {
549
- // NOTE: each condition implies a potentially distinct set. we only benefit
550
- // from using indexes here if EVERY condition uses an index. if any one
551
- // index requires a table scan, we gain nothing from the indexes.
552
- // NOTE: results must be DISTINCT-ified if we leverage indexes.
553
- if (
554
- predicateIndexes.length > 0 &&
555
- predicateIndexes.every(i => i.index && i.predicate.operator === 'eq')
556
- ) {
557
- const distinctResults = new Map<string, T>();
558
- for (const predicateIndex of predicateIndexes) {
559
- const resultGroup = <T[]>(
560
- await predicateIndex.index!.getAll(predicateIndex.predicate.operand)
561
- );
562
- for (const item of resultGroup) {
563
- // TODO: custom PK
564
- distinctResults.set(item.id, item);
565
- }
566
- }
567
-
568
- // we could conceivably check for special conditions and return early here.
569
- // but, this is simpler and has not yet had a measurable performance impact.
570
- candidateResults = Array.from(distinctResults.values());
571
- } else {
572
- // either no usable indexes or not all conditions can use one.
573
- candidateResults = <T[]>await this.getAll(storeName);
574
- }
575
- } else {
576
- // nothing intelligent we can do with `not` groups unless or until we start
577
- // smashing comparison operators against indexes -- at which point we could
578
- // perform some reversal here.
579
- candidateResults = <T[]>await this.getAll(storeName);
580
- }
590
+ const all = <T[]>await this.getAll(storeName);
581
591
 
582
592
  const filtered = predicateObjs
583
- ? candidateResults.filter(m => validatePredicate(m, type, predicateObjs))
584
- : candidateResults;
593
+ ? all.filter(m => validatePredicate(m, type, predicateObjs))
594
+ : all;
585
595
 
586
596
  return filtered;
587
597
  }
@@ -590,7 +600,26 @@ class IndexedDBAdapter implements Adapter {
590
600
  records: T[],
591
601
  pagination?: PaginationInput<T>
592
602
  ): T[] {
593
- return inMemoryPagination(records, pagination);
603
+ if (pagination && records.length > 1) {
604
+ if (pagination.sort) {
605
+ const sortPredicates = ModelSortPredicateCreator.getPredicates(
606
+ pagination.sort
607
+ );
608
+
609
+ if (sortPredicates.length) {
610
+ const compareFn = sortCompareFunction(sortPredicates);
611
+ records.sort(compareFn);
612
+ }
613
+ }
614
+
615
+ const { page = 0, limit = 0 } = pagination;
616
+ const start = Math.max(0, page * limit) || 0;
617
+
618
+ const end = limit > 0 ? start + limit : records.length;
619
+
620
+ return records.slice(start, end);
621
+ }
622
+ return records;
594
623
  }
595
624
 
596
625
  private async enginePagination<T extends PersistentModel>(
@@ -658,15 +687,14 @@ class IndexedDBAdapter implements Adapter {
658
687
  const deleteQueue: { storeName: string; items: T[] }[] = [];
659
688
 
660
689
  if (isModelConstructor(modelOrModelConstructor)) {
661
- const modelConstructor =
662
- modelOrModelConstructor as PersistentModelConstructor<T>;
663
- const nameSpace = this.namespaceResolver(modelConstructor) as NAMESPACES;
690
+ const modelConstructor = modelOrModelConstructor;
691
+ const nameSpace = this.namespaceResolver(modelConstructor);
664
692
 
665
693
  const storeName = this.getStorenameForModel(modelConstructor);
666
694
 
667
695
  const models = await this.query(modelConstructor, condition);
668
696
  const relations =
669
- this.schema.namespaces![nameSpace].relationships![modelConstructor.name]
697
+ this.schema.namespaces[nameSpace].relationships[modelConstructor.name]
670
698
  .relationTypes;
671
699
 
672
700
  if (condition !== undefined) {
@@ -709,13 +737,11 @@ class IndexedDBAdapter implements Adapter {
709
737
  return [models, deletedModels];
710
738
  }
711
739
  } else {
712
- const model = modelOrModelConstructor as T;
740
+ const model = modelOrModelConstructor;
713
741
 
714
742
  const modelConstructor = Object.getPrototypeOf(model)
715
743
  .constructor as PersistentModelConstructor<T>;
716
- const namespaceName = this.namespaceResolver(
717
- modelConstructor
718
- ) as NAMESPACES;
744
+ const namespaceName = this.namespaceResolver(modelConstructor);
719
745
 
720
746
  const storeName = this.getStorenameForModel(modelConstructor);
721
747
 
@@ -734,10 +760,9 @@ class IndexedDBAdapter implements Adapter {
734
760
  }
735
761
 
736
762
  const predicates = ModelPredicateCreator.getPredicates(condition);
737
- const { predicates: predicateObjs, type } =
738
- predicates as PredicatesGroup<T>;
763
+ const { predicates: predicateObjs, type } = predicates;
739
764
 
740
- const isValid = validatePredicate(fromDB as T, type, predicateObjs);
765
+ const isValid = validatePredicate(fromDB, type, predicateObjs);
741
766
 
742
767
  if (!isValid) {
743
768
  const msg = 'Conditional update failed';
@@ -748,7 +773,7 @@ class IndexedDBAdapter implements Adapter {
748
773
  await tx.done;
749
774
 
750
775
  const relations =
751
- this.schema.namespaces[namespaceName].relationships![
776
+ this.schema.namespaces[namespaceName].relationships[
752
777
  modelConstructor.name
753
778
  ].relationTypes;
754
779
 
@@ -761,7 +786,7 @@ class IndexedDBAdapter implements Adapter {
761
786
  );
762
787
  } else {
763
788
  const relations =
764
- this.schema.namespaces[namespaceName].relationships![
789
+ this.schema.namespaces[namespaceName].relationships[
765
790
  modelConstructor.name
766
791
  ].relationTypes;
767
792
 
@@ -791,18 +816,18 @@ class IndexedDBAdapter implements Adapter {
791
816
  items: T[] | IDBValidKey[];
792
817
  }[]
793
818
  ) {
794
- const connectionStoreNames = deleteQueue!.map(({ storeName }) => {
819
+ const connectionStoreNames = deleteQueue.map(({ storeName }) => {
795
820
  return storeName;
796
821
  });
797
822
 
798
823
  const tx = this.db.transaction([...connectionStoreNames], 'readwrite');
799
- for await (const deleteItem of deleteQueue!) {
824
+ for await (const deleteItem of deleteQueue) {
800
825
  const { storeName, items } = deleteItem;
801
826
  const store = tx.objectStore(storeName);
802
827
 
803
828
  for await (const item of items) {
804
829
  if (item) {
805
- let key: IDBValidKey | undefined;
830
+ let key: IDBValidKey;
806
831
 
807
832
  if (typeof item === 'object') {
808
833
  const keyValues = this.getIndexKeyValuesFromModel(item as T);
@@ -826,7 +851,7 @@ class IndexedDBAdapter implements Adapter {
826
851
  relations: RelationType[],
827
852
  models: T[],
828
853
  srcModel: string,
829
- nameSpace: NAMESPACES,
854
+ nameSpace: string,
830
855
  deleteQueue: { storeName: string; items: T[] }[]
831
856
  ): Promise<void> {
832
857
  for await (const rel of relations) {
@@ -862,7 +887,7 @@ class IndexedDBAdapter implements Adapter {
862
887
  );
863
888
 
864
889
  await this.deleteTraverse(
865
- this.schema.namespaces[nameSpace].relationships![modelName]
890
+ this.schema.namespaces[nameSpace].relationships[modelName]
866
891
  .relationTypes,
867
892
  recordToDelete ? [recordToDelete] : [],
868
893
  modelName,
@@ -885,7 +910,7 @@ class IndexedDBAdapter implements Adapter {
885
910
  // If we deprecate, we'll need to re-gen the MIPR in __tests__/schema.ts > newSchema
886
911
  // otherwise some unit tests will fail
887
912
  index = getIndex(
888
- this.schema.namespaces[nameSpace].relationships![modelName]
913
+ this.schema.namespaces[nameSpace].relationships[modelName]
889
914
  .relationTypes,
890
915
  srcModel
891
916
  );
@@ -903,7 +928,7 @@ class IndexedDBAdapter implements Adapter {
903
928
  );
904
929
 
905
930
  await this.deleteTraverse(
906
- this.schema.namespaces[nameSpace].relationships![modelName]
931
+ this.schema.namespaces[nameSpace].relationships[modelName]
907
932
  .relationTypes,
908
933
  recordToDelete ? [recordToDelete] : [],
909
934
  modelName,
@@ -918,15 +943,15 @@ class IndexedDBAdapter implements Adapter {
918
943
  const index =
919
944
  // explicit bi-directional @hasMany and @manyToMany
920
945
  getIndex(
921
- this.schema.namespaces[nameSpace].relationships![modelName]
946
+ this.schema.namespaces[nameSpace].relationships[modelName]
922
947
  .relationTypes,
923
948
  srcModel
924
949
  ) ||
925
950
  // uni and/or implicit @hasMany
926
951
  getIndexFromAssociation(
927
- this.schema.namespaces[nameSpace].relationships![modelName]
952
+ this.schema.namespaces[nameSpace].relationships[modelName]
928
953
  .indexes,
929
- associatedWith!
954
+ associatedWith
930
955
  );
931
956
  const keyValues = this.getIndexKeyValuesFromModel(model);
932
957
 
@@ -937,7 +962,7 @@ class IndexedDBAdapter implements Adapter {
937
962
  .getAll(this.canonicalKeyPath(keyValues));
938
963
 
939
964
  await this.deleteTraverse(
940
- this.schema.namespaces[nameSpace].relationships![modelName]
965
+ this.schema.namespaces[nameSpace].relationships[modelName]
941
966
  .relationTypes,
942
967
  childrenArray,
943
968
  modelName,
@@ -950,7 +975,7 @@ class IndexedDBAdapter implements Adapter {
950
975
  // Intentionally blank
951
976
  break;
952
977
  default:
953
- throw new Error(`Invalid relation type ${relationType}`);
978
+ exhaustiveCheck(relationType);
954
979
  break;
955
980
  }
956
981
  }
@@ -959,7 +984,7 @@ class IndexedDBAdapter implements Adapter {
959
984
  storeName: getStorename(nameSpace, srcModel),
960
985
  items: models.map(record =>
961
986
  this.modelInstanceCreator(
962
- this.getModelConstructorByModelName!(nameSpace, srcModel),
987
+ this.getModelConstructorByModelName(nameSpace, srcModel),
963
988
  record
964
989
  )
965
990
  ),
@@ -973,8 +998,8 @@ class IndexedDBAdapter implements Adapter {
973
998
 
974
999
  await idb.deleteDB(this.dbName);
975
1000
 
976
- this.db = undefined!;
977
- this.initPromise = undefined!;
1001
+ this.db = undefined;
1002
+ this.initPromise = undefined;
978
1003
  }
979
1004
 
980
1005
  async batchSave<T extends PersistentModel>(
@@ -1004,7 +1029,7 @@ class IndexedDBAdapter implements Adapter {
1004
1029
  model,
1005
1030
  this.schema.namespaces[namespaceName],
1006
1031
  this.modelInstanceCreator,
1007
- this.getModelConstructorByModelName!
1032
+ this.getModelConstructorByModelName
1008
1033
  );
1009
1034
 
1010
1035
  const keyValues = this.getIndexKeyValuesFromModel(model);
@@ -1018,7 +1043,7 @@ class IndexedDBAdapter implements Adapter {
1018
1043
  const { instance } = connectedModels.find(({ instance }) => {
1019
1044
  const instanceKeyValues = this.getIndexKeyValuesFromModel(instance);
1020
1045
  return keysEqual(instanceKeyValues, keyValues);
1021
- })!;
1046
+ });
1022
1047
 
1023
1048
  result.push([
1024
1049
  <T>(<unknown>instance),
@@ -1050,7 +1075,7 @@ class IndexedDBAdapter implements Adapter {
1050
1075
  });
1051
1076
 
1052
1077
  const { indexes } =
1053
- this.schema.namespaces[namespaceName].relationships![modelName];
1078
+ this.schema.namespaces[namespaceName].relationships[modelName];
1054
1079
 
1055
1080
  indexes.forEach(([idxName, keyPath, options]) => {
1056
1081
  store.createIndex(idxName, keyPath, options);
@@ -7,10 +7,10 @@ const getDefaultAdapter: () => Adapter = () => {
7
7
  const { isBrowser } = browserOrNode();
8
8
 
9
9
  if ((isBrowser && window.indexedDB) || (isWebWorker() && self.indexedDB)) {
10
- return IndexedDBAdapter as Adapter;
10
+ return IndexedDBAdapter;
11
11
  }
12
12
 
13
- return AsyncStorageAdapter as Adapter;
13
+ return AsyncStorageAdapter;
14
14
  };
15
15
 
16
16
  export default getDefaultAdapter;