@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
package/src/Entity.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Result, asyncResult } from '@expo/results';
1
+ import { Result } from '@expo/results';
2
2
 
3
3
  import { EntityCompanionDefinition } from './EntityCompanionProvider';
4
4
  import { CreateMutator, UpdateMutator } from './EntityMutator';
@@ -29,7 +29,7 @@ export default abstract class Entity<
29
29
  TFields extends object,
30
30
  TID extends NonNullable<TFields[TSelectedFields]>,
31
31
  TViewerContext extends ViewerContext,
32
- TSelectedFields extends keyof TFields = keyof TFields
32
+ TSelectedFields extends keyof TFields = keyof TFields,
33
33
  > extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields> {
34
34
  /**
35
35
  * Vend mutator for creating a new entity in given query context.
@@ -50,7 +50,7 @@ export default abstract class Entity<
50
50
  TMEntity,
51
51
  TMSelectedFields
52
52
  >,
53
- TMSelectedFields extends keyof TMFields = keyof TMFields
53
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
54
54
  >(
55
55
  this: IEntityClass<
56
56
  TMFields,
@@ -61,7 +61,10 @@ export default abstract class Entity<
61
61
  TMSelectedFields
62
62
  >,
63
63
  viewerContext: TMViewerContext2,
64
- queryContext: EntityQueryContext
64
+ queryContext: EntityQueryContext = viewerContext
65
+ .getViewerScopedEntityCompanionForClass(this)
66
+ .getQueryContextProvider()
67
+ .getQueryContext(),
65
68
  ): CreateMutator<TMFields, TMID, TMViewerContext, TMEntity, TMPrivacyPolicy, TMSelectedFields> {
66
69
  return viewerContext
67
70
  .getViewerScopedEntityCompanionForClass(this)
@@ -87,7 +90,7 @@ export default abstract class Entity<
87
90
  TMEntity,
88
91
  TMSelectedFields
89
92
  >,
90
- TMSelectedFields extends keyof TMFields = keyof TMFields
93
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
91
94
  >(
92
95
  this: IEntityClass<
93
96
  TMFields,
@@ -98,7 +101,11 @@ export default abstract class Entity<
98
101
  TMSelectedFields
99
102
  >,
100
103
  existingEntity: TMEntity,
101
- queryContext: EntityQueryContext
104
+ queryContext: EntityQueryContext = existingEntity
105
+ .getViewerContext()
106
+ .getViewerScopedEntityCompanionForClass(this)
107
+ .getQueryContextProvider()
108
+ .getQueryContext(),
102
109
  ): UpdateMutator<TMFields, TMID, TMViewerContext, TMEntity, TMPrivacyPolicy, TMSelectedFields> {
103
110
  return existingEntity
104
111
  .getViewerContext()
@@ -124,7 +131,7 @@ export default abstract class Entity<
124
131
  TMEntity,
125
132
  TMSelectedFields
126
133
  >,
127
- TMSelectedFields extends keyof TMFields = keyof TMFields
134
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
128
135
  >(
129
136
  this: IEntityClass<
130
137
  TMFields,
@@ -135,7 +142,11 @@ export default abstract class Entity<
135
142
  TMSelectedFields
136
143
  >,
137
144
  existingEntity: TMEntity,
138
- queryContext: EntityQueryContext
145
+ queryContext: EntityQueryContext = existingEntity
146
+ .getViewerContext()
147
+ .getViewerScopedEntityCompanionForClass(this)
148
+ .getQueryContextProvider()
149
+ .getQueryContext(),
139
150
  ): Promise<Result<void>> {
140
151
  return existingEntity
141
152
  .getViewerContext()
@@ -162,7 +173,7 @@ export default abstract class Entity<
162
173
  TMEntity,
163
174
  TMSelectedFields
164
175
  >,
165
- TMSelectedFields extends keyof TMFields = keyof TMFields
176
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
166
177
  >(
167
178
  this: IEntityClass<
168
179
  TMFields,
@@ -173,7 +184,11 @@ export default abstract class Entity<
173
184
  TMSelectedFields
174
185
  >,
175
186
  existingEntity: TMEntity,
176
- queryContext: EntityQueryContext
187
+ queryContext: EntityQueryContext = existingEntity
188
+ .getViewerContext()
189
+ .getViewerScopedEntityCompanionForClass(this)
190
+ .getQueryContextProvider()
191
+ .getQueryContext(),
177
192
  ): Promise<void> {
178
193
  return existingEntity
179
194
  .getViewerContext()
@@ -182,113 +197,6 @@ export default abstract class Entity<
182
197
  .forDelete(existingEntity, queryContext)
183
198
  .enforceDeleteAsync();
184
199
  }
185
-
186
- /**
187
- * Check whether an entity loaded by a viewer can be updated by that same viewer.
188
- *
189
- * @remarks
190
- *
191
- * This may be useful in situations relying upon the thrown privacy policy thrown authorization error
192
- * is insufficient for the task at hand. When dealing with purely a sequence of mutations it is easy
193
- * to roll back all mutations given a single authorization error by wrapping them in a single transaction.
194
- * When certain portions of a mutation cannot be rolled back transactionally (third pary calls,
195
- * legacy code, etc), using this method can help decide whether the sequence of mutations will fail before
196
- * attempting them. Note that if any privacy policy rules use a piece of data being updated in the mutations
197
- * the result of this method and the update mutation itself may differ.
198
- *
199
- * @param existingEntity - entity loaded by viewer
200
- * @param queryContext - query context in which to perform the check
201
- */
202
- static async canViewerUpdateAsync<
203
- TMFields extends object,
204
- TMID extends NonNullable<TMFields[TMSelectedFields]>,
205
- TMViewerContext extends ViewerContext,
206
- TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
207
- TMPrivacyPolicy extends EntityPrivacyPolicy<
208
- TMFields,
209
- TMID,
210
- TMViewerContext,
211
- TMEntity,
212
- TMSelectedFields
213
- >,
214
- TMSelectedFields extends keyof TMFields = keyof TMFields
215
- >(
216
- this: IEntityClass<
217
- TMFields,
218
- TMID,
219
- TMViewerContext,
220
- TMEntity,
221
- TMPrivacyPolicy,
222
- TMSelectedFields
223
- >,
224
- existingEntity: TMEntity,
225
- queryContext: EntityQueryContext
226
- ): Promise<boolean> {
227
- const companion = existingEntity
228
- .getViewerContext()
229
- .getViewerScopedEntityCompanionForClass(this);
230
- const privacyPolicy = companion.entityCompanion.privacyPolicy;
231
- const evaluationResult = await asyncResult(
232
- privacyPolicy.authorizeUpdateAsync(
233
- existingEntity.getViewerContext(),
234
- queryContext,
235
- { cascadingDeleteCause: null },
236
- existingEntity,
237
- companion.getMetricsAdapter()
238
- )
239
- );
240
- return evaluationResult.ok;
241
- }
242
-
243
- /**
244
- * Check whether an entity loaded by a viewer can be deleted by that same viewer.
245
- *
246
- * @remarks
247
- * See remarks for canViewerUpdate.
248
- *
249
- * @param existingEntity - entity loaded by viewer
250
- * @param queryContext - query context in which to perform the check
251
- */
252
- static async canViewerDeleteAsync<
253
- TMFields extends object,
254
- TMID extends NonNullable<TMFields[TMSelectedFields]>,
255
- TMViewerContext extends ViewerContext,
256
- TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
257
- TMPrivacyPolicy extends EntityPrivacyPolicy<
258
- TMFields,
259
- TMID,
260
- TMViewerContext,
261
- TMEntity,
262
- TMSelectedFields
263
- >,
264
- TMSelectedFields extends keyof TMFields = keyof TMFields
265
- >(
266
- this: IEntityClass<
267
- TMFields,
268
- TMID,
269
- TMViewerContext,
270
- TMEntity,
271
- TMPrivacyPolicy,
272
- TMSelectedFields
273
- >,
274
- existingEntity: TMEntity,
275
- queryContext: EntityQueryContext
276
- ): Promise<boolean> {
277
- const companion = existingEntity
278
- .getViewerContext()
279
- .getViewerScopedEntityCompanionForClass(this);
280
- const privacyPolicy = companion.entityCompanion.privacyPolicy;
281
- const evaluationResult = await asyncResult(
282
- privacyPolicy.authorizeDeleteAsync(
283
- existingEntity.getViewerContext(),
284
- queryContext,
285
- { cascadingDeleteCause: null },
286
- existingEntity,
287
- companion.getMetricsAdapter()
288
- )
289
- );
290
- return evaluationResult.ok;
291
- }
292
200
  }
