@expo/entity 0.16.0 → 0.20.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 (210) hide show
  1. package/build/EnforcingEntityLoader.js +2 -2
  2. package/build/EnforcingEntityLoader.js.map +1 -1
  3. package/build/Entity.js +8 -2
  4. package/build/Entity.js.map +1 -1
  5. package/build/EntityAssociationLoader.js +3 -3
  6. package/build/EntityAssociationLoader.js.map +1 -1
  7. package/build/EntityCompanion.d.ts +5 -0
  8. package/build/EntityCompanion.js +8 -1
  9. package/build/EntityCompanion.js.map +1 -1
  10. package/build/EntityCompanionProvider.d.ts +1 -1
  11. package/build/EntityCompanionProvider.js +5 -5
  12. package/build/EntityCompanionProvider.js.map +1 -1
  13. package/build/EntityConfiguration.d.ts +1 -1
  14. package/build/EntityConfiguration.js +3 -3
  15. package/build/EntityConfiguration.js.map +1 -1
  16. package/build/EntityDatabaseAdapter.d.ts +4 -4
  17. package/build/EntityDatabaseAdapter.js +13 -13
  18. package/build/EntityDatabaseAdapter.js.map +1 -1
  19. package/build/EntityFieldDefinition.d.ts +77 -0
  20. package/build/EntityFieldDefinition.js +53 -0
  21. package/build/EntityFieldDefinition.js.map +1 -0
  22. package/build/EntityFields.d.ts +5 -78
  23. package/build/EntityFields.js +19 -61
  24. package/build/EntityFields.js.map +1 -1
  25. package/build/EntityLoader.d.ts +3 -1
  26. package/build/EntityLoader.js +19 -15
  27. package/build/EntityLoader.js.map +1 -1
  28. package/build/EntityLoaderFactory.d.ts +3 -1
  29. package/build/EntityLoaderFactory.js +3 -2
  30. package/build/EntityLoaderFactory.js.map +1 -1
  31. package/build/EntityMutationInfo.d.ts +26 -0
  32. package/build/EntityMutationInfo.js +10 -0
  33. package/build/EntityMutationInfo.js.map +1 -0
  34. package/build/EntityMutationTriggerConfiguration.d.ts +4 -4
  35. package/build/EntityMutationValidator.d.ts +3 -3
  36. package/build/EntityMutationValidator.js.map +1 -1
  37. package/build/EntityMutator.d.ts +5 -16
  38. package/build/EntityMutator.js +62 -58
  39. package/build/EntityMutator.js.map +1 -1
  40. package/build/EntityPrivacyPolicy.d.ts +5 -4
  41. package/build/EntityPrivacyPolicy.js +60 -12
  42. package/build/EntityPrivacyPolicy.js.map +1 -1
  43. package/build/EntityQueryContext.d.ts +13 -0
  44. package/build/EntityQueryContext.js +18 -0
  45. package/build/EntityQueryContext.js.map +1 -1
  46. package/build/EntitySecondaryCacheLoader.js +2 -2
  47. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  48. package/build/ReadonlyEntity.js +3 -4
  49. package/build/ReadonlyEntity.js.map +1 -1
  50. package/build/ViewerScopedEntityCompanion.d.ts +5 -0
  51. package/build/ViewerScopedEntityCompanion.js +6 -0
  52. package/build/ViewerScopedEntityCompanion.js.map +1 -1
  53. package/build/__tests__/EnforcingEntityLoader-test.js +82 -82
  54. package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
  55. package/build/__tests__/Entity-test.js +6 -6
  56. package/build/__tests__/Entity-test.js.map +1 -1
  57. package/build/__tests__/EntityAssociationLoader-test.js +40 -40
  58. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  59. package/build/__tests__/EntityCommonUseCases-test.js +11 -11
  60. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  61. package/build/__tests__/EntityCompanion-test.js +3 -3
  62. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  63. package/build/__tests__/EntityCompanionProvider-test.js +1 -1
  64. package/build/__tests__/EntityCompanionProvider-test.js.map +1 -1
  65. package/build/__tests__/EntityDatabaseAdapter-test.js +12 -12
  66. package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
  67. package/build/__tests__/EntityEdges-test.js +103 -6
  68. package/build/__tests__/EntityEdges-test.js.map +1 -1
  69. package/build/__tests__/EntityFields-test.js +18 -26
  70. package/build/__tests__/EntityFields-test.js.map +1 -1
  71. package/build/__tests__/EntityLoader-constructor-test.d.ts +22 -0
  72. package/build/__tests__/EntityLoader-constructor-test.js +111 -0
  73. package/build/__tests__/EntityLoader-constructor-test.js.map +1 -0
  74. package/build/__tests__/EntityLoader-test.js +81 -73
  75. package/build/__tests__/EntityLoader-test.js.map +1 -1
  76. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.d.ts +1 -0
  77. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +81 -0
  78. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -0
  79. package/build/__tests__/EntityMutator-test.js +138 -136
  80. package/build/__tests__/EntityMutator-test.js.map +1 -1
  81. package/build/__tests__/EntityPrivacyPolicy-test.js +143 -67
  82. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  83. package/build/__tests__/EntitySecondaryCacheLoader-test.js +15 -15
  84. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
  85. package/build/__tests__/EntitySelfReferentialEdges-test.js +13 -12
  86. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  87. package/build/__tests__/ReadonlyEntity-test.js +12 -12
  88. package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
  89. package/build/__tests__/ViewerContext-test.js +2 -2
  90. package/build/__tests__/ViewerContext-test.js.map +1 -1
  91. package/build/__tests__/ViewerScopedEntityCompanion-test.js +2 -2
  92. package/build/__tests__/ViewerScopedEntityCompanion-test.js.map +1 -1
  93. package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js +2 -2
  94. package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js.map +1 -1
  95. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js +5 -5
  96. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
  97. package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js +5 -5
  98. package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js.map +1 -1
  99. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +5 -5
  100. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  101. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +2 -2
  102. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  103. package/build/__tests__/entityUtils-test.js +21 -21
  104. package/build/__tests__/entityUtils-test.js.map +1 -1
  105. package/build/index.d.ts +3 -0
  106. package/build/index.js +5 -1
  107. package/build/index.js.map +1 -1
  108. package/build/internal/EntityDataManager.js +8 -7
  109. package/build/internal/EntityDataManager.js.map +1 -1
  110. package/build/internal/EntityFieldTransformationUtils.js +2 -2
  111. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  112. package/build/internal/ReadThroughEntityCache.js +4 -4
  113. package/build/internal/ReadThroughEntityCache.js.map +1 -1
  114. package/build/internal/__tests__/EntityDataManager-test.js +21 -21
  115. package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
  116. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +8 -8
  117. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
  118. package/build/internal/__tests__/ReadThroughEntityCache-test.js +48 -48
  119. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  120. package/build/metrics/EntityMetricsUtils.js +1 -1
  121. package/build/metrics/EntityMetricsUtils.js.map +1 -1
  122. package/build/metrics/IEntityMetricsAdapter.d.ts +16 -0
  123. package/build/metrics/IEntityMetricsAdapter.js +6 -1
  124. package/build/metrics/IEntityMetricsAdapter.js.map +1 -1
  125. package/build/metrics/NoOpEntityMetricsAdapter.d.ts +2 -1
  126. package/build/metrics/NoOpEntityMetricsAdapter.js +1 -0
  127. package/build/metrics/NoOpEntityMetricsAdapter.js.map +1 -1
  128. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js +4 -4
  129. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
  130. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js +4 -4
  131. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
  132. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js +4 -4
  133. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
  134. package/build/testfixtures/DateIDTestEntity.js.map +1 -1
  135. package/build/testfixtures/SimpleTestEntity.js.map +1 -1
  136. package/build/testfixtures/TestEntity.d.ts +6 -6
  137. package/build/testfixtures/TestEntity.js +4 -4
  138. package/build/testfixtures/TestEntity.js.map +1 -1
  139. package/build/testfixtures/TestEntity2.d.ts +5 -5
  140. package/build/testfixtures/TestEntity2.js.map +1 -1
  141. package/build/testfixtures/TestEntityNumberKey.js +1 -1
  142. package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
  143. package/build/utils/collections/__tests__/maps-test.js +13 -13
  144. package/build/utils/collections/__tests__/maps-test.js.map +1 -1
  145. package/build/utils/collections/maps.js +1 -1
  146. package/build/utils/collections/maps.js.map +1 -1
  147. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +6 -6
  148. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +1 -1
  149. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
  150. package/build/utils/testing/StubCacheAdapter.js +1 -1
  151. package/build/utils/testing/StubCacheAdapter.js.map +1 -1
  152. package/build/utils/testing/StubDatabaseAdapter.js +7 -7
  153. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  154. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +26 -26
  155. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
  156. package/build/utils/testing/describeFieldTestCase.d.ts +2 -0
  157. package/build/utils/testing/describeFieldTestCase.js +18 -0
  158. package/build/utils/testing/describeFieldTestCase.js.map +1 -0
  159. package/package.json +2 -1
  160. package/src/Entity.ts +10 -2
  161. package/src/EntityAssociationLoader.ts +1 -1
  162. package/src/EntityCompanion.ts +10 -2
  163. package/src/EntityCompanionProvider.ts +5 -9
  164. package/src/EntityConfiguration.ts +1 -1
  165. package/src/EntityDatabaseAdapter.ts +10 -8
  166. package/src/EntityFieldDefinition.ts +124 -0
  167. package/src/EntityFields.ts +11 -126
  168. package/src/EntityLoader.ts +12 -4
  169. package/src/EntityLoaderFactory.ts +5 -2
  170. package/src/EntityMutationInfo.ts +47 -0
  171. package/src/EntityMutationTriggerConfiguration.ts +5 -5
  172. package/src/EntityMutationValidator.ts +10 -4
  173. package/src/EntityMutator.ts +98 -76
  174. package/src/EntityPrivacyPolicy.ts +77 -19
  175. package/src/EntityQueryContext.ts +20 -0
  176. package/src/ReadonlyEntity.ts +3 -2
  177. package/src/ViewerScopedEntityCompanion.ts +8 -0
  178. package/src/__tests__/Entity-test.ts +8 -8
  179. package/src/__tests__/EntityCommonUseCases-test.ts +4 -4
  180. package/src/__tests__/EntityEdges-test.ts +169 -14
  181. package/src/__tests__/EntityFields-test.ts +6 -23
  182. package/src/__tests__/EntityLoader-constructor-test.ts +177 -0
  183. package/src/__tests__/EntityLoader-test.ts +48 -20
  184. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +105 -0
  185. package/src/__tests__/EntityMutator-test.ts +153 -146
  186. package/src/__tests__/EntityPrivacyPolicy-test.ts +215 -78
  187. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -9
  188. package/src/__tests__/EntitySelfReferentialEdges-test.ts +6 -5
  189. package/src/__tests__/ReadonlyEntity-test.ts +1 -1
  190. package/src/__tests__/ViewerContext-test.ts +7 -6
  191. package/src/__tests__/ViewerScopedEntityCompanion-test.ts +11 -10
  192. package/src/__tests__/ViewerScopedEntityMutatorFactory-test.ts +4 -3
  193. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +6 -6
  194. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +4 -4
  195. package/src/index.ts +3 -0
  196. package/src/internal/EntityDataManager.ts +2 -1
  197. package/src/internal/__tests__/EntityDataManager-test.ts +6 -6
  198. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +15 -13
  199. package/src/metrics/EntityMetricsUtils.ts +56 -50
  200. package/src/metrics/IEntityMetricsAdapter.ts +23 -0
  201. package/src/metrics/NoOpEntityMetricsAdapter.ts +2 -0
  202. package/src/testfixtures/DateIDTestEntity.ts +4 -4
  203. package/src/testfixtures/SimpleTestEntity.ts +4 -4
  204. package/src/testfixtures/TestEntity.ts +8 -8
  205. package/src/testfixtures/TestEntity2.ts +4 -4
  206. package/src/testfixtures/TestEntityNumberKey.ts +6 -6
  207. package/src/utils/testing/StubDatabaseAdapter.ts +4 -4
  208. package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +18 -18
  209. package/src/utils/testing/describeFieldTestCase.ts +21 -0
  210. package/CHANGELOG.md +0 -241
