@expo/entity 0.55.0 → 0.57.0

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 (163) hide show
  1. package/build/src/AuthorizationResultBasedEntityAssociationLoader.d.ts +1 -1
  2. package/build/src/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -1
  3. package/build/src/AuthorizationResultBasedEntityLoader.d.ts +18 -24
  4. package/build/src/AuthorizationResultBasedEntityLoader.js +37 -56
  5. package/build/src/AuthorizationResultBasedEntityLoader.js.map +1 -1
  6. package/build/src/AuthorizationResultBasedEntityMutator.js +26 -19
  7. package/build/src/AuthorizationResultBasedEntityMutator.js.map +1 -1
  8. package/build/src/EnforcingEntityCreator.d.ts +1 -1
  9. package/build/src/EnforcingEntityCreator.js +1 -1
  10. package/build/src/EnforcingEntityLoader.d.ts +1 -58
  11. package/build/src/EnforcingEntityLoader.js +0 -65
  12. package/build/src/EnforcingEntityLoader.js.map +1 -1
  13. package/build/src/Entity.d.ts +6 -0
  14. package/build/src/Entity.js +6 -0
  15. package/build/src/Entity.js.map +1 -1
  16. package/build/src/EntityCompanion.d.ts +2 -2
  17. package/build/src/EntityCompanion.js.map +1 -1
  18. package/build/src/EntityCompanionProvider.d.ts +1 -1
  19. package/build/src/EntityCompanionProvider.js +4 -4
  20. package/build/src/EntityConfiguration.d.ts +1 -1
  21. package/build/src/EntityConfiguration.js +1 -2
  22. package/build/src/EntityConfiguration.js.map +1 -1
  23. package/build/src/{EntityLoaderUtils.d.ts → EntityConstructionUtils.d.ts} +15 -29
  24. package/build/src/EntityConstructionUtils.js +118 -0
  25. package/build/src/EntityConstructionUtils.js.map +1 -0
  26. package/build/src/EntityDatabaseAdapter.d.ts +10 -108
  27. package/build/src/EntityDatabaseAdapter.js +14 -76
  28. package/build/src/EntityDatabaseAdapter.js.map +1 -1
  29. package/build/src/EntityFieldDefinition.d.ts +1 -1
  30. package/build/src/EntityInvalidationUtils.d.ts +41 -0
  31. package/build/src/EntityInvalidationUtils.js +71 -0
  32. package/build/src/EntityInvalidationUtils.js.map +1 -0
  33. package/build/src/EntityLoader.d.ts +0 -6
  34. package/build/src/EntityLoader.js +0 -7
  35. package/build/src/EntityLoader.js.map +1 -1
  36. package/build/src/EntityLoaderFactory.d.ts +4 -0
  37. package/build/src/EntityLoaderFactory.js +10 -3
  38. package/build/src/EntityLoaderFactory.js.map +1 -1
  39. package/build/src/EntityPrivacyPolicy.d.ts +27 -0
  40. package/build/src/EntityPrivacyPolicy.js +22 -1
  41. package/build/src/EntityPrivacyPolicy.js.map +1 -1
  42. package/build/src/EntitySecondaryCacheLoader.d.ts +14 -3
  43. package/build/src/EntitySecondaryCacheLoader.js +21 -4
  44. package/build/src/EntitySecondaryCacheLoader.js.map +1 -1
  45. package/build/src/ReadonlyEntity.d.ts +4 -5
  46. package/build/src/ReadonlyEntity.js +7 -8
  47. package/build/src/ReadonlyEntity.js.map +1 -1
  48. package/build/src/ViewerContext.d.ts +6 -6
  49. package/build/src/ViewerContext.js +8 -8
  50. package/build/src/ViewerScopedEntityCompanion.d.ts +1 -1
  51. package/build/src/ViewerScopedEntityCompanion.js.map +1 -1
  52. package/build/src/ViewerScopedEntityLoaderFactory.d.ts +4 -0
  53. package/build/src/ViewerScopedEntityLoaderFactory.js +6 -0
  54. package/build/src/ViewerScopedEntityLoaderFactory.js.map +1 -1
  55. package/build/src/errors/EntityDatabaseAdapterError.d.ts +4 -0
  56. package/build/src/errors/EntityDatabaseAdapterError.js +13 -1
  57. package/build/src/errors/EntityDatabaseAdapterError.js.map +1 -1
  58. package/build/src/errors/EntityError.d.ts +2 -1
  59. package/build/src/errors/EntityError.js +1 -0
  60. package/build/src/errors/EntityError.js.map +1 -1
  61. package/build/src/index.d.ts +2 -1
  62. package/build/src/index.js +2 -1
  63. package/build/src/index.js.map +1 -1
  64. package/build/src/internal/EntityDataManager.d.ts +8 -16
  65. package/build/src/internal/EntityDataManager.js +8 -18
  66. package/build/src/internal/EntityDataManager.js.map +1 -1
  67. package/build/src/internal/EntityFieldTransformationUtils.js.map +1 -1
  68. package/build/src/internal/EntityLoadInterfaces.d.ts +2 -0
  69. package/build/src/internal/EntityLoadInterfaces.js +2 -0
  70. package/build/src/internal/EntityLoadInterfaces.js.map +1 -1
  71. package/build/src/internal/EntityTableDataCoordinator.d.ts +2 -0
  72. package/build/src/internal/EntityTableDataCoordinator.js +4 -0
  73. package/build/src/internal/EntityTableDataCoordinator.js.map +1 -1
  74. package/build/src/metrics/EntityMetricsUtils.d.ts +1 -0
  75. package/build/src/metrics/EntityMetricsUtils.js +15 -1
  76. package/build/src/metrics/EntityMetricsUtils.js.map +1 -1
  77. package/build/src/metrics/IEntityMetricsAdapter.d.ts +4 -1
  78. package/build/src/metrics/IEntityMetricsAdapter.js +3 -0
  79. package/build/src/metrics/IEntityMetricsAdapter.js.map +1 -1
  80. package/build/src/rules/AllowIfAllSubRulesAllowPrivacyPolicyRule.d.ts +2 -2
  81. package/build/src/rules/AllowIfAnySubRuleAllowsPrivacyPolicyRule.d.ts +2 -2
  82. package/build/src/rules/EvaluateIfEntityFieldPredicatePrivacyPolicyRule.d.ts +2 -2
  83. package/build/src/rules/PrivacyPolicyRule.d.ts +2 -2
  84. package/build/src/utils/EntityPrivacyUtils.js +11 -20
  85. package/build/src/utils/EntityPrivacyUtils.js.map +1 -1
  86. package/build/src/utils/collections/maps.d.ts +2 -2
  87. package/build/src/utils/collections/maps.js +2 -2
  88. package/package.json +4 -4
  89. package/src/AuthorizationResultBasedEntityAssociationLoader.ts +4 -7
  90. package/src/AuthorizationResultBasedEntityLoader.ts +58 -88
  91. package/src/AuthorizationResultBasedEntityMutator.ts +35 -20
  92. package/src/EnforcingEntityCreator.ts +1 -1
  93. package/src/EnforcingEntityLoader.ts +1 -95
  94. package/src/Entity.ts +6 -0
  95. package/src/EntityCompanion.ts +2 -2
  96. package/src/EntityCompanionProvider.ts +4 -4
  97. package/src/EntityConfiguration.ts +8 -5
  98. package/src/EntityConstructionUtils.ts +168 -0
  99. package/src/EntityDatabaseAdapter.ts +32 -222
  100. package/src/EntityFieldDefinition.ts +1 -1
  101. package/src/{EntityLoaderUtils.ts → EntityInvalidationUtils.ts} +5 -96
  102. package/src/EntityLoader.ts +0 -16
  103. package/src/EntityLoaderFactory.ts +50 -10
  104. package/src/EntityPrivacyPolicy.ts +44 -1
  105. package/src/EntitySecondaryCacheLoader.ts +54 -3
  106. package/src/ReadonlyEntity.ts +9 -11
  107. package/src/ViewerContext.ts +10 -10
  108. package/src/ViewerScopedEntityCompanion.ts +1 -1
  109. package/src/ViewerScopedEntityLoaderFactory.ts +37 -0
  110. package/src/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.ts +3 -5
  111. package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +34 -419
  112. package/src/__tests__/ComposedCacheAdapter-test.ts +3 -3
  113. package/src/__tests__/EnforcingEntityLoader-test.ts +2 -134
  114. package/src/__tests__/EntityCompanion-test.ts +18 -0
  115. package/src/__tests__/EntityConfiguration-test.ts +4 -4
  116. package/src/__tests__/EntityDatabaseAdapter-test.ts +33 -68
  117. package/src/__tests__/EntityEdges-test.ts +10 -10
  118. package/src/__tests__/EntityLoader-test.ts +6 -4
  119. package/src/__tests__/EntityMutator-test.ts +27 -15
  120. package/src/__tests__/EntityPrivacyPolicy-test.ts +102 -0
  121. package/src/__tests__/EntityQueryContext-test.ts +11 -11
  122. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +10 -5
  123. package/src/__tests__/EntitySelfReferentialEdges-test.ts +6 -6
  124. package/src/__tests__/GenericEntityCacheAdapter-test.ts +18 -15
  125. package/src/__tests__/GenericSecondaryEntityCache-test.ts +27 -5
  126. package/src/__tests__/ReadonlyEntity-test.ts +6 -4
  127. package/src/__tests__/ViewerContext-test.ts +4 -4
  128. package/src/__tests__/ViewerScopedEntityCompanion-test.ts +1 -0
  129. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +0 -17
  130. package/src/errors/EntityDatabaseAdapterError.ts +14 -0
  131. package/src/errors/EntityError.ts +1 -0
  132. package/src/errors/__tests__/EntityDatabaseAdapterError-test.ts +9 -0
  133. package/src/errors/__tests__/EntityError-test.ts +13 -5
  134. package/src/index.ts +2 -1
  135. package/src/internal/EntityDataManager.ts +19 -54
  136. package/src/internal/EntityFieldTransformationUtils.ts +5 -5
  137. package/src/internal/EntityLoadInterfaces.ts +2 -0
  138. package/src/internal/EntityTableDataCoordinator.ts +2 -2
  139. package/src/internal/__tests__/CompositeFieldHolder-test.ts +8 -2
  140. package/src/internal/__tests__/EntityDataManager-test.ts +71 -202
  141. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +39 -24
  142. package/src/metrics/EntityMetricsUtils.ts +23 -0
  143. package/src/metrics/IEntityMetricsAdapter.ts +3 -0
  144. package/src/metrics/__tests__/EntityMetricsUtils-test.ts +120 -0
  145. package/src/rules/AllowIfAllSubRulesAllowPrivacyPolicyRule.ts +2 -2
  146. package/src/rules/AllowIfAnySubRuleAllowsPrivacyPolicyRule.ts +2 -2
  147. package/src/rules/EvaluateIfEntityFieldPredicatePrivacyPolicyRule.ts +2 -2
  148. package/src/rules/PrivacyPolicyRule.ts +2 -2
  149. package/src/rules/__tests__/AllowIfAllSubRulesAllowPrivacyPolicyRule-test.ts +4 -4
  150. package/src/rules/__tests__/AllowIfAnySubRuleAllowsPrivacyPolicyRule-test.ts +4 -4
  151. package/src/rules/__tests__/AllowIfInParentCascadeDeletionPrivacyPolicyRule-test.ts +11 -1
  152. package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -2
  153. package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -2
  154. package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -2
  155. package/src/rules/__tests__/EvaluateIfEntityFieldPredicatePrivacyPolicyRule-test.ts +3 -3
  156. package/src/utils/EntityPrivacyUtils.ts +18 -29
  157. package/src/utils/__testfixtures__/PrivacyPolicyRuleTestUtils.ts +2 -2
  158. package/src/utils/__testfixtures__/StubDatabaseAdapter.ts +13 -101
  159. package/src/utils/__tests__/EntityCreationUtils-test.ts +6 -6
  160. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +2 -2
  161. package/src/utils/collections/maps.ts +2 -2
  162. package/build/src/EntityLoaderUtils.js +0 -147
  163. package/build/src/EntityLoaderUtils.js.map +0 -1
