@expo/entity 0.39.0 → 0.41.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 (175) hide show
  1. package/build/AuthorizationResultBasedEntityAssociationLoader.d.ts +99 -0
  2. package/build/AuthorizationResultBasedEntityAssociationLoader.js +122 -0
  3. package/build/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -0
  4. package/build/AuthorizationResultBasedEntityLoader.d.ts +1 -1
  5. package/build/AuthorizationResultBasedEntityLoader.js.map +1 -1
  6. package/build/{EntityMutator.d.ts → AuthorizationResultBasedEntityMutator.d.ts} +5 -17
  7. package/build/{EntityMutator.js → AuthorizationResultBasedEntityMutator.js} +22 -48
  8. package/build/AuthorizationResultBasedEntityMutator.js.map +1 -0
  9. package/build/EnforcingEntityAssociationLoader.d.ts +79 -0
  10. package/build/EnforcingEntityAssociationLoader.js +62 -0
  11. package/build/EnforcingEntityAssociationLoader.js.map +1 -0
  12. package/build/EnforcingEntityCreator.d.ts +24 -0
  13. package/build/EnforcingEntityCreator.js +32 -0
  14. package/build/EnforcingEntityCreator.js.map +1 -0
  15. package/build/EnforcingEntityDeleter.d.ts +17 -0
  16. package/build/EnforcingEntityDeleter.js +22 -0
  17. package/build/EnforcingEntityDeleter.js.map +1 -0
  18. package/build/EnforcingEntityUpdater.d.ts +24 -0
  19. package/build/EnforcingEntityUpdater.js +32 -0
  20. package/build/EnforcingEntityUpdater.js.map +1 -0
  21. package/build/Entity.d.ts +26 -8
  22. package/build/Entity.js +38 -25
  23. package/build/Entity.js.map +1 -1
  24. package/build/EntityAssociationLoader.d.ts +12 -91
  25. package/build/EntityAssociationLoader.js +20 -126
  26. package/build/EntityAssociationLoader.js.map +1 -1
  27. package/build/EntityCreator.d.ts +27 -0
  28. package/build/EntityCreator.js +39 -0
  29. package/build/EntityCreator.js.map +1 -0
  30. package/build/EntityDeleter.d.ts +27 -0
  31. package/build/EntityDeleter.js +40 -0
  32. package/build/EntityDeleter.js.map +1 -0
  33. package/build/EntityLoader.d.ts +4 -14
  34. package/build/EntityLoader.js +7 -20
  35. package/build/EntityLoader.js.map +1 -1
  36. package/build/EntityLoaderFactory.d.ts +2 -2
  37. package/build/EntityLoaderFactory.js +4 -2
  38. package/build/EntityLoaderFactory.js.map +1 -1
  39. package/build/EntityMutatorFactory.d.ts +4 -4
  40. package/build/EntityMutatorFactory.js +4 -4
  41. package/build/EntityMutatorFactory.js.map +1 -1
  42. package/build/EntitySecondaryCacheLoader.d.ts +3 -3
  43. package/build/EntitySecondaryCacheLoader.js +1 -3
  44. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  45. package/build/EntityUpdater.d.ts +27 -0
  46. package/build/EntityUpdater.js +40 -0
  47. package/build/EntityUpdater.js.map +1 -0
  48. package/build/ReadonlyEntity.d.ts +24 -5
  49. package/build/ReadonlyEntity.js +33 -7
  50. package/build/ReadonlyEntity.js.map +1 -1
  51. package/build/ViewerScopedEntityLoaderFactory.d.ts +2 -2
  52. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  53. package/build/ViewerScopedEntityMutatorFactory.d.ts +4 -4
  54. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  55. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.d.ts +1 -0
  56. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js +242 -0
  57. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js.map +1 -0
  58. package/build/__tests__/{EntityLoader-constructor-test.js → AuthorizationResultBasedEntityLoader-constructor-test.js} +10 -10
  59. package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js.map +1 -0
  60. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.d.ts +1 -0
  61. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js +401 -0
  62. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js.map +1 -0
  63. package/build/__tests__/EnforcingEntityAssociationLoader-test.d.ts +1 -0
  64. package/build/__tests__/EnforcingEntityAssociationLoader-test.js +115 -0
  65. package/build/__tests__/EnforcingEntityAssociationLoader-test.js.map +1 -0
  66. package/build/__tests__/Entity-test.js +63 -5
  67. package/build/__tests__/Entity-test.js.map +1 -1
  68. package/build/__tests__/EntityAssociationLoader-test.js +14 -184
  69. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  70. package/build/__tests__/EntityCommonUseCases-test.js +34 -20
  71. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  72. package/build/__tests__/EntityCompanion-test.js +17 -7
  73. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  74. package/build/__tests__/EntityEdges-test.js +57 -71
  75. package/build/__tests__/EntityEdges-test.js.map +1 -1
  76. package/build/__tests__/EntityLoader-test.js +22 -386
  77. package/build/__tests__/EntityLoader-test.js.map +1 -1
  78. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +6 -9
  79. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  80. package/build/__tests__/EntityMutator-test.js +67 -70
  81. package/build/__tests__/EntityMutator-test.js.map +1 -1
  82. package/build/__tests__/EntityPrivacyPolicy-test.js +17 -7
  83. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  84. package/build/__tests__/EntitySecondaryCacheLoader-test.js +7 -7
  85. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
  86. package/build/__tests__/EntitySelfReferentialEdges-test.js +47 -81
  87. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  88. package/build/__tests__/ReadonlyEntity-test.js +40 -7
  89. package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
  90. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +6 -10
  91. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  92. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +10 -22
  93. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  94. package/build/errors/EntityCacheAdapterError.js +17 -7
  95. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  96. package/build/errors/EntityDatabaseAdapterError.js +17 -7
  97. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  98. package/build/errors/EntityInvalidFieldValueError.js +17 -7
  99. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  100. package/build/errors/EntityNotAuthorizedError.js +17 -7
  101. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  102. package/build/errors/EntityNotFoundError.js +17 -7
  103. package/build/errors/EntityNotFoundError.js.map +1 -1
  104. package/build/index.d.ts +19 -11
  105. package/build/index.js +24 -7
  106. package/build/index.js.map +1 -1
  107. package/build/internal/__tests__/EntityDataManager-test.js +42 -32
  108. package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
  109. package/build/internal/__tests__/ReadThroughEntityCache-test.js +17 -7
  110. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  111. package/build/rules/AlwaysAllowPrivacyPolicyRule.js +17 -7
  112. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  113. package/build/rules/AlwaysDenyPrivacyPolicyRule.js +17 -7
  114. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  115. package/build/rules/AlwaysSkipPrivacyPolicyRule.js +17 -7
  116. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  117. package/build/utils/EntityPrivacyUtils.js +4 -8
  118. package/build/utils/EntityPrivacyUtils.js.map +1 -1
  119. package/build/utils/__tests__/EntityPrivacyUtils-test.js +38 -28
  120. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -1
  121. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js +5 -5
  122. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js.map +1 -1
  123. package/build/utils/testing/StubDatabaseAdapter.js +17 -7
  124. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  125. package/build/utils/testing/StubQueryContextProvider.d.ts +1 -3
  126. package/build/utils/testing/StubQueryContextProvider.js +1 -3
  127. package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
  128. package/build/utils/testing/createUnitTestEntityCompanionProvider.js +2 -1
  129. package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +1 -1
  130. package/package.json +19 -3
  131. package/src/AuthorizationResultBasedEntityAssociationLoader.ts +490 -0
  132. package/src/AuthorizationResultBasedEntityLoader.ts +1 -1
  133. package/src/{EntityMutator.ts → AuthorizationResultBasedEntityMutator.ts} +62 -58
  134. package/src/EnforcingEntityAssociationLoader.ts +390 -0
  135. package/src/EnforcingEntityCreator.ts +55 -0
  136. package/src/EnforcingEntityDeleter.ts +44 -0
  137. package/src/EnforcingEntityUpdater.ts +55 -0
  138. package/src/Entity.ts +140 -29
  139. package/src/EntityAssociationLoader.ts +38 -495
  140. package/src/EntityCreator.ts +73 -0
  141. package/src/EntityDeleter.ts +73 -0
  142. package/src/EntityLoader.ts +10 -49
  143. package/src/EntityLoaderFactory.ts +20 -3
  144. package/src/EntityMutatorFactory.ts +32 -7
  145. package/src/EntitySecondaryCacheLoader.ts +5 -7
  146. package/src/EntityUpdater.ts +73 -0
  147. package/src/ReadonlyEntity.ts +121 -7
  148. package/src/ViewerScopedEntityLoaderFactory.ts +9 -2
  149. package/src/ViewerScopedEntityMutatorFactory.ts +29 -4
  150. package/src/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.ts +323 -0
  151. package/src/__tests__/{EntityLoader-constructor-test.ts → AuthorizationResultBasedEntityLoader-constructor-test.ts} +16 -9
  152. package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +730 -0
  153. package/src/__tests__/EnforcingEntityAssociationLoader-test.ts +253 -0
  154. package/src/__tests__/Entity-test.ts +77 -5
  155. package/src/__tests__/EntityAssociationLoader-test.ts +15 -260
  156. package/src/__tests__/EntityCommonUseCases-test.ts +24 -15
  157. package/src/__tests__/EntityEdges-test.ts +44 -64
  158. package/src/__tests__/EntityLoader-test.ts +29 -681
  159. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +8 -9
  160. package/src/__tests__/EntityMutator-test.ts +116 -103
  161. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
  162. package/src/__tests__/EntitySelfReferentialEdges-test.ts +65 -81
  163. package/src/__tests__/ReadonlyEntity-test.ts +47 -7
  164. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +15 -15
  165. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +19 -22
  166. package/src/index.ts +19 -11
  167. package/src/internal/__tests__/EntityDataManager-test.ts +25 -25
  168. package/src/utils/EntityPrivacyUtils.ts +10 -13
  169. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +21 -23
  170. package/src/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.ts +5 -5
  171. package/src/utils/testing/StubQueryContextProvider.ts +1 -3
  172. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +3 -1
  173. package/build/EntityMutator.js.map +0 -1
  174. package/build/__tests__/EntityLoader-constructor-test.js.map +0 -1
  175. /package/build/__tests__/{EntityLoader-constructor-test.d.ts → AuthorizationResultBasedEntityLoader-constructor-test.d.ts} +0 -0