@@ -1,4 +1,4 @@
1
- import { mock, instance, spy, verify, anyOfClass } from 'ts-mockito';
1
+ import { mock, instance, spy, verify, anyOfClass, anything, objectContaining } from 'ts-mockito';
2
2
 
3
3
  import Entity from '../Entity';
4
4
  import { EntityCompanionDefinition } from '../EntityCompanionProvider';
@@ -6,11 +6,15 @@ import EntityConfiguration from '../EntityConfiguration';
6
6
  import { UUIDField } from '../EntityFields';
7
7
  import EntityPrivacyPolicy, {
8
8
  EntityPrivacyPolicyEvaluator,
9
+ EntityAuthorizationAction,
9
10
  EntityPrivacyPolicyEvaluationMode,
10
11
  } from '../EntityPrivacyPolicy';
11
12
  import { EntityQueryContext } from '../EntityQueryContext';
12
13
  import ViewerContext from '../ViewerContext';
13
14
  import EntityNotAuthorizedError from '../errors/EntityNotAuthorizedError';
15
+ import IEntityMetricsAdapter, {
16
+ EntityMetricsAuthorizationResult,
17
+ } from '../metrics/IEntityMetricsAdapter';
14
18
  import AlwaysAllowPrivacyPolicyRule from '../rules/AlwaysAllowPrivacyPolicyRule';
