@expo/entity 0.35.0 → 0.36.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 (309) hide show
  1. package/build/AuthorizationResultBasedEntityLoader.d.ts +128 -0
  2. package/build/AuthorizationResultBasedEntityLoader.js +196 -0
  3. package/build/AuthorizationResultBasedEntityLoader.js.map +1 -0
  4. package/build/ComposedEntityCacheAdapter.js +1 -0
  5. package/build/ComposedEntityCacheAdapter.js.map +1 -1
  6. package/build/ComposedSecondaryEntityCache.js +1 -0
  7. package/build/ComposedSecondaryEntityCache.js.map +1 -1
  8. package/build/EnforcingEntityLoader.d.ts +5 -4
  9. package/build/EnforcingEntityLoader.js +4 -2
  10. package/build/EnforcingEntityLoader.js.map +1 -1
  11. package/build/Entity.d.ts +0 -27
  12. package/build/Entity.js +0 -50
  13. package/build/Entity.js.map +1 -1
  14. package/build/EntityAssociationLoader.d.ts +1 -1
  15. package/build/EntityAssociationLoader.js +17 -8
  16. package/build/EntityAssociationLoader.js.map +1 -1
  17. package/build/EntityCompanion.js +9 -1
  18. package/build/EntityCompanion.js.map +1 -1
  19. package/build/EntityCompanionProvider.d.ts +3 -1
  20. package/build/EntityCompanionProvider.js +10 -4
  21. package/build/EntityCompanionProvider.js.map +1 -1
  22. package/build/EntityConfiguration.d.ts +2 -1
  23. package/build/EntityConfiguration.js +19 -1
  24. package/build/EntityConfiguration.js.map +1 -1
  25. package/build/EntityDatabaseAdapter.d.ts +2 -2
  26. package/build/EntityDatabaseAdapter.js +5 -3
  27. package/build/EntityDatabaseAdapter.js.map +1 -1
  28. package/build/EntityFieldDefinition.d.ts +21 -10
  29. package/build/EntityFieldDefinition.js +8 -9
  30. package/build/EntityFieldDefinition.js.map +1 -1
  31. package/build/EntityFields.d.ts +10 -0
  32. package/build/EntityFields.js +15 -1
  33. package/build/EntityFields.js.map +1 -1
  34. package/build/EntityLoader.d.ts +12 -125
  35. package/build/EntityLoader.js +24 -239
  36. package/build/EntityLoader.js.map +1 -1
  37. package/build/EntityLoaderFactory.d.ts +1 -1
  38. package/build/EntityLoaderFactory.js +3 -0
  39. package/build/EntityLoaderFactory.js.map +1 -1
  40. package/build/EntityLoaderUtils.d.ts +58 -0
  41. package/build/EntityLoaderUtils.js +109 -0
  42. package/build/EntityLoaderUtils.js.map +1 -0
  43. package/build/EntityMutator.d.ts +1 -0
  44. package/build/EntityMutator.js +71 -56
  45. package/build/EntityMutator.js.map +1 -1
  46. package/build/EntityMutatorFactory.js +9 -0
  47. package/build/EntityMutatorFactory.js.map +1 -1
  48. package/build/EntityPrivacyPolicy.d.ts +11 -5
  49. package/build/EntityPrivacyPolicy.js +5 -7
  50. package/build/EntityPrivacyPolicy.js.map +1 -1
  51. package/build/EntityQueryContext.d.ts +2 -1
  52. package/build/EntityQueryContext.js +11 -6
  53. package/build/EntityQueryContext.js.map +1 -1
  54. package/build/EntitySecondaryCacheLoader.js +5 -1
  55. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  56. package/build/GenericEntityCacheAdapter.js +1 -0
  57. package/build/GenericEntityCacheAdapter.js.map +1 -1
  58. package/build/GenericSecondaryEntityCache.js +2 -0
  59. package/build/GenericSecondaryEntityCache.js.map +1 -1
  60. package/build/IEntityCacheAdapterProvider.d.ts +1 -1
  61. package/build/IEntityDatabaseAdapterProvider.d.ts +1 -1
  62. package/build/ReadonlyEntity.js +5 -1
  63. package/build/ReadonlyEntity.js.map +1 -1
  64. package/build/ViewerContext.js +2 -0
  65. package/build/ViewerContext.js.map +1 -1
  66. package/build/ViewerScopedEntityCompanion.js +2 -0
  67. package/build/ViewerScopedEntityCompanion.js.map +1 -1
  68. package/build/ViewerScopedEntityCompanionProvider.d.ts +0 -1
  69. package/build/ViewerScopedEntityCompanionProvider.js +2 -1
  70. package/build/ViewerScopedEntityCompanionProvider.js.map +1 -1
  71. package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
  72. package/build/ViewerScopedEntityLoaderFactory.js +2 -0
  73. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  74. package/build/ViewerScopedEntityMutatorFactory.js +2 -0
  75. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  76. package/build/__tests__/ComposedCacheAdapter-test.js +2 -0
  77. package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
  78. package/build/__tests__/ComposedSecondaryEntityCache-test.js +1 -0
  79. package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +1 -1
  80. package/build/__tests__/EnforcingEntityLoader-test.js +101 -113
  81. package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
  82. package/build/__tests__/Entity-test.js +0 -132
  83. package/build/__tests__/Entity-test.js.map +1 -1
  84. package/build/__tests__/EntityAssociationLoader-test.js +6 -2
  85. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  86. package/build/__tests__/EntityCommonUseCases-test.js +24 -22
  87. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  88. package/build/__tests__/EntityCompanion-test.js +26 -3
  89. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  90. package/build/__tests__/EntityConfiguration-test.js +103 -0
  91. package/build/__tests__/EntityConfiguration-test.js.map +1 -0
  92. package/build/__tests__/EntityDatabaseAdapter-test.js +6 -0
  93. package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
  94. package/build/__tests__/EntityEdges-test.js +61 -20
  95. package/build/__tests__/EntityEdges-test.js.map +1 -1
  96. package/build/__tests__/EntityFields-test.js +6 -0
  97. package/build/__tests__/EntityFields-test.js.map +1 -1
  98. package/build/__tests__/EntityLoader-constructor-test.js +16 -17
  99. package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
  100. package/build/__tests__/EntityLoader-test.js +74 -22
  101. package/build/__tests__/EntityLoader-test.js.map +1 -1
  102. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +12 -15
  103. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  104. package/build/__tests__/EntityMutator-test.js +54 -9
  105. package/build/__tests__/EntityMutator-test.js.map +1 -1
  106. package/build/__tests__/EntityPrivacyPolicy-test.js +77 -59
  107. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  108. package/build/__tests__/EntityQueryContext-test.js +9 -0
  109. package/build/__tests__/EntityQueryContext-test.js.map +1 -1
  110. package/build/__tests__/EntitySelfReferentialEdges-test.js +42 -25
  111. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  112. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
  113. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +20 -18
  114. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  115. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +12 -15
  116. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  117. package/build/entityUtils.d.ts +1 -1
  118. package/build/entityUtils.js.map +1 -1
  119. package/build/errors/EntityCacheAdapterError.js +2 -5
  120. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  121. package/build/errors/EntityDatabaseAdapterError.js +14 -35
  122. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  123. package/build/errors/EntityError.js +1 -0
  124. package/build/errors/EntityError.js.map +1 -1
  125. package/build/errors/EntityInvalidFieldValueError.js +2 -2
  126. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  127. package/build/errors/EntityNotAuthorizedError.js +3 -2
  128. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  129. package/build/errors/EntityNotFoundError.js +2 -2
  130. package/build/errors/EntityNotFoundError.js.map +1 -1
  131. package/build/index.d.ts +1 -0
  132. package/build/index.js +1 -0
  133. package/build/index.js.map +1 -1
  134. package/build/internal/EntityDataManager.d.ts +1 -1
  135. package/build/internal/EntityDataManager.js +6 -1
  136. package/build/internal/EntityDataManager.js.map +1 -1
  137. package/build/internal/EntityFieldTransformationUtils.d.ts +5 -5
  138. package/build/internal/EntityFieldTransformationUtils.js +5 -8
  139. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  140. package/build/internal/EntityTableDataCoordinator.d.ts +1 -1
  141. package/build/internal/EntityTableDataCoordinator.js +5 -0
  142. package/build/internal/EntityTableDataCoordinator.js.map +1 -1
  143. package/build/internal/ReadThroughEntityCache.d.ts +1 -1
  144. package/build/internal/ReadThroughEntityCache.js +2 -0
  145. package/build/internal/ReadThroughEntityCache.js.map +1 -1
  146. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +6 -2
  147. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
  148. package/build/internal/__tests__/ReadThroughEntityCache-test.js +33 -0
  149. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  150. package/build/metrics/IEntityMetricsAdapter.d.ts +1 -1
  151. package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +1 -1
  152. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  153. package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +1 -1
  154. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  155. package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +1 -1
  156. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  157. package/build/rules/PrivacyPolicyRule.d.ts +1 -1
  158. package/build/rules/PrivacyPolicyRule.js.map +1 -1
  159. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
  160. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
  161. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
  162. package/build/testfixtures/DateIDTestEntity.js +12 -15
  163. package/build/testfixtures/DateIDTestEntity.js.map +1 -1
  164. package/build/testfixtures/SimpleTestEntity.js +12 -15
  165. package/build/testfixtures/SimpleTestEntity.js.map +1 -1
  166. package/build/testfixtures/TestEntity.js +12 -15
  167. package/build/testfixtures/TestEntity.js.map +1 -1
  168. package/build/testfixtures/TestEntity2.js +12 -15
  169. package/build/testfixtures/TestEntity2.js.map +1 -1
  170. package/build/testfixtures/TestEntityNumberKey.js +12 -15
  171. package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
  172. package/build/testfixtures/TestEntityWithMutationTriggers.d.ts +36 -0
  173. package/build/testfixtures/TestEntityWithMutationTriggers.js +82 -0
  174. package/build/testfixtures/TestEntityWithMutationTriggers.js.map +1 -0
  175. package/build/utils/EntityPrivacyUtils.d.ts +34 -0
  176. package/build/utils/EntityPrivacyUtils.js +160 -0
  177. package/build/utils/EntityPrivacyUtils.js.map +1 -0
  178. package/build/utils/__tests__/EntityPrivacyUtils-test.d.ts +1 -0
  179. package/build/utils/__tests__/EntityPrivacyUtils-test.js +395 -0
  180. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -0
  181. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.d.ts +1 -0
  182. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js +26 -0
  183. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js.map +1 -0
  184. package/build/utils/collections/maps.js.map +1 -1
  185. package/build/utils/mergeEntityMutationTriggerConfigurations.d.ts +4 -0
  186. package/build/utils/mergeEntityMutationTriggerConfigurations.js +28 -0
  187. package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -0
  188. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -1
  189. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
  190. package/build/utils/testing/StubCacheAdapter.d.ts +3 -3
  191. package/build/utils/testing/StubCacheAdapter.js +3 -3
  192. package/build/utils/testing/StubCacheAdapter.js.map +1 -1
  193. package/build/utils/testing/StubDatabaseAdapter.d.ts +2 -2
  194. package/build/utils/testing/StubDatabaseAdapter.js +4 -2
  195. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  196. package/build/utils/testing/StubDatabaseAdapterProvider.d.ts +1 -1
  197. package/build/utils/testing/StubDatabaseAdapterProvider.js +1 -3
  198. package/build/utils/testing/StubDatabaseAdapterProvider.js.map +1 -1
  199. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.d.ts +1 -0
  200. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js +42 -0
  201. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js.map +1 -0
  202. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +53 -0
  203. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
  204. package/build/utils/testing/describeFieldTestCase.js.map +1 -1
  205. package/package.json +4 -3
  206. package/src/AuthorizationResultBasedEntityLoader.ts +297 -0
  207. package/src/ComposedEntityCacheAdapter.ts +6 -6
  208. package/src/ComposedSecondaryEntityCache.ts +8 -8
  209. package/src/EnforcingEntityLoader.ts +20 -19
  210. package/src/Entity.ts +11 -126
  211. package/src/EntityAssociationLoader.ts +40 -41
  212. package/src/EntityCompanion.ts +8 -4
  213. package/src/EntityCompanionProvider.ts +24 -16
  214. package/src/EntityConfiguration.ts +18 -7
  215. package/src/EntityDatabaseAdapter.ts +41 -41
  216. package/src/EntityFieldDefinition.ts +28 -18
  217. package/src/EntityFields.ts +15 -0
  218. package/src/EntityLoader.ts +63 -357
  219. package/src/EntityLoaderFactory.ts +10 -4
  220. package/src/EntityLoaderUtils.ts +149 -0
  221. package/src/EntityMutationInfo.ts +2 -2
  222. package/src/EntityMutationTriggerConfiguration.ts +5 -5
  223. package/src/EntityMutationValidator.ts +2 -2
  224. package/src/EntityMutator.ts +146 -144
  225. package/src/EntityMutatorFactory.ts +8 -8
  226. package/src/EntityPrivacyPolicy.ts +78 -28
  227. package/src/EntityQueryContext.ts +14 -13
  228. package/src/EntityQueryContextProvider.ts +5 -5
  229. package/src/EntitySecondaryCacheLoader.ts +13 -11
  230. package/src/GenericEntityCacheAdapter.ts +10 -10
  231. package/src/GenericSecondaryEntityCache.ts +6 -6
  232. package/src/IEntityCacheAdapter.ts +4 -4
  233. package/src/IEntityCacheAdapterProvider.ts +2 -2
  234. package/src/IEntityDatabaseAdapterProvider.ts +2 -2
  235. package/src/ReadonlyEntity.ts +5 -5
  236. package/src/ViewerContext.ts +5 -5
  237. package/src/ViewerScopedEntityCompanion.ts +4 -4
  238. package/src/ViewerScopedEntityCompanionProvider.ts +4 -5
  239. package/src/ViewerScopedEntityLoaderFactory.ts +10 -4
  240. package/src/ViewerScopedEntityMutatorFactory.ts +5 -5
  241. package/src/__tests__/ComposedCacheAdapter-test.ts +12 -10
  242. package/src/__tests__/ComposedSecondaryEntityCache-test.ts +8 -8
  243. package/src/__tests__/EnforcingEntityLoader-test.ts +236 -159
  244. package/src/__tests__/Entity-test.ts +0 -202
  245. package/src/__tests__/EntityAssociationLoader-test.ts +29 -25
  246. package/src/__tests__/EntityCommonUseCases-test.ts +29 -13
  247. package/src/__tests__/EntityCompanion-test.ts +57 -5
  248. package/src/__tests__/EntityConfiguration-test.ts +118 -0
  249. package/src/__tests__/EntityDatabaseAdapter-test.ts +11 -11
  250. package/src/__tests__/EntityEdges-test.ts +108 -36
  251. package/src/__tests__/EntityFields-test.ts +14 -2
  252. package/src/__tests__/EntityLoader-constructor-test.ts +20 -7
  253. package/src/__tests__/EntityLoader-test.ts +214 -86
  254. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +2 -2
  255. package/src/__tests__/EntityMutator-test.ts +281 -96
  256. package/src/__tests__/EntityPrivacyPolicy-test.ts +166 -53
  257. package/src/__tests__/EntityQueryContext-test.ts +30 -12
  258. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
  259. package/src/__tests__/EntitySelfReferentialEdges-test.ts +46 -26
  260. package/src/__tests__/GenericEntityCacheAdapter-test.ts +2 -2
  261. package/src/__tests__/ViewerContext-test.ts +1 -1
  262. package/src/__tests__/ViewerScopedEntityCompanion-test.ts +2 -2
  263. package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +2 -2
  264. package/src/__tests__/ViewerScopedEntityLoaderFactory-test.ts +2 -1
  265. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +19 -19
  266. package/src/__tests__/entityUtils-test.ts +2 -2
  267. package/src/entityUtils.ts +4 -4
  268. package/src/errors/EntityError.ts +4 -1
  269. package/src/errors/EntityInvalidFieldValueError.ts +2 -2
  270. package/src/errors/EntityNotAuthorizedError.ts +3 -3
  271. package/src/errors/EntityNotFoundError.ts +2 -2
  272. package/src/index.ts +1 -0
  273. package/src/internal/EntityDataManager.ts +24 -24
  274. package/src/internal/EntityFieldTransformationUtils.ts +39 -32
  275. package/src/internal/EntityTableDataCoordinator.ts +3 -3
  276. package/src/internal/ReadThroughEntityCache.ts +9 -9
  277. package/src/internal/__tests__/EntityDataManager-test.ts +51 -51
  278. package/src/internal/__tests__/EntityFieldTransformationUtils-test.ts +14 -10
  279. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +74 -18
  280. package/src/metrics/EntityMetricsUtils.ts +4 -4
  281. package/src/metrics/IEntityMetricsAdapter.ts +1 -1
  282. package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +9 -3
  283. package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +9 -3
  284. package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +9 -3
  285. package/src/rules/PrivacyPolicyRule.ts +9 -3
  286. package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -1
  287. package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -1
  288. package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -1
  289. package/src/testfixtures/TestEntity.ts +1 -1
  290. package/src/testfixtures/TestEntityWithMutationTriggers.ts +156 -0
  291. package/src/utils/EntityPrivacyUtils.ts +325 -0
  292. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +570 -0
  293. package/src/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.ts +29 -0
  294. package/src/utils/collections/__tests__/maps-test.ts +2 -2
  295. package/src/utils/collections/maps.ts +11 -11
  296. package/src/utils/mergeEntityMutationTriggerConfigurations.ts +44 -0
  297. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +25 -22
  298. package/src/utils/testing/StubCacheAdapter.ts +17 -15
  299. package/src/utils/testing/StubDatabaseAdapter.ts +35 -30
  300. package/src/utils/testing/StubDatabaseAdapterProvider.ts +2 -2
  301. package/src/utils/testing/StubQueryContextProvider.ts +2 -2
  302. package/src/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.ts +42 -0
  303. package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +111 -29
  304. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +2 -2
  305. package/src/utils/testing/describeFieldTestCase.ts +1 -1
  306. package/build/__tests__/EntityDataConfiguration-test.js +0 -68
  307. package/build/__tests__/EntityDataConfiguration-test.js.map +0 -1
  308. package/src/__tests__/EntityDataConfiguration-test.ts +0 -77
  309. /package/build/__tests__/{EntityDataConfiguration-test.d.ts → EntityConfiguration-test.d.ts} +0 -0