@@ -1,687 +1,35 @@
1
- import { enforceAsyncResult } from '@expo/results';
2
- import { mock, instance, verify, spy, deepEqual, anyOfClass, anything, when } from 'ts-mockito';
3
- import { v4 as uuidv4 } from 'uuid';
4
-
5
- import { OrderByOrdering } from '../EntityDatabaseAdapter';
1
+ import AuthorizationResultBasedEntityLoader from '../AuthorizationResultBasedEntityLoader';
2
+ import EnforcingEntityLoader from '../EnforcingEntityLoader';
6
3
  import EntityLoader from '../EntityLoader';
7
- import { EntityPrivacyPolicyEvaluationContext } from '../EntityPrivacyPolicy';
4
+ import EntityLoaderUtils from '../EntityLoaderUtils';
8
5
  import ViewerContext from '../ViewerContext';
9
- import { enforceResultsAsync } from '../entityUtils';
10
- import EntityNotFoundError from '../errors/EntityNotFoundError';
11
- import EntityDataManager from '../internal/EntityDataManager';
12
- import ReadThroughEntityCache from '../internal/ReadThroughEntityCache';
13
- import IEntityMetricsAdapter from '../metrics/IEntityMetricsAdapter';
14
- import TestEntity, {
15
- TestFields,
16
- TestEntityPrivacyPolicy,
17
- testEntityConfiguration,
18
- } from '../testfixtures/TestEntity';
19
- import { NoCacheStubCacheAdapterProvider } from '../utils/testing/StubCacheAdapter';
20
- import StubDatabaseAdapter from '../utils/testing/StubDatabaseAdapter';
21
- import StubQueryContextProvider from '../utils/testing/StubQueryContextProvider';
6
+ import SimpleTestEntity from '../testfixtures/SimpleTestEntity';
7
+ import { createUnitTestEntityCompanionProvider } from '../utils/testing/createUnitTestEntityCompanionProvider';
22
8
 