15
19
  import AlwaysDenyPrivacyPolicyRule from '../rules/AlwaysDenyPrivacyPolicyRule';
16
20
  import AlwaysSkipPrivacyPolicyRule from '../rules/AlwaysSkipPrivacyPolicyRule';
@@ -33,16 +37,16 @@ class BlahEntity extends Entity<BlahFields, string, ViewerContext> {
33
37
  }
34
38
 
35
39
  class AlwaysDenyPolicy extends EntityPrivacyPolicy<BlahFields, string, ViewerContext, BlahEntity> {
36
- protected readonly createRules = [
40
+ protected override readonly createRules = [
37
41
  new AlwaysDenyPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
38
42
  ];
39
- protected readonly readRules = [
43
+ protected override readonly readRules = [
40
44
  new AlwaysDenyPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
41
45
  ];
42
- protected readonly updateRules = [
46
+ protected override readonly updateRules = [
43
47
  new AlwaysDenyPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
44
48
  ];
45
- protected readonly deleteRules = [
49
+ protected override readonly deleteRules = [
46
50
  new AlwaysDenyPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
47
51
  ];
48
52
  }
@@ -53,7 +57,7 @@ class DryRunAlwaysDenyPolicy extends AlwaysDenyPolicy {
53
57
  _error: EntityNotAuthorizedError<BlahFields, string, ViewerContext, BlahEntity>
54
58
  ): void {}
55
59
 
56
- protected getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
60
+ protected override getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
57
61
  BlahFields,
58
62
  string,
59
63
  ViewerContext,
@@ -72,7 +76,7 @@ class LoggingEnforceAlwaysDenyPolicy extends AlwaysDenyPolicy {
72
76
  _error: EntityNotAuthorizedError<BlahFields, string, ViewerContext, BlahEntity>
73
77
  ): void {}
74
78
 
75
- protected getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
79
+ protected override getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
76
80
  BlahFields,
77
81
  string,
78
82
  ViewerContext,
@@ -86,16 +90,16 @@ class LoggingEnforceAlwaysDenyPolicy extends AlwaysDenyPolicy {
86
90
  }
87
91
 
88
92
  class AlwaysAllowPolicy extends EntityPrivacyPolicy<BlahFields, string, ViewerContext, BlahEntity> {
89
- protected readonly createRules = [
93
+ protected override readonly createRules = [
90
94
  new AlwaysAllowPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
91
95
  ];
92
- protected readonly readRules = [
96
+ protected override readonly readRules = [
93
97
  new AlwaysAllowPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
94
98
  ];
95
- protected readonly updateRules = [
99
+ protected override readonly updateRules = [
96
100
  new AlwaysAllowPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
97
101
  ];
98
- protected readonly deleteRules = [
102
+ protected override readonly deleteRules = [
99
103
  new AlwaysAllowPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
100
104
  ];
101
105
  }
@@ -106,7 +110,7 @@ class DryRunAlwaysAllowPolicy extends AlwaysAllowPolicy {
106
110
  _error: EntityNotAuthorizedError<BlahFields, string, ViewerContext, BlahEntity>
107
111
  ): void {}
108
112
 
109
- protected getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
113
+ protected override getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
110
114
  BlahFields,
111
115
  string,
112
116
  ViewerContext,
@@ -125,7 +129,7 @@ class LoggingEnforceAlwaysAllowPolicy extends AlwaysAllowPolicy {
125
129
  _error: EntityNotAuthorizedError<BlahFields, string, ViewerContext, BlahEntity>
126
130
  ): void {}
127
131
 
128
- protected getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
132
+ protected override getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
129
133
  BlahFields,
130
134
  string,
131
135
  ViewerContext,
@@ -139,16 +143,16 @@ class LoggingEnforceAlwaysAllowPolicy extends AlwaysAllowPolicy {
139
143
  }
140
144
 
141
145
  class SkipAllPolicy extends EntityPrivacyPolicy<BlahFields, string, ViewerContext, BlahEntity> {
142
- protected readonly createRules = [
146
+ protected override readonly createRules = [
143
147
  new AlwaysSkipPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
144
148
  ];
145
- protected readonly readRules = [
149
+ protected override readonly readRules = [
146
150
  new AlwaysSkipPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
147
151
  ];
148
- protected readonly updateRules = [
152
+ protected override readonly updateRules = [
149
153
  new AlwaysSkipPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
150
154
  ];
151
- protected readonly deleteRules = [
155
+ protected override readonly deleteRules = [
152
156
  new AlwaysSkipPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
153
157
  ];
154
158
  }
@@ -169,10 +173,10 @@ class AlwaysThrowPrivacyPolicyRule extends PrivacyPolicyRule<
169
173
  }
170
174
 
171
175
  class ThrowAllPolicy extends EntityPrivacyPolicy<BlahFields, string, ViewerContext, BlahEntity> {
172
- protected readonly createRules = [new AlwaysThrowPrivacyPolicyRule()];
173
- protected readonly readRules = [new AlwaysThrowPrivacyPolicyRule()];
174
- protected readonly updateRules = [new AlwaysThrowPrivacyPolicyRule()];
175
- protected readonly deleteRules = [new AlwaysThrowPrivacyPolicyRule()];
176
+ protected override readonly createRules = [new AlwaysThrowPrivacyPolicyRule()];
177
+ protected override readonly readRules = [new AlwaysThrowPrivacyPolicyRule()];
178
+ protected override readonly updateRules = [new AlwaysThrowPrivacyPolicyRule()];
179
+ protected override readonly deleteRules = [new AlwaysThrowPrivacyPolicyRule()];
176
180
  }
177
181
 
178
182
  class DryRunThrowAllPolicy extends ThrowAllPolicy {
@@ -181,7 +185,7 @@ class DryRunThrowAllPolicy extends ThrowAllPolicy {
181
185
  _error: EntityNotAuthorizedError<BlahFields, string, ViewerContext, BlahEntity>
182
186
  ): void {}
183
187
 
184
- protected getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
188
+ protected override getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
185
189
  BlahFields,
186
190
  string,
187
191
  ViewerContext,
@@ -200,7 +204,7 @@ class LoggingEnforceThrowAllPolicy extends ThrowAllPolicy {
200
204
  _error: EntityNotAuthorizedError<BlahFields, string, ViewerContext, BlahEntity>
201
205
  ): void {}
202
206
 
203
- protected getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
207
+ protected override getPrivacyPolicyEvaluator(): EntityPrivacyPolicyEvaluator<
204
208
  BlahFields,
205
209
  string,
206
210
  ViewerContext,
@@ -214,10 +218,10 @@ class LoggingEnforceThrowAllPolicy extends ThrowAllPolicy {
214
218
  }
215
219
 
216
220
  class EmptyPolicy extends EntityPrivacyPolicy<BlahFields, string, ViewerContext, BlahEntity> {
217
- protected readonly createRules = [];
218
- protected readonly readRules = [];
219
- protected readonly updateRules = [];
220
- protected readonly deleteRules = [];
221
+ protected override readonly createRules = [];
222
+ protected override readonly readRules = [];
223
+ protected override readonly updateRules = [];
224
+ protected override readonly deleteRules = [];
221
225
  }
222
226
 
223
227
  const blahEntityCompanionDefinition = new EntityCompanionDefinition({
@@ -237,143 +241,276 @@ const blahEntityCompanionDefinition = new EntityCompanionDefinition({
237
241
  });
238
242
 
239
243
  describe(EntityPrivacyPolicy, () => {
240
- it('throws EntityNotAuthorizedError when deny', async () => {
241
- const viewerContext = instance(mock(ViewerContext));
242
- const queryContext = instance(mock(EntityQueryContext));
243
- const entity = new BlahEntity(viewerContext, { id: '1' });
244
- const policy = new AlwaysDenyPolicy();
245
- await expect(
246
- policy.authorizeCreateAsync(viewerContext, queryContext, entity)
247
- ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
248
- });
244
+ describe(EntityPrivacyPolicyEvaluationMode.ENFORCE.toString(), () => {
245
+ it('throws EntityNotAuthorizedError when deny', async () => {
246
+ const viewerContext = instance(mock(ViewerContext));
247
+ const queryContext = instance(mock(EntityQueryContext));
248
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
249
+ const metricsAdapter = instance(metricsAdapterMock);
250
+ const entity = new BlahEntity(viewerContext, { id: '1' });
251
+ const policy = new AlwaysDenyPolicy();
252
+ await expect(
253
+ policy.authorizeCreateAsync(viewerContext, queryContext, entity, metricsAdapter)
254
+ ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
255
+ verify(
256
+ metricsAdapterMock.logAuthorizationEvent(
257
+ objectContaining({
258
+ entityClassName: entity.constructor.name,
259
+ action: EntityAuthorizationAction.CREATE,
260
+ evaluationResult: EntityMetricsAuthorizationResult.DENY,
261
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.ENFORCE,
262
+ })
263
+ )
264
+ ).once();
265
+ });
249
266
 
250
- it('returns entity when allowed', async () => {
251
- const viewerContext = instance(mock(ViewerContext));
252
- const queryContext = instance(mock(EntityQueryContext));
253
- const entity = new BlahEntity(viewerContext, { id: '1' });
254
- const policy = new AlwaysAllowPolicy();
255
- const approvedEntity = await policy.authorizeCreateAsync(viewerContext, queryContext, entity);
256
- expect(approvedEntity).toEqual(entity);
257
- });
267
+ it('returns entity when allowed', async () => {
268
+ const viewerContext = instance(mock(ViewerContext));
269
+ const queryContext = instance(mock(EntityQueryContext));
270
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
271
+ const metricsAdapter = instance(metricsAdapterMock);
272
+ const entity = new BlahEntity(viewerContext, { id: '1' });
273
+ const policy = new AlwaysAllowPolicy();
274
+ const approvedEntity = await policy.authorizeCreateAsync(
275
+ viewerContext,
276
+ queryContext,
277
+ entity,
278
+ metricsAdapter
279
+ );
280
+ expect(approvedEntity).toEqual(entity);
281
+ verify(
282
+ metricsAdapterMock.logAuthorizationEvent(
283
+ objectContaining({
284
+ entityClassName: entity.constructor.name,
285
+ action: EntityAuthorizationAction.CREATE,
286
+ evaluationResult: EntityMetricsAuthorizationResult.ALLOW,
287
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.ENFORCE,
288
+ })
289
+ )
290
+ ).once();
291
+ });
258
292
 
259
- it('throws EntityNotAuthorizedError when all skipped', async () => {
260
- const viewerContext = instance(mock(ViewerContext));
261
- const queryContext = instance(mock(EntityQueryContext));
262
- const entity = new BlahEntity(viewerContext, { id: '1' });
263
- const policy = new SkipAllPolicy();
264
- await expect(
265
- policy.authorizeCreateAsync(viewerContext, queryContext, entity)
266
- ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
267
- });
293
+ it('throws EntityNotAuthorizedError when all skipped', async () => {
294
+ const viewerContext = instance(mock(ViewerContext));
295
+ const queryContext = instance(mock(EntityQueryContext));
296
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
297
+ const metricsAdapter = instance(metricsAdapterMock);
298
+ const entity = new BlahEntity(viewerContext, { id: '1' });
299
+ const policy = new SkipAllPolicy();
300
+ await expect(
301
+ policy.authorizeCreateAsync(viewerContext, queryContext, entity, metricsAdapter)
302
+ ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
303
+ verify(
304
+ metricsAdapterMock.logAuthorizationEvent(
305
+ objectContaining({
306
+ entityClassName: entity.constructor.name,
307
+ action: EntityAuthorizationAction.CREATE,
308
+ evaluationResult: EntityMetricsAuthorizationResult.DENY,
309
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.ENFORCE,
310
+ })
311
+ )
312
+ ).once();
313
+ });
268
314
 
269
- it('throws EntityNotAuthorizedError when empty policy', async () => {
270
- const viewerContext = instance(mock(ViewerContext));
271
- const queryContext = instance(mock(EntityQueryContext));
272
- const entity = new BlahEntity(viewerContext, { id: '1' });
273
- const policy = new EmptyPolicy();
274
- await expect(
275
- policy.authorizeCreateAsync(viewerContext, queryContext, entity)
276
- ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
277
- });
315
+ it('throws EntityNotAuthorizedError when empty policy', async () => {
316
+ const viewerContext = instance(mock(ViewerContext));
317
+ const queryContext = instance(mock(EntityQueryContext));
318
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
319
+ const metricsAdapter = instance(metricsAdapterMock);
320
+ const entity = new BlahEntity(viewerContext, { id: '1' });
321
+ const policy = new EmptyPolicy();
322
+ await expect(
323
+ policy.authorizeCreateAsync(viewerContext, queryContext, entity, metricsAdapter)
324
+ ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
325
+ verify(
326
+ metricsAdapterMock.logAuthorizationEvent(
327
+ objectContaining({
328
+ entityClassName: entity.constructor.name,
329
+ action: EntityAuthorizationAction.CREATE,
330
+ evaluationResult: EntityMetricsAuthorizationResult.DENY,
331
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.ENFORCE,
332
+ })
333
+ )
334
+ ).once();
335
+ });
278
336
 
279
- it('throws when rule throws', async () => {
280
- const viewerContext = instance(mock(ViewerContext));
281
- const queryContext = instance(mock(EntityQueryContext));
282
- const entity = new BlahEntity(viewerContext, { id: '1' });
283
- const policy = new ThrowAllPolicy();
284
- await expect(
285
- policy.authorizeCreateAsync(viewerContext, queryContext, entity)
286
- ).rejects.toThrowError('WooHoo!');
337
+ it('throws when rule throws', async () => {
338
+ const viewerContext = instance(mock(ViewerContext));
339
+ const queryContext = instance(mock(EntityQueryContext));
340
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
341
+ const metricsAdapter = instance(metricsAdapterMock);
342
+ const entity = new BlahEntity(viewerContext, { id: '1' });
343
+ const policy = new ThrowAllPolicy();
344
+ await expect(
345
+ policy.authorizeCreateAsync(viewerContext, queryContext, entity, metricsAdapter)
346
+ ).rejects.toThrowError('WooHoo!');
347
+ verify(metricsAdapterMock.logAuthorizationEvent(anything())).never();
348
+ });
287
349
  });
288
350
 
289
- describe('dry run', () => {
351
+ describe(EntityPrivacyPolicyEvaluationMode.DRY_RUN.toString(), () => {
290
352
  it('returns entity when denied but calls denialHandler', async () => {
291
353
  const viewerContext = instance(mock(ViewerContext));
292
354
  const queryContext = instance(mock(EntityQueryContext));
355
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
356
+ const metricsAdapter = instance(metricsAdapterMock);
293
357
  const entity = new BlahEntity(viewerContext, { id: '1' });
294
358
  const policy = new DryRunAlwaysDenyPolicy();
295
359
 
296
360
  const policySpy = spy(policy);
297
361
 
298
- const approvedEntity = await policy.authorizeCreateAsync(viewerContext, queryContext, entity);
362
+ const approvedEntity = await policy.authorizeCreateAsync(
363
+ viewerContext,
364
+ queryContext,
365
+ entity,
366
+ metricsAdapter
367
+ );
299
368
  expect(approvedEntity).toEqual(entity);
300
369
 
301
370
  verify(policySpy.denyHandler(anyOfClass(EntityNotAuthorizedError))).once();
371
+
372
+ verify(
373
+ metricsAdapterMock.logAuthorizationEvent(
374
+ objectContaining({
375
+ entityClassName: entity.constructor.name,
376
+ action: EntityAuthorizationAction.CREATE,
377
+ evaluationResult: EntityMetricsAuthorizationResult.DENY,
378
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.DRY_RUN,
379
+ })
380
+ )
381
+ ).once();
302
382
  });
303
383
 
304
384
  it('does not log when not denied', async () => {
305
385
  const viewerContext = instance(mock(ViewerContext));
306
386
  const queryContext = instance(mock(EntityQueryContext));
387
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
388
+ const metricsAdapter = instance(metricsAdapterMock);
307
389
  const entity = new BlahEntity(viewerContext, { id: '1' });
308
390
  const policy = new DryRunAlwaysAllowPolicy();
309
391
 
310
392
  const policySpy = spy(policy);
311
393
 
312
- const approvedEntity = await policy.authorizeCreateAsync(viewerContext, queryContext, entity);
394
+ const approvedEntity = await policy.authorizeCreateAsync(
395
+ viewerContext,
396
+ queryContext,
397
+ entity,
398
+ metricsAdapter
399
+ );
313
400
  expect(approvedEntity).toEqual(entity);
314
401
 
315
402
  verify(policySpy.denyHandler(anyOfClass(EntityNotAuthorizedError))).never();
403
+
404
+ verify(
405
+ metricsAdapterMock.logAuthorizationEvent(
406
+ objectContaining({
407
+ entityClassName: entity.constructor.name,
408
+ action: EntityAuthorizationAction.CREATE,
409
+ evaluationResult: EntityMetricsAuthorizationResult.ALLOW,
410
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.DRY_RUN,
411
+ })
412
+ )
413
+ ).once();
316
414
  });
317
415
 
318
416
  it('passes through other errors', async () => {
319
417
  const viewerContext = instance(mock(ViewerContext));
320
418
  const queryContext = instance(mock(EntityQueryContext));
419
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
420
+ const metricsAdapter = instance(metricsAdapterMock);
321
421
  const entity = new BlahEntity(viewerContext, { id: '1' });
322
422
  const policy = new DryRunThrowAllPolicy();
323
423
 
324
424
  const policySpy = spy(policy);
325
425
 
326
426
  await expect(
327
- policy.authorizeCreateAsync(viewerContext, queryContext, entity)
427
+ policy.authorizeCreateAsync(viewerContext, queryContext, entity, metricsAdapter)
328
428
  ).rejects.toThrowError('WooHoo!');
329
429
 
330
430
  verify(policySpy.denyHandler(anyOfClass(EntityNotAuthorizedError))).never();
431
+
432
+ verify(metricsAdapterMock.logAuthorizationEvent(anything())).never();
331
433
  });
332
434
  });
333
435
 
334
- describe('logging enforce', () => {
436
+ describe(EntityPrivacyPolicyEvaluationMode.ENFORCE_AND_LOG.toString(), () => {
335
437
  it('denies when denied but calls denialHandler', async () => {
336
438
  const viewerContext = instance(mock(ViewerContext));
337
439
  const queryContext = instance(mock(EntityQueryContext));
440
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
441
+ const metricsAdapter = instance(metricsAdapterMock);
338
442
  const entity = new BlahEntity(viewerContext, { id: '1' });
339
443
  const policy = new LoggingEnforceAlwaysDenyPolicy();
340
444
 
341
445
  const policySpy = spy(policy);
342
446
 
343
447
  await expect(
344
- policy.authorizeCreateAsync(viewerContext, queryContext, entity)
448
+ policy.authorizeCreateAsync(viewerContext, queryContext, entity, metricsAdapter)
345
449
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
346
450
 
347
451
  verify(policySpy.denyHandler(anyOfClass(EntityNotAuthorizedError))).once();
452
+
453
+ verify(
454
+ metricsAdapterMock.logAuthorizationEvent(
455
+ objectContaining({
456
+ entityClassName: entity.constructor.name,
457
+ action: EntityAuthorizationAction.CREATE,
458
+ evaluationResult: EntityMetricsAuthorizationResult.DENY,
459
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.ENFORCE_AND_LOG,
460
+ })
461
+ )
462
+ ).once();
348
463
  });
349
464
 
350
465
  it('does not log when not denied', async () => {
351
466
  const viewerContext = instance(mock(ViewerContext));
352
467
  const queryContext = instance(mock(EntityQueryContext));
468
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
469
+ const metricsAdapter = instance(metricsAdapterMock);
353
470
  const entity = new BlahEntity(viewerContext, { id: '1' });
354
471
  const policy = new LoggingEnforceAlwaysAllowPolicy();
355
472
 
356
473
  const policySpy = spy(policy);
357
474
 
358
- const approvedEntity = await policy.authorizeCreateAsync(viewerContext, queryContext, entity);
475
+ const approvedEntity = await policy.authorizeCreateAsync(
476
+ viewerContext,
477
+ queryContext,
478
+ entity,
479
+ metricsAdapter
480
+ );
359
481
  expect(approvedEntity).toEqual(entity);
360
482
 
361
483
  verify(policySpy.denyHandler(anyOfClass(EntityNotAuthorizedError))).never();
484
+
485
+ verify(
486
+ metricsAdapterMock.logAuthorizationEvent(
487
+ objectContaining({
488
+ entityClassName: entity.constructor.name,
489
+ action: EntityAuthorizationAction.CREATE,
490
+ evaluationResult: EntityMetricsAuthorizationResult.ALLOW,
491
+ privacyPolicyEvaluationMode: EntityPrivacyPolicyEvaluationMode.ENFORCE_AND_LOG,
492
+ })
493
+ )
494
+ ).once();
362
495
  });
363
496
 
364
497
  it('passes through other errors', async () => {
365
498
  const viewerContext = instance(mock(ViewerContext));
366
499
  const queryContext = instance(mock(EntityQueryContext));
500
+ const metricsAdapterMock = mock<IEntityMetricsAdapter>();
501
+ const metricsAdapter = instance(metricsAdapterMock);
367
502
  const entity = new BlahEntity(viewerContext, { id: '1' });
368
503
  const policy = new LoggingEnforceThrowAllPolicy();
369
504
 
370
505
  const policySpy = spy(policy);
371
506
 
372
507
  await expect(
373
- policy.authorizeCreateAsync(viewerContext, queryContext, entity)
508
+ policy.authorizeCreateAsync(viewerContext, queryContext, entity, metricsAdapter)
374
509
  ).rejects.toThrowError('WooHoo!');
375
510
 
376
511
  verify(policySpy.denyHandler(anyOfClass(EntityNotAuthorizedError))).never();
512
+
513
+ verify(metricsAdapterMock.logAuthorizationEvent(anything())).never();
377
514
  });
378
515
  });
379
516
  });
@@ -35,9 +35,8 @@ describe(EntitySecondaryCacheLoader, () => {
35
35
  const createdEntity = await SimpleTestEntity.creator(vc1).enforceCreateAsync();
36
36
  const loadParams = { id: createdEntity.getID() };
37
37
 
38
- const secondaryEntityCacheMock = mock<
39
- ISecondaryEntityCache<SimpleTestFields, TestLoadParams>
40
- >();
38
+ const secondaryEntityCacheMock =
39
+ mock<ISecondaryEntityCache<SimpleTestFields, TestLoadParams>>();
41
40
  when(
42
41
  secondaryEntityCacheMock.loadManyThroughAsync(deepEqual([loadParams]), anything())
43
42
  ).thenResolve(new Map());
@@ -61,9 +60,8 @@ describe(EntitySecondaryCacheLoader, () => {
61
60
  const createdEntity = await SimpleTestEntity.creator(vc1).enforceCreateAsync();
62
61
  const loadParams = { id: createdEntity.getID() };
63
62
 
64
- const secondaryEntityCacheMock = mock<
65
- ISecondaryEntityCache<SimpleTestFields, TestLoadParams>
66
- >();
63
+ const secondaryEntityCacheMock =
64
+ mock<ISecondaryEntityCache<SimpleTestFields, TestLoadParams>>();
67
65
  when(
68
66
  secondaryEntityCacheMock.loadManyThroughAsync(deepEqual([loadParams]), anything())
69
67
  ).thenResolve(new Map([[loadParams, createdEntity.getAllFields()]]));
@@ -80,6 +78,7 @@ describe(EntitySecondaryCacheLoader, () => {
80
78
  spiedPrivacyPolicy.authorizeReadAsync(
81
79
  vc1,
82
80
  anyOfClass(EntityNonTransactionalQueryContext),
81
+ anything(),
83
82
  anything()
84
83
  )
85
84
  ).once();
@@ -93,9 +92,8 @@ describe(EntitySecondaryCacheLoader, () => {
93
92
  const createdEntity = await SimpleTestEntity.creator(vc1).enforceCreateAsync();
94
93
  const loadParams = { id: createdEntity.getID() };
95
94
 
96
- const secondaryEntityCacheMock = mock<
97
- ISecondaryEntityCache<SimpleTestFields, TestLoadParams>
98
- >();
95
+ const secondaryEntityCacheMock =
96
+ mock<ISecondaryEntityCache<SimpleTestFields, TestLoadParams>>();
99
97
  const secondaryEntityCache = instance(secondaryEntityCacheMock);
100
98
  const loader = SimpleTestEntity.loader(vc1);
101
99
  const secondaryCacheLoader = new TestSecondaryRedisCacheLoader(secondaryEntityCache, loader);
@@ -1,7 +1,8 @@
1
1
  import Entity from '../Entity';
2
2
  import { EntityCompanionDefinition } from '../EntityCompanionProvider';
3
3
  import EntityConfiguration from '../EntityConfiguration';
4
- import { UUIDField, EntityEdgeDeletionBehavior } from '../EntityFields';
4
+ import { EntityEdgeDeletionBehavior } from '../EntityFieldDefinition';
5
+ import { UUIDField } from '../EntityFields';
5
6
  import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
6
7
  import { CacheStatus } from '../internal/ReadThroughEntityCache';
7
8
  import AlwaysAllowPrivacyPolicyRule from '../rules/AlwaysAllowPrivacyPolicyRule';
@@ -21,16 +22,16 @@ class CategoryPrivacyPolicy extends EntityPrivacyPolicy<
21
22
  any,
22
23
  any
23
24
  > {
24
- protected readonly readRules = [
25
+ protected override readonly readRules = [
25
26
  new AlwaysAllowPrivacyPolicyRule<CategoryFields, string, TestViewerContext, any, any>(),
26
27
  ];
27
- protected readonly createRules = [
28
+ protected override readonly createRules = [
28
29
  new AlwaysAllowPrivacyPolicyRule<CategoryFields, string, TestViewerContext, any, any>(),
29
30
  ];
30
- protected readonly updateRules = [
31
+ protected override readonly updateRules = [
31
32
  new AlwaysAllowPrivacyPolicyRule<CategoryFields, string, TestViewerContext, any, any>(),
32
33
  ];
33
- protected readonly deleteRules = [
34
+ protected override readonly deleteRules = [
34
35
  new AlwaysAllowPrivacyPolicyRule<CategoryFields, string, TestViewerContext, any, any>(),
35
36
  ];
36
37
  }
@@ -60,7 +60,7 @@ describe(ReadonlyEntity, () => {
60
60
  customIdField: '1',
61
61
  testIndexedField: '2',
62
62
  stringField: '3',
63
- numberField: 4,
63
+ intField: 4,
64
64
  dateField: new Date(),
65
65
  nullableField: null,
66
66
  });
@@ -17,12 +17,13 @@ describe(ViewerContext, () => {
17
17
  it('creates a new transactional query context', async () => {
18
18
  const companionProvider = createUnitTestEntityCompanionProvider();
19
19
  const viewerContext = new ViewerContext(companionProvider);
20
- const didCreateTransaction = await viewerContext.runInTransactionForDatabaseAdaptorFlavorAsync(
21
- 'postgres',
22
- async (queryContext) => {
23
- return queryContext.isInTransaction();
24
- }
25
- );
20
+ const didCreateTransaction =
21
+ await viewerContext.runInTransactionForDatabaseAdaptorFlavorAsync(
22
+ 'postgres',
23
+ async (queryContext) => {
24
+ return queryContext.isInTransaction();
25
+ }
26
+ );
26
27
  expect(didCreateTransaction).toBe(true);
27
28
  });
28
29
  });
@@ -10,16 +10,17 @@ import TestEntity, { TestFields, TestEntityPrivacyPolicy } from '../testfixtures
10
10
  describe(ViewerScopedEntityCompanion, () => {
11
11
  it('returns viewer scoped loader and mutator factory', () => {
12
12
  const vc = instance(mock(ViewerContext));
13
- const entityCompanion = mock<
14
- EntityCompanion<
15
- TestFields,
16
- string,
17
- ViewerContext,
18
- TestEntity,
19
- TestEntityPrivacyPolicy,
20
- keyof TestFields
21
- >
22
- >();
13
+ const entityCompanion =
14
+ mock<
15
+ EntityCompanion<
16
+ TestFields,
17
+ string,
18
+ ViewerContext,
19
+ TestEntity,
20
+ TestEntityPrivacyPolicy,
21
+ keyof TestFields
22
+ >
23
+ >();
23
24
  const viewerScopedEntityCompanion = new ViewerScopedEntityCompanion(entityCompanion, vc);
24
25
  expect(viewerScopedEntityCompanion.getLoaderFactory()).toBeInstanceOf(
25
26
  ViewerScopedEntityLoaderFactory
@@ -10,9 +10,10 @@ describe(ViewerScopedEntityMutatorFactory, () => {
10
10
  it('correctly scopes viewer to entity mutations', async () => {
11
11
  const viewerContext = instance(mock(ViewerContext));
12
12
  const queryContext = instance(mock(EntityQueryContext));
13
- const baseMutatorFactory = mock<
14
- EntityMutatorFactory<TestFields, string, ViewerContext, TestEntity, TestEntityPrivacyPolicy>
15
- >(EntityMutatorFactory);
13
+ const baseMutatorFactory =
14
+ mock<
15
+ EntityMutatorFactory<TestFields, string, ViewerContext, TestEntity, TestEntityPrivacyPolicy>
16
+ >(EntityMutatorFactory);
16
17
  const baseMutatorFactoryInstance = instance(baseMutatorFactory);
17
18
 
18
19
  const viewerScopedEntityLoader = new ViewerScopedEntityMutatorFactory<