@@ -1,12 +1,6 @@
1
1
  import Entity from '../Entity';
2
- import { EntityCompanionDefinition } from '../EntityCompanionProvider';
3
- import EntityConfiguration from '../EntityConfiguration';
4
- import { UUIDField } from '../EntityFields';
5
2
  import { CreateMutator, UpdateMutator } from '../EntityMutator';
6
- import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
7
3
  import ViewerContext from '../ViewerContext';
8
- import AlwaysAllowPrivacyPolicyRule from '../rules/AlwaysAllowPrivacyPolicyRule';
9
- import AlwaysDenyPrivacyPolicyRule from '../rules/AlwaysDenyPrivacyPolicyRule';
10
4
  import SimpleTestEntity from '../testfixtures/SimpleTestEntity';
11
5
  import { createUnitTestEntityCompanionProvider } from '../utils/testing/createUnitTestEntityCompanionProvider';
12
6
 
@@ -35,200 +29,4 @@ describe(Entity, () => {
35
29
  expect(SimpleTestEntity.updater(testEntity)).toBeInstanceOf(UpdateMutator);
36
30
  });
37
31
  });
38
-
39
- describe('canViewerUpdateAsync', () => {
40
- it('appropriately executes update privacy policy', async () => {
41
- const companionProvider = createUnitTestEntityCompanionProvider();
42
- const viewerContext = new ViewerContext(companionProvider);
43
- const data = {
44
- id: 'what',
45
- };
46
- const testEntity = new SimpleTestDenyDeleteEntity({
47
- viewerContext,
48
- id: 'what',
49
- databaseFields: data,
50
- selectedFields: data,
51
- });
52
- const canViewerUpdate = await SimpleTestDenyDeleteEntity.canViewerUpdateAsync(testEntity);
53
- expect(canViewerUpdate).toBe(true);
54
- });
55
-
56
- it('denies when policy denies', async () => {
57
- const companionProvider = createUnitTestEntityCompanionProvider();
58
- const viewerContext = new ViewerContext(companionProvider);
59
- const data = {
60
- id: 'what',
61
- };
62
- const testEntity = new SimpleTestDenyUpdateEntity({
63
- viewerContext,
64
- id: 'what',
65
- databaseFields: data,
66
- selectedFields: data,
67
- });
68
- const canViewerUpdate = await SimpleTestDenyUpdateEntity.canViewerUpdateAsync(testEntity);
69
- expect(canViewerUpdate).toBe(false);
70
- });
71
- });
72
-
73
- describe('canViewerDeleteAsync', () => {
74
- it('appropriately executes update privacy policy', async () => {
75
- const companionProvider = createUnitTestEntityCompanionProvider();
76
- const viewerContext = new ViewerContext(companionProvider);
77
- const data = {
78
- id: 'what',
79
- };
80
- const testEntity = new SimpleTestDenyUpdateEntity({
81
- viewerContext,
82
- id: 'what',
83
- databaseFields: data,
84
- selectedFields: data,
85
- });
86
- const canViewerDelete = await SimpleTestDenyUpdateEntity.canViewerDeleteAsync(testEntity);
87
- expect(canViewerDelete).toBe(true);
88
- });
89
-
90
- it('denies when policy denies', async () => {
91
- const companionProvider = createUnitTestEntityCompanionProvider();
92
- const viewerContext = new ViewerContext(companionProvider);
93
- const data = {
94
- id: 'what',
95
- };
96
- const testEntity = new SimpleTestDenyDeleteEntity({
97
- viewerContext,
98
- id: 'what',
99
- databaseFields: data,
100
- selectedFields: data,
101
- });
102
- const canViewerDelete = await SimpleTestDenyDeleteEntity.canViewerDeleteAsync(testEntity);
103
- expect(canViewerDelete).toBe(false);
104
- });
105
- });
106
32
  });