23
9
  describe(EntityLoader, () => {
24
- it('loads entities', async () => {
25
- const dateToInsert = new Date();
26
- const viewerContext = instance(mock(ViewerContext));
27
- const privacyPolicyEvaluationContext =
28
- instance(
29
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
30
- );
31
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
32
- const queryContext = StubQueryContextProvider.getQueryContext();
33
-
34
- const id1 = uuidv4();
35
- const id2 = uuidv4();
36
- const databaseAdapter = new StubDatabaseAdapter<TestFields>(
37
- testEntityConfiguration,
38
- StubDatabaseAdapter.convertFieldObjectsToDataStore(
39
- testEntityConfiguration,
40
- new Map([
41
- [
42
- testEntityConfiguration.tableName,
43
- [
44
- {
45
- customIdField: id1,
46
- testIndexedField: 'h1',
47
- intField: 5,
48
- stringField: 'huh',
49
- dateField: dateToInsert,
50
- nullableField: null,
51
- },
52
- {
53
- customIdField: id2,
54
- testIndexedField: 'h2',
55
- intField: 3,
56
- stringField: 'huh',
57
- dateField: dateToInsert,
58
- nullableField: null,
59
- },
60
- ],
61
- ],
62
- ]),
63
- ),
64
- );
65
- const privacyPolicy = new TestEntityPrivacyPolicy();
66
- const cacheAdapterProvider = new NoCacheStubCacheAdapterProvider();
67
- const cacheAdapter = cacheAdapterProvider.getCacheAdapter(testEntityConfiguration);
68
- const entityCache = new ReadThroughEntityCache(testEntityConfiguration, cacheAdapter);
69
- const dataManager = new EntityDataManager(
70
- databaseAdapter,
71
- entityCache,
72
- StubQueryContextProvider,
73
- instance(mock<IEntityMetricsAdapter>()),
74
- TestEntity.name,
75
- );
76
- const entityLoader = new EntityLoader(
77
- viewerContext,
78
- queryContext,
79
- privacyPolicyEvaluationContext,
80
- testEntityConfiguration,
81
- TestEntity,
82
- /* entitySelectedFields */ undefined,
83
- privacyPolicy,
84
- dataManager,
85
- metricsAdapter,
86
- );
87
- const entity = await enforceAsyncResult(
88
- entityLoader.withAuthorizationResults().loadByIDAsync(id1),
89
- );
90
- expect(entity.getID()).toEqual(id1);
91
- expect(entity.getField('dateField')).toEqual(dateToInsert);
92
-
93
- const entities = await enforceResultsAsync(
94
- entityLoader.withAuthorizationResults().loadManyByFieldEqualingAsync('stringField', 'huh'),
95
- );
96
- expect(entities.map((m) => m.getID())).toEqual([id1, id2]);
97
-
98
- const entityResultNumber3 = await entityLoader
99
- .withAuthorizationResults()
100
- .loadByFieldEqualingAsync('intField', 3);
101
- expect(entityResultNumber3).not.toBeNull();
102
- expect(entityResultNumber3!.enforceValue().getID()).toEqual(id2);
103
-
104
- const entityResultNumber4 = await entityLoader
105
- .withAuthorizationResults()
106
- .loadByFieldEqualingAsync('intField', 4);
107
- expect(entityResultNumber4).toBeNull();
108
-
109
- const entityResultDuplicateValues = await entityLoader
110
- .enforcing()
111
- .loadManyByFieldEqualingManyAsync('stringField', ['huh', 'huh']);
112
- expect(entityResultDuplicateValues.size).toBe(1);
113
- expect(entityResultDuplicateValues.get('huh')?.map((m) => m.getID())).toEqual([id1, id2]);
114
-
115
- await expect(
116
- entityLoader.withAuthorizationResults().loadByFieldEqualingAsync('stringField', 'huh'),
117
- ).rejects.toThrowError(
118
- 'loadByFieldEqualing: Multiple entities of type TestEntity found for stringField=huh',
119
- );
120
-
121
- await expect(
122
- entityLoader.withAuthorizationResults().loadByIDNullableAsync(uuidv4()),
123
- ).resolves.toBeNull();
124
- await expect(
125
- entityLoader.withAuthorizationResults().loadByIDNullableAsync(id1),
126
- ).resolves.not.toBeNull();
127
-
128
- const nonExistentId = uuidv4();
129
- const manyIdResults = await entityLoader
130
- .withAuthorizationResults()
131
- .loadManyByIDsNullableAsync([nonExistentId, id1]);
132
- expect(manyIdResults.get(nonExistentId)).toBeNull();
133
- expect(manyIdResults.get(id1)).not.toBeNull();
134
-
135
- await expect(
136
- enforceAsyncResult(entityLoader.withAuthorizationResults().loadByIDAsync(nonExistentId)),
137
- ).rejects.toThrow(EntityNotFoundError);
138
-
139
- await expect(
140
- entityLoader.withAuthorizationResults().loadByIDAsync('not-a-uuid'),
141
- ).rejects.toThrowError('Entity field not valid: TestEntity (customIdField = not-a-uuid)');
142
- });
143
-
144
- it('loads entities with loadManyByFieldEqualityConjunction', async () => {
145
- const privacyPolicy = new TestEntityPrivacyPolicy();
146
- const spiedPrivacyPolicy = spy(privacyPolicy);
147
- const viewerContext = instance(mock(ViewerContext));
148
- const privacyPolicyEvaluationContext =
149
- instance(
150
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
151
- );
152
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
153
- const queryContext = StubQueryContextProvider.getQueryContext();
154
-
155
- const id1 = uuidv4();
156
- const id2 = uuidv4();
157
- const id3 = uuidv4();
158
- const databaseAdapter = new StubDatabaseAdapter<TestFields>(
159
- testEntityConfiguration,
160
- StubDatabaseAdapter.convertFieldObjectsToDataStore(
161
- testEntityConfiguration,
162
- new Map([
163
- [
164
- testEntityConfiguration.tableName,
165
- [
166
- {
167
- customIdField: id1,
168
- stringField: 'huh',
169
- intField: 4,
170
- testIndexedField: '4',
171
- dateField: new Date(),
172
- nullableField: null,
173
- },
174
- {
175
- customIdField: id2,
176
- stringField: 'huh',
177
- intField: 4,
178
- testIndexedField: '5',
179
- dateField: new Date(),
180
- nullableField: null,
181
- },
182
- {
183
- customIdField: id3,
184
- stringField: 'huh2',
185
- intField: 4,
186
- testIndexedField: '6',
187
- dateField: new Date(),
188
- nullableField: null,
189
- },
190
- ],
191
- ],
192
- ]),
193
- ),
194
- );
195
- const cacheAdapterProvider = new NoCacheStubCacheAdapterProvider();
196
- const cacheAdapter = cacheAdapterProvider.getCacheAdapter(testEntityConfiguration);
197
- const entityCache = new ReadThroughEntityCache(testEntityConfiguration, cacheAdapter);
198
- const dataManager = new EntityDataManager(
199
- databaseAdapter,
200
- entityCache,
201
- StubQueryContextProvider,
202
- instance(mock<IEntityMetricsAdapter>()),
203
- TestEntity.name,
204
- );
205
- const entityLoader = new EntityLoader(
206
- viewerContext,
207
- queryContext,
208
- privacyPolicyEvaluationContext,
209
- testEntityConfiguration,
210
- TestEntity,
211
- /* entitySelectedFields */ undefined,
212
- privacyPolicy,
213
- dataManager,
214
- metricsAdapter,
215
- );
216
- const entities = await enforceResultsAsync(
217
- entityLoader.withAuthorizationResults().loadManyByFieldEqualityConjunctionAsync([
218
- {
219
- fieldName: 'stringField',
220
- fieldValue: 'huh',
221
- },
222
- {
223
- fieldName: 'intField',
224
- fieldValues: [4],
225
- },
226
- ]),
227
- );
228
- expect(entities).toHaveLength(2);
229
- verify(
230
- spiedPrivacyPolicy.authorizeReadAsync(
231
- viewerContext,
232
- queryContext,
233
- privacyPolicyEvaluationContext,
234
- anyOfClass(TestEntity),
235
- anything(),
236
- ),
237
- ).twice();
238
-
239
- await expect(
240
- entityLoader
241
- .withAuthorizationResults()
242
- .loadManyByFieldEqualityConjunctionAsync([
243
- { fieldName: 'customIdField', fieldValue: 'not-a-uuid' },
244
- ]),
245
- ).rejects.toThrowError('Entity field not valid: TestEntity (customIdField = not-a-uuid)');
246
- });
247
-
248
- it('loads entities with loadFirstByFieldEqualityConjunction', async () => {
249
- const privacyPolicy = new TestEntityPrivacyPolicy();
250
- const spiedPrivacyPolicy = spy(privacyPolicy);
251
- const viewerContext = instance(mock(ViewerContext));
252
- const privacyPolicyEvaluationContext =
253
- instance(
254
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
255
- );
256
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
257
- const queryContext = StubQueryContextProvider.getQueryContext();
258
-
259
- const id1 = uuidv4();
260
- const id2 = uuidv4();
261
- const id3 = uuidv4();
262
- const databaseAdapter = new StubDatabaseAdapter<TestFields>(
263
- testEntityConfiguration,
264
- StubDatabaseAdapter.convertFieldObjectsToDataStore(
265
- testEntityConfiguration,
266
- new Map([
267
- [
268
- testEntityConfiguration.tableName,
269
- [
270
- {
271
- customIdField: id1,
272
- stringField: 'huh',
273
- intField: 4,
274
- testIndexedField: '4',
275
- dateField: new Date(),
276
- nullableField: null,
277
- },
278
- {
279
- customIdField: id2,
280
- stringField: 'huh',
281
- intField: 4,
282
- testIndexedField: '5',
283
- dateField: new Date(),
284
- nullableField: null,
285
- },
286
- {
287
- customIdField: id3,
288
- stringField: 'huh2',
289
- intField: 4,
290
- testIndexedField: '6',
291
- dateField: new Date(),
292
- nullableField: null,
293
- },
294
- ],
295
- ],
296
- ]),
297
- ),
298
- );
299
- const cacheAdapterProvider = new NoCacheStubCacheAdapterProvider();
300
- const cacheAdapter = cacheAdapterProvider.getCacheAdapter(testEntityConfiguration);
301
- const entityCache = new ReadThroughEntityCache(testEntityConfiguration, cacheAdapter);
302
- const dataManager = new EntityDataManager(
303
- databaseAdapter,
304
- entityCache,
305
- StubQueryContextProvider,
306
- instance(mock<IEntityMetricsAdapter>()),
307
- TestEntity.name,
308
- );
309
- const entityLoader = new EntityLoader(
310
- viewerContext,
311
- queryContext,
312
- privacyPolicyEvaluationContext,
313
- testEntityConfiguration,
314
- TestEntity,
315
- /* entitySelectedFields */ undefined,
316
- privacyPolicy,
317
- dataManager,
318
- metricsAdapter,
319
- );
320
- const result = await entityLoader
321
- .withAuthorizationResults()
322
- .loadFirstByFieldEqualityConjunctionAsync(
323
- [
324
- {
325
- fieldName: 'stringField',
326
- fieldValue: 'huh',
327
- },
328
- {
329
- fieldName: 'intField',
330
- fieldValue: 4,
331
- },
332
- ],
333
- { orderBy: [{ fieldName: 'testIndexedField', order: OrderByOrdering.DESCENDING }] },
334
- );
335
- expect(result).not.toBeNull();
336
- expect(result!.ok).toBe(true);
337
- expect(result!.enforceValue().getField('testIndexedField')).toEqual('5');
338
- verify(
339
- spiedPrivacyPolicy.authorizeReadAsync(
340
- viewerContext,
341
- queryContext,
342
- privacyPolicyEvaluationContext,
343
- anyOfClass(TestEntity),
344
- anything(),
345
- ),
346
- ).once();
347
- });
348
-
349
- it('loads entities with loadManyByRawWhereClauseAsync', async () => {
350
- const privacyPolicy = new TestEntityPrivacyPolicy();
351
- const spiedPrivacyPolicy = spy(privacyPolicy);
352
- const viewerContext = instance(mock(ViewerContext));
353
- const privacyPolicyEvaluationContext =
354
- instance(
355
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
356
- );
357
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
358
- const queryContext = StubQueryContextProvider.getQueryContext();
359
-
360
- const dataManagerMock = mock<EntityDataManager<TestFields>>(EntityDataManager);
361
- when(
362
- dataManagerMock.loadManyByRawWhereClauseAsync(
363
- queryContext,
364
- anything(),
365
- anything(),
366
- anything(),
367
- ),
368
- ).thenResolve([
369
- {
370
- customIdField: 'id',
371
- stringField: 'huh',
372
- intField: 4,
373
- testIndexedField: '4',
374
- dateField: new Date(),
375
- nullableField: null,
376
- },
377
- ]);
378
- const dataManager = instance(dataManagerMock);
379
- const entityLoader = new EntityLoader(
380
- viewerContext,
381
- queryContext,
382
- privacyPolicyEvaluationContext,
383
- testEntityConfiguration,
384
- TestEntity,
385
- /* entitySelectedFields */ undefined,
386
- privacyPolicy,
387
- dataManager,
388
- metricsAdapter,
389
- );
390
- const result = await entityLoader
391
- .withAuthorizationResults()
392
- .loadManyByRawWhereClauseAsync('id = ?', [1], {
393
- orderBy: [{ fieldName: 'testIndexedField', order: OrderByOrdering.DESCENDING }],
394
- });
395
- expect(result).toHaveLength(1);
396
- expect(result[0]).not.toBeNull();
397
- expect(result[0]!.ok).toBe(true);
398
- expect(result[0]!.enforceValue().getField('testIndexedField')).toEqual('4');
399
- verify(
400
- spiedPrivacyPolicy.authorizeReadAsync(
401
- viewerContext,
402
- queryContext,
403
- privacyPolicyEvaluationContext,
404
- anyOfClass(TestEntity),
405
- anything(),
406
- ),
407
- ).once();
408
- });
409
-
410
- it('authorizes loaded entities', async () => {
411
- const privacyPolicy = new TestEntityPrivacyPolicy();
412
- const spiedPrivacyPolicy = spy(privacyPolicy);
413
-
414
- const viewerContext = instance(mock(ViewerContext));
415
- const privacyPolicyEvaluationContext =
416
- instance(
417
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
418
- );
419
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
420
- const queryContext = StubQueryContextProvider.getQueryContext();
421
-
422
- const id1 = uuidv4();
423
- const databaseAdapter = new StubDatabaseAdapter<TestFields>(
424
- testEntityConfiguration,
425
- StubDatabaseAdapter.convertFieldObjectsToDataStore(
426
- testEntityConfiguration,
427
- new Map([
428
- [
429
- testEntityConfiguration.tableName,
430
- [
431
- {
432
- customIdField: id1,
433
- stringField: 'huh',
434
- testIndexedField: '1',
435
- intField: 3,
436
- dateField: new Date(),
437
- nullableField: null,
438
- },
439
- ],
440
- ],
441
- ]),
442
- ),
443
- );
444
- const cacheAdapterProvider = new NoCacheStubCacheAdapterProvider();
445
- const cacheAdapter = cacheAdapterProvider.getCacheAdapter(testEntityConfiguration);
446
- const entityCache = new ReadThroughEntityCache(testEntityConfiguration, cacheAdapter);
447
- const dataManager = new EntityDataManager(
448
- databaseAdapter,
449
- entityCache,
450
- StubQueryContextProvider,
451
- instance(mock<IEntityMetricsAdapter>()),
452
- TestEntity.name,
453
- );
454
- const entityLoader = new EntityLoader(
455
- viewerContext,
456
- queryContext,
457
- privacyPolicyEvaluationContext,
458
- testEntityConfiguration,
459
- TestEntity,
460
- /* entitySelectedFields */ undefined,
461
- privacyPolicy,
462
- dataManager,
463
- metricsAdapter,
464
- );
465
- const entity = await enforceAsyncResult(
466
- entityLoader.withAuthorizationResults().loadByIDAsync(id1),
467
- );
468
- verify(
469
- spiedPrivacyPolicy.authorizeReadAsync(
470
- viewerContext,
471
- queryContext,
472
- privacyPolicyEvaluationContext,
473
- entity,
474
- anything(),
475
- ),
476
- ).once();
477
- });
478
-
479
- it('invalidates upon invalidate one', async () => {
480
- const viewerContext = instance(mock(ViewerContext));
481
- const privacyPolicyEvaluationContext =
482
- instance(
483
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
484
- );
485
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
486
- const queryContext = StubQueryContextProvider.getQueryContext();
487
- const privacyPolicy = instance(mock(TestEntityPrivacyPolicy));
488
- const dataManagerMock = mock<EntityDataManager<TestFields>>();
489
- const dataManagerInstance = instance(dataManagerMock);
490
-
491
- const id1 = uuidv4();
492
- const entityLoader = new EntityLoader(
493
- viewerContext,
494
- queryContext,
495
- privacyPolicyEvaluationContext,
496
- testEntityConfiguration,
497
- TestEntity,
498
- /* entitySelectedFields */ undefined,
499
- privacyPolicy,
500
- dataManagerInstance,
501
- metricsAdapter,
502
- );
503
- await entityLoader.utils().invalidateFieldsAsync({ customIdField: id1 } as any);
504
-
505
- verify(
506
- dataManagerMock.invalidateObjectFieldsAsync(deepEqual({ customIdField: id1 } as any)),
507
- ).once();
508
- });
509
-
510
- it('invalidates upon invalidate by field', async () => {
511
- const viewerContext = instance(mock(ViewerContext));
512
- const privacyPolicyEvaluationContext =
513
- instance(
514
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
515
- );
516
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
517
- const queryContext = StubQueryContextProvider.getQueryContext();
518
- const privacyPolicy = instance(mock(TestEntityPrivacyPolicy));
519
- const dataManagerMock = mock<EntityDataManager<TestFields>>();
520
- const dataManagerInstance = instance(dataManagerMock);
521
-
522
- const id1 = uuidv4();
523
- const entityLoader = new EntityLoader(
524
- viewerContext,
525
- queryContext,
526
- privacyPolicyEvaluationContext,
527
- testEntityConfiguration,
528
- TestEntity,
529
- /* entitySelectedFields */ undefined,
530
- privacyPolicy,
531
- dataManagerInstance,
532
- metricsAdapter,
533
- );
534
- await entityLoader.utils().invalidateFieldsAsync({ customIdField: id1 } as any);
535
- verify(
536
- dataManagerMock.invalidateObjectFieldsAsync(deepEqual({ customIdField: id1 } as any)),
537
- ).once();
538
- });
539
-
540
- it('invalidates upon invalidate by entity', async () => {
541
- const viewerContext = instance(mock(ViewerContext));
542
- const privacyPolicyEvaluationContext =
543
- instance(
544
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
545
- );
546
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
547
- const queryContext = StubQueryContextProvider.getQueryContext();
548
- const privacyPolicy = instance(mock(TestEntityPrivacyPolicy));
549
- const dataManagerMock = mock<EntityDataManager<TestFields>>();
550
- const dataManagerInstance = instance(dataManagerMock);
551
-
552
- const id1 = uuidv4();
553
- const entityMock = mock(TestEntity);
554
- when(entityMock.getAllDatabaseFields()).thenReturn({ customIdField: id1 } as any);
555
- const entityInstance = instance(entityMock);
556
-
557
- const entityLoader = new EntityLoader(
558
- viewerContext,
559
- queryContext,
560
- privacyPolicyEvaluationContext,
561
- testEntityConfiguration,
562
- TestEntity,
563
- /* entitySelectedFields */ undefined,
564
- privacyPolicy,
565
- dataManagerInstance,
566
- metricsAdapter,
567
- );
568
- await entityLoader.utils().invalidateEntityAsync(entityInstance);
569
- verify(
570
- dataManagerMock.invalidateObjectFieldsAsync(deepEqual({ customIdField: id1 } as any)),
571
- ).once();
572
- });
573
-
574
- it('returns error result when not allowed', async () => {
575
- const viewerContext = instance(mock(ViewerContext));
576
- const privacyPolicyEvaluationContext =
577
- instance(
578
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
579
- );
580
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
581
- const queryContext = StubQueryContextProvider.getQueryContext();
582
- const privacyPolicyMock = mock(TestEntityPrivacyPolicy);
583
- const dataManagerMock = mock<EntityDataManager<TestFields>>();
584
-
585
- const id1 = uuidv4();
586
- when(
587
- dataManagerMock.loadManyByFieldEqualingAsync(anything(), anything(), anything()),
588
- ).thenResolve(new Map().set(id1, [{ customIdField: id1 }]));
589
-
590
- const rejectionError = new Error();
591
-
592
- when(
593
- privacyPolicyMock.authorizeReadAsync(
594
- viewerContext,
595
- queryContext,
596
- privacyPolicyEvaluationContext,
597
- anyOfClass(TestEntity),
598
- anything(),
599
- ),
600
- ).thenReject(rejectionError);
601
-
602
- const privacyPolicy = instance(privacyPolicyMock);
603
- const dataManagerInstance = instance(dataManagerMock);
604
-
605
- const entityLoader = new EntityLoader(
606
- viewerContext,
607
- queryContext,
608
- privacyPolicyEvaluationContext,
609
- testEntityConfiguration,
610
- TestEntity,
611
- /* entitySelectedFields */ undefined,
612
- privacyPolicy,
613
- dataManagerInstance,
614
- metricsAdapter,
615
- );
616
-
617
- const entityResult = await entityLoader.withAuthorizationResults().loadByIDAsync(id1);
618
- expect(entityResult.ok).toBe(false);
619
- expect(entityResult.reason).toEqual(rejectionError);
620
- expect(entityResult.value).toBe(undefined);
621
- });
622
-
623
- it('throws upon database adapter error', async () => {
624
- const viewerContext = instance(mock(ViewerContext));
625
- const privacyPolicyEvaluationContext =
626
- instance(
627
- mock<EntityPrivacyPolicyEvaluationContext<TestFields, string, ViewerContext, TestEntity>>(),
628
- );
629
- const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
630
- const queryContext = StubQueryContextProvider.getQueryContext();
631
- const privacyPolicy = instance(mock(TestEntityPrivacyPolicy));
632
- const dataManagerMock = mock<EntityDataManager<TestFields>>();
633
-
634
- const error = new Error();
635
-
636
- when(
637
- dataManagerMock.loadManyByFieldEqualingAsync(anything(), anything(), anything()),
638
- ).thenReject(error);
639
-
640
- const dataManagerInstance = instance(dataManagerMock);
641
-
642
- const entityLoader = new EntityLoader(
643
- viewerContext,
644
- queryContext,
645
- privacyPolicyEvaluationContext,
646
- testEntityConfiguration,
647
- TestEntity,
648
- /* entitySelectedFields */ undefined,
649
- privacyPolicy,
650
- dataManagerInstance,
651
- metricsAdapter,
652
- );
653
-
654
- const loadByValue = uuidv4();
655
-
656
- await expect(
657
- entityLoader.withAuthorizationResults().loadByIDAsync(loadByValue),
658
- ).rejects.toEqual(error);
659
- await expect(entityLoader.enforcing().loadByIDAsync(loadByValue)).rejects.toEqual(error);
660
- await expect(
661
- entityLoader.withAuthorizationResults().loadManyByIDsAsync([loadByValue]),
662
- ).rejects.toEqual(error);
663
- await expect(entityLoader.enforcing().loadManyByIDsAsync([loadByValue])).rejects.toEqual(error);
664
- await expect(
665
- entityLoader.withAuthorizationResults().loadManyByIDsNullableAsync([loadByValue]),
666
- ).rejects.toEqual(error);
667
- await expect(
668
- entityLoader.enforcing().loadManyByIDsNullableAsync([loadByValue]),
669
- ).rejects.toEqual(error);
670
- await expect(
671
- entityLoader
672
- .withAuthorizationResults()
673
- .loadManyByFieldEqualingAsync('customIdField', loadByValue),
674
- ).rejects.toEqual(error);
675
- await expect(
676
- entityLoader.enforcing().loadManyByFieldEqualingAsync('customIdField', loadByValue),
677
- ).rejects.toEqual(error);
678
- await expect(
679
- entityLoader
680
- .withAuthorizationResults()
681
- .loadManyByFieldEqualingManyAsync('customIdField', [loadByValue]),
682
- ).rejects.toEqual(error);
683
- await expect(
684
- entityLoader.enforcing().loadManyByFieldEqualingManyAsync('customIdField', [loadByValue]),
685
- ).rejects.toEqual(error);
10
+ describe('enforcing', () => {
11
+ it('creates a new EnforcingEntityLoader', async () => {
12
+ const companionProvider = createUnitTestEntityCompanionProvider();
13
+ const viewerContext = new ViewerContext(companionProvider);
14
+ expect(SimpleTestEntity.loader(viewerContext)).toBeInstanceOf(EnforcingEntityLoader);
15
+ });
16
+ });
17
+
18
+ describe('withAuthorizationResults', () => {
19
+ it('creates a new AuthorizationResultBasedEntityLoader', async () => {
20
+ const companionProvider = createUnitTestEntityCompanionProvider();
21
+ const viewerContext = new ViewerContext(companionProvider);
22
+ expect(SimpleTestEntity.loaderWithAuthorizationResults(viewerContext)).toBeInstanceOf(
23
+ AuthorizationResultBasedEntityLoader,
24
+ );
25
+ });
26
+ });
27
+
28
+ describe('utils', () => {
29
+ it('returns a instance of EntityLoaderUtils', async () => {
30
+ const companionProvider = createUnitTestEntityCompanionProvider();
31
+ const viewerContext = new ViewerContext(companionProvider);
32
+ expect(SimpleTestEntity.loaderUtils(viewerContext)).toBeInstanceOf(EntityLoaderUtils);
33
+ });
686
34
  });
687
35
  });