293
201
 
294
202
  /**
@@ -306,7 +214,7 @@ export interface IEntityClass<
306
214
  TEntity,
307
215
  TSelectedFields
308
216
  >,
309
- TSelectedFields extends keyof TFields = keyof TFields
217
+ TSelectedFields extends keyof TFields = keyof TFields,
310
218
  > {
311
219
  new (constructorParam: {
312
220
  viewerContext: TViewerContext;
@@ -16,7 +16,7 @@ export default class EntityAssociationLoader<
16
16
  TID extends NonNullable<TFields[TSelectedFields]>,
17
17
  TViewerContext extends ViewerContext,
18
18
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
19
- TSelectedFields extends keyof TFields
19
+ TSelectedFields extends keyof TFields,
20
20
  > {
21
21
  constructor(private readonly entity: TEntity) {}
22
22
 
@@ -44,7 +44,7 @@ export default class EntityAssociationLoader<
44
44
  TAssociatedEntity,
45
45
  TAssociatedSelectedFields
46
46
  >,
47
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
47
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
48
48
  >(
49
49
  fieldIdentifyingAssociatedEntity: TIdentifyingField,
50
50
  associatedEntityClass: IEntityClass<
@@ -55,7 +55,11 @@ export default class EntityAssociationLoader<
55
55
  TAssociatedPrivacyPolicy,
56
56
  TAssociatedSelectedFields
57
57
  >,
58
- queryContext: EntityQueryContext
58
+ queryContext: EntityQueryContext = this.entity
59
+ .getViewerContext()
60
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
61
+ .getQueryContextProvider()
62
+ .getQueryContext(),
59
63
  ): Promise<
60
64
  Result<null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity>
61
65
  > {
@@ -70,9 +74,11 @@ export default class EntityAssociationLoader<
70
74
  .getViewerContext()
71
75
  .getViewerScopedEntityCompanionForClass(associatedEntityClass)
72
76
  .getLoaderFactory()
73
- .forLoad(queryContext, { cascadingDeleteCause: null });
77
+ .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
74
78
 
75
- return (await loader.loadByIDAsync(associatedEntityID as unknown as TAssociatedID)) as Result<
79
+ return (await loader
80
+ .withAuthorizationResults()
81
+ .loadByIDAsync(associatedEntityID as unknown as TAssociatedID)) as Result<
76
82
  null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
77
83
  >;
78
84
  }
@@ -102,7 +108,7 @@ export default class EntityAssociationLoader<
102
108
  TAssociatedEntity,
103
109
  TAssociatedSelectedFields
104
110
  >,
105
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
111
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
106
112
  >(
107
113
  associatedEntityClass: IEntityClass<
108
114
  TAssociatedFields,
@@ -113,18 +119,21 @@ export default class EntityAssociationLoader<
113
119
  TAssociatedSelectedFields
114
120
  >,
115
121
  associatedEntityFieldContainingThisID: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
116
- queryContext: EntityQueryContext
122
+ queryContext: EntityQueryContext = this.entity
123
+ .getViewerContext()
124
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
125
+ .getQueryContextProvider()
126
+ .getQueryContext(),
117
127
  ): Promise<readonly Result<TAssociatedEntity>[]> {
118
128
  const thisID = this.entity.getID();
119
129
  const loader = this.entity
120
130
  .getViewerContext()
121
131
  .getViewerScopedEntityCompanionForClass(associatedEntityClass)
122
132
  .getLoaderFactory()
123
- .forLoad(queryContext, { cascadingDeleteCause: null });
124
- return await loader.loadManyByFieldEqualingAsync(
125
- associatedEntityFieldContainingThisID,
126
- thisID as any
127
- );
133
+ .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
134
+ return await loader
135
+ .withAuthorizationResults()
136
+ .loadManyByFieldEqualingAsync(associatedEntityFieldContainingThisID, thisID as any);
128
137
  }
129
138
 
130
139
  /**
@@ -151,7 +160,7 @@ export default class EntityAssociationLoader<
151
160
  TAssociatedEntity,
152
161
  TAssociatedSelectedFields
153
162
  >,
154
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
163
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
155
164
  >(
156
165
  fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
157
166
  associatedEntityClass: IEntityClass<
@@ -163,7 +172,11 @@ export default class EntityAssociationLoader<
163
172
  TAssociatedSelectedFields
164
173
  >,
165
174
  associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
166
- queryContext: EntityQueryContext
175
+ queryContext: EntityQueryContext = this.entity
176
+ .getViewerContext()
177
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
178
+ .getQueryContextProvider()
179
+ .getQueryContext(),
167
180
  ): Promise<Result<TAssociatedEntity> | null> {
168
181
  const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
169
182
  if (!associatedFieldValue) {
@@ -173,11 +186,10 @@ export default class EntityAssociationLoader<
173
186
  .getViewerContext()
174
187
  .getViewerScopedEntityCompanionForClass(associatedEntityClass)
175
188
  .getLoaderFactory()
176
- .forLoad(queryContext, { cascadingDeleteCause: null });
177
- return await loader.loadByFieldEqualingAsync(
178
- associatedEntityLookupByField,
179
- associatedFieldValue as any
180
- );
189
+ .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
190
+ return await loader
191
+ .withAuthorizationResults()
192
+ .loadByFieldEqualingAsync(associatedEntityLookupByField, associatedFieldValue as any);
181
193
  }
182
194
 
183
195
  /**
@@ -204,7 +216,7 @@ export default class EntityAssociationLoader<
204
216
  TAssociatedEntity,
205
217
  TAssociatedSelectedFields
206
218
  >,
207
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
219
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
208
220
  >(
209
221
  fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
210
222
  associatedEntityClass: IEntityClass<
@@ -216,7 +228,11 @@ export default class EntityAssociationLoader<
216
228
  TAssociatedSelectedFields
217
229
  >,
218
230
  associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
219
- queryContext: EntityQueryContext
231
+ queryContext: EntityQueryContext = this.entity
232
+ .getViewerContext()
233
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
234
+ .getQueryContextProvider()
235
+ .getQueryContext(),
220
236
  ): Promise<readonly Result<TAssociatedEntity>[]> {
221
237
  const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
222
238
  if (!associatedFieldValue) {
@@ -227,11 +243,10 @@ export default class EntityAssociationLoader<
227
243
  .getViewerContext()
228
244
  .getViewerScopedEntityCompanionForClass(associatedEntityClass)
229
245
  .getLoaderFactory()
230
- .forLoad(queryContext, { cascadingDeleteCause: null });
231
- return await loader.loadManyByFieldEqualingAsync(
232
- associatedEntityLookupByField,
233
- associatedFieldValue as any
234
- );
246
+ .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
247
+ return await loader
248
+ .withAuthorizationResults()
249
+ .loadManyByFieldEqualingAsync(associatedEntityLookupByField, associatedFieldValue as any);
235
250
  }
236
251
 
237
252
  /**
@@ -251,7 +266,7 @@ export default class EntityAssociationLoader<
251
266
  TEntity2,
252
267
  TSelectedFields2
253
268
  >,
254
- TSelectedFields2 extends keyof TFields2 = keyof TFields2
269
+ TSelectedFields2 extends keyof TFields2 = keyof TFields2,
255
270
  >(
256
271
  loadDirectives: [
257
272
  EntityLoadThroughDirective<
@@ -263,9 +278,9 @@ export default class EntityAssociationLoader<
263
278
  TPrivacyPolicy2,
264
279
  TSelectedFields,
265
280
  TSelectedFields2
266
- >
281
+ >,
267
282
  ],
268
- queryContext: EntityQueryContext
283
+ queryContext?: EntityQueryContext,
269
284
  ): Promise<Result<TEntity2> | null>;
270
285
 
271
286
  /**
@@ -296,7 +311,7 @@ export default class EntityAssociationLoader<
296
311
  TSelectedFields3
297
312
  >,
298
313
  TSelectedFields2 extends keyof TFields2 = keyof TFields2,
299
- TSelectedFields3 extends keyof TFields3 = keyof TFields3
314
+ TSelectedFields3 extends keyof TFields3 = keyof TFields3,
300
315
  >(
301
316
  loadDirectives: [
302
317
  EntityLoadThroughDirective<
@@ -318,9 +333,9 @@ export default class EntityAssociationLoader<
318
333
  TPrivacyPolicy3,
319
334
  TSelectedFields2,
320
335
  TSelectedFields3
321
- >
336
+ >,
322
337
  ],
323
- queryContext: EntityQueryContext
338
+ queryContext?: EntityQueryContext,
324
339
  ): Promise<Result<TEntity3> | null>;
325
340
 
326
341
  /**
@@ -362,9 +377,9 @@ export default class EntityAssociationLoader<
362
377
  >,
363
378
  TSelectedFields2 extends keyof TFields2 = keyof TFields2,
364
379
  TSelectedFields3 extends keyof TFields3 = keyof TFields3,
365
- TSelectedFields4 extends keyof TFields4 = keyof TFields4
380
+ TSelectedFields4 extends keyof TFields4 = keyof TFields4,
366
381
  >(
367
- loadDirective: [
382
+ loadDirectives: [
368
383
  EntityLoadThroughDirective<
369
384
  TViewerContext,
370
385
  TFields,
@@ -394,9 +409,9 @@ export default class EntityAssociationLoader<
394
409
  TPrivacyPolicy4,
395
410
  TSelectedFields3,
396
411
  TSelectedFields4
397
- >
412
+ >,
398
413
  ],
399
- queryContext: EntityQueryContext
414
+ queryContext?: EntityQueryContext,
400
415
  ): Promise<Result<TEntity4> | null>;
401
416
 
402
417
  /**
@@ -407,12 +422,12 @@ export default class EntityAssociationLoader<
407
422
  */