107
-
108
- type TestEntityFields = {
109
- id: string;
110
- };
111
-
112
- const testEntityConfiguration = new EntityConfiguration<TestEntityFields>({
113
- idField: 'id',
114
- tableName: 'blah',
115
- schema: {
116
- id: new UUIDField({
117
- columnName: 'custom_id',
118
- }),
119
- },
120
- databaseAdapterFlavor: 'postgres',
121
- cacheAdapterFlavor: 'redis',
122
- });
123
-
124
- class SimpleTestDenyUpdateEntityPrivacyPolicy extends EntityPrivacyPolicy<
125
- TestEntityFields,
126
- string,
127
- ViewerContext,
128
- SimpleTestDenyUpdateEntity
129
- > {
130
- protected override readonly readRules = [
131
- new AlwaysAllowPrivacyPolicyRule<
132
- TestEntityFields,
133
- string,
134
- ViewerContext,
135
- SimpleTestDenyUpdateEntity
136
- >(),
137
- ];
138
- protected override readonly createRules = [
139
- new AlwaysAllowPrivacyPolicyRule<
140
- TestEntityFields,
141
- string,
142
- ViewerContext,
143
- SimpleTestDenyUpdateEntity
144
- >(),
145
- ];
146
- protected override readonly updateRules = [
147
- new AlwaysDenyPrivacyPolicyRule<
148
- TestEntityFields,
149
- string,
150
- ViewerContext,
151
- SimpleTestDenyUpdateEntity
152
- >(),
153
- ];
154
- protected override readonly deleteRules = [
155
- new AlwaysAllowPrivacyPolicyRule<
156
- TestEntityFields,
157
- string,
158
- ViewerContext,
159
- SimpleTestDenyUpdateEntity
160
- >(),
161
- ];
162
- }
163
-
164
- class SimpleTestDenyDeleteEntityPrivacyPolicy extends EntityPrivacyPolicy<
165
- TestEntityFields,
166
- string,
167
- ViewerContext,
168
- SimpleTestDenyDeleteEntity
169
- > {
170
- protected override readonly readRules = [
171
- new AlwaysAllowPrivacyPolicyRule<
172
- TestEntityFields,
173
- string,
174
- ViewerContext,
175
- SimpleTestDenyDeleteEntity
176
- >(),
177
- ];
178
- protected override readonly createRules = [
179
- new AlwaysAllowPrivacyPolicyRule<
180
- TestEntityFields,
181
- string,
182
- ViewerContext,
183
- SimpleTestDenyDeleteEntity
184
- >(),
185
- ];
186
- protected override readonly updateRules = [
187
- new AlwaysAllowPrivacyPolicyRule<
188
- TestEntityFields,
189
- string,
190
- ViewerContext,
191
- SimpleTestDenyDeleteEntity
192
- >(),
193
- ];
194
- protected override readonly deleteRules = [
195
- new AlwaysDenyPrivacyPolicyRule<
196
- TestEntityFields,
197
- string,
198
- ViewerContext,
199
- SimpleTestDenyDeleteEntity
200
- >(),
201
- ];
202
- }
203
-
204
- class SimpleTestDenyUpdateEntity extends Entity<TestEntityFields, string, ViewerContext> {
205
- static defineCompanionDefinition(): EntityCompanionDefinition<
206
- TestEntityFields,
207
- string,
208
- ViewerContext,
209
- SimpleTestDenyUpdateEntity,
210
- SimpleTestDenyUpdateEntityPrivacyPolicy
211
- > {
212
- return {
213
- entityClass: SimpleTestDenyUpdateEntity,
214
- entityConfiguration: testEntityConfiguration,
215
- privacyPolicyClass: SimpleTestDenyUpdateEntityPrivacyPolicy,
216
- };
217
- }
218
- }
219
-
220
- class SimpleTestDenyDeleteEntity extends Entity<TestEntityFields, string, ViewerContext> {
221
- static defineCompanionDefinition(): EntityCompanionDefinition<
222
- TestEntityFields,
223
- string,
224
- ViewerContext,
225
- SimpleTestDenyDeleteEntity,
226
- SimpleTestDenyDeleteEntityPrivacyPolicy
227
- > {
228
- return {
229
- entityClass: SimpleTestDenyDeleteEntity,
230
- entityConfiguration: testEntityConfiguration,
231
- privacyPolicyClass: SimpleTestDenyDeleteEntityPrivacyPolicy,
232
- };
233
- }
234
- }
@@ -14,20 +14,20 @@ describe(EntityAssociationLoader, () => {
14
14
  const companionProvider = createUnitTestEntityCompanionProvider();
15
15
  const viewerContext = new TestViewerContext(companionProvider);
16
16
  const testOtherEntity = await enforceAsyncResult(
17
- TestEntity.creator(viewerContext).createAsync()
17
+ TestEntity.creator(viewerContext).createAsync(),
18
18
  );
19
19
  const testEntity = await enforceAsyncResult(
20
20
  TestEntity.creator(viewerContext)
21
21
  .setField('stringField', testOtherEntity.getID())
22
- .createAsync()
22
+ .createAsync(),
23
23
  );
24
24
  const loadedOther = await enforceAsyncResult(
25
- testEntity.associationLoader().loadAssociatedEntityAsync('stringField', TestEntity)
25
+ testEntity.associationLoader().loadAssociatedEntityAsync('stringField', TestEntity),
26
26
  );
27
27
  expect(loadedOther.getID()).toEqual(testOtherEntity.getID());
28
28
 
29
29
  const loadedOther2 = await enforceAsyncResult(
30
- testEntity.associationLoader().loadAssociatedEntityAsync('nullableField', TestEntity)
30
+ testEntity.associationLoader().loadAssociatedEntityAsync('nullableField', TestEntity),
31
31
  );
32
32
  expect(loadedOther2).toBeNull();
33
33
  });
