@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
@@ -7,16 +7,19 @@ import EntityConfiguration from '../EntityConfiguration';
7
7
  import { UUIDField } from '../EntityFields';
8
8
  import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from '../EntityPrivacyPolicy';
9
9
  import { EntityQueryContext } from '../EntityQueryContext';
10
+ import ViewerContext from '../ViewerContext';
10
11
  import { enforceResultsAsync } from '../entityUtils';
11
12
  import EntityNotAuthorizedError from '../errors/EntityNotAuthorizedError';
12
13
  import AlwaysAllowPrivacyPolicyRule from '../rules/AlwaysAllowPrivacyPolicyRule';
13
14
  import AlwaysDenyPrivacyPolicyRule from '../rules/AlwaysDenyPrivacyPolicyRule';
14
15
  import PrivacyPolicyRule, { RuleEvaluationResult } from '../rules/PrivacyPolicyRule';
15
- import TestViewerContext from '../testfixtures/TestViewerContext';
16
16
  import { createUnitTestEntityCompanionProvider } from '../utils/testing/createUnitTestEntityCompanionProvider';
17
17
 
18
- class TestUserViewerContext extends TestViewerContext {
19
- constructor(entityCompanionProvider: EntityCompanionProvider, private readonly userID: string) {
18
+ class TestUserViewerContext extends ViewerContext {
19
+ constructor(
20
+ entityCompanionProvider: EntityCompanionProvider,
21
+ private readonly userID: string,
22
+ ) {
20
23
  super(entityCompanionProvider);
21
24
  }
22
25
 
@@ -69,8 +72,13 @@ class DenyIfNotOwnerPrivacyPolicyRule extends PrivacyPolicyRule<
69
72
  async evaluateAsync(
70
73
  viewerContext: TestUserViewerContext,
71
74
  _queryContext: EntityQueryContext,
72
- _evaluationContext: EntityPrivacyPolicyEvaluationContext,
73
- entity: BlahEntity
75
+ _evaluationContext: EntityPrivacyPolicyEvaluationContext<
76
+ BlahFields,
77
+ string,
78
+ TestUserViewerContext,
79
+ BlahEntity
80
+ >,
81
+ entity: BlahEntity,
74
82
  ): Promise<RuleEvaluationResult> {
75
83
  if (viewerContext.getUserID() === entity.getField('ownerID')) {
76
84
  return RuleEvaluationResult.SKIP;
@@ -82,23 +90,23 @@ class DenyIfNotOwnerPrivacyPolicyRule extends PrivacyPolicyRule<
82
90
  class BlahEntityPrivacyPolicy extends EntityPrivacyPolicy<
83
91
  BlahFields,
84
92
  string,
85
- TestUserViewerContext,
93
+ ViewerContext,
86
94
  BlahEntity
87
95
  > {
88
96
  protected override readonly createRules = [
89
97
  new DenyIfNotOwnerPrivacyPolicyRule(),
90
- new AlwaysAllowPrivacyPolicyRule<BlahFields, string, TestUserViewerContext, BlahEntity>(),
98
+ new AlwaysAllowPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
91
99
  ];
92
100
  protected override readonly readRules = [
93
101
  new DenyIfNotOwnerPrivacyPolicyRule(),
94
- new AlwaysAllowPrivacyPolicyRule<BlahFields, string, TestUserViewerContext, BlahEntity>(),
102
+ new AlwaysAllowPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
95
103
  ];
96
104
  protected override readonly updateRules = [
97
105
  new DenyIfNotOwnerPrivacyPolicyRule(),
98
- new AlwaysAllowPrivacyPolicyRule<BlahFields, string, TestUserViewerContext, BlahEntity>(),
106
+ new AlwaysAllowPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
99
107
  ];
100
108
  protected override readonly deleteRules = [
101
- new AlwaysDenyPrivacyPolicyRule<BlahFields, string, TestUserViewerContext, BlahEntity>(),
109
+ new AlwaysDenyPrivacyPolicyRule<BlahFields, string, ViewerContext, BlahEntity>(),
102
110
  ];
103
111
  }
104
112
 
@@ -110,21 +118,15 @@ it('runs through a common workflow', async () => {
110
118
  const vc2 = new TestUserViewerContext(entityCompanionProvider, uuidv4());
111
119
 
112
120
  const blahOwner1 = await enforceAsyncResult(
113
- BlahEntity.creator(vc1, vc1.getQueryContext())
114
- .setField('ownerID', vc1.getUserID()!)
115
- .createAsync()
121
+ BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync(),
116
122
  );
117
123
 
118
124
  await enforceAsyncResult(
119
- BlahEntity.creator(vc1, vc1.getQueryContext())
120
- .setField('ownerID', vc1.getUserID()!)
121
- .createAsync()
125
+ BlahEntity.creator(vc1).setField('ownerID', vc1.getUserID()!).createAsync(),
122
126
  );
123
127
 
124
128
  const blahOwner2 = await enforceAsyncResult(
125
- BlahEntity.creator(vc2, vc2.getQueryContext())
126
- .setField('ownerID', vc2.getUserID()!)
127
- .createAsync()
129
+ BlahEntity.creator(vc2).setField('ownerID', vc2.getUserID()!).createAsync(),
128
130
  );
129
131
 
130
132
  // sanity check created objects
@@ -134,44 +136,40 @@ it('runs through a common workflow', async () => {
134
136
  // check that two people can't read each others data
135
137
  await expect(
136
138
  enforceAsyncResult(
137
- BlahEntity.loader(vc1, vc1.getQueryContext()).loadByIDAsync(blahOwner2.getID())
138
- )
139
+ BlahEntity.loader(vc1).withAuthorizationResults().loadByIDAsync(blahOwner2.getID()),
140
+ ),
139
141
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
140
142
  await expect(
141
143
  enforceAsyncResult(
142
- BlahEntity.loader(vc2, vc2.getQueryContext()).loadByIDAsync(blahOwner1.getID())
143
- )
144
+ BlahEntity.loader(vc2).withAuthorizationResults().loadByIDAsync(blahOwner1.getID()),
145
+ ),
144
146
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
145
147
 
146
148
  // check that all of owner 1's objects can be loaded
147
149
  const results = await enforceResultsAsync(
148
- BlahEntity.loader(vc1, vc1.getQueryContext()).loadManyByFieldEqualingAsync(
149
- 'ownerID',
150
- vc1.getUserID()!
151
- )
150
+ BlahEntity.loader(vc1)
151
+ .withAuthorizationResults()
152
+ .loadManyByFieldEqualingAsync('ownerID', vc1.getUserID()!),
152
153
  );
153
154
  expect(results).toHaveLength(2);
154
155
 
155
156
  // check that two people can't create objects owned by others
156
157
  await expect(
157
158
  enforceAsyncResult(
158
- BlahEntity.creator(vc2, vc2.getQueryContext())
159
- .setField('ownerID', blahOwner1.getID())
160
- .createAsync()
161
- )
159
+ BlahEntity.creator(vc2).setField('ownerID', blahOwner1.getID()).createAsync(),
160
+ ),
162
161
  ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
163
162
 
164
163
  // check that empty load many returns nothing
165
- const results2 = await BlahEntity.loader(
166
- vc1,
167
- vc1.getQueryContext()
168
- ).loadManyByFieldEqualingManyAsync('ownerID', []);
164
+ const results2 = await BlahEntity.loader(vc1)
165
+ .withAuthorizationResults()
166
+ .loadManyByFieldEqualingManyAsync('ownerID', []);
169
167
  for (const value in results2.values) {
170
168
  expect(value).toHaveLength(0);
171
169
  }
172
170
 
173
171
  // check that the user can't delete their own data (as specified by privacy rules)
174
- await expect(
175
- enforceAsyncResult(BlahEntity.deleteAsync(blahOwner2, vc1.getQueryContext()))
176
- ).rejects.toBeInstanceOf(EntityNotAuthorizedError);
172
+ await expect(enforceAsyncResult(BlahEntity.deleteAsync(blahOwner2))).rejects.toBeInstanceOf(
173
+ EntityNotAuthorizedError,
174
+ );
177
175
  });
@@ -3,25 +3,77 @@ import { instance, mock, when } from 'ts-mockito';
3
3
  import EntityCompanion from '../EntityCompanion';
4
4
  import EntityCompanionProvider from '../EntityCompanionProvider';
5
5
  import EntityLoaderFactory from '../EntityLoaderFactory';
6
+ import EntityMutationTriggerConfiguration from '../EntityMutationTriggerConfiguration';
6
7
  import EntityMutatorFactory from '../EntityMutatorFactory';
8
+ import ViewerContext from '../ViewerContext';
7
9
  import EntityTableDataCoordinator from '../internal/EntityTableDataCoordinator';
8
10
  import IEntityMetricsAdapter from '../metrics/IEntityMetricsAdapter';
9
- import TestEntity, { testEntityConfiguration, TestFields } from '../testfixtures/TestEntity';
11
+ import NoOpEntityMetricsAdapter from '../metrics/NoOpEntityMetricsAdapter';
12
+ import TestEntityWithMutationTriggers, {
13
+ TestMTFields,
14
+ testEntityMTConfiguration,
15
+ TestMutationTrigger,
16
+ } from '../testfixtures/TestEntityWithMutationTriggers';
10
17
 
11
18
  describe(EntityCompanion, () => {
12
19
  it('correctly instantiates mutator and loader factories', () => {
13
20
  const entityCompanionProvider = instance(mock<EntityCompanionProvider>());
14
21
 
15
- const tableDataCoordinatorMock = mock<EntityTableDataCoordinator<TestFields>>();
16
- when(tableDataCoordinatorMock.entityConfiguration).thenReturn(testEntityConfiguration);
22
+ const tableDataCoordinatorMock = mock<EntityTableDataCoordinator<TestMTFields>>();
23
+ when(tableDataCoordinatorMock.entityConfiguration).thenReturn(testEntityMTConfiguration);
17
24
 
18
25
  const companion = new EntityCompanion(
19
26
  entityCompanionProvider,
20
- TestEntity.defineCompanionDefinition(),
27
+ TestEntityWithMutationTriggers.defineCompanionDefinition(),
21
28
  instance(tableDataCoordinatorMock),
22
- instance(mock<IEntityMetricsAdapter>())
29
+ instance(mock<IEntityMetricsAdapter>()),
23
30
  );
24
31
  expect(companion.getLoaderFactory()).toBeInstanceOf(EntityLoaderFactory);
25
32
  expect(companion.getMutatorFactory()).toBeInstanceOf(EntityMutatorFactory);
26
33
  });
34
+
35
+ it('correctly merges local and global mutation triggers', () => {
36
+ const globalMutationTriggers: EntityMutationTriggerConfiguration<
37
+ TestMTFields,
38
+ string,
39
+ ViewerContext,
40
+ TestEntityWithMutationTriggers,
41
+ keyof TestMTFields
42
+ > = {
43
+ afterCreate: [new TestMutationTrigger('globalAfterCreate')],
44
+ afterAll: [new TestMutationTrigger('globalAfterAll')],
45
+ };
46
+
47
+ const metricsAdapter = new NoOpEntityMetricsAdapter();
48
+
49
+ const entityCompanionProvider = new EntityCompanionProvider(
50
+ metricsAdapter,
51
+ new Map(),
52
+ new Map(),
53
+ globalMutationTriggers,
54
+ );
55
+
56
+ const tableDataCoordinatorMock = mock<EntityTableDataCoordinator<TestMTFields>>();
57
+ when(tableDataCoordinatorMock.entityConfiguration).thenReturn(testEntityMTConfiguration);
58
+
59
+ const companion = new EntityCompanion(
60
+ entityCompanionProvider,
61
+ TestEntityWithMutationTriggers.defineCompanionDefinition(),
62
+ instance(tableDataCoordinatorMock),
63
+ instance(mock<IEntityMetricsAdapter>()),
64
+ );
65
+ expect(companion.getLoaderFactory()).toBeInstanceOf(EntityLoaderFactory);
66
+ expect(companion.getMutatorFactory()).toBeInstanceOf(EntityMutatorFactory);
67
+
68
+ const mergedTriggers = companion.getMutatorFactory()['mutationTriggers'];
69
+
70
+ const localTriggers = companion.entityCompanionDefinition.mutationTriggers;
71
+ expect(localTriggers).toBeTruthy();
72
+
73
+ expect(mergedTriggers).toStrictEqual({
74
+ afterCreate: [localTriggers!.afterCreate![0], globalMutationTriggers.afterCreate![0]],
75
+ afterAll: [localTriggers!.afterAll![0], globalMutationTriggers!.afterAll![0]],
76
+ afterCommit: [localTriggers!.afterCommit![0]],
77
+ });
78
+ });
27
79
  });
@@ -0,0 +1,118 @@
1
+ import EntityConfiguration from '../EntityConfiguration';
2
+ import { UUIDField, StringField } from '../EntityFields';
3
+
4
+ describe(EntityConfiguration, () => {
5
+ describe('when valid', () => {
6
+ type BlahT = {
7
+ id: string;
8
+ cacheable: string;
9
+ uniqueButNotCacheable: string;
10
+ };
11
+
12
+ type Blah2T = {
13
+ id: string;
14
+ };
15
+
16
+ const blahEntityConfiguration = new EntityConfiguration<BlahT>({
17
+ idField: 'id',
18
+ tableName: 'blah_table',
19
+ schema: {
20
+ id: new UUIDField({
21
+ columnName: 'id',
22
+ }),
23
+ cacheable: new StringField({
24
+ columnName: 'cacheable',
25
+ cache: true,
26
+ }),
27
+ uniqueButNotCacheable: new StringField({
28
+ columnName: 'unique_but_not_cacheable',
29
+ }),
30
+ },
31
+ databaseAdapterFlavor: 'postgres',
32
+ cacheAdapterFlavor: 'redis',
33
+ });
34
+
35
+ it('returns correct fields', () => {
36
+ expect(blahEntityConfiguration.idField).toEqual('id');
37
+ expect(blahEntityConfiguration.tableName).toEqual('blah_table');
38
+ expect(blahEntityConfiguration.databaseAdapterFlavor).toEqual('postgres');
39
+ expect(blahEntityConfiguration.cacheAdapterFlavor).toEqual('redis');
40
+ });
41
+
42
+ it('filters cacheable fields', () => {
43
+ expect(blahEntityConfiguration.cacheableKeys).toEqual(new Set(['cacheable']));
44
+ });
45
+
46
+ describe('cache key version', () => {
47
+ it('defaults to 0', () => {
48
+ const entityConfiguration = new EntityConfiguration<Blah2T>({
49
+ idField: 'id',
50
+ tableName: 'blah',
51
+ schema: {
52
+ id: new UUIDField({
53
+ columnName: 'id',
54
+ }),
55
+ },
56
+ databaseAdapterFlavor: 'postgres',
57
+ cacheAdapterFlavor: 'redis',
58
+ });
59
+ expect(entityConfiguration.cacheKeyVersion).toEqual(0);
60
+ });
61
+
62
+ it('sets to custom version', () => {
63
+ const entityConfiguration = new EntityConfiguration<Blah2T>({
64
+ idField: 'id',
65
+ tableName: 'blah',
66
+ schema: {
67
+ id: new UUIDField({
68
+ columnName: 'id',
69
+ }),
70
+ },
71
+ databaseAdapterFlavor: 'postgres',
72
+ cacheAdapterFlavor: 'redis',
73
+ cacheKeyVersion: 100,
74
+ });
75
+ expect(entityConfiguration.cacheKeyVersion).toEqual(100);
76
+ });
77
+ });
78
+ });
79
+
80
+ describe('validation', () => {
81
+ describe('disallows keys of JS Object prototype for safety', () => {
82
+ test.each([
83
+ 'constructor',
84
+ '__defineGetter__',
85
+ '__defineSetter__',
86
+ 'hasOwnProperty',
87
+ '__lookupGetter__',
88
+ '__lookupSetter__',
89
+ 'isPrototypeOf',
90
+ 'propertyIsEnumerable',
91
+ 'toString',
92
+ 'valueOf',
93
+ '__proto__',
94
+ 'toLocaleString',
95
+ ])('disallows %p as field key', (keyName) => {
96
+ expect(
97
+ () =>
98
+ new EntityConfiguration<any>({
99
+ idField: 'id',
100
+ tableName: 'blah_table',
101
+ schema: {
102
+ id: new UUIDField({
103
+ columnName: 'id',
104
+ }),
105
+ [keyName]: new StringField({
106
+ columnName: 'any',
107
+ }),
108
+ },
109
+ databaseAdapterFlavor: 'postgres',
110
+ cacheAdapterFlavor: 'redis',
111
+ }),
112
+ ).toThrow(
113
+ `Entity field name not allowed to prevent conflicts with standard Object prototype fields: ${keyName}`,
114
+ );
115
+ });
116
+ });
117
+ });
118
+ });
@@ -48,7 +48,7 @@ class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields> {
48
48
  _queryInterface: any,
49
49
  _tableName: string,
50
50
  _tableField: string,
51
- _tableValues: readonly any[]
51
+ _tableValues: readonly any[],
52
52
  ): Promise<object[]> {
53
53
  return this.fetchResults;
54
54
  }
@@ -57,7 +57,7 @@ class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields> {
57
57
  _queryInterface: any,
58
58
  _tableName: string,
59
59
  _rawWhereClause: string,
60
- _bindings: object | any[]
60
+ _bindings: object | any[],
61
61
  ): Promise<object[]> {
62
62
  return this.fetchRawWhereResults;
63
63
  }
@@ -66,7 +66,7 @@ class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields> {
66
66
  _queryInterface: any,
67
67
  _tableName: string,
68
68
  _tableFieldSingleValueEqualityOperands: TableFieldSingleValueEqualityCondition[],
69
- _tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[]
69
+ _tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[],
70
70
  ): Promise<object[]> {
71
71
  return this.fetchEqualityConditionResults;
72
72
  }
@@ -74,7 +74,7 @@ class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields> {
74
74
  protected async insertInternalAsync(
75
75
  _queryInterface: any,
76
76
  _tableName: string,
77
- _object: object
77
+ _object: object,
78
78
  ): Promise<object[]> {
79
79
  return this.insertResults;
80
80
  }
@@ -84,7 +84,7 @@ class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields> {
84
84
  _tableName: string,
85
85
  _tableIdField: string,
86
86
  _id: any,
87
- _object: object
87
+ _object: object,
88
88
  ): Promise<object[]> {
89
89
  return this.updateResults;
90
90
  }
@@ -93,7 +93,7 @@ class TestEntityDatabaseAdapter extends EntityDatabaseAdapter<TestFields> {
93
93
  _queryInterface: any,
94
94
  _tableName: string,
95
95
  _tableIdField: string,
96
- _id: any
96
+ _id: any,
97
97
  ): Promise<number> {
98
98
  return this.deleteCount;
99
99
  }
@@ -166,7 +166,7 @@ describe(EntityDatabaseAdapter, () => {
166
166
  const queryContext = instance(mock(EntityQueryContext));
167
167
  const adapter = new TestEntityDatabaseAdapter({ insertResults: [] });
168
168
  await expect(adapter.insertAsync(queryContext, {} as any)).rejects.toThrowError(
169
- 'Empty results from database adapter insert'
169
+ 'Empty results from database adapter insert',
170
170
  );
171
171
  });
172
172
 
@@ -176,7 +176,7 @@ describe(EntityDatabaseAdapter, () => {
176
176
  insertResults: [{ string_field: 'hello' }, { string_field: 'hello2' }],
177
177
  });
178
178
  await expect(adapter.insertAsync(queryContext, {} as any)).rejects.toThrowError(
179
- 'Excessive results from database adapter insert'
179
+ 'Excessive results from database adapter insert',
180
180
  );
181
181
  });
182
182
  });
@@ -193,7 +193,7 @@ describe(EntityDatabaseAdapter, () => {
193
193
  const queryContext = instance(mock(EntityQueryContext));
194
194
  const adapter = new TestEntityDatabaseAdapter({ updateResults: [] });
195
195
  await expect(
196
- adapter.updateAsync(queryContext, 'customIdField', 'wat', {} as any)
196
+ adapter.updateAsync(queryContext, 'customIdField', 'wat', {} as any),
197
197
  ).rejects.toThrowError('Empty results from database adapter update');
198
198
  });
199
199
 
@@ -203,7 +203,7 @@ describe(EntityDatabaseAdapter, () => {
203
203
  updateResults: [{ string_field: 'hello' }, { string_field: 'hello2' }],
204
204
  });
205
205
  await expect(
206
- adapter.updateAsync(queryContext, 'customIdField', 'wat', {} as any)
206
+ adapter.updateAsync(queryContext, 'customIdField', 'wat', {} as any),
207
207
  ).rejects.toThrowError('Excessive results from database adapter update');
208
208
  });
209
209
  });
@@ -213,7 +213,7 @@ describe(EntityDatabaseAdapter, () => {
213
213
  const queryContext = instance(mock(EntityQueryContext));
214
214
  const adapter = new TestEntityDatabaseAdapter({ deleteCount: 2 });
215
215
  await expect(adapter.deleteAsync(queryContext, 'customIdField', 'wat')).rejects.toThrowError(
216
- 'Excessive deletions from database adapter delet'
216
+ 'Excessive deletions from database adapter delet',
217
217
  );
218
218
  });
219
219
  });