408
423
  async loadAssociatedEntityThroughAsync(
409
424
  loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
410
- queryContext: EntityQueryContext
425
+ queryContext?: EntityQueryContext,
411
426
  ): Promise<Result<ReadonlyEntity<any, any, any, any>> | null>;
412
427
 
413
428
  async loadAssociatedEntityThroughAsync(
414
429
  loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
415
- queryContext: EntityQueryContext
430
+ queryContext?: EntityQueryContext,
416
431
  ): Promise<Result<ReadonlyEntity<any, any, any, any>> | null> {
417
432
  let currentEntity: ReadonlyEntity<any, any, any, any> = this.entity;
418
433
  for (const loadDirective of loadDirectives) {
@@ -429,7 +444,7 @@ export default class EntityAssociationLoader<
429
444
  fieldIdentifyingAssociatedEntity,
430
445
  associatedEntityClass,
431
446
  associatedEntityLookupByField,
432
- queryContext
447
+ queryContext,
433
448
  );
434
449
  } else {
435
450
  const associatedEntityResultLocal = await currentEntity
@@ -437,7 +452,7 @@ export default class EntityAssociationLoader<
437
452
  .loadAssociatedEntityAsync(
438
453
  fieldIdentifyingAssociatedEntity,
439
454
  associatedEntityClass,
440
- queryContext
455
+ queryContext,
441
456
  );
442
457
 
443
458
  if (associatedEntityResultLocal.ok && associatedEntityResultLocal.value === null) {
@@ -482,7 +497,7 @@ export interface EntityLoadThroughDirective<
482
497
  TAssociatedSelectedFields
483
498
  >,
484
499
  TSelectedFields extends keyof TFields = keyof TFields,
485
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
500
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
486
501
  > {
487
502
  /**
488
503
  * Class of entity to load at this step.
@@ -7,6 +7,7 @@ import ReadonlyEntity from './ReadonlyEntity';
7
7
  import ViewerContext from './ViewerContext';
8
8
  import EntityTableDataCoordinator from './internal/EntityTableDataCoordinator';
9
9
  import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
10
+ import { mergeEntityMutationTriggerConfigurations } from './utils/mergeEntityMutationTriggerConfigurations';
10
11
 
11
12
  export interface IPrivacyPolicyClass<TPrivacyPolicy> {
12
13
  new (): TPrivacyPolicy;
@@ -27,7 +28,7 @@ export default class EntityCompanion<
27
28
  TEntity,
28
29
  TSelectedFields
29
30
  >,
30
- TSelectedFields extends keyof TFields
31
+ TSelectedFields extends keyof TFields,
31
32
  > {
32
33
  public readonly privacyPolicy: TPrivacyPolicy;
33
34
 
@@ -59,7 +60,7 @@ export default class EntityCompanion<
59
60
  TSelectedFields
60
61
  >,
61
62
  private readonly tableDataCoordinator: EntityTableDataCoordinator<TFields>,
62
- private readonly metricsAdapter: IEntityMetricsAdapter
63
+ private readonly metricsAdapter: IEntityMetricsAdapter,
63
64
  ) {
64
65
  this.privacyPolicy = new entityCompanionDefinition.privacyPolicyClass();
65
66
  this.entityLoaderFactory = new EntityLoaderFactory<
@@ -76,10 +77,13 @@ export default class EntityCompanion<
76
77
  entityCompanionDefinition.entityClass,
77
78
  this.privacyPolicy,
78
79
  entityCompanionDefinition.mutationValidators ?? [],
79
- entityCompanionDefinition.mutationTriggers ?? {},
80
+ mergeEntityMutationTriggerConfigurations(
81
+ entityCompanionDefinition.mutationTriggers ?? {},
82
+ entityCompanionProvider.globalMutationTriggers ?? {},
83
+ ),
80
84
  this.entityLoaderFactory,
81
85
  tableDataCoordinator.databaseAdapter,
82
- metricsAdapter
86
+ metricsAdapter,
83
87
  );
84
88
  }
85
89
 
@@ -61,7 +61,7 @@ export interface EntityCompanionDefinition<
61
61
  TEntity,
62
62
  TSelectedFields
63
63
  >,
64
- TSelectedFields extends keyof TFields = keyof TFields
64
+ TSelectedFields extends keyof TFields = keyof TFields,
65
65
  > {
66
66
  /**
67
67
  * The concrete Entity class for which this is the definition.
@@ -139,6 +139,7 @@ export default class EntityCompanionProvider {
139
139
  * @param metricsAdapter - An IEntityMetricsAdapter for collecting metrics on this instance
140
140
  * @param databaseAdapterFlavors - Database adapter configurations for this instance
141
141
  * @param cacheAdapterFlavors - Cache adapter configurations for this instance
142
+ * @param globalMutationTriggers - Optional set of EntityMutationTrigger to run for all entity mutations systemwide.
142
143
  */
143
144
  constructor(
144
145
  public readonly metricsAdapter: IEntityMetricsAdapter,
@@ -146,7 +147,14 @@ export default class EntityCompanionProvider {
146
147
  DatabaseAdapterFlavor,
147
148
  DatabaseAdapterFlavorDefinition
148
149
  >,
149
- private cacheAdapterFlavors: ReadonlyMap<CacheAdapterFlavor, CacheAdapterFlavorDefinition>
150
+ private cacheAdapterFlavors: ReadonlyMap<CacheAdapterFlavor, CacheAdapterFlavorDefinition>,
151
+ readonly globalMutationTriggers: EntityMutationTriggerConfiguration<
152
+ any,
153
+ any,
154
+ any,
155
+ any,
156
+ any
157
+ > = {},
150
158
  ) {}
151
159
 
152
160
  /**
@@ -167,7 +175,7 @@ export default class EntityCompanionProvider {
167
175
  TEntity,
168
176
  TSelectedFields
169
177
  >,
170
- TSelectedFields extends keyof TFields
178
+ TSelectedFields extends keyof TFields,
171
179
  >(
172
180
  entityClass: IEntityClass<
173
181
  TFields,
@@ -176,58 +184,58 @@ export default class EntityCompanionProvider {
176
184
  TEntity,
177
185
  TPrivacyPolicy,
178
186
  TSelectedFields
179
- >
187
+ >,
180
188
  ): EntityCompanion<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
181
189
  const entityCompanionDefinition = computeIfAbsent(
182
190
  this.companionDefinitionMap,
183
191
  entityClass.name,
184
- () => entityClass.defineCompanionDefinition()
192
+ () => entityClass.defineCompanionDefinition(),
185
193
  );
186
194
  const tableDataCoordinator = this.getTableDataCoordinatorForEntity(
187
195
  entityCompanionDefinition.entityConfiguration,
188
- entityClass.name
196
+ entityClass.name,
189
197
  );
190
198
  return computeIfAbsent(this.companionMap, entityClass.name, () => {
191
199
  return new EntityCompanion(
192
200
  this,
193
201
  entityCompanionDefinition,
194
202
  tableDataCoordinator,
195
- this.metricsAdapter
203
+ this.metricsAdapter,
196
204
  );
197
205
  });
198
206
  }
199
207
 
200
208
  getQueryContextProviderForDatabaseAdaptorFlavor(
201
- databaseAdapterFlavor: DatabaseAdapterFlavor
209
+ databaseAdapterFlavor: DatabaseAdapterFlavor,
202
210
  ): EntityQueryContextProvider {
203
211
  const entityDatabaseAdapterFlavor = this.databaseAdapterFlavors.get(databaseAdapterFlavor);
204
212
  invariant(
205
213
  entityDatabaseAdapterFlavor,
206
- `No database adaptor configuration found for flavor: ${databaseAdapterFlavor}`
214
+ `No database adaptor configuration found for flavor: ${databaseAdapterFlavor}`,
207
215
  );
208
216
 
209
217
  return entityDatabaseAdapterFlavor.queryContextProvider;
210
218
  }
211
219
 
212
- private getTableDataCoordinatorForEntity<TFields>(
220
+ private getTableDataCoordinatorForEntity<TFields extends Record<string, any>>(
213
221
  entityConfiguration: EntityConfiguration<TFields>,
214
- entityClassName: string
222
+ entityClassName: string,
215
223
  ): EntityTableDataCoordinator<TFields> {
216
224
  return computeIfAbsent(this.tableDataCoordinatorMap, entityConfiguration.tableName, () => {
217
225
  const entityDatabaseAdapterFlavor = this.databaseAdapterFlavors.get(
218
- entityConfiguration.databaseAdapterFlavor
226
+ entityConfiguration.databaseAdapterFlavor,
219
227
  );
220
228
  invariant(
221
229
  entityDatabaseAdapterFlavor,
222
- `No database adaptor configuration found for flavor: ${entityConfiguration.databaseAdapterFlavor}`
230
+ `No database adaptor configuration found for flavor: ${entityConfiguration.databaseAdapterFlavor}`,
223
231
  );
224
232
 
225
233
  const entityCacheAdapterFlavor = this.cacheAdapterFlavors.get(
226
- entityConfiguration.cacheAdapterFlavor
234
+ entityConfiguration.cacheAdapterFlavor,
227
235
  );
228
236
  invariant(
229
237
  entityCacheAdapterFlavor,
230
- `No cache adaptor configuration found for flavor: ${entityConfiguration.cacheAdapterFlavor}`
238
+ `No cache adaptor configuration found for flavor: ${entityConfiguration.cacheAdapterFlavor}`,
231
239
  );
232
240
 
233
241
  return new EntityTableDataCoordinator(
@@ -236,7 +244,7 @@ export default class EntityCompanionProvider {
236
244
  entityCacheAdapterFlavor.cacheAdapterProvider,
237
245
  entityDatabaseAdapterFlavor.queryContextProvider,
238
246
  this.metricsAdapter,
239
- entityClassName
247
+ entityClassName,
240
248
  );
241
249
  });
242
250
  }