@@ -39,13 +39,13 @@ describe(EntityAssociationLoader, () => {
39
39
  const viewerContext = new TestViewerContext(companionProvider);
40
40
  const testEntity = await enforceAsyncResult(TestEntity.creator(viewerContext).createAsync());
41
41
  const testOtherEntity1 = await enforceAsyncResult(
42
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync()
42
+ TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
43
43
  );
44
44
  const testOtherEntity2 = await enforceAsyncResult(
45
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync()
45
+ TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
46
46
  );
47
47
  const loaded = await enforceResultsAsync(
48
- testEntity.associationLoader().loadManyAssociatedEntitiesAsync(TestEntity, 'stringField')
48
+ testEntity.associationLoader().loadManyAssociatedEntitiesAsync(TestEntity, 'stringField'),
49
49
  );
50
50
  expect(loaded).toHaveLength(2);
51
51
  expect(loaded.find((e) => e.getID() === testOtherEntity1.getID())).not.toBeUndefined();
@@ -58,12 +58,12 @@ describe(EntityAssociationLoader, () => {
58
58
  const companionProvider = createUnitTestEntityCompanionProvider();
59
59
  const viewerContext = new TestViewerContext(companionProvider);
60
60
  const testOtherEntity = await enforceAsyncResult(
61
- TestEntity.creator(viewerContext).createAsync()
61
+ TestEntity.creator(viewerContext).createAsync(),
62
62
  );
63
63
  const testEntity = await enforceAsyncResult(
64
64
  TestEntity.creator(viewerContext)
65
65
  .setField('stringField', testOtherEntity.getID())
66
- .createAsync()
66
+ .createAsync(),
67
67
  );
68
68
  const loadedOtherResult = await testEntity
69
69
  .associationLoader()
@@ -75,7 +75,7 @@ describe(EntityAssociationLoader, () => {
75
75
  const companionProvider = createUnitTestEntityCompanionProvider();
76
76
  const viewerContext = new TestViewerContext(companionProvider);
77
77
  const testEntity = await enforceAsyncResult(
78
- TestEntity.creator(viewerContext).setField('stringField', uuidv4()).createAsync()
78
+ TestEntity.creator(viewerContext).setField('stringField', uuidv4()).createAsync(),
79
79
  );
80
80
  const loadedOtherResult = await testEntity
81
81
  .associationLoader()
@@ -87,7 +87,7 @@ describe(EntityAssociationLoader, () => {
87
87
  const companionProvider = createUnitTestEntityCompanionProvider();
88
88
  const viewerContext = new TestViewerContext(companionProvider);
89
89
  const testEntity = await enforceAsyncResult(
90
- TestEntity.creator(viewerContext).setField('stringField', 'blah').createAsync()
90
+ TestEntity.creator(viewerContext).setField('stringField', 'blah').createAsync(),
91
91
  );
92
92
  const loadedOtherResult = await testEntity
93
93
  .associationLoader()
@@ -102,10 +102,10 @@ describe(EntityAssociationLoader, () => {
102
102
  const viewerContext = new TestViewerContext(companionProvider);
103
103
  const testEntity = await enforceAsyncResult(TestEntity.creator(viewerContext).createAsync());
104
104
  const testOtherEntity1 = await enforceAsyncResult(
105
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync()
105
+ TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
106
106
  );
107
107
  const testOtherEntity2 = await enforceAsyncResult(
108
- TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync()
108
+ TestEntity.creator(viewerContext).setField('stringField', testEntity.getID()).createAsync(),
109
109
  );
110
110
  const loaded = await enforceResultsAsync(
111
111
  testEntity
@@ -113,8 +113,8 @@ describe(EntityAssociationLoader, () => {
113
113
  .loadManyAssociatedEntitiesByFieldEqualingAsync(
114
114
  'customIdField',
115
115
  TestEntity,
116
- 'stringField'
117
- )
116
+ 'stringField',
117
+ ),
118
118
  );
119
119
  expect(loaded).toHaveLength(2);
120
120
  expect(loaded.find((e) => e.getID() === testOtherEntity1.getID())).not.toBeUndefined();
@@ -131,8 +131,8 @@ describe(EntityAssociationLoader, () => {
131
131
  .loadManyAssociatedEntitiesByFieldEqualingAsync(
132
132
  'nullableField',
133
133
  TestEntity,
134
- 'stringField'
135
- )
134
+ 'stringField',
135
+ ),
136
136
  );
137
137
  expect(loaded).toHaveLength(0);
138
138
  });
@@ -144,15 +144,19 @@ describe(EntityAssociationLoader, () => {
144
144
  const viewerContext = new TestViewerContext(companionProvider);
145
145
  const testEntity4 = await enforceAsyncResult(TestEntity.creator(viewerContext).createAsync());
146
146
  const testEntity3 = await enforceAsyncResult(
147
- TestEntity2.creator(viewerContext).setField('foreignKey', testEntity4.getID()).createAsync()
147
+ TestEntity2.creator(viewerContext)
148
+ .setField('foreignKey', testEntity4.getID())
149
+ .createAsync(),
148
150
  );
149
151
  const testEntity2 = await enforceAsyncResult(
150
152
  TestEntity.creator(viewerContext)
151
153
  .setField('testIndexedField', testEntity3.getID())
152
- .createAsync()
154
+ .createAsync(),
153
155
  );
154
156
  const testEntity = await enforceAsyncResult(
155
- TestEntity2.creator(viewerContext).setField('foreignKey', testEntity2.getID()).createAsync()
157
+ TestEntity2.creator(viewerContext)
158
+ .setField('foreignKey', testEntity2.getID())
159
+ .createAsync(),
156
160
  );
157
161
 
158
162
  const loaded2Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
@@ -197,7 +201,7 @@ describe(EntityAssociationLoader, () => {
197
201
  const viewerContext = new TestViewerContext(companionProvider);
198
202
 
199
203
  const testEntity = await enforceAsyncResult(
200
- TestEntity2.creator(viewerContext).setField('foreignKey', uuidv4()).createAsync()
204
+ TestEntity2.creator(viewerContext).setField('foreignKey', uuidv4()).createAsync(),
201
205
  );
202
206
 
203
207
  const loadResult = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
@@ -215,10 +219,10 @@ describe(EntityAssociationLoader, () => {
215
219
 
216
220
  const fieldValue = uuidv4();
217
221
  const testEntity2 = await enforceAsyncResult(
218
- TestEntity.creator(viewerContext).setField('stringField', fieldValue).createAsync()
222
+ TestEntity.creator(viewerContext).setField('stringField', fieldValue).createAsync(),
219
223
  );
220
224
  const testEntity = await enforceAsyncResult(
221
- TestEntity2.creator(viewerContext).setField('foreignKey', fieldValue).createAsync()
225
+ TestEntity2.creator(viewerContext).setField('foreignKey', fieldValue).createAsync(),
222
226
  );
223
227
 
224
228
  const loaded2Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
@@ -236,7 +240,7 @@ describe(EntityAssociationLoader, () => {
236
240
  const viewerContext = new TestViewerContext(companionProvider);
237
241
 
238
242
  const testEntity = await enforceAsyncResult(
239
- TestEntity2.creator(viewerContext).setField('foreignKey', uuidv4()).createAsync()
243
+ TestEntity2.creator(viewerContext).setField('foreignKey', uuidv4()).createAsync(),
240
244
  );
241
245
 
242
246
  const loaded2Result = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
@@ -254,7 +258,7 @@ describe(EntityAssociationLoader, () => {
254
258
  const viewerContext = new TestViewerContext(companionProvider);
255
259
 
256
260
  const testEntity = await enforceAsyncResult(
257
- TestEntity.creator(viewerContext).setField('nullableField', null).createAsync()
261
+ TestEntity.creator(viewerContext).setField('nullableField', null).createAsync(),
258
262
  );
259
263
 
260
264
  const loadedResult = await testEntity.associationLoader().loadAssociatedEntityThroughAsync([
@@ -16,7 +16,10 @@ import PrivacyPolicyRule, { RuleEvaluationResult } from '../rules/PrivacyPolicyR
16
16
  import { createUnitTestEntityCompanionProvider } from '../utils/testing/createUnitTestEntityCompanionProvider';
17
17
 
18
18
  class TestUserViewerContext extends ViewerContext {
19
- constructor(entityCompanionProvider: EntityCompanionProvider, private readonly userID: string) {
19
+ constructor(
20
+ entityCompanionProvider: EntityCompanionProvider,
21
+ private readonly userID: string,
22
+ ) {
20
23
  super(entityCompanionProvider);
21
24
  }
22
25
 
@@ -69,8 +72,13 @@ class DenyIfNotOwnerPrivacyPolicyRule extends PrivacyPolicyRule<
69
72
  async evaluateAsync(
70
73
  viewerContext: TestUserViewerContext,
71
74
  _queryContext: EntityQueryContext,
72
- _evaluationContext: EntityPrivacyPolicyEvaluationContext,
73
- entity: BlahEntity
75
+ _evaluationContext: EntityPrivacyPolicyEvaluationContext<
76
+ BlahFields,
77
+ string,
78
+ TestUserViewerContext,
79
+ BlahEntity
80
+ >,
81
+ entity: BlahEntity,
74
82
  ): Promise<RuleEvaluationResult> {
75
83
  if (viewerContext.getUserID() === entity.getField('ownerID')) {
76
84
  return RuleEvaluationResult.SKIP;
@@ -110,15 +118,15 @@ it('runs through a common workflow', async () => {
110
118
  const vc2 = new TestUserViewerContext(entityCompanionProvider, uuidv4());
111
119
 
112
120
  const blahOwner1 = await enforceAsyncResult(
113
- BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync()
121
+ BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync(),
114
122
  );
115
123
 
116
124
  await enforceAsyncResult(
117
- BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync()
125
+ BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync(),
118
126
  );
119
127
 
120
128
  const blahOwner2 = await enforceAsyncResult(
121
- BlahEntity.creator(vc2).setField('ownerID', vc2.getUserID()!).createAsync()
129
+ BlahEntity.creator(vc2).setField('ownerID', vc2.getUserID()!).createAsync(),
122
130
  );
123
131
 
124
132
  // sanity check created objects
@@ -127,33 +135,41 @@ it('runs through a common workflow', async () => {
127
135
 
128
136
  // check that two people can't read each others data
129
137
  await expect(
130
- enforceAsyncResult(BlahEntity.loader(vc1).loadByIDAsync(blahOwner2.getID()))
138
+ enforceAsyncResult(
139
+ BlahEntity.loader(vc1).withAuthorizationResults().loadByIDAsync(blahOwner2.getID()),
140
+ ),
131
141
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
132
142
  await expect(
133
- enforceAsyncResult(BlahEntity.loader(vc2).loadByIDAsync(blahOwner1.getID()))
143
+ enforceAsyncResult(
144
+ BlahEntity.loader(vc2).withAuthorizationResults().loadByIDAsync(blahOwner1.getID()),
145
+ ),
134
146
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
135
147
 
136
148
  // check that all of owner 1's objects can be loaded
137
149
  const results = await enforceResultsAsync(
138
- BlahEntity.loader(vc1).loadManyByFieldEqualingAsync('ownerID', vc1.getUserID()!)
150
+ BlahEntity.loader(vc1)
151
+ .withAuthorizationResults()
152
+ .loadManyByFieldEqualingAsync('ownerID', vc1.getUserID()!),
139
153
  );
140
154
  expect(results).toHaveLength(2);
141
155
 
142
156
  // check that two people can't create objects owned by others
143
157
  await expect(
144
158
  enforceAsyncResult(
145
- BlahEntity.creator(vc2).setField('ownerID', blahOwner1.getID()).createAsync()
146
- )
159
+ BlahEntity.creator(vc2).setField('ownerID', blahOwner1.getID()).createAsync(),
160
+ ),
147
161
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
148
162
 
149
163
  // check that empty load many returns nothing
150
- const results2 = await BlahEntity.loader(vc1).loadManyByFieldEqualingManyAsync('ownerID', []);
164
+ const results2 = await BlahEntity.loader(vc1)
165
+ .withAuthorizationResults()
166
+ .loadManyByFieldEqualingManyAsync('ownerID', []);
151
167
  for (const value in results2.values) {
152
168
  expect(value).toHaveLength(0);
153
169
  }
154
170
 
155
171
  // check that the user can't delete their own data (as specified by privacy rules)
156
172
  await expect(enforceAsyncResult(BlahEntity.deleteAsync(blahOwner2))).rejects.toBeInstanceOf(
157
- EntityNotAuthorizedError
173
+ EntityNotAuthorizedError,
158
174
  );
159
175
  });
@@ -3,25 +3,77 @@ import { instance, mock, when } from 'ts-mockito';
3
3
  import EntityCompanion from '../EntityCompanion';
4
4
  import EntityCompanionProvider from '../EntityCompanionProvider';
5
5
  import EntityLoaderFactory from '../EntityLoaderFactory';
6
+ import EntityMutationTriggerConfiguration from '../EntityMutationTriggerConfiguration';
6
7
  import EntityMutatorFactory from '../EntityMutatorFactory';
8
+ import ViewerContext from '../ViewerContext';
7
9
  import EntityTableDataCoordinator from '../internal/EntityTableDataCoordinator';
8
10
  import IEntityMetricsAdapter from '../metrics/IEntityMetricsAdapter';
9
- import TestEntity, { testEntityConfiguration, TestFields } from '../testfixtures/TestEntity';
11
+ import NoOpEntityMetricsAdapter from '../metrics/NoOpEntityMetricsAdapter';
12
+ import TestEntityWithMutationTriggers, {
13
+ TestMTFields,
14
+ testEntityMTConfiguration,
15
+ TestMutationTrigger,
16
+ } from '../testfixtures/TestEntityWithMutationTriggers';
10
17
 
11
18
  describe(EntityCompanion, () => {
12
19
  it('correctly instantiates mutator and loader factories', () => {
13
20
  const entityCompanionProvider = instance(mock<EntityCompanionProvider>());
14
21
 
15
- const tableDataCoordinatorMock = mock<EntityTableDataCoordinator<TestFields>>();
16
- when(tableDataCoordinatorMock.entityConfiguration).thenReturn(testEntityConfiguration);
22
+ const tableDataCoordinatorMock = mock<EntityTableDataCoordinator<TestMTFields>>();
23
+ when(tableDataCoordinatorMock.entityConfiguration).thenReturn(testEntityMTConfiguration);
17
24
 
18
25
  const companion = new EntityCompanion(
19
26
  entityCompanionProvider,
20
- TestEntity.defineCompanionDefinition(),
27
+ TestEntityWithMutationTriggers.defineCompanionDefinition(),
21
28
  instance(tableDataCoordinatorMock),
22
- instance(mock<IEntityMetricsAdapter>())
29
+ instance(mock<IEntityMetricsAdapter>()),
23
30
  );
24
31
  expect(companion.getLoaderFactory()).toBeInstanceOf(EntityLoaderFactory);
25
32
  expect(companion.getMutatorFactory()).toBeInstanceOf(EntityMutatorFactory);
26
33
  });
34
+
35
+ it('correctly merges local and global mutation triggers', () => {
36
+ const globalMutationTriggers: EntityMutationTriggerConfiguration<
37
+ TestMTFields,
38
+ string,
39
+ ViewerContext,
40
+ TestEntityWithMutationTriggers,
41
+ keyof TestMTFields
42
+ > = {
43
+ afterCreate: [new TestMutationTrigger('globalAfterCreate')],
44
+ afterAll: [new TestMutationTrigger('globalAfterAll')],
45
+ };
46
+
47
+ const metricsAdapter = new NoOpEntityMetricsAdapter();
48
+
49
+ const entityCompanionProvider = new EntityCompanionProvider(
50
+ metricsAdapter,
51
+ new Map(),
52
+ new Map(),
53
+ globalMutationTriggers,
54
+ );
55
+
56
+ const tableDataCoordinatorMock = mock<EntityTableDataCoordinator<TestMTFields>>();
57
+ when(tableDataCoordinatorMock.entityConfiguration).thenReturn(testEntityMTConfiguration);
58
+
59
+ const companion = new EntityCompanion(
60
+ entityCompanionProvider,
61
+ TestEntityWithMutationTriggers.defineCompanionDefinition(),
62
+ instance(tableDataCoordinatorMock),
63
+ instance(mock<IEntityMetricsAdapter>()),
64
+ );
65
+ expect(companion.getLoaderFactory()).toBeInstanceOf(EntityLoaderFactory);
66
+ expect(companion.getMutatorFactory()).toBeInstanceOf(EntityMutatorFactory);
67
+
68
+ const mergedTriggers = companion.getMutatorFactory()['mutationTriggers'];
69
+
70
+ const localTriggers = companion.entityCompanionDefinition.mutationTriggers;
71
+ expect(localTriggers).toBeTruthy();
72
+
73
+ expect(mergedTriggers).toStrictEqual({
74
+ afterCreate: [localTriggers!.afterCreate![0], globalMutationTriggers.afterCreate![0]],
75
+ afterAll: [localTriggers!.afterAll![0], globalMutationTriggers!.afterAll![0]],
76
+ afterCommit: [localTriggers!.afterCommit![0]],
77
+ });
78
+ });
27
79
  });
@@ -0,0 +1,118 @@
1
+ import EntityConfiguration from '../EntityConfiguration';
2
+ import { UUIDField, StringField } from '../EntityFields';
3
+
4
+ describe(EntityConfiguration, () => {
5
+ describe('when valid', () => {
6
+ type BlahT = {
7
+ id: string;
8
+ cacheable: string;
9
+ uniqueButNotCacheable: string;
10
+ };
11
+
12
+ type Blah2T = {
13
+ id: string;
14
+ };
15
+
16
+ const blahEntityConfiguration = new EntityConfiguration<BlahT>({
17
+ idField: 'id',
18
+ tableName: 'blah_table',
19
+ schema: {
20
+ id: new UUIDField({
21
+ columnName: 'id',
22
+ }),
23
+ cacheable: new StringField({
24
+ columnName: 'cacheable',
25
+ cache: true,
26
+ }),
27
+ uniqueButNotCacheable: new StringField({
28
+ columnName: 'unique_but_not_cacheable',
29
+ }),
30
+ },
31
+ databaseAdapterFlavor: 'postgres',
32
+ cacheAdapterFlavor: 'redis',
33
+ });
34
+
35
+ it('returns correct fields', () => {
36
+ expect(blahEntityConfiguration.idField).toEqual('id');
37
+ expect(blahEntityConfiguration.tableName).toEqual('blah_table');
38
+ expect(blahEntityConfiguration.databaseAdapterFlavor).toEqual('postgres');
39
+ expect(blahEntityConfiguration.cacheAdapterFlavor).toEqual('redis');
40
+ });
41
+
42
+ it('filters cacheable fields', () => {
43
+ expect(blahEntityConfiguration.cacheableKeys).toEqual(new Set(['cacheable']));
44
+ });
45
+
46
+ describe('cache key version', () => {
47
+ it('defaults to 0', () => {
48
+ const entityConfiguration = new EntityConfiguration<Blah2T>({
49
+ idField: 'id',
50
+ tableName: 'blah',
51
+ schema: {
52
+ id: new UUIDField({
53
+ columnName: 'id',
54
+ }),
55
+ },
56
+ databaseAdapterFlavor: 'postgres',
57
+ cacheAdapterFlavor: 'redis',
58
+ });
59
+ expect(entityConfiguration.cacheKeyVersion).toEqual(0);
60
+ });
61
+
62
+ it('sets to custom version', () => {
63
+ const entityConfiguration = new EntityConfiguration<Blah2T>({
64
+ idField: 'id',
65
+ tableName: 'blah',
66
+ schema: {
67
+ id: new UUIDField({
68
+ columnName: 'id',
69
+ }),
70
+ },
71
+ databaseAdapterFlavor: 'postgres',
72
+ cacheAdapterFlavor: 'redis',
73
+ cacheKeyVersion: 100,
74
+ });
75
+ expect(entityConfiguration.cacheKeyVersion).toEqual(100);
76
+ });
77
+ });
78
+ });
79
+
80
+ describe('validation', () => {
81
+ describe('disallows keys of JS Object prototype for safety', () => {
82
+ test.each([
83
+ 'constructor',
84
+ '__defineGetter__',
85
+ '__defineSetter__',
86
+ 'hasOwnProperty',
87
+ '__lookupGetter__',
88
+ '__lookupSetter__',
89
+ 'isPrototypeOf',
90
+ 'propertyIsEnumerable',
91
+ 'toString',
92
+ 'valueOf',
93
+ '__proto__',
94
+ 'toLocaleString',
95
+ ])('disallows %p as field key', (keyName) => {
96
+ expect(
97
+ () =>
98
+ new EntityConfiguration<any>({
99
+ idField: 'id',
100
+ tableName: 'blah_table',
101
+ schema: {
102
+ id: new UUIDField({
103
+ columnName: 'id',
104
+ }),
105
+ [keyName]: new StringField({
106
+ columnName: 'any',
107
+ }),
108
+ },
109
+ databaseAdapterFlavor: 'postgres',
110
+ cacheAdapterFlavor: 'redis',
111
+ }),
112
+ ).toThrow(
113
+ `Entity field name not allowed to prevent conflicts with standard Object prototype fields: ${keyName}`,
114
+ );
115
+ });
116
+ });
117
+ });
118
+ });