@expo/entity 0.34.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 (333) 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 +4 -31
  12. package/build/Entity.js +19 -46
  13. package/build/Entity.js.map +1 -1
  14. package/build/EntityAssociationLoader.d.ts +9 -9
  15. package/build/EntityAssociationLoader.js +37 -12
  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/EntityQueryContextProvider.d.ts +1 -1
  55. package/build/EntityQueryContextProvider.js +1 -1
  56. package/build/EntityQueryContextProvider.js.map +1 -1
  57. package/build/EntitySecondaryCacheLoader.js +5 -1
  58. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  59. package/build/GenericEntityCacheAdapter.js +1 -0
  60. package/build/GenericEntityCacheAdapter.js.map +1 -1
  61. package/build/GenericSecondaryEntityCache.js +2 -0
  62. package/build/GenericSecondaryEntityCache.js.map +1 -1
  63. package/build/IEntityCacheAdapterProvider.d.ts +1 -1
  64. package/build/IEntityDatabaseAdapterProvider.d.ts +1 -1
  65. package/build/ReadonlyEntity.d.ts +1 -1
  66. package/build/ReadonlyEntity.js +9 -2
  67. package/build/ReadonlyEntity.js.map +1 -1
  68. package/build/ViewerContext.d.ts +2 -2
  69. package/build/ViewerContext.js +5 -3
  70. package/build/ViewerContext.js.map +1 -1
  71. package/build/ViewerScopedEntityCompanion.js +2 -0
  72. package/build/ViewerScopedEntityCompanion.js.map +1 -1
  73. package/build/ViewerScopedEntityCompanionProvider.d.ts +0 -1
  74. package/build/ViewerScopedEntityCompanionProvider.js +2 -1
  75. package/build/ViewerScopedEntityCompanionProvider.js.map +1 -1
  76. package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
  77. package/build/ViewerScopedEntityLoaderFactory.js +2 -0
  78. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  79. package/build/ViewerScopedEntityMutatorFactory.js +2 -0
  80. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  81. package/build/__tests__/ComposedCacheAdapter-test.js +2 -0
  82. package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
  83. package/build/__tests__/ComposedSecondaryEntityCache-test.js +1 -0
  84. package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +1 -1
  85. package/build/__tests__/EnforcingEntityLoader-test.js +101 -113
  86. package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
  87. package/build/__tests__/Entity-test.js +5 -137
  88. package/build/__tests__/Entity-test.js.map +1 -1
  89. package/build/__tests__/EntityAssociationLoader-test.js +37 -65
  90. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  91. package/build/__tests__/EntityCommonUseCases-test.js +31 -37
  92. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  93. package/build/__tests__/EntityCompanion-test.js +26 -3
  94. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  95. package/build/__tests__/EntityConfiguration-test.js +103 -0
  96. package/build/__tests__/EntityConfiguration-test.js.map +1 -0
  97. package/build/__tests__/EntityDatabaseAdapter-test.js +6 -0
  98. package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
  99. package/build/__tests__/EntityEdges-test.js +89 -80
  100. package/build/__tests__/EntityEdges-test.js.map +1 -1
  101. package/build/__tests__/EntityFields-test.js +6 -0
  102. package/build/__tests__/EntityFields-test.js.map +1 -1
  103. package/build/__tests__/EntityLoader-constructor-test.js +17 -18
  104. package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
  105. package/build/__tests__/EntityLoader-test.js +93 -41
  106. package/build/__tests__/EntityLoader-test.js.map +1 -1
  107. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +18 -21
  108. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  109. package/build/__tests__/EntityMutator-test.js +74 -29
  110. package/build/__tests__/EntityMutator-test.js.map +1 -1
  111. package/build/__tests__/EntityPrivacyPolicy-test.js +77 -59
  112. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  113. package/build/__tests__/EntityQueryContext-test.js +9 -0
  114. package/build/__tests__/EntityQueryContext-test.js.map +1 -1
  115. package/build/__tests__/EntitySecondaryCacheLoader-test.js +10 -10
  116. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
  117. package/build/__tests__/EntitySelfReferentialEdges-test.js +59 -74
  118. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  119. package/build/__tests__/ReadonlyEntity-test.js +13 -13
  120. package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
  121. package/build/__tests__/ViewerContext-test.js +2 -2
  122. package/build/__tests__/ViewerContext-test.js.map +1 -1
  123. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
  124. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +26 -28
  125. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  126. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +25 -30
  127. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  128. package/build/entityUtils.d.ts +1 -1
  129. package/build/entityUtils.js.map +1 -1
  130. package/build/errors/EntityCacheAdapterError.js +2 -5
  131. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  132. package/build/errors/EntityDatabaseAdapterError.js +14 -35
  133. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  134. package/build/errors/EntityError.js +1 -0
  135. package/build/errors/EntityError.js.map +1 -1
  136. package/build/errors/EntityInvalidFieldValueError.js +2 -2
  137. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  138. package/build/errors/EntityNotAuthorizedError.js +3 -2
  139. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  140. package/build/errors/EntityNotFoundError.js +2 -2
  141. package/build/errors/EntityNotFoundError.js.map +1 -1
  142. package/build/index.d.ts +1 -0
  143. package/build/index.js +1 -0
  144. package/build/index.js.map +1 -1
  145. package/build/internal/EntityDataManager.d.ts +1 -1
  146. package/build/internal/EntityDataManager.js +7 -2
  147. package/build/internal/EntityDataManager.js.map +1 -1
  148. package/build/internal/EntityFieldTransformationUtils.d.ts +5 -5
  149. package/build/internal/EntityFieldTransformationUtils.js +5 -8
  150. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  151. package/build/internal/EntityTableDataCoordinator.d.ts +1 -1
  152. package/build/internal/EntityTableDataCoordinator.js +5 -0
  153. package/build/internal/EntityTableDataCoordinator.js.map +1 -1
  154. package/build/internal/ReadThroughEntityCache.d.ts +1 -1
  155. package/build/internal/ReadThroughEntityCache.js +2 -0
  156. package/build/internal/ReadThroughEntityCache.js.map +1 -1
  157. package/build/internal/__tests__/EntityDataManager-test.js +11 -11
  158. package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
  159. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +6 -2
  160. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
  161. package/build/internal/__tests__/ReadThroughEntityCache-test.js +33 -0
  162. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  163. package/build/metrics/IEntityMetricsAdapter.d.ts +1 -1
  164. package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +1 -1
  165. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  166. package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +1 -1
  167. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  168. package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +1 -1
  169. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  170. package/build/rules/PrivacyPolicyRule.d.ts +1 -1
  171. package/build/rules/PrivacyPolicyRule.js.map +1 -1
  172. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
  173. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
  174. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
  175. package/build/testfixtures/DateIDTestEntity.js +12 -15
  176. package/build/testfixtures/DateIDTestEntity.js.map +1 -1
  177. package/build/testfixtures/SimpleTestEntity.d.ts +8 -8
  178. package/build/testfixtures/SimpleTestEntity.js +12 -15
  179. package/build/testfixtures/SimpleTestEntity.js.map +1 -1
  180. package/build/testfixtures/TestEntity.d.ts +12 -12
  181. package/build/testfixtures/TestEntity.js +12 -15
  182. package/build/testfixtures/TestEntity.js.map +1 -1
  183. package/build/testfixtures/TestEntity2.d.ts +8 -8
  184. package/build/testfixtures/TestEntity2.js +12 -15
  185. package/build/testfixtures/TestEntity2.js.map +1 -1
  186. package/build/testfixtures/TestEntityNumberKey.js +12 -15
  187. package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
  188. package/build/testfixtures/TestEntityWithMutationTriggers.d.ts +36 -0
  189. package/build/testfixtures/TestEntityWithMutationTriggers.js +82 -0
  190. package/build/testfixtures/TestEntityWithMutationTriggers.js.map +1 -0
  191. package/build/testfixtures/TestViewerContext.d.ts +0 -3
  192. package/build/testfixtures/TestViewerContext.js +0 -6
  193. package/build/testfixtures/TestViewerContext.js.map +1 -1
  194. package/build/utils/EntityPrivacyUtils.d.ts +34 -0
  195. package/build/utils/EntityPrivacyUtils.js +160 -0
  196. package/build/utils/EntityPrivacyUtils.js.map +1 -0
  197. package/build/utils/__tests__/EntityPrivacyUtils-test.d.ts +1 -0
  198. package/build/utils/__tests__/EntityPrivacyUtils-test.js +395 -0
  199. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -0
  200. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.d.ts +1 -0
  201. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js +26 -0
  202. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js.map +1 -0
  203. package/build/utils/collections/maps.js.map +1 -1
  204. package/build/utils/mergeEntityMutationTriggerConfigurations.d.ts +4 -0
  205. package/build/utils/mergeEntityMutationTriggerConfigurations.js +28 -0
  206. package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -0
  207. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -1
  208. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
  209. package/build/utils/testing/StubCacheAdapter.d.ts +3 -3
  210. package/build/utils/testing/StubCacheAdapter.js +3 -3
  211. package/build/utils/testing/StubCacheAdapter.js.map +1 -1
  212. package/build/utils/testing/StubDatabaseAdapter.d.ts +2 -2
  213. package/build/utils/testing/StubDatabaseAdapter.js +4 -2
  214. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  215. package/build/utils/testing/StubDatabaseAdapterProvider.d.ts +1 -1
  216. package/build/utils/testing/StubDatabaseAdapterProvider.js +1 -3
  217. package/build/utils/testing/StubDatabaseAdapterProvider.js.map +1 -1
  218. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.d.ts +1 -0
  219. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js +42 -0
  220. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js.map +1 -0
  221. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +53 -0
  222. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
  223. package/build/utils/testing/describeFieldTestCase.js.map +1 -1
  224. package/package.json +4 -3
  225. package/src/AuthorizationResultBasedEntityLoader.ts +297 -0
  226. package/src/ComposedEntityCacheAdapter.ts +6 -6
  227. package/src/ComposedSecondaryEntityCache.ts +8 -8
  228. package/src/EnforcingEntityLoader.ts +20 -19
  229. package/src/Entity.ts +26 -118
  230. package/src/EntityAssociationLoader.ts +56 -41
  231. package/src/EntityCompanion.ts +8 -4
  232. package/src/EntityCompanionProvider.ts +24 -16
  233. package/src/EntityConfiguration.ts +18 -7
  234. package/src/EntityDatabaseAdapter.ts +41 -41
  235. package/src/EntityFieldDefinition.ts +28 -18
  236. package/src/EntityFields.ts +15 -0
  237. package/src/EntityLoader.ts +63 -357
  238. package/src/EntityLoaderFactory.ts +10 -4
  239. package/src/EntityLoaderUtils.ts +149 -0
  240. package/src/EntityMutationInfo.ts +2 -2
  241. package/src/EntityMutationTriggerConfiguration.ts +5 -5
  242. package/src/EntityMutationValidator.ts +2 -2
  243. package/src/EntityMutator.ts +146 -144
  244. package/src/EntityMutatorFactory.ts +8 -8
  245. package/src/EntityPrivacyPolicy.ts +78 -28
  246. package/src/EntityQueryContext.ts +14 -13
  247. package/src/EntityQueryContextProvider.ts +6 -6
  248. package/src/EntitySecondaryCacheLoader.ts +13 -11
  249. package/src/GenericEntityCacheAdapter.ts +10 -10
  250. package/src/GenericSecondaryEntityCache.ts +6 -6
  251. package/src/IEntityCacheAdapter.ts +4 -4
  252. package/src/IEntityCacheAdapterProvider.ts +2 -2
  253. package/src/IEntityDatabaseAdapterProvider.ts +2 -2
  254. package/src/ReadonlyEntity.ts +8 -5
  255. package/src/ViewerContext.ts +10 -10
  256. package/src/ViewerScopedEntityCompanion.ts +4 -4
  257. package/src/ViewerScopedEntityCompanionProvider.ts +4 -5
  258. package/src/ViewerScopedEntityLoaderFactory.ts +10 -4
  259. package/src/ViewerScopedEntityMutatorFactory.ts +5 -5
  260. package/src/__tests__/ComposedCacheAdapter-test.ts +12 -10
  261. package/src/__tests__/ComposedSecondaryEntityCache-test.ts +8 -8
  262. package/src/__tests__/EnforcingEntityLoader-test.ts +236 -159
  263. package/src/__tests__/Entity-test.ts +5 -223
  264. package/src/__tests__/EntityAssociationLoader-test.ts +91 -169
  265. package/src/__tests__/EntityCommonUseCases-test.ts +36 -38
  266. package/src/__tests__/EntityCompanion-test.ts +57 -5
  267. package/src/__tests__/EntityConfiguration-test.ts +118 -0
  268. package/src/__tests__/EntityDatabaseAdapter-test.ts +11 -11
  269. package/src/__tests__/EntityEdges-test.ts +128 -118
  270. package/src/__tests__/EntityFields-test.ts +14 -2
  271. package/src/__tests__/EntityLoader-constructor-test.ts +21 -8
  272. package/src/__tests__/EntityLoader-test.ts +233 -105
  273. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +17 -20
  274. package/src/__tests__/EntityMutator-test.ts +342 -163
  275. package/src/__tests__/EntityPrivacyPolicy-test.ts +166 -53
  276. package/src/__tests__/EntityQueryContext-test.ts +30 -12
  277. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +17 -26
  278. package/src/__tests__/EntitySelfReferentialEdges-test.ts +67 -115
  279. package/src/__tests__/GenericEntityCacheAdapter-test.ts +2 -2
  280. package/src/__tests__/ReadonlyEntity-test.ts +13 -15
  281. package/src/__tests__/ViewerContext-test.ts +3 -4
  282. package/src/__tests__/ViewerScopedEntityCompanion-test.ts +2 -2
  283. package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +2 -2
  284. package/src/__tests__/ViewerScopedEntityLoaderFactory-test.ts +2 -1
  285. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +34 -45
  286. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +22 -30
  287. package/src/__tests__/entityUtils-test.ts +2 -2
  288. package/src/entityUtils.ts +4 -4
  289. package/src/errors/EntityError.ts +4 -1
  290. package/src/errors/EntityInvalidFieldValueError.ts +2 -2
  291. package/src/errors/EntityNotAuthorizedError.ts +3 -3
  292. package/src/errors/EntityNotFoundError.ts +2 -2
  293. package/src/index.ts +1 -0
  294. package/src/internal/EntityDataManager.ts +25 -25
  295. package/src/internal/EntityFieldTransformationUtils.ts +39 -32
  296. package/src/internal/EntityTableDataCoordinator.ts +3 -3
  297. package/src/internal/ReadThroughEntityCache.ts +9 -9
  298. package/src/internal/__tests__/EntityDataManager-test.ts +62 -62
  299. package/src/internal/__tests__/EntityFieldTransformationUtils-test.ts +14 -10
  300. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +74 -18
  301. package/src/metrics/EntityMetricsUtils.ts +4 -4
  302. package/src/metrics/IEntityMetricsAdapter.ts +1 -1
  303. package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +9 -3
  304. package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +9 -3
  305. package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +9 -3
  306. package/src/rules/PrivacyPolicyRule.ts +9 -3
  307. package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -1
  308. package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -1
  309. package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -1
  310. package/src/testfixtures/SimpleTestEntity.ts +8 -8
  311. package/src/testfixtures/TestEntity.ts +13 -16
  312. package/src/testfixtures/TestEntity2.ts +8 -8
  313. package/src/testfixtures/TestEntityWithMutationTriggers.ts +156 -0
  314. package/src/testfixtures/TestViewerContext.ts +1 -12
  315. package/src/utils/EntityPrivacyUtils.ts +325 -0
  316. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +570 -0
  317. package/src/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.ts +29 -0
  318. package/src/utils/collections/__tests__/maps-test.ts +2 -2
  319. package/src/utils/collections/maps.ts +11 -11
  320. package/src/utils/mergeEntityMutationTriggerConfigurations.ts +44 -0
  321. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +25 -22
  322. package/src/utils/testing/StubCacheAdapter.ts +17 -15
  323. package/src/utils/testing/StubDatabaseAdapter.ts +35 -30
  324. package/src/utils/testing/StubDatabaseAdapterProvider.ts +2 -2
  325. package/src/utils/testing/StubQueryContextProvider.ts +2 -2
  326. package/src/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.ts +42 -0
  327. package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +111 -29
  328. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +2 -2
  329. package/src/utils/testing/describeFieldTestCase.ts +1 -1
  330. package/build/__tests__/EntityDataConfiguration-test.js +0 -68
  331. package/build/__tests__/EntityDataConfiguration-test.js.map +0 -1
  332. package/src/__tests__/EntityDataConfiguration-test.ts +0 -77
  333. /package/build/__tests__/{EntityDataConfiguration-test.d.ts → EntityConfiguration-test.d.ts} +0 -0