@@ -439,139 +439,6 @@ describe(EnforcingEntityLoader, () => {
439
439
  });
440
440
  });
441
441
 
442
- describe('loadFirstByFieldEqualityConjunction', () => {
443
- it('throws when result is unsuccessful', async () => {
444
- const nonEnforcingEntityLoaderMock = mock<
445
- AuthorizationResultBasedEntityLoader<any, any, any, any, any, any>
446
- >(AuthorizationResultBasedEntityLoader);
447
- const rejection = new Error();
448
- when(
449
- nonEnforcingEntityLoaderMock.loadFirstByFieldEqualityConjunctionAsync(
450
- anything(),
451
- anything(),
452
- ),
453
- ).thenResolve(result(rejection));
454
- const nonEnforcingEntityLoader = instance(nonEnforcingEntityLoaderMock);
455
- const enforcingEntityLoader = new EnforcingEntityLoader(nonEnforcingEntityLoader);
456
- await expect(
457
- enforcingEntityLoader.loadFirstByFieldEqualityConjunctionAsync(anything(), anything()),
458
- ).rejects.toThrow(rejection);
459
- });
460
-
461
- it('returns value when result is successful', async () => {
462
- const nonEnforcingEntityLoaderMock = mock<
463
- AuthorizationResultBasedEntityLoader<any, any, any, any, any, any>
464
- >(AuthorizationResultBasedEntityLoader);
465
- const resolved = {};
466
- when(
467
- nonEnforcingEntityLoaderMock.loadFirstByFieldEqualityConjunctionAsync(
468
- anything(),
469
- anything(),
470
- ),
471
- ).thenResolve(result(resolved));
472
- const nonEnforcingEntityLoader = instance(nonEnforcingEntityLoaderMock);
473
- const enforcingEntityLoader = new EnforcingEntityLoader(nonEnforcingEntityLoader);
474
- await expect(
475
- enforcingEntityLoader.loadFirstByFieldEqualityConjunctionAsync(anything(), anything()),
476
- ).resolves.toEqual(resolved);
477
- });
478
-
479
- it('returns null when the query is successful but no rows match', async () => {
480
- const nonEnforcingEntityLoaderMock = mock<
481
- AuthorizationResultBasedEntityLoader<any, any, any, any, any, any>
482
- >(AuthorizationResultBasedEntityLoader);
483
- when(
484
- nonEnforcingEntityLoaderMock.loadFirstByFieldEqualityConjunctionAsync(
485
- anything(),
486
- anything(),
487
- ),
488
- ).thenResolve(null);
489
- const nonEnforcingEntityLoader = instance(nonEnforcingEntityLoaderMock);
490
- const enforcingEntityLoader = new EnforcingEntityLoader(nonEnforcingEntityLoader);
491
- await expect(
492
- enforcingEntityLoader.loadFirstByFieldEqualityConjunctionAsync(anything(), anything()),
493
- ).resolves.toBeNull();
494
- });
495
- });
496
-
497
- describe('loadManyByFieldEqualityConjunction', () => {
498
- it('throws when result is unsuccessful', async () => {
499
- const nonEnforcingEntityLoaderMock = mock<
500
- AuthorizationResultBasedEntityLoader<any, any, any, any, any, any>
501
- >(AuthorizationResultBasedEntityLoader);
502
- const rejection = new Error();
503
- when(
504
- nonEnforcingEntityLoaderMock.loadManyByFieldEqualityConjunctionAsync(
505
- anything(),
506
- anything(),
507
- ),
508
- ).thenResolve([result(rejection)]);
509
- const nonEnforcingEntityLoader = instance(nonEnforcingEntityLoaderMock);
510
- const enforcingEntityLoader = new EnforcingEntityLoader(nonEnforcingEntityLoader);
511
- await expect(
512
- enforcingEntityLoader.loadManyByFieldEqualityConjunctionAsync(anything(), anything()),
513
- ).rejects.toThrow(rejection);
514
- });
515
-
516
- it('returns value when result is successful', async () => {
517
- const nonEnforcingEntityLoaderMock = mock<
518
- AuthorizationResultBasedEntityLoader<any, any, any, any, any, any>
519
- >(AuthorizationResultBasedEntityLoader);
520
- const resolved = {};
521
- when(
522
- nonEnforcingEntityLoaderMock.loadManyByFieldEqualityConjunctionAsync(
523
- anything(),
524
- anything(),
525
- ),
526
- ).thenResolve([result(resolved)]);
527
- const nonEnforcingEntityLoader = instance(nonEnforcingEntityLoaderMock);
528
- const enforcingEntityLoader = new EnforcingEntityLoader(nonEnforcingEntityLoader);
529
- await expect(
530
- enforcingEntityLoader.loadManyByFieldEqualityConjunctionAsync(anything(), anything()),
531
- ).resolves.toEqual([resolved]);
532
- });
533
- });
534
-
535
- describe('loadManyByRawWhereClause', () => {
536
- it('throws when result is unsuccessful', async () => {
537
- const nonEnforcingEntityLoaderMock = mock<
538
- AuthorizationResultBasedEntityLoader<any, any, any, any, any, any>
539
- >(AuthorizationResultBasedEntityLoader);
540
- const rejection = new Error();
541
- when(
542
- nonEnforcingEntityLoaderMock.loadManyByRawWhereClauseAsync(
543
- anything(),
544
- anything(),
545
- anything(),
546
- ),
547
- ).thenResolve([result(rejection)]);
548
- const nonEnforcingEntityLoader = instance(nonEnforcingEntityLoaderMock);
549
- const enforcingEntityLoader = new EnforcingEntityLoader(nonEnforcingEntityLoader);
550
- await expect(
551
- enforcingEntityLoader.loadManyByRawWhereClauseAsync(anything(), anything(), anything()),
552
- ).rejects.toThrow(rejection);
553
- });
554
-
555
- it('returns value when result is successful', async () => {
556
- const nonEnforcingEntityLoaderMock = mock<
557
- AuthorizationResultBasedEntityLoader<any, any, any, any, any, any>
558
- >(AuthorizationResultBasedEntityLoader);
559
- const resolved = {};
560
- when(
561
- nonEnforcingEntityLoaderMock.loadManyByRawWhereClauseAsync(
562
- anything(),
563
- anything(),
564
- anything(),
565
- ),
566
- ).thenResolve([result(resolved)]);
567
- const nonEnforcingEntityLoader = instance(nonEnforcingEntityLoaderMock);
568
- const enforcingEntityLoader = new EnforcingEntityLoader(nonEnforcingEntityLoader);
569
- await expect(
570
- enforcingEntityLoader.loadManyByRawWhereClauseAsync(anything(), anything(), anything()),
571
- ).resolves.toEqual([resolved]);
572
- });
573
- });
574
-
575
442
  it('has the same method names as EntityLoader', () => {
576
443
  const enforcingLoaderProperties = Object.getOwnPropertyNames(EnforcingEntityLoader.prototype);
577
444
  const nonEnforcingLoaderProperties = Object.getOwnPropertyNames(
@@ -580,7 +447,8 @@ describe(EnforcingEntityLoader, () => {
580
447
 
581
448
  // ensure known differences still exist for sanity check
582
449
  const knownLoaderOnlyDifferences = [
583
- 'validateFieldAndValues',
450
+ 'loadOneByFieldEqualingAsync', // private method used in EntityPrivacyUtils that is not intended to be part of the public API of AuthorizationResultBasedEntityLoader, and has no equivalent in EnforcingEntityLoader
451
+ 'validateFieldAndValueAndConvertToHolders',
584
452
  'validateFieldAndValuesAndConvertToHolders',
585
453
  'validateCompositeFieldAndValuesAndConvertToHolders',
586
454
  'constructAndAuthorizeEntitiesFromCompositeFieldValueHolderMapAsync',
@@ -78,4 +78,22 @@ describe(EntityCompanion, () => {
78
78
  afterCommit: [localTriggers!.afterCommit![0]],
79
79
  });
80
80
  });
81
+ it('returns correct metrics adapter', () => {
82
+ const entityCompanionProvider = instance(mock<EntityCompanionProvider>());
83
+
84
+ const tableDataCoordinatorMock = mock<EntityTableDataCoordinator<TestMTFields, 'id'>>();
85
+ when(tableDataCoordinatorMock.entityConfiguration).thenReturn(testEntityMTConfiguration);
86
+
87
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
88
+ const metricsAdapterInstance = instance(metricsAdapterMock);
89
+
90
+ const companion = new EntityCompanion(
91
+ entityCompanionProvider,
92
+ TestEntityWithMutationTriggers.defineCompanionDefinition(),
93
+ instance(tableDataCoordinatorMock),
94
+ metricsAdapterInstance,
95
+ );
96
+
97
+ expect(companion.getMetricsAdapter()).toBe(metricsAdapterInstance);
98
+ });
81
99
  });
@@ -46,8 +46,8 @@ describe(EntityConfiguration, () => {
46
46
  expect(blahEntityConfiguration.databaseAdapterFlavor).toEqual('postgres');
47
47
  expect(blahEntityConfiguration.cacheAdapterFlavor).toEqual('redis');
48
48
  expect(blahEntityConfiguration.compositeFieldInfo.getAllCompositeFieldHolders()).toEqual([
49
- new CompositeFieldHolder(['id', 'cacheable']),
50
- new CompositeFieldHolder(['id', 'uniqueButNotCacheable']),
49
+ new CompositeFieldHolder<BlahT, 'id'>(['id', 'cacheable']),
50
+ new CompositeFieldHolder<BlahT, 'id'>(['id', 'uniqueButNotCacheable']),
51
51
  ]);
52
52
  });
53
53
 
@@ -175,7 +175,7 @@ describe(EntityConfiguration, () => {
175
175
  ])('disallows %p as field key', (keyName) => {
176
176
  expect(
177
177
  () =>
178
- new EntityConfiguration<any, 'id'>({
178
+ new EntityConfiguration<{ id: string }, 'id'>({
179
179
  idField: 'id',
180
180
  tableName: 'blah_table',
181
181
  schema: {
@@ -186,7 +186,7 @@ describe(EntityConfiguration, () => {
186
186
  [keyName]: new StringField({
187
187
  columnName: 'any',
188
188
  }),
189
- } as any,
189
+ },
190
190
  databaseAdapterFlavor: 'postgres',
191
191
  cacheAdapterFlavor: 'redis',
192
192
  }),
@@ -1,11 +1,7 @@
1
1
  import { describe, expect, it } from '@jest/globals';
2
2
  import { instance, mock } from 'ts-mockito';
3
3
 
4
- import {
5
- EntityDatabaseAdapter,
6
- TableFieldMultiValueEqualityCondition,
7
- TableFieldSingleValueEqualityCondition,
8
- } from '../EntityDatabaseAdapter';
4
+ import { EntityDatabaseAdapter } from '../EntityDatabaseAdapter';
9
5
  import { EntityQueryContext } from '../EntityQueryContext';
10
6
  import {
11
7
  EntityDatabaseAdapterEmptyInsertResultError,
@@ -21,33 +17,29 @@ import { TestFields, testEntityConfiguration } from '../utils/__testfixtures__/T
21
17
 
22
18
  class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields, 'customIdField'> {
23
19
  private readonly fetchResults: object[];
20
+ private readonly fetchOneResult: object | null;
24
21
  private readonly insertResults: object[];
25
22
  private readonly updateResults: object[];
26
- private readonly fetchEqualityConditionResults: object[];
27
- private readonly fetchRawWhereResults: object[];
28
23
  private readonly deleteCount: number;
29
24
 
30
25
  constructor({
31
26
  fetchResults = [],
27
+ fetchOneResult = null,
32
28
  insertResults = [],
33
29
  updateResults = [],
34
- fetchEqualityConditionResults = [],
35
- fetchRawWhereResults = [],
36
30
  deleteCount = 0,
37
31
  }: {
38
32
  fetchResults?: object[];
33
+ fetchOneResult?: object | null;
39
34
  insertResults?: object[];
40
35
  updateResults?: object[];
41
- fetchEqualityConditionResults?: object[];
42
- fetchRawWhereResults?: object[];
43
36
  deleteCount?: number;
44
37
  }) {
45
38
  super(testEntityConfiguration);
46
39
  this.fetchResults = fetchResults;
40
+ this.fetchOneResult = fetchOneResult;
47
41
  this.insertResults = insertResults;
48
42
  this.updateResults = updateResults;
49
- this.fetchEqualityConditionResults = fetchEqualityConditionResults;
50
- this.fetchRawWhereResults = fetchRawWhereResults;
51
43
  this.deleteCount = deleteCount;
52
44
  }
53
45
 
@@ -64,22 +56,13 @@ class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields, 'custo
64
56
  return this.fetchResults;
65
57
  }
66
58
 
67
- protected async fetchManyByRawWhereClauseInternalAsync(
68
- _queryInterface: any,
69
- _tableName: string,
70
- _rawWhereClause: string,
71
- _bindings: object | any[],
72
- ): Promise<object[]> {
73
- return this.fetchRawWhereResults;
74
- }
75
-
76
- protected async fetchManyByFieldEqualityConjunctionInternalAsync(
59
+ protected async fetchOneWhereInternalAsync(
77
60
  _queryInterface: any,
78
61
  _tableName: string,
79
- _tableFieldSingleValueEqualityOperands: TableFieldSingleValueEqualityCondition[],
80
- _tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[],
81
- ): Promise<object[]> {
82
- return this.fetchEqualityConditionResults;
62
+ _tableColumns: readonly string[],
63
+ _tableTuple: readonly any[],
64
+ ): Promise<object | null> {
65
+ return this.fetchOneResult;
83
66
  }
84
67
 
85
68
  protected async insertInternalAsync(
@@ -117,7 +100,7 @@ describe(EntityDatabaseAdapter, () => {
117
100
  const adapter = new TestEntityDatabaseAdapter({ fetchResults: [{ string_field: 'hello' }] });
118
101
  const result = await adapter.fetchManyWhereAsync(
119
102
  queryContext,
120
- new SingleFieldHolder('stringField'),
103
+ new SingleFieldHolder<TestFields, 'customIdField', 'stringField'>('stringField'),
121
104
  [new SingleFieldValueHolder('hello')],
122
105
  );
123
106
  expect(result.get(new SingleFieldValueHolder('hello'))).toEqual([{ stringField: 'hello' }]);
@@ -130,7 +113,7 @@ describe(EntityDatabaseAdapter, () => {
130
113
  });
131
114
  const result = await adapter.fetchManyWhereAsync(
132
115
  queryContext,
133
- new SingleFieldHolder('stringField'),
116
+ new SingleFieldHolder<TestFields, 'customIdField', 'stringField'>('stringField'),
134
117
  [new SingleFieldValueHolder('hello'), new SingleFieldValueHolder('wat')],
135
118
  );
136
119
  expect(result.get(new SingleFieldValueHolder('hello'))).toEqual([{ stringField: 'hello' }]);
@@ -170,7 +153,7 @@ describe(EntityDatabaseAdapter, () => {
170
153
  const adapter = new TestEntityDatabaseAdapter({});
171
154
  const result = await adapter.fetchManyWhereAsync(
172
155
  queryContext,
173
- new SingleFieldHolder('stringField'),
156
+ new SingleFieldHolder<TestFields, 'customIdField', 'stringField'>('stringField'),
174
157
  [new SingleFieldValueHolder('what'), new SingleFieldValueHolder('who')],
175
158
  );
176
159
  expect(Array.from(result.keys()).map((v) => v.fieldValue)).toEqual(['what', 'who']);
@@ -182,9 +165,11 @@ describe(EntityDatabaseAdapter, () => {
182
165
  fetchResults: [{ string_field: null }],
183
166
  });
184
167
  await expect(
185
- adapter.fetchManyWhereAsync(queryContext, new SingleFieldHolder('stringField'), [
186
- new SingleFieldValueHolder('hello'),
187
- ]),
168
+ adapter.fetchManyWhereAsync(
169
+ queryContext,
170
+ new SingleFieldHolder<TestFields, 'customIdField', 'stringField'>('stringField'),
171
+ [new SingleFieldValueHolder('hello')],
172
+ ),
188
173
  ).rejects.toThrow(
189
174
  'One or more fields from the object is invalid for key SingleField(stringField); {"stringField":null}. This may indicate a faulty database adapter implementation.',
190
175
  );
@@ -196,9 +181,11 @@ describe(EntityDatabaseAdapter, () => {
196
181
  fetchResults: [{ string_field: undefined }],
197
182
  });
198
183
  await expect(
199
- adapter.fetchManyWhereAsync(queryContext, new SingleFieldHolder('stringField'), [
200
- new SingleFieldValueHolder('hello'),
201
- ]),
184
+ adapter.fetchManyWhereAsync(
185
+ queryContext,
186
+ new SingleFieldHolder<TestFields, 'customIdField', 'stringField'>('stringField'),
187
+ [new SingleFieldValueHolder('hello')],
188
+ ),
202
189
  ).rejects.toThrow(
203
190
  'One or more fields from the object is invalid for key SingleField(stringField); {}. This may indicate a faulty database adapter implementation.',
204
191
  );
@@ -237,40 +224,18 @@ describe(EntityDatabaseAdapter, () => {
237
224
  });
238
225
  });
239
226
 
240
- describe('fetchManyByFieldEqualityConjunction', () => {
241
- it('transforms object', async () => {
242
- const queryContext = instance(mock(EntityQueryContext));
243
- const adapter = new TestEntityDatabaseAdapter({
244
- fetchEqualityConditionResults: [{ string_field: 'hello' }],
245
- });
246
- const results = await adapter.fetchManyByFieldEqualityConjunctionAsync(queryContext, [], {});
247
- expect(results).toEqual([{ stringField: 'hello' }]);
248
- });
249
- });
250
-
251
- describe('fetchManyWithRawWhereClause', () => {
252
- it('transforms object', async () => {
253
- const queryContext = instance(mock(EntityQueryContext));
254
- const adapter = new TestEntityDatabaseAdapter({
255
- fetchRawWhereResults: [{ string_field: 'hello' }],
256
- });
257
- const results = await adapter.fetchManyByRawWhereClauseAsync(queryContext, 'hello', [], {});
258
- expect(results).toEqual([{ stringField: 'hello' }]);
259
- });
260
- });
261
-
262
227
  describe('insertAsync', () => {
263
228
  it('transforms object', async () => {
264
229
  const queryContext = instance(mock(EntityQueryContext));
265
230
  const adapter = new TestEntityDatabaseAdapter({ insertResults: [{ string_field: 'hello' }] });
266
- const result = await adapter.insertAsync(queryContext, {} as any);
231
+ const result = await adapter.insertAsync(queryContext, {});
267
232
  expect(result).toEqual({ stringField: 'hello' });
268
233
  });
269
234
 
270
235
  it('throws when insert result count zero', async () => {
271
236
  const queryContext = instance(mock(EntityQueryContext));
272
237
  const adapter = new TestEntityDatabaseAdapter({ insertResults: [] });
273
- await expect(adapter.insertAsync(queryContext, {} as any)).rejects.toThrow(
238
+ await expect(adapter.insertAsync(queryContext, {})).rejects.toThrow(
274
239
  EntityDatabaseAdapterEmptyInsertResultError,
275
240
  );
276
241
  });
@@ -280,7 +245,7 @@ describe(EntityDatabaseAdapter, () => {
280
245
  const adapter = new TestEntityDatabaseAdapter({
281
246
  insertResults: [{ string_field: 'hello' }, { string_field: 'hello2' }],
282
247
  });
283
- await expect(adapter.insertAsync(queryContext, {} as any)).rejects.toThrow(
248
+ await expect(adapter.insertAsync(queryContext, {})).rejects.toThrow(
284
249
  EntityDatabaseAdapterExcessiveInsertResultError,
285
250
  );
286
251
  });
@@ -290,16 +255,16 @@ describe(EntityDatabaseAdapter, () => {
290
255
  it('transforms object', async () => {
291
256
  const queryContext = instance(mock(EntityQueryContext));
292
257
  const adapter = new TestEntityDatabaseAdapter({ updateResults: [{ string_field: 'hello' }] });
293
- const result = await adapter.updateAsync(queryContext, 'customIdField', 'wat', {} as any);
258
+ const result = await adapter.updateAsync(queryContext, 'customIdField', 'wat', {});
294
259
  expect(result).toEqual({ stringField: 'hello' });
295
260
  });
296
261
 
297
262
  it('throws when update result count zero', async () => {
298
263
  const queryContext = instance(mock(EntityQueryContext));
299
264
  const adapter = new TestEntityDatabaseAdapter({ updateResults: [] });
300
- await expect(
301
- adapter.updateAsync(queryContext, 'customIdField', 'wat', {} as any),
302
- ).rejects.toThrow(EntityDatabaseAdapterEmptyUpdateResultError);
265
+ await expect(adapter.updateAsync(queryContext, 'customIdField', 'wat', {})).rejects.toThrow(
266
+ EntityDatabaseAdapterEmptyUpdateResultError,
267
+ );
303
268
  });
304
269
 
305
270
  it('throws when update result count greater than 1', async () => {
@@ -307,9 +272,9 @@ describe(EntityDatabaseAdapter, () => {
307
272
  const adapter = new TestEntityDatabaseAdapter({
308
273
  updateResults: [{ string_field: 'hello' }, { string_field: 'hello2' }],
309
274
  });
310
- await expect(
311
- adapter.updateAsync(queryContext, 'customIdField', 'wat', {} as any),
312
- ).rejects.toThrow(EntityDatabaseAdapterExcessiveUpdateResultError);
275
+ await expect(adapter.updateAsync(queryContext, 'customIdField', 'wat', {})).rejects.toThrow(
276
+ EntityDatabaseAdapterExcessiveUpdateResultError,
277
+ );
313
278
  });
314
279
  });
315
280
 
@@ -772,7 +772,7 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
772
772
  'id'
773
773
  >;
774
774
  const childCachedBefore = await childCacheAdapter.loadManyAsync(
775
- new SingleFieldHolder('parent_id'),
775
+ new SingleFieldHolder<ChildFields, 'id', 'parent_id'>('parent_id'),
776
776
  [new SingleFieldValueHolder(parent.getID())],
777
777
  );
778
778
  expect(childCachedBefore.get(new SingleFieldValueHolder(parent.getID()))?.status).toEqual(
@@ -783,9 +783,9 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
783
783
  GrandChildEntity,
784
784
  )['entityCompanion']['tableDataCoordinator'][
785
785
  'cacheAdapter'
786
- ] as InMemoryFullCacheStubCacheAdapter<ChildFields, 'id'>;
786
+ ] as InMemoryFullCacheStubCacheAdapter<GrandChildFields, 'id'>;
787
787
  const grandChildCachedBefore = await grandChildCacheAdapter.loadManyAsync(
788
- new SingleFieldHolder('parent_id'),
788
+ new SingleFieldHolder<GrandChildFields, 'id', 'parent_id'>('parent_id'),
789
789
  [new SingleFieldValueHolder(child.getID())],
790
790
  );
791
791
  expect(grandChildCachedBefore.get(new SingleFieldValueHolder(child.getID()))?.status).toEqual(
@@ -797,7 +797,7 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
797
797
  privacyPolicyEvaluationRecords.shouldRecord = false;
798
798
 
799
799
  const childCachedAfter = await childCacheAdapter.loadManyAsync(
800
- new SingleFieldHolder('parent_id'),
800
+ new SingleFieldHolder<ChildFields, 'id', 'parent_id'>('parent_id'),
801
801
  [new SingleFieldValueHolder(parent.getID())],
802
802
  );
803
803
  expect(childCachedAfter.get(new SingleFieldValueHolder(parent.getID()))?.status).toEqual(
@@ -805,7 +805,7 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
805
805
  );
806
806
 
807
807
  const grandChildCachedAfter = await grandChildCacheAdapter.loadManyAsync(
808
- new SingleFieldHolder('parent_id'),
808
+ new SingleFieldHolder<GrandChildFields, 'id', 'parent_id'>('parent_id'),
809
809
  [new SingleFieldValueHolder(child.getID())],
810
810
  );
811
811
  expect(grandChildCachedAfter.get(new SingleFieldValueHolder(child.getID()))?.status).toEqual(
@@ -922,7 +922,7 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
922
922
  'id'
923
923
  >;
924
924
  const childCachedBefore = await childCacheAdapter.loadManyAsync(
925
- new SingleFieldHolder('parent_id'),
925
+ new SingleFieldHolder<ChildFields, 'id', 'parent_id'>('parent_id'),
926
926
  [new SingleFieldValueHolder(parent.getID())],
927
927
  );
928
928
  expect(childCachedBefore.get(new SingleFieldValueHolder(parent.getID()))?.status).toEqual(
@@ -933,9 +933,9 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
933
933
  GrandChildEntity,
934
934
  )['entityCompanion']['tableDataCoordinator'][
935
935
  'cacheAdapter'
936
- ] as InMemoryFullCacheStubCacheAdapter<ChildFields, 'id'>;
936
+ ] as InMemoryFullCacheStubCacheAdapter<GrandChildFields, 'id'>;
937
937
  const grandChildCachedBefore = await grandChildCacheAdapter.loadManyAsync(
938
- new SingleFieldHolder('parent_id'),
938
+ new SingleFieldHolder<GrandChildFields, 'id', 'parent_id'>('parent_id'),
939
939
  [new SingleFieldValueHolder(child.getID())],
940
940
  );
941
941
  expect(grandChildCachedBefore.get(new SingleFieldValueHolder(child.getID()))?.status).toEqual(
@@ -947,7 +947,7 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
947
947
  privacyPolicyEvaluationRecords.shouldRecord = false;
948
948
 
949
949
  const childCachedAfter = await childCacheAdapter.loadManyAsync(
950
- new SingleFieldHolder('parent_id'),
950
+ new SingleFieldHolder<ChildFields, 'id', 'parent_id'>('parent_id'),
951
951
  [new SingleFieldValueHolder(parent.getID())],
952
952
  );
953
953
  expect(childCachedAfter.get(new SingleFieldValueHolder(parent.getID()))?.status).toEqual(
@@ -955,7 +955,7 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
955
955
  );
956
956
 
957
957
  const grandChildCachedAfter = await grandChildCacheAdapter.loadManyAsync(
958
- new SingleFieldHolder('parent_id'),
958
+ new SingleFieldHolder<GrandChildFields, 'id', 'parent_id'>('parent_id'),
959
959
  [new SingleFieldValueHolder(child.getID())],
960
960
  );
961
961
  expect(grandChildCachedAfter.get(new SingleFieldValueHolder(child.getID()))?.status).toEqual(
@@ -2,8 +2,8 @@ import { describe, expect, it } from '@jest/globals';
2
2
 
3
3
  import { AuthorizationResultBasedEntityLoader } from '../AuthorizationResultBasedEntityLoader';
4
4
  import { EnforcingEntityLoader } from '../EnforcingEntityLoader';
5
+ import { EntityInvalidationUtils } from '../EntityInvalidationUtils';
5
6
  import { EntityLoader } from '../EntityLoader';
6
- import { EntityLoaderUtils } from '../EntityLoaderUtils';
7
7
  import { ViewerContext } from '../ViewerContext';
8
8
  import { SimpleTestEntity } from '../utils/__testfixtures__/SimpleTestEntity';
9
9
  import { createUnitTestEntityCompanionProvider } from '../utils/__testfixtures__/createUnitTestEntityCompanionProvider';
@@ -27,11 +27,13 @@ describe(EntityLoader, () => {
27
27
  });
28
28
  });
29
29
 
30
- describe('utils', () => {
31
- it('returns a instance of EntityLoaderUtils', async () => {
30
+ describe('invalidationUtils', () => {
31
+ it('returns a instance of EntityInvalidationUtils', async () => {
32
32
  const companionProvider = createUnitTestEntityCompanionProvider();
33
33
  const viewerContext = new ViewerContext(companionProvider);
34
- expect(SimpleTestEntity.loaderUtils(viewerContext)).toBeInstanceOf(EntityLoaderUtils);
34
+ expect(SimpleTestEntity.invalidationUtils(viewerContext)).toBeInstanceOf(
35
+ EntityInvalidationUtils,
36
+ );
35
37
  });
36
38
  });
37
39
  });
@@ -16,9 +16,9 @@ import { v4 as uuidv4 } from 'uuid';
16
16
  import { AuthorizationResultBasedEntityLoader } from '../AuthorizationResultBasedEntityLoader';
17
17
  import { EntityCompanionProvider } from '../EntityCompanionProvider';
18
18
  import { EntityConfiguration } from '../EntityConfiguration';
19
+ import { EntityConstructionUtils } from '../EntityConstructionUtils';
19
20
  import { EntityDatabaseAdapter } from '../EntityDatabaseAdapter';
20
21
  import { EntityLoaderFactory } from '../EntityLoaderFactory';
21
- import { EntityLoaderUtils } from '../EntityLoaderUtils';
22
22
  import {
23
23
  EntityCascadingDeletionInfo,
24
24
  EntityMutationType,
@@ -370,10 +370,10 @@ const createEntityMutatorFactory = (
370
370
  ),
371
371
  );
372
372
  const customStubDatabaseAdapterProvider: IEntityDatabaseAdapterProvider = {
373
- getDatabaseAdapter<TFields extends Record<'customIdField', any>>(
374
- _entityConfiguration: EntityConfiguration<TFields, 'customIdField'>,
375
- ): EntityDatabaseAdapter<TFields, 'customIdField'> {
376
- return databaseAdapter as any as EntityDatabaseAdapter<TFields, 'customIdField'>;
373
+ getDatabaseAdapter<TFields extends Record<string, any>, TIDField extends keyof TFields>(
374
+ _entityConfiguration: EntityConfiguration<TFields, TIDField>,
375
+ ): EntityDatabaseAdapter<TFields, TIDField> {
376
+ return databaseAdapter as any as EntityDatabaseAdapter<TFields, TIDField>;
377
377
  },
378
378
  };
379
379
  const metricsAdapter = new NoOpEntityMetricsAdapter();
@@ -1499,9 +1499,9 @@ describe(EntityMutatorFactory, () => {
1499
1499
  keyof SimpleTestFields
1500
1500
  >
1501
1501
  >(AuthorizationResultBasedEntityLoader);
1502
- const entityLoaderUtilsMock =
1502
+ const entityConstructionUtilsMock =
1503
1503
  mock<
1504
- EntityLoaderUtils<
1504
+ EntityConstructionUtils<
1505
1505
  SimpleTestFields,
1506
1506
  'id',
1507
1507
  ViewerContext,
@@ -1509,9 +1509,8 @@ describe(EntityMutatorFactory, () => {
1509
1509
  SimpleTestEntityPrivacyPolicy,
1510
1510
  keyof SimpleTestFields
1511
1511
  >
1512
- >(EntityLoaderUtils);
1513
- when(entityLoaderUtilsMock.constructEntity(anything())).thenReturn(fakeEntity);
1514
- when(entityLoaderMock.utils).thenReturn(instance(entityLoaderUtilsMock));
1512
+ >(EntityConstructionUtils);
1513
+ when(entityConstructionUtilsMock.constructEntity(anything())).thenReturn(fakeEntity);
1515
1514
  const entityLoader = instance(entityLoaderMock);
1516
1515
 
1517
1516
  const entityLoaderFactoryMock =
@@ -1532,6 +1531,13 @@ describe(EntityMutatorFactory, () => {
1532
1531
  anything(),
1533
1532
  ),
1534
1533
  ).thenReturn(entityLoader);
1534
+ when(
1535
+ entityLoaderFactoryMock.constructionUtils(
1536
+ viewerContext,
1537
+ anyOfClass(EntityTransactionalQueryContext),
1538
+ anything(),
1539
+ ),
1540
+ ).thenReturn(instance(entityConstructionUtilsMock));
1535
1541
  const entityLoaderFactory = instance(entityLoaderFactoryMock);
1536
1542
 
1537
1543
  const rejectionError = new Error();
@@ -1634,9 +1640,9 @@ describe(EntityMutatorFactory, () => {
1634
1640
  keyof SimpleTestFields
1635
1641
  >
1636
1642
  >(AuthorizationResultBasedEntityLoader);
1637
- const entityLoaderUtilsMock =
1643
+ const entityConstructionUtilsMock =
1638
1644
  mock<
1639
- EntityLoaderUtils<
1645
+ EntityConstructionUtils<
1640
1646
  SimpleTestFields,
1641
1647
  'id',
1642
1648
  ViewerContext,
@@ -1644,9 +1650,8 @@ describe(EntityMutatorFactory, () => {
1644
1650
  SimpleTestEntityPrivacyPolicy,
1645
1651
  keyof SimpleTestFields
1646
1652
  >
1647
- >(EntityLoaderUtils);
1648
- when(entityLoaderUtilsMock.constructEntity(anything())).thenReturn(fakeEntity);
1649
- when(entityLoaderMock.utils).thenReturn(instance(entityLoaderUtilsMock));
1653
+ >(EntityConstructionUtils);
1654
+ when(entityConstructionUtilsMock.constructEntity(anything())).thenReturn(fakeEntity);
1650
1655
  const entityLoader = instance(entityLoaderMock);
1651
1656
 
1652
1657
  const entityLoaderFactoryMock =
@@ -1667,6 +1672,13 @@ describe(EntityMutatorFactory, () => {
1667
1672
  anything(),
1668
1673
  ),
1669
1674
  ).thenReturn(entityLoader);
1675
+ when(
1676
+ entityLoaderFactoryMock.constructionUtils(
1677
+ viewerContext,
1678
+ anyOfClass(EntityTransactionalQueryContext),
1679
+ anything(),
1680
+ ),
1681
+ ).thenReturn(instance(entityConstructionUtilsMock));
1670
1682
  const entityLoaderFactory = instance(entityLoaderFactoryMock);
1671
1683
 
1672
1684
  const rejectionError = new Error();