@@ -0,0 +1,570 @@
1
+ import Entity from '../../Entity';
2
+ import { EntityCompanionDefinition } from '../../EntityCompanionProvider';
3
+ import EntityConfiguration from '../../EntityConfiguration';
4
+ import { EntityEdgeDeletionBehavior } from '../../EntityFieldDefinition';
5
+ import { UUIDField } from '../../EntityFields';
6
+ import EntityPrivacyPolicy, {
7
+ EntityPrivacyPolicyEvaluationContext,
8
+ } from '../../EntityPrivacyPolicy';
9
+ import { EntityQueryContext } from '../../EntityQueryContext';
10
+ import ReadonlyEntity from '../../ReadonlyEntity';
11
+ import ViewerContext from '../../ViewerContext';
12
+ import AlwaysAllowPrivacyPolicyRule from '../../rules/AlwaysAllowPrivacyPolicyRule';
13
+ import AlwaysDenyPrivacyPolicyRule from '../../rules/AlwaysDenyPrivacyPolicyRule';
14
+ import { RuleEvaluationResult } from '../../rules/PrivacyPolicyRule';
15
+ import { canViewerDeleteAsync, canViewerUpdateAsync } from '../EntityPrivacyUtils';
16
+ import { createUnitTestEntityCompanionProvider } from '../testing/createUnitTestEntityCompanionProvider';
17
+
18
+ describe(canViewerUpdateAsync, () => {
19
+ it('appropriately executes update privacy policy', async () => {
20
+ const companionProvider = createUnitTestEntityCompanionProvider();
21
+ const viewerContext = new ViewerContext(companionProvider);
22
+ const testEntity = await SimpleTestDenyDeleteEntity.creator(viewerContext).enforceCreateAsync();
23
+ const canViewerUpdate = await canViewerUpdateAsync(SimpleTestDenyDeleteEntity, testEntity);
24
+ expect(canViewerUpdate).toBe(true);
25
+ });
26
+
27
+ it('denies when policy denies', async () => {
28
+ const companionProvider = createUnitTestEntityCompanionProvider();
29
+ const viewerContext = new ViewerContext(companionProvider);
30
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(viewerContext).enforceCreateAsync();
31
+ const canViewerUpdate = await canViewerUpdateAsync(SimpleTestDenyUpdateEntity, testEntity);
32
+ expect(canViewerUpdate).toBe(false);
33
+ });
34
+
35
+ it('rethrows non-authorization errors', async () => {
36
+ const companionProvider = createUnitTestEntityCompanionProvider();
37
+ const viewerContext = new ViewerContext(companionProvider);
38
+ const testEntity =
39
+ await SimpleTestThrowOtherErrorEntity.creator(viewerContext).enforceCreateAsync();
40
+ await expect(canViewerUpdateAsync(SimpleTestThrowOtherErrorEntity, testEntity)).rejects.toThrow(
41
+ 'update error',
42
+ );
43
+ });
44
+ });
45
+
46
+ describe(canViewerDeleteAsync, () => {
47
+ it('appropriately executes update privacy policy', async () => {
48
+ const companionProvider = createUnitTestEntityCompanionProvider();
49
+ const viewerContext = new ViewerContext(companionProvider);
50
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(viewerContext).enforceCreateAsync();
51
+ const canViewerDelete = await canViewerDeleteAsync(SimpleTestDenyUpdateEntity, testEntity);
52
+ expect(canViewerDelete).toBe(true);
53
+ });
54
+
55
+ it('denies when policy denies', async () => {
56
+ const companionProvider = createUnitTestEntityCompanionProvider();
57
+ const viewerContext = new ViewerContext(companionProvider);
58
+ const testEntity = await SimpleTestDenyDeleteEntity.creator(viewerContext).enforceCreateAsync();
59
+ const canViewerDelete = await canViewerDeleteAsync(SimpleTestDenyDeleteEntity, testEntity);
60
+ expect(canViewerDelete).toBe(false);
61
+ });
62
+
63
+ it('denies when recursive policy denies for CASCADE_DELETE', async () => {
64
+ const companionProvider = createUnitTestEntityCompanionProvider();
65
+ const viewerContext = new ViewerContext(companionProvider);
66
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(viewerContext).enforceCreateAsync();
67
+ // add another entity referencing testEntity that would cascade deletion to itself when testEntity is deleted
68
+ await LeafDenyDeleteEntity.creator(viewerContext)
69
+ .setField('simple_test_deny_update_cascade_delete_id', testEntity.getID())
70
+ .enforceCreateAsync();
71
+ const canViewerDelete = await canViewerDeleteAsync(SimpleTestDenyUpdateEntity, testEntity);
72
+ expect(canViewerDelete).toBe(false);
73
+ });
74
+
75
+ it('denies when recursive policy denies for SET_NULL', async () => {
76
+ const companionProvider = createUnitTestEntityCompanionProvider();
77
+ const viewerContext = new ViewerContext(companionProvider);
78
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(viewerContext).enforceCreateAsync();
79
+ // add another entity referencing testEntity that would set null to its column when testEntity is deleted
80
+ await LeafDenyUpdateEntity.creator(viewerContext)
81
+ .setField('simple_test_deny_update_set_null_id', testEntity.getID())
82
+ .enforceCreateAsync();
83
+ const canViewerDelete = await canViewerDeleteAsync(SimpleTestDenyUpdateEntity, testEntity);
84
+ expect(canViewerDelete).toBe(false);
85
+ });
86
+
87
+ it('allows when recursive policy allows for CASCADE_DELETE and SET_NULL', async () => {
88
+ const companionProvider = createUnitTestEntityCompanionProvider();
89
+ const viewerContext = new ViewerContext(companionProvider);
90
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(viewerContext).enforceCreateAsync();
91
+ // add another entity referencing testEntity that would cascade deletion to itself when testEntity is deleted
92
+ await LeafDenyUpdateEntity.creator(viewerContext)
93
+ .setField('simple_test_deny_update_cascade_delete_id', testEntity.getID())
94
+ .enforceCreateAsync();
95
+ // add another entity referencing testEntity that would set null to its column when testEntity is deleted
96
+ await LeafDenyDeleteEntity.creator(viewerContext)
97
+ .setField('simple_test_deny_update_set_null_id', testEntity.getID())
98
+ .enforceCreateAsync();
99
+
100
+ const canViewerDelete = await canViewerDeleteAsync(SimpleTestDenyUpdateEntity, testEntity);
101
+ expect(canViewerDelete).toBe(true);
102
+ });
103
+
104
+ it('rethrows non-authorization errors', async () => {
105
+ const companionProvider = createUnitTestEntityCompanionProvider();
106
+ const viewerContext = new ViewerContext(companionProvider);
107
+ const testEntity =
108
+ await SimpleTestThrowOtherErrorEntity.creator(viewerContext).enforceCreateAsync();
109
+ await expect(
110
+ canViewerDeleteAsync(SimpleTestThrowOtherErrorEntity, testEntity),
111
+ ).rejects.toThrowError('delete error');
112
+ });
113
+
114
+ it('returns false when edge cannot be read', async () => {
115
+ const companionProvider = createUnitTestEntityCompanionProvider();
116
+ const viewerContext = new ViewerContext(companionProvider);
117
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(viewerContext).enforceCreateAsync();
118
+ await LeafDenyReadEntity.creator(viewerContext)
119
+ .setField('simple_test_id', testEntity.getID())
120
+ .enforceCreateAsync();
121
+ const canViewerDelete = await canViewerDeleteAsync(SimpleTestDenyUpdateEntity, testEntity);
122
+ expect(canViewerDelete).toBe(false);
123
+ });
124
+
125
+ it('rethrows non-authorization edge read errors', async () => {
126
+ const companionProvider = createUnitTestEntityCompanionProvider();
127
+ const viewerContext = new ViewerContext(companionProvider);
128
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(viewerContext).enforceCreateAsync();
129
+ await SimpleTestThrowOtherErrorEntity.creator(viewerContext)
130
+ .setField('simple_test_id', testEntity.getID())
131
+ .enforceCreateAsync();
132
+ await expect(canViewerDeleteAsync(SimpleTestDenyUpdateEntity, testEntity)).rejects.toThrowError(
133
+ 'read in cascading delete error',
134
+ );
135
+ });
136
+
137
+ it('supports running within a transaction', async () => {
138
+ const companionProvider = createUnitTestEntityCompanionProvider();
139
+ const viewerContext = new ViewerContext(companionProvider);
140
+ const canViewerDelete = await viewerContext.runInTransactionForDatabaseAdaptorFlavorAsync(
141
+ 'postgres',
142
+ async (queryContext) => {
143
+ const testEntity = await SimpleTestDenyUpdateEntity.creator(
144
+ viewerContext,
145
+ queryContext,
146
+ ).enforceCreateAsync();
147
+ await LeafDenyReadEntity.creator(viewerContext, queryContext)
148
+ .setField('simple_test_id', testEntity.getID())
149
+ .enforceCreateAsync();
150
+ // this would fail if transactions weren't supported or correctly passed through
151
+ return await canViewerDeleteAsync(SimpleTestDenyUpdateEntity, testEntity, queryContext);
152
+ },
153
+ );
154
+
155
+ expect(canViewerDelete).toBe(true);
156
+ });
157
+ });
158
+
159
+ type TestEntityFields = {
160
+ id: string;
161
+ };
162
+
163
+ type TestLeafDenyDeleteFields = {
164
+ id: string;
165
+ simple_test_deny_update_cascade_delete_id: string | null;
166
+ simple_test_deny_update_set_null_id: string | null;
167
+ };
168
+
169
+ type TestLeafDenyUpdateFields = {
170
+ id: string;
171
+ unused_other_association: string | null;
172
+ simple_test_deny_update_set_null_id: string | null;
173
+ simple_test_deny_update_cascade_delete_id: string | null;
174
+ };
175
+
176
+ type TestLeafDenyReadFields = {
177
+ id: string;
178
+ simple_test_id: string | null;
179
+ };
180
+
181
+ type TestEntityThrowOtherErrorFields = {
182
+ id: string;
183
+ simple_test_id: string | null;
184
+ };
185
+
186
+ class DenyUpdateEntityPrivacyPolicy<
187
+ TFields extends object,
188
+ TID extends NonNullable<TFields[TSelectedFields]>,
189
+ TViewerContext extends ViewerContext,
190
+ TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
191
+ TSelectedFields extends keyof TFields = keyof TFields,
192
+ > extends EntityPrivacyPolicy<TFields, TID, TViewerContext, TEntity, TSelectedFields> {
193
+ protected override readonly readRules = [
194
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
195
+ ];
196
+ protected override readonly createRules = [
197
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
198
+ ];
199
+ protected override readonly updateRules = [
200
+ new AlwaysDenyPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
201
+ ];
202
+ protected override readonly deleteRules = [
203
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
204
+ ];
205
+ }
206
+
207
+ class DenyDeleteEntityPrivacyPolicy<
208
+ TFields extends object,
209
+ TID extends NonNullable<TFields[TSelectedFields]>,
210
+ TViewerContext extends ViewerContext,
211
+ TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
212
+ TSelectedFields extends keyof TFields = keyof TFields,
213
+ > extends EntityPrivacyPolicy<TFields, TID, TViewerContext, TEntity, TSelectedFields> {
214
+ protected override readonly readRules = [
215
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
216
+ ];
217
+ protected override readonly createRules = [
218
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
219
+ ];
220
+ protected override readonly updateRules = [
221
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
222
+ ];
223
+ protected override readonly deleteRules = [
224
+ new AlwaysDenyPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
225
+ ];
226
+ }
227
+
228
+ class ThrowOtherErrorEntityPrivacyPolicy<
229
+ TFields extends object,
230
+ TID extends NonNullable<TFields[TSelectedFields]>,
231
+ TViewerContext extends ViewerContext,
232
+ TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
233
+ TSelectedFields extends keyof TFields = keyof TFields,
234
+ > extends EntityPrivacyPolicy<TFields, TID, TViewerContext, TEntity, TSelectedFields> {
235
+ protected override readonly readRules = [
236
+ {
237
+ async evaluateAsync(
238
+ _viewerContext: TViewerContext,
239
+ _queryContext: EntityQueryContext,
240
+ evaluationContext: EntityPrivacyPolicyEvaluationContext<
241
+ TFields,
242
+ TID,
243
+ TViewerContext,
244
+ TEntity,
245
+ TSelectedFields
246
+ >,
247
+ _entity: TEntity,
248
+ ): Promise<RuleEvaluationResult> {
249
+ if (evaluationContext.cascadingDeleteCause) {
250
+ throw new Error('read in cascading delete error');
251
+ }
252
+ return RuleEvaluationResult.SKIP;
253
+ },
254
+ },
255
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
256
+ ];
257
+ protected override readonly createRules = [
258
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
259
+ ];
260
+ protected override readonly updateRules = [
261
+ {
262
+ async evaluateAsync(): Promise<RuleEvaluationResult> {
263
+ throw new Error('update error');
264
+ },
265
+ },
266
+ ];
267
+ protected override readonly deleteRules = [
268
+ {
269
+ async evaluateAsync(): Promise<RuleEvaluationResult> {
270
+ throw new Error('delete error');
271
+ },
272
+ },
273
+ ];
274
+ }
275
+
276
+ class DenyReadEntityPrivacyPolicy<
277
+ TFields extends object,
278
+ TID extends NonNullable<TFields[TSelectedFields]>,
279
+ TViewerContext extends ViewerContext,
280
+ TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
281
+ TSelectedFields extends keyof TFields = keyof TFields,
282
+ > extends EntityPrivacyPolicy<TFields, TID, TViewerContext, TEntity, TSelectedFields> {
283
+ protected override readonly readRules = [
284
+ {
285
+ async evaluateAsync(
286
+ _viewerContext: TViewerContext,
287
+ queryContext: EntityQueryContext,
288
+ evaluationContext: EntityPrivacyPolicyEvaluationContext<
289
+ TFields,
290
+ TID,
291
+ TViewerContext,
292
+ TEntity,
293
+ TSelectedFields
294
+ >,
295
+ _entity: TEntity,
296
+ ): Promise<RuleEvaluationResult> {
297
+ if (queryContext.isInTransaction()) {
298
+ return RuleEvaluationResult.ALLOW;
299
+ }
300
+ return evaluationContext.cascadingDeleteCause
301
+ ? RuleEvaluationResult.SKIP
302
+ : RuleEvaluationResult.ALLOW;
303
+ },
304
+ },
305
+ ];
306
+ protected override readonly createRules = [
307
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
308
+ ];
309
+ protected override readonly updateRules = [
310
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
311
+ ];
312
+ protected override readonly deleteRules = [
313
+ new AlwaysAllowPrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields>(),
314
+ ];
315
+ }
316
+
317
+ class LeafDenyUpdateEntity extends Entity<TestLeafDenyUpdateFields, string, ViewerContext> {
318
+ static defineCompanionDefinition(): EntityCompanionDefinition<
319
+ TestLeafDenyUpdateFields,
320
+ string,
321
+ ViewerContext,
322
+ LeafDenyUpdateEntity,
323
+ DenyUpdateEntityPrivacyPolicy<
324
+ TestLeafDenyUpdateFields,
325
+ string,
326
+ ViewerContext,
327
+ LeafDenyUpdateEntity
328
+ >
329
+ > {
330
+ return {
331
+ entityClass: LeafDenyUpdateEntity,
332
+ entityConfiguration: new EntityConfiguration<TestLeafDenyUpdateFields>({
333
+ idField: 'id',
334
+ tableName: 'leaf_1',
335
+ schema: {
336
+ id: new UUIDField({
337
+ columnName: 'custom_id',
338
+ }),
339
+ // to ensure edge traversal doesn't process other edges
340
+ unused_other_association: new UUIDField({
341
+ columnName: 'unused_other_association',
342
+ association: {
343
+ associatedEntityClass: LeafDenyDeleteEntity,
344
+ edgeDeletionBehavior: EntityEdgeDeletionBehavior.SET_NULL,
345
+ },
346
+ }),
347
+ // deletion behavior should fail since this entity can't be updated and a SET NULL does an update
348
+ simple_test_deny_update_set_null_id: new UUIDField({
349
+ columnName: 'simple_test_deny_update_set_null_id',
350
+ association: {
351
+ associatedEntityClass: SimpleTestDenyUpdateEntity,
352
+ edgeDeletionBehavior: EntityEdgeDeletionBehavior.SET_NULL,
353
+ },
354
+ }),
355
+ // deletion behavior should succeed since this entity can be deleted
356
+ simple_test_deny_update_cascade_delete_id: new UUIDField({
357
+ columnName: 'simple_test_deny_update_cascade_delete_id',
358
+ association: {
359
+ associatedEntityClass: SimpleTestDenyUpdateEntity,
360
+ edgeDeletionBehavior: EntityEdgeDeletionBehavior.CASCADE_DELETE,
361
+ },
362
+ }),
363
+ },
364
+ databaseAdapterFlavor: 'postgres',
365
+ cacheAdapterFlavor: 'redis',
366
+ }),
367
+ privacyPolicyClass: DenyUpdateEntityPrivacyPolicy,
368
+ };
369
+ }
370
+ }
371
+
372
+ class LeafDenyDeleteEntity extends Entity<TestLeafDenyDeleteFields, string, ViewerContext> {
373
+ static defineCompanionDefinition(): EntityCompanionDefinition<
374
+ TestLeafDenyDeleteFields,
375
+ string,
376
+ ViewerContext,
377
+ LeafDenyDeleteEntity,
378
+ DenyDeleteEntityPrivacyPolicy<
379
+ TestLeafDenyDeleteFields,
380
+ string,
381
+ ViewerContext,
382
+ LeafDenyDeleteEntity
383
+ >
384
+ > {
385
+ return {
386
+ entityClass: LeafDenyDeleteEntity,
387
+ entityConfiguration: new EntityConfiguration<TestLeafDenyDeleteFields>({
388
+ idField: 'id',
389
+ tableName: 'leaf_2',
390
+ schema: {
391
+ id: new UUIDField({
392
+ columnName: 'custom_id',
393
+ }),
394
+ // deletion behavior should fail since this entity can't be deleted
395
+ simple_test_deny_update_cascade_delete_id: new UUIDField({
396
+ columnName: 'simple_test_deny_update_cascade_delete_id',
397
+ association: {
398
+ associatedEntityClass: SimpleTestDenyUpdateEntity,
399
+ edgeDeletionBehavior: EntityEdgeDeletionBehavior.CASCADE_DELETE,
400
+ },
401
+ }),
402
+ // deletion behavior should succeed since this entity can be updated and a SET NULL does an update
403
+ simple_test_deny_update_set_null_id: new UUIDField({
404
+ columnName: 'simple_test_deny_update_set_null_id',
405
+ association: {
406
+ associatedEntityClass: SimpleTestDenyUpdateEntity,
407
+ edgeDeletionBehavior: EntityEdgeDeletionBehavior.SET_NULL,
408
+ },
409
+ }),
410
+ },
411
+ databaseAdapterFlavor: 'postgres',
412
+ cacheAdapterFlavor: 'redis',
413
+ }),
414
+ privacyPolicyClass: DenyDeleteEntityPrivacyPolicy,
415
+ };
416
+ }
417
+ }
418
+
419
+ class LeafDenyReadEntity extends Entity<TestLeafDenyReadFields, string, ViewerContext> {
420
+ static defineCompanionDefinition(): EntityCompanionDefinition<
421
+ TestLeafDenyReadFields,
422
+ string,
423
+ ViewerContext,
424
+ LeafDenyReadEntity,
425
+ DenyReadEntityPrivacyPolicy<TestLeafDenyReadFields, string, ViewerContext, LeafDenyReadEntity>
426
+ > {
427
+ return {
428
+ entityClass: LeafDenyReadEntity,
429
+ entityConfiguration: new EntityConfiguration<TestLeafDenyReadFields>({
430
+ idField: 'id',
431
+ tableName: 'leaf_4',
432
+ inboundEdges: [],
433
+ schema: {
434
+ id: new UUIDField({
435
+ columnName: 'custom_id',
436
+ }),
437
+ simple_test_id: new UUIDField({
438
+ columnName: 'simple_test_id',
439
+ association: {
440
+ associatedEntityClass: SimpleTestDenyUpdateEntity,
441
+ associatedEntityLookupByField: 'id',
442
+ edgeDeletionBehavior: EntityEdgeDeletionBehavior.SET_NULL,
443
+ },
444
+ }),
445
+ },
446
+ databaseAdapterFlavor: 'postgres',
447
+ cacheAdapterFlavor: 'redis',
448
+ }),
449
+ privacyPolicyClass: DenyReadEntityPrivacyPolicy,
450
+ };
451
+ }
452
+ }
453
+
454
+ class SimpleTestDenyUpdateEntity extends Entity<TestEntityFields, string, ViewerContext> {
455
+ static defineCompanionDefinition(): EntityCompanionDefinition<
456
+ TestEntityFields,
457
+ string,
458
+ ViewerContext,
459
+ SimpleTestDenyUpdateEntity,
460
+ DenyUpdateEntityPrivacyPolicy<
461
+ TestEntityFields,
462
+ string,
463
+ ViewerContext,
464
+ SimpleTestDenyUpdateEntity
465
+ >
466
+ > {
467
+ return {
468
+ entityClass: SimpleTestDenyUpdateEntity,
469
+ entityConfiguration: new EntityConfiguration<TestEntityFields>({
470
+ idField: 'id',
471
+ tableName: 'blah',
472
+ inboundEdges: [
473
+ LeafDenyUpdateEntity,
474
+ LeafDenyDeleteEntity,
475
+ LeafDenyReadEntity,
476
+ SimpleTestThrowOtherErrorEntity,
477
+ ],
478
+ schema: {
479
+ id: new UUIDField({
480
+ columnName: 'custom_id',
481
+ }),
482
+ },
483
+ databaseAdapterFlavor: 'postgres',
484
+ cacheAdapterFlavor: 'redis',
485
+ }),
486
+ privacyPolicyClass: DenyUpdateEntityPrivacyPolicy,
487
+ };
488
+ }
489
+ }
490
+
491
+ class SimpleTestDenyDeleteEntity extends Entity<TestEntityFields, string, ViewerContext> {
492
+ static defineCompanionDefinition(): EntityCompanionDefinition<
493
+ TestEntityFields,
494
+ string,
495
+ ViewerContext,
496
+ SimpleTestDenyDeleteEntity,
497
+ DenyDeleteEntityPrivacyPolicy<
498
+ TestEntityFields,
499
+ string,
500
+ ViewerContext,
501
+ SimpleTestDenyDeleteEntity
502
+ >
503
+ > {
504
+ return {
505
+ entityClass: SimpleTestDenyDeleteEntity,
506
+ entityConfiguration: new EntityConfiguration<TestEntityFields>({
507
+ idField: 'id',
508
+ tableName: 'blah_2',
509
+ inboundEdges: [
510
+ LeafDenyUpdateEntity,
511
+ LeafDenyDeleteEntity,
512
+ LeafDenyReadEntity,
513
+ SimpleTestThrowOtherErrorEntity,
514
+ ],
515
+ schema: {
516
+ id: new UUIDField({
517
+ columnName: 'custom_id',
518
+ }),
519
+ },
520
+ databaseAdapterFlavor: 'postgres',
521
+ cacheAdapterFlavor: 'redis',
522
+ }),
523
+ privacyPolicyClass: DenyDeleteEntityPrivacyPolicy,
524
+ };
525
+ }
526
+ }
527
+
528
+ class SimpleTestThrowOtherErrorEntity extends Entity<
529
+ TestEntityThrowOtherErrorFields,
530
+ string,
531
+ ViewerContext
532
+ > {
533
+ static defineCompanionDefinition(): EntityCompanionDefinition<
534
+ TestEntityThrowOtherErrorFields,
535
+ string,
536
+ ViewerContext,
537
+ SimpleTestThrowOtherErrorEntity,
538
+ ThrowOtherErrorEntityPrivacyPolicy<
539
+ TestEntityThrowOtherErrorFields,
540
+ string,
541
+ ViewerContext,
542
+ SimpleTestThrowOtherErrorEntity
543
+ >
544
+ > {
545
+ return {
546
+ entityClass: SimpleTestThrowOtherErrorEntity,
547
+ entityConfiguration: new EntityConfiguration<TestEntityThrowOtherErrorFields>({
548
+ idField: 'id',
549
+ tableName: 'blah_3',
550
+ inboundEdges: [],
551
+ schema: {
552
+ id: new UUIDField({
553
+ columnName: 'custom_id',
554
+ }),
555
+ simple_test_id: new UUIDField({
556
+ columnName: 'simple_test_id',
557
+ association: {
558
+ associatedEntityClass: SimpleTestDenyUpdateEntity,
559
+ associatedEntityLookupByField: 'id',
560
+ edgeDeletionBehavior: EntityEdgeDeletionBehavior.SET_NULL,
561
+ },
562
+ }),
563
+ },
564
+ databaseAdapterFlavor: 'postgres',
565
+ cacheAdapterFlavor: 'redis',
566
+ }),
567
+ privacyPolicyClass: ThrowOtherErrorEntityPrivacyPolicy,
568
+ };
569
+ }
570
+ }
@@ -0,0 +1,29 @@
1
+ import { TestMutationTrigger } from '../../testfixtures/TestEntityWithMutationTriggers';
2
+ import { mergeEntityMutationTriggerConfigurations } from '../mergeEntityMutationTriggerConfigurations';
3
+
4
+ describe(mergeEntityMutationTriggerConfigurations, () => {
5
+ it('successfully merges triggers', async () => {
6
+ const firstAfter = new TestMutationTrigger('2');
7
+ const secondAfter = new TestMutationTrigger('3');
8
+
9
+ const merged = mergeEntityMutationTriggerConfigurations(
10
+ {
11
+ beforeAll: [new TestMutationTrigger('1')],
12
+ afterAll: [firstAfter],
13
+ },
14
+ {
15
+ afterAll: [secondAfter],
16
+ },
17
+ );
18
+
19
+ expect(merged.beforeAll?.length).toBe(1);
20
+ expect(merged.afterAll).toEqual([firstAfter, secondAfter]);
21
+ expect(merged.beforeCreate?.length).toBeFalsy();
22
+ expect(merged.afterCreate?.length).toBeFalsy();
23
+ expect(merged.beforeUpdate?.length).toBeFalsy();
24
+ expect(merged.afterUpdate?.length).toBeFalsy();
25
+ expect(merged.beforeDelete?.length).toBeFalsy();
26
+ expect(merged.afterDelete?.length).toBeFalsy();
27
+ expect(merged.afterCommit?.length).toBeFalsy();
28
+ });
29
+ });
@@ -70,7 +70,7 @@ describe(zipToMap, () => {
70
70
  const keys = [1, 2];
71
71
  const values = [1];
72
72
  expect(() => zipToMap(keys, values)).toThrowError(
73
- 'zipToMap input length mismatch: keys[2], values[1]'
73
+ 'zipToMap input length mismatch: keys[2], values[1]',
74
74
  );
75
75
  });
76
76
  });
@@ -115,7 +115,7 @@ describe(reduceMapAsync, () => {
115
115
  const reduction = await reduceMapAsync(
116
116
  map,
117
117
  async (acc, v, k) => acc.concat(v).concat(k),
118
- 'initial-'
118
+ 'initial-',
119
119
  );
120
120
  expect(reduction).toEqual('initial-aabb');
121
121
  });