@expo/entity 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/build/AuthorizationResultBasedEntityLoader.d.ts +128 -0
  2. package/build/AuthorizationResultBasedEntityLoader.js +196 -0
  3. package/build/AuthorizationResultBasedEntityLoader.js.map +1 -0
  4. package/build/ComposedEntityCacheAdapter.js +1 -0
  5. package/build/ComposedEntityCacheAdapter.js.map +1 -1
  6. package/build/ComposedSecondaryEntityCache.js +1 -0
  7. package/build/ComposedSecondaryEntityCache.js.map +1 -1
  8. package/build/EnforcingEntityLoader.d.ts +5 -4
  9. package/build/EnforcingEntityLoader.js +4 -2
  10. package/build/EnforcingEntityLoader.js.map +1 -1
  11. package/build/Entity.d.ts +0 -27
  12. package/build/Entity.js +0 -50
  13. package/build/Entity.js.map +1 -1
  14. package/build/EntityAssociationLoader.d.ts +1 -1
  15. package/build/EntityAssociationLoader.js +17 -8
  16. package/build/EntityAssociationLoader.js.map +1 -1
  17. package/build/EntityCompanion.js +9 -1
  18. package/build/EntityCompanion.js.map +1 -1
  19. package/build/EntityCompanionProvider.d.ts +3 -1
  20. package/build/EntityCompanionProvider.js +10 -4
  21. package/build/EntityCompanionProvider.js.map +1 -1
  22. package/build/EntityConfiguration.d.ts +2 -1
  23. package/build/EntityConfiguration.js +19 -1
  24. package/build/EntityConfiguration.js.map +1 -1
  25. package/build/EntityDatabaseAdapter.d.ts +2 -2
  26. package/build/EntityDatabaseAdapter.js +5 -3
  27. package/build/EntityDatabaseAdapter.js.map +1 -1
  28. package/build/EntityFieldDefinition.d.ts +21 -10
  29. package/build/EntityFieldDefinition.js +8 -9
  30. package/build/EntityFieldDefinition.js.map +1 -1
  31. package/build/EntityFields.d.ts +10 -0
  32. package/build/EntityFields.js +15 -1
  33. package/build/EntityFields.js.map +1 -1
  34. package/build/EntityLoader.d.ts +12 -125
  35. package/build/EntityLoader.js +24 -239
  36. package/build/EntityLoader.js.map +1 -1
  37. package/build/EntityLoaderFactory.d.ts +1 -1
  38. package/build/EntityLoaderFactory.js +3 -0
  39. package/build/EntityLoaderFactory.js.map +1 -1
  40. package/build/EntityLoaderUtils.d.ts +58 -0
  41. package/build/EntityLoaderUtils.js +109 -0
  42. package/build/EntityLoaderUtils.js.map +1 -0
  43. package/build/EntityMutator.d.ts +1 -0
  44. package/build/EntityMutator.js +71 -56
  45. package/build/EntityMutator.js.map +1 -1
  46. package/build/EntityMutatorFactory.js +9 -0
  47. package/build/EntityMutatorFactory.js.map +1 -1
  48. package/build/EntityPrivacyPolicy.d.ts +11 -5
  49. package/build/EntityPrivacyPolicy.js +5 -7
  50. package/build/EntityPrivacyPolicy.js.map +1 -1
  51. package/build/EntityQueryContext.d.ts +2 -1
  52. package/build/EntityQueryContext.js +11 -6
  53. package/build/EntityQueryContext.js.map +1 -1
  54. package/build/EntitySecondaryCacheLoader.js +5 -1
  55. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  56. package/build/GenericEntityCacheAdapter.js +1 -0
  57. package/build/GenericEntityCacheAdapter.js.map +1 -1
  58. package/build/GenericSecondaryEntityCache.js +2 -0
  59. package/build/GenericSecondaryEntityCache.js.map +1 -1
  60. package/build/IEntityCacheAdapterProvider.d.ts +1 -1
  61. package/build/IEntityDatabaseAdapterProvider.d.ts +1 -1
  62. package/build/ReadonlyEntity.js +5 -1
  63. package/build/ReadonlyEntity.js.map +1 -1
  64. package/build/ViewerContext.js +2 -0
  65. package/build/ViewerContext.js.map +1 -1
  66. package/build/ViewerScopedEntityCompanion.js +2 -0
  67. package/build/ViewerScopedEntityCompanion.js.map +1 -1
  68. package/build/ViewerScopedEntityCompanionProvider.d.ts +0 -1
  69. package/build/ViewerScopedEntityCompanionProvider.js +2 -1
  70. package/build/ViewerScopedEntityCompanionProvider.js.map +1 -1
  71. package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
  72. package/build/ViewerScopedEntityLoaderFactory.js +2 -0
  73. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  74. package/build/ViewerScopedEntityMutatorFactory.js +2 -0
  75. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  76. package/build/__tests__/ComposedCacheAdapter-test.js +2 -0
  77. package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
  78. package/build/__tests__/ComposedSecondaryEntityCache-test.js +1 -0
  79. package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +1 -1
  80. package/build/__tests__/EnforcingEntityLoader-test.js +101 -113
  81. package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
  82. package/build/__tests__/Entity-test.js +0 -132
  83. package/build/__tests__/Entity-test.js.map +1 -1
  84. package/build/__tests__/EntityAssociationLoader-test.js +6 -2
  85. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  86. package/build/__tests__/EntityCommonUseCases-test.js +24 -22
  87. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  88. package/build/__tests__/EntityCompanion-test.js +26 -3
  89. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  90. package/build/__tests__/EntityConfiguration-test.js +103 -0
  91. package/build/__tests__/EntityConfiguration-test.js.map +1 -0
  92. package/build/__tests__/EntityDatabaseAdapter-test.js +6 -0
  93. package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
  94. package/build/__tests__/EntityEdges-test.js +61 -20
  95. package/build/__tests__/EntityEdges-test.js.map +1 -1
  96. package/build/__tests__/EntityFields-test.js +6 -0
  97. package/build/__tests__/EntityFields-test.js.map +1 -1
  98. package/build/__tests__/EntityLoader-constructor-test.js +16 -17
  99. package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
  100. package/build/__tests__/EntityLoader-test.js +74 -22
  101. package/build/__tests__/EntityLoader-test.js.map +1 -1
  102. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +12 -15
  103. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  104. package/build/__tests__/EntityMutator-test.js +54 -9
  105. package/build/__tests__/EntityMutator-test.js.map +1 -1
  106. package/build/__tests__/EntityPrivacyPolicy-test.js +77 -59
  107. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  108. package/build/__tests__/EntityQueryContext-test.js +9 -0
  109. package/build/__tests__/EntityQueryContext-test.js.map +1 -1
  110. package/build/__tests__/EntitySelfReferentialEdges-test.js +42 -25
  111. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  112. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
  113. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +20 -18
  114. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  115. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +12 -15
  116. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  117. package/build/entityUtils.d.ts +1 -1
  118. package/build/entityUtils.js.map +1 -1
  119. package/build/errors/EntityCacheAdapterError.js +2 -5
  120. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  121. package/build/errors/EntityDatabaseAdapterError.js +14 -35
  122. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  123. package/build/errors/EntityError.js +1 -0
  124. package/build/errors/EntityError.js.map +1 -1
  125. package/build/errors/EntityInvalidFieldValueError.js +2 -2
  126. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  127. package/build/errors/EntityNotAuthorizedError.js +3 -2
  128. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  129. package/build/errors/EntityNotFoundError.js +2 -2
  130. package/build/errors/EntityNotFoundError.js.map +1 -1
  131. package/build/index.d.ts +26 -20
  132. package/build/index.js +38 -28
  133. package/build/index.js.map +1 -1
  134. package/build/internal/EntityDataManager.d.ts +1 -1
  135. package/build/internal/EntityDataManager.js +6 -1
  136. package/build/internal/EntityDataManager.js.map +1 -1
  137. package/build/internal/EntityFieldTransformationUtils.d.ts +5 -5
  138. package/build/internal/EntityFieldTransformationUtils.js +5 -8
  139. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  140. package/build/internal/EntityTableDataCoordinator.d.ts +1 -1
  141. package/build/internal/EntityTableDataCoordinator.js +5 -0
  142. package/build/internal/EntityTableDataCoordinator.js.map +1 -1
  143. package/build/internal/ReadThroughEntityCache.d.ts +1 -1
  144. package/build/internal/ReadThroughEntityCache.js +2 -0
  145. package/build/internal/ReadThroughEntityCache.js.map +1 -1
  146. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +6 -2
  147. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
  148. package/build/internal/__tests__/ReadThroughEntityCache-test.js +33 -0
  149. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  150. package/build/metrics/IEntityMetricsAdapter.d.ts +1 -1
  151. package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +1 -1
  152. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  153. package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +1 -1
  154. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  155. package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +1 -1
  156. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  157. package/build/rules/PrivacyPolicyRule.d.ts +1 -1
  158. package/build/rules/PrivacyPolicyRule.js.map +1 -1
  159. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
  160. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
  161. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
  162. package/build/testfixtures/DateIDTestEntity.js +12 -15
  163. package/build/testfixtures/DateIDTestEntity.js.map +1 -1
  164. package/build/testfixtures/SimpleTestEntity.js +12 -15
  165. package/build/testfixtures/SimpleTestEntity.js.map +1 -1
  166. package/build/testfixtures/TestEntity.js +12 -15
  167. package/build/testfixtures/TestEntity.js.map +1 -1
  168. package/build/testfixtures/TestEntity2.js +12 -15
  169. package/build/testfixtures/TestEntity2.js.map +1 -1
  170. package/build/testfixtures/TestEntityNumberKey.js +12 -15
  171. package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
  172. package/build/testfixtures/TestEntityWithMutationTriggers.d.ts +36 -0
  173. package/build/testfixtures/TestEntityWithMutationTriggers.js +82 -0
  174. package/build/testfixtures/TestEntityWithMutationTriggers.js.map +1 -0
  175. package/build/utils/EntityPrivacyUtils.d.ts +34 -0
  176. package/build/utils/EntityPrivacyUtils.js +160 -0
  177. package/build/utils/EntityPrivacyUtils.js.map +1 -0
  178. package/build/utils/__tests__/EntityPrivacyUtils-test.d.ts +1 -0
  179. package/build/utils/__tests__/EntityPrivacyUtils-test.js +395 -0
  180. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -0
  181. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.d.ts +1 -0
  182. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js +26 -0
  183. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js.map +1 -0
  184. package/build/utils/collections/maps.js.map +1 -1
  185. package/build/utils/mergeEntityMutationTriggerConfigurations.d.ts +4 -0
  186. package/build/utils/mergeEntityMutationTriggerConfigurations.js +28 -0
  187. package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -0
  188. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -1
  189. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
  190. package/build/utils/testing/StubCacheAdapter.d.ts +3 -3
  191. package/build/utils/testing/StubCacheAdapter.js +3 -3
  192. package/build/utils/testing/StubCacheAdapter.js.map +1 -1
  193. package/build/utils/testing/StubDatabaseAdapter.d.ts +2 -2
  194. package/build/utils/testing/StubDatabaseAdapter.js +4 -2
  195. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  196. package/build/utils/testing/StubDatabaseAdapterProvider.d.ts +1 -1
  197. package/build/utils/testing/StubDatabaseAdapterProvider.js +1 -3
  198. package/build/utils/testing/StubDatabaseAdapterProvider.js.map +1 -1
  199. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.d.ts +1 -0
  200. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js +42 -0
  201. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js.map +1 -0
  202. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +53 -0
  203. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
  204. package/build/utils/testing/describeFieldTestCase.js.map +1 -1
  205. package/package.json +5 -4
  206. package/src/AuthorizationResultBasedEntityLoader.ts +297 -0
  207. package/src/ComposedEntityCacheAdapter.ts +6 -6
  208. package/src/ComposedSecondaryEntityCache.ts +8 -8
  209. package/src/EnforcingEntityLoader.ts +20 -19
  210. package/src/Entity.ts +11 -126
  211. package/src/EntityAssociationLoader.ts +40 -41
  212. package/src/EntityCompanion.ts +8 -4
  213. package/src/EntityCompanionProvider.ts +24 -16
  214. package/src/EntityConfiguration.ts +18 -7
  215. package/src/EntityDatabaseAdapter.ts +41 -41
  216. package/src/EntityFieldDefinition.ts +28 -18
  217. package/src/EntityFields.ts +15 -0
  218. package/src/EntityLoader.ts +63 -357
  219. package/src/EntityLoaderFactory.ts +10 -4
  220. package/src/EntityLoaderUtils.ts +149 -0
  221. package/src/EntityMutationInfo.ts +2 -2
  222. package/src/EntityMutationTriggerConfiguration.ts +5 -5
  223. package/src/EntityMutationValidator.ts +2 -2
  224. package/src/EntityMutator.ts +146 -144
  225. package/src/EntityMutatorFactory.ts +8 -8
  226. package/src/EntityPrivacyPolicy.ts +78 -28
  227. package/src/EntityQueryContext.ts +14 -13
  228. package/src/EntityQueryContextProvider.ts +5 -5
  229. package/src/EntitySecondaryCacheLoader.ts +13 -11
  230. package/src/GenericEntityCacheAdapter.ts +10 -10
  231. package/src/GenericSecondaryEntityCache.ts +6 -6
  232. package/src/IEntityCacheAdapter.ts +4 -4
  233. package/src/IEntityCacheAdapterProvider.ts +2 -2
  234. package/src/IEntityDatabaseAdapterProvider.ts +2 -2
  235. package/src/ReadonlyEntity.ts +5 -5
  236. package/src/ViewerContext.ts +5 -5
  237. package/src/ViewerScopedEntityCompanion.ts +4 -4
  238. package/src/ViewerScopedEntityCompanionProvider.ts +4 -5
  239. package/src/ViewerScopedEntityLoaderFactory.ts +10 -4
  240. package/src/ViewerScopedEntityMutatorFactory.ts +5 -5
  241. package/src/__tests__/ComposedCacheAdapter-test.ts +12 -10
  242. package/src/__tests__/ComposedSecondaryEntityCache-test.ts +8 -8
  243. package/src/__tests__/EnforcingEntityLoader-test.ts +236 -159
  244. package/src/__tests__/Entity-test.ts +0 -202
  245. package/src/__tests__/EntityAssociationLoader-test.ts +29 -25
  246. package/src/__tests__/EntityCommonUseCases-test.ts +29 -13
  247. package/src/__tests__/EntityCompanion-test.ts +57 -5
  248. package/src/__tests__/EntityConfiguration-test.ts +118 -0
  249. package/src/__tests__/EntityDatabaseAdapter-test.ts +11 -11
  250. package/src/__tests__/EntityEdges-test.ts +108 -36
  251. package/src/__tests__/EntityFields-test.ts +14 -2
  252. package/src/__tests__/EntityLoader-constructor-test.ts +20 -7
  253. package/src/__tests__/EntityLoader-test.ts +214 -86
  254. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +2 -2
  255. package/src/__tests__/EntityMutator-test.ts +281 -96
  256. package/src/__tests__/EntityPrivacyPolicy-test.ts +166 -53
  257. package/src/__tests__/EntityQueryContext-test.ts +30 -12
  258. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
  259. package/src/__tests__/EntitySelfReferentialEdges-test.ts +46 -26
  260. package/src/__tests__/GenericEntityCacheAdapter-test.ts +2 -2
  261. package/src/__tests__/ViewerContext-test.ts +1 -1
  262. package/src/__tests__/ViewerScopedEntityCompanion-test.ts +2 -2
  263. package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +2 -2
  264. package/src/__tests__/ViewerScopedEntityLoaderFactory-test.ts +2 -1
  265. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +19 -19
  266. package/src/__tests__/entityUtils-test.ts +2 -2
  267. package/src/entityUtils.ts +4 -4
  268. package/src/errors/EntityError.ts +4 -1
  269. package/src/errors/EntityInvalidFieldValueError.ts +2 -2
  270. package/src/errors/EntityNotAuthorizedError.ts +3 -3
  271. package/src/errors/EntityNotFoundError.ts +2 -2
  272. package/src/index.ts +26 -20
  273. package/src/internal/EntityDataManager.ts +24 -24
  274. package/src/internal/EntityFieldTransformationUtils.ts +39 -32
  275. package/src/internal/EntityTableDataCoordinator.ts +3 -3
  276. package/src/internal/ReadThroughEntityCache.ts +9 -9
  277. package/src/internal/__tests__/EntityDataManager-test.ts +51 -51
  278. package/src/internal/__tests__/EntityFieldTransformationUtils-test.ts +14 -10
  279. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +74 -18
  280. package/src/metrics/EntityMetricsUtils.ts +4 -4
  281. package/src/metrics/IEntityMetricsAdapter.ts +1 -1
  282. package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +9 -3
  283. package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +9 -3
  284. package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +9 -3
  285. package/src/rules/PrivacyPolicyRule.ts +9 -3
  286. package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -1
  287. package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -1
  288. package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -1
  289. package/src/testfixtures/TestEntity.ts +1 -1
  290. package/src/testfixtures/TestEntityWithMutationTriggers.ts +156 -0
  291. package/src/utils/EntityPrivacyUtils.ts +325 -0
  292. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +570 -0
  293. package/src/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.ts +29 -0
  294. package/src/utils/collections/__tests__/maps-test.ts +2 -2
  295. package/src/utils/collections/maps.ts +11 -11
  296. package/src/utils/mergeEntityMutationTriggerConfigurations.ts +44 -0
  297. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +25 -22
  298. package/src/utils/testing/StubCacheAdapter.ts +17 -15
  299. package/src/utils/testing/StubDatabaseAdapter.ts +35 -30
  300. package/src/utils/testing/StubDatabaseAdapterProvider.ts +2 -2
  301. package/src/utils/testing/StubQueryContextProvider.ts +2 -2
  302. package/src/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.ts +42 -0
  303. package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +111 -29
  304. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +2 -2
  305. package/src/utils/testing/describeFieldTestCase.ts +1 -1
  306. package/build/__tests__/EntityDataConfiguration-test.js +0 -68
  307. package/build/__tests__/EntityDataConfiguration-test.js.map +0 -1
  308. package/src/__tests__/EntityDataConfiguration-test.ts +0 -77
  309. /package/build/__tests__/{EntityDataConfiguration-test.d.ts → EntityConfiguration-test.d.ts} +0 -0
@@ -8,7 +8,7 @@ export const timeAndLogLoadEventAsync =
8
8
  (
9
9
  metricsAdapter: IEntityMetricsAdapter,
10
10
  loadType: EntityMetricsLoadType,
11
- entityClassName: string
11
+ entityClassName: string,
12
12
  ) =>
13
13
  async <TFields>(promise: Promise<readonly Readonly<TFields>[]>) => {
14
14
  const startTime = Date.now();
@@ -29,10 +29,10 @@ export const timeAndLogLoadMapEventAsync =
29
29
  (
30
30
  metricsAdapter: IEntityMetricsAdapter,
31
31
  loadType: EntityMetricsLoadType,
32
- entityClassName: string
32
+ entityClassName: string,
33
33
  ) =>
34
34
  async <TFields, N extends keyof TFields>(
35
- promise: Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Readonly<TFields>[]>>
35
+ promise: Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Readonly<TFields>[]>>,
36
36
  ) => {
37
37
  const startTime = Date.now();
38
38
  const result = await promise;
@@ -54,7 +54,7 @@ export const timeAndLogMutationEventAsync =
54
54
  (
55
55
  metricsAdapter: IEntityMetricsAdapter,
56
56
  mutationType: EntityMetricsMutationType,
57
- entityClassName: string
57
+ entityClassName: string,
58
58
  ) =>
59
59
  async <T>(promise: Promise<T>) => {
60
60
  const startTime = Date.now();
@@ -140,7 +140,7 @@ export default interface IEntityMetricsAdapter {
140
140
  * Called when a dataloader, cache, or database load is initiated via the standard
141
141
  * load methods (not equality conjunction or raw). Most commonly used for logging
142
142
  * a waterfall to determine dataloader and cache hit rates and ratios.
143
- * @param fieldValueCount - count of field values being loaded for a field
143
+ * @param incrementLoadCountEvent - count of field values being loaded for a field
144
144
  */
145
145
  incrementDataManagerLoadCount(incrementLoadCountEvent: IncrementLoadCountEvent): void;
146
146
  }
@@ -12,13 +12,19 @@ export default class AlwaysAllowPrivacyPolicyRule<
12
12
  TID extends NonNullable<TFields[TSelectedFields]>,
13
13
  TViewerContext extends ViewerContext,
14
14
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
15
- TSelectedFields extends keyof TFields = keyof TFields
15
+ TSelectedFields extends keyof TFields = keyof TFields,
16
16
  > extends PrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields> {
17
17
  async evaluateAsync(
18
18
  _viewerContext: TViewerContext,
19
19
  _queryContext: EntityQueryContext,
20
- _evaluationContext: EntityPrivacyPolicyEvaluationContext,
21
- _entity: TEntity
20
+ _evaluationContext: EntityPrivacyPolicyEvaluationContext<
21
+ TFields,
22
+ TID,
23
+ TViewerContext,
24
+ TEntity,
25
+ TSelectedFields
26
+ >,
27
+ _entity: TEntity,
22
28
  ): Promise<RuleEvaluationResult> {
23
29
  return RuleEvaluationResult.ALLOW;
24
30
  }
@@ -12,13 +12,19 @@ export default class AlwaysDenyPrivacyPolicyRule<
12
12
  TID extends NonNullable<TFields[TSelectedFields]>,
13
13
  TViewerContext extends ViewerContext,
14
14
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
15
- TSelectedFields extends keyof TFields = keyof TFields
15
+ TSelectedFields extends keyof TFields = keyof TFields,
16
16
  > extends PrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields> {
17
17
  async evaluateAsync(
18
18
  _viewerContext: TViewerContext,
19
19
  _queryContext: EntityQueryContext,
20
- _evaluationContext: EntityPrivacyPolicyEvaluationContext,
21
- _entity: TEntity
20
+ _evaluationContext: EntityPrivacyPolicyEvaluationContext<
21
+ TFields,
22
+ TID,
23
+ TViewerContext,
24
+ TEntity,
25
+ TSelectedFields
26
+ >,
27
+ _entity: TEntity,
22
28
  ): Promise<RuleEvaluationResult> {
23
29
  return RuleEvaluationResult.DENY;
24
30
  }
@@ -12,13 +12,19 @@ export default class AlwaysSkipPrivacyPolicyRule<
12
12
  TID extends NonNullable<TFields[TSelectedFields]>,
13
13
  TViewerContext extends ViewerContext,
14
14
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
15
- TSelectedFields extends keyof TFields = keyof TFields
15
+ TSelectedFields extends keyof TFields = keyof TFields,
16
16
  > extends PrivacyPolicyRule<TFields, TID, TViewerContext, TEntity, TSelectedFields> {
17
17
  async evaluateAsync(
18
18
  _viewerContext: TViewerContext,
19
19
  _queryContext: EntityQueryContext,
20
- _evaluationContext: EntityPrivacyPolicyEvaluationContext,
21
- _entity: TEntity
20
+ _evaluationContext: EntityPrivacyPolicyEvaluationContext<
21
+ TFields,
22
+ TID,
23
+ TViewerContext,
24
+ TEntity,
25
+ TSelectedFields
26
+ >,
27
+ _entity: TEntity,
22
28
  ): Promise<RuleEvaluationResult> {
23
29
  return RuleEvaluationResult.SKIP;
24
30
  }
@@ -41,12 +41,18 @@ export default abstract class PrivacyPolicyRule<
41
41
  TID extends NonNullable<TFields[TSelectedFields]>,
42
42
  TViewerContext extends ViewerContext,
43
43
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
44
- TSelectedFields extends keyof TFields = keyof TFields
44
+ TSelectedFields extends keyof TFields = keyof TFields,
45
45
  > {
46
46
  abstract evaluateAsync(
47
47
  viewerContext: TViewerContext,
48
48
  queryContext: EntityQueryContext,
49
- evaluationContext: EntityPrivacyPolicyEvaluationContext,
50
- entity: TEntity
49
+ evaluationContext: EntityPrivacyPolicyEvaluationContext<
50
+ TFields,
51
+ TID,
52
+ TViewerContext,
53
+ TEntity,
54
+ TSelectedFields
55
+ >,
56
+ entity: TEntity,
51
57
  ): Promise<RuleEvaluationResult>;
52
58
  }
@@ -11,7 +11,8 @@ describePrivacyPolicyRule(new AlwaysAllowPrivacyPolicyRule(), {
11
11
  {
12
12
  viewerContext: instance(mock(ViewerContext)),
13
13
  queryContext: instance(mock(EntityQueryContext)),
14
- evaluationContext: instance(mock<EntityPrivacyPolicyEvaluationContext>()),
14
+ evaluationContext:
15
+ instance(mock<EntityPrivacyPolicyEvaluationContext<any, any, any, any, any>>()),
15
16
  entity: anything(),
16
17
  },
17
18
  ],
@@ -11,7 +11,8 @@ describePrivacyPolicyRule(new AlwaysDenyPrivacyPolicyRule(), {
11
11
  {
12
12
  viewerContext: instance(mock(ViewerContext)),
13
13
  queryContext: instance(mock(EntityQueryContext)),
14
- evaluationContext: instance(mock<EntityPrivacyPolicyEvaluationContext>()),
14
+ evaluationContext:
15
+ instance(mock<EntityPrivacyPolicyEvaluationContext<any, any, any, any, any>>()),
15
16
  entity: anything(),
16
17
  },
17
18
  ],
@@ -11,7 +11,8 @@ describePrivacyPolicyRule(new AlwaysSkipPrivacyPolicyRule(), {
11
11
  {
12
12
  viewerContext: instance(mock(ViewerContext)),
13
13
  queryContext: instance(mock(EntityQueryContext)),
14
- evaluationContext: instance(mock<EntityPrivacyPolicyEvaluationContext>()),
14
+ evaluationContext:
15
+ instance(mock<EntityPrivacyPolicyEvaluationContext<any, any, any, any, any>>()),
15
16
  entity: anything(),
16
17
  },
17
18
  ],
@@ -99,7 +99,7 @@ export default class TestEntity extends Entity<TestFields, string, ViewerContext
99
99
  id: testValue,
100
100
  databaseFields: fields,
101
101
  selectedFields: fields,
102
- })
102
+ }),
103
103
  );
104
104
  }
105
105
 
@@ -0,0 +1,156 @@
1
+ import Entity from '../Entity';
2
+ import { EntityCompanionDefinition } from '../EntityCompanionProvider';
3
+ import EntityConfiguration from '../EntityConfiguration';
4
+ import { StringField, UUIDField } from '../EntityFields';
5
+ import { EntityTriggerMutationInfo } from '../EntityMutationInfo';
6
+ import {
7
+ EntityMutationTrigger,
8
+ EntityNonTransactionalMutationTrigger,
9
+ } from '../EntityMutationTriggerConfiguration';
10
+ import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
11
+ import { EntityQueryContext } from '../EntityQueryContext';
12
+ import ViewerContext from '../ViewerContext';
13
+ import AlwaysAllowPrivacyPolicyRule from '../rules/AlwaysAllowPrivacyPolicyRule';
14
+
15
+ export type TestMTFields = {
16
+ id: string;
17
+ stringField: string;
18
+ };
19
+
20
+ export const testEntityMTConfiguration = new EntityConfiguration<TestMTFields>({
21
+ idField: 'id',
22
+ tableName: 'test_entity_should_not_write_to_db_3',
23
+ schema: {
24
+ id: new UUIDField({
25
+ columnName: 'id',
26
+ }),
27
+ stringField: new StringField({
28
+ columnName: 'string_field',
29
+ }),
30
+ },
31
+ databaseAdapterFlavor: 'postgres',
32
+ cacheAdapterFlavor: 'redis',
33
+ });
34
+
35
+ export class TestEntityMTPrivacyPolicy extends EntityPrivacyPolicy<
36
+ TestMTFields,
37
+ string,
38
+ ViewerContext,
39
+ TestEntityWithMutationTriggers
40
+ > {
41
+ protected override readonly readRules = [
42
+ new AlwaysAllowPrivacyPolicyRule<
43
+ TestMTFields,
44
+ string,
45
+ ViewerContext,
46
+ TestEntityWithMutationTriggers
47
+ >(),
48
+ ];
49
+ protected override readonly createRules = [
50
+ new AlwaysAllowPrivacyPolicyRule<
51
+ TestMTFields,
52
+ string,
53
+ ViewerContext,
54
+ TestEntityWithMutationTriggers
55
+ >(),
56
+ ];
57
+ protected override readonly updateRules = [
58
+ new AlwaysAllowPrivacyPolicyRule<
59
+ TestMTFields,
60
+ string,
61
+ ViewerContext,
62
+ TestEntityWithMutationTriggers
63
+ >(),
64
+ ];
65
+ protected override readonly deleteRules = [
66
+ new AlwaysAllowPrivacyPolicyRule<
67
+ TestMTFields,
68
+ string,
69
+ ViewerContext,
70
+ TestEntityWithMutationTriggers
71
+ >(),
72
+ ];
73
+ }
74
+
75
+ export class TestMutationTrigger extends EntityMutationTrigger<
76
+ TestMTFields,
77
+ string,
78
+ ViewerContext,
79
+ TestEntityWithMutationTriggers,
80
+ keyof TestMTFields
81
+ > {
82
+ constructor(
83
+ // @ts-expect-error key is never used but is helpful for debugging
84
+ private readonly key: string,
85
+ ) {
86
+ super();
87
+ }
88
+
89
+ async executeAsync(
90
+ _viewerContext: ViewerContext,
91
+ _queryContext: EntityQueryContext,
92
+ _entity: TestEntityWithMutationTriggers,
93
+ _mutationInfo: EntityTriggerMutationInfo<
94
+ TestMTFields,
95
+ string,
96
+ ViewerContext,
97
+ TestEntityWithMutationTriggers,
98
+ keyof TestMTFields
99
+ >,
100
+ ): Promise<void> {}
101
+ }
102
+
103
+ export class NonTransactionalTestMutationTrigger extends EntityNonTransactionalMutationTrigger<
104
+ TestMTFields,
105
+ string,
106
+ ViewerContext,
107
+ TestEntityWithMutationTriggers,
108
+ keyof TestMTFields
109
+ > {
110
+ constructor(
111
+ // @ts-expect-error key is never used but is helpful for debugging
112
+ private readonly key: string,
113
+ ) {
114
+ super();
115
+ }
116
+
117
+ async executeAsync(
118
+ _viewerContext: ViewerContext,
119
+ _entity: TestEntityWithMutationTriggers,
120
+ _mutationInfo: EntityTriggerMutationInfo<
121
+ TestMTFields,
122
+ string,
123
+ ViewerContext,
124
+ TestEntityWithMutationTriggers,
125
+ keyof TestMTFields
126
+ >,
127
+ ): Promise<void> {}
128
+ }
129
+
130
+ /**
131
+ * A test Entity that has one afterCreate and one afterAll trigger
132
+ */
133
+ export default class TestEntityWithMutationTriggers extends Entity<
134
+ TestMTFields,
135
+ string,
136
+ ViewerContext
137
+ > {
138
+ static defineCompanionDefinition(): EntityCompanionDefinition<
139
+ TestMTFields,
140
+ string,
141
+ ViewerContext,
142
+ TestEntityWithMutationTriggers,
143
+ TestEntityMTPrivacyPolicy
144
+ > {
145
+ return {
146
+ entityClass: TestEntityWithMutationTriggers,
147
+ entityConfiguration: testEntityMTConfiguration,
148
+ privacyPolicyClass: TestEntityMTPrivacyPolicy,
149
+ mutationTriggers: {
150
+ afterCreate: [new TestMutationTrigger('localAfterCreate')],
151
+ afterAll: [new TestMutationTrigger('localAfterAll')],
152
+ afterCommit: [new NonTransactionalTestMutationTrigger('localAfterCommit')],
153
+ },
154
+ };
155
+ }
156
+ }
@@ -0,0 +1,325 @@
1
+ import { asyncResult } from '@expo/results';
2
+
3
+ import Entity, { IEntityClass } from '../Entity';
4
+ import { EntityEdgeDeletionBehavior } from '../EntityFieldDefinition';
5
+ import { EntityCascadingDeletionInfo } from '../EntityMutationInfo';
6
+ import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
7
+ import { EntityQueryContext } from '../EntityQueryContext';
8
+ import ViewerContext from '../ViewerContext';
9
+ import { failedResults } from '../entityUtils';
10
+ import EntityNotAuthorizedError from '../errors/EntityNotAuthorizedError';
11
+
12
+ /**
13
+ * Check whether an entity loaded by a viewer can be updated by that same viewer.
14
+ *
15
+ * @remarks
16
+ *
17
+ * This may be useful in situations relying upon the thrown privacy policy thrown authorization error
18
+ * is insufficient for the task at hand. When dealing with purely a sequence of mutations it is easy
19
+ * to roll back all mutations given a single authorization error by wrapping them in a single transaction.
20
+ * When certain portions of a mutation cannot be rolled back transactionally (third pary calls,
21
+ * legacy code, etc), using this method can help decide whether the sequence of mutations will fail before
22
+ * attempting them. Note that if any privacy policy rules use a piece of data being updated in the mutations
23
+ * the result of this method and the update mutation itself may differ.
24
+ *
25
+ * @param entityClass - class of entity
26
+ * @param sourceEntity - entity loaded by viewer
27
+ * @param queryContext - query context in which to perform the check
28
+ */
29
+ export async function canViewerUpdateAsync<
30
+ TMFields extends object,
31
+ TMID extends NonNullable<TMFields[TMSelectedFields]>,
32
+ TMViewerContext extends ViewerContext,
33
+ TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
34
+ TMPrivacyPolicy extends EntityPrivacyPolicy<
35
+ TMFields,
36
+ TMID,
37
+ TMViewerContext,
38
+ TMEntity,
39
+ TMSelectedFields
40
+ >,
41
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
42
+ >(
43
+ entityClass: IEntityClass<
44
+ TMFields,
45
+ TMID,
46
+ TMViewerContext,
47
+ TMEntity,
48
+ TMPrivacyPolicy,
49
+ TMSelectedFields
50
+ >,
51
+ sourceEntity: TMEntity,
52
+ queryContext: EntityQueryContext = sourceEntity
53
+ .getViewerContext()
54
+ .getViewerScopedEntityCompanionForClass(entityClass)
55
+ .getQueryContextProvider()
56
+ .getQueryContext(),
57
+ ): Promise<boolean> {
58
+ return await canViewerUpdateInternalAsync(
59
+ entityClass,
60
+ sourceEntity,
61
+ /* cascadingDeleteCause */ null,
62
+ queryContext,
63
+ );
64
+ }
65
+
66
+ async function canViewerUpdateInternalAsync<
67
+ TMFields extends object,
68
+ TMID extends NonNullable<TMFields[TMSelectedFields]>,
69
+ TMViewerContext extends ViewerContext,
70
+ TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
71
+ TMPrivacyPolicy extends EntityPrivacyPolicy<
72
+ TMFields,
73
+ TMID,
74
+ TMViewerContext,
75
+ TMEntity,
76
+ TMSelectedFields
77
+ >,
78
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
79
+ >(
80
+ entityClass: IEntityClass<
81
+ TMFields,
82
+ TMID,
83
+ TMViewerContext,
84
+ TMEntity,
85
+ TMPrivacyPolicy,
86
+ TMSelectedFields
87
+ >,
88
+ sourceEntity: TMEntity,
89
+ cascadingDeleteCause: EntityCascadingDeletionInfo | null,
90
+ queryContext: EntityQueryContext,
91
+ ): Promise<boolean> {
92
+ const companion = sourceEntity
93
+ .getViewerContext()
94
+ .getViewerScopedEntityCompanionForClass(entityClass);
95
+ const privacyPolicy = companion.entityCompanion.privacyPolicy;
96
+ const evaluationResult = await asyncResult(
97
+ privacyPolicy.authorizeUpdateAsync(
98
+ sourceEntity.getViewerContext(),
99
+ queryContext,
100
+ { previousValue: null, cascadingDeleteCause },
101
+ sourceEntity,
102
+ companion.getMetricsAdapter(),
103
+ ),
104
+ );
105
+ if (!evaluationResult.ok) {
106
+ if (evaluationResult.reason instanceof EntityNotAuthorizedError) {
107
+ return false;
108
+ } else {
109
+ throw evaluationResult.reason;
110
+ }
111
+ }
112
+ return evaluationResult.ok;
113
+ }
114
+
115
+ /**
116
+ * Check whether a single entity loaded by a viewer can be deleted by that same viewer.
117
+ * This recursively checks edge cascade permissions (EntityEdgeDeletionBehavior) as well.
118
+ *
119
+ * @remarks
120
+ * See remarks for canViewerUpdate.
121
+ *
122
+ * @param entityClass - class of entity
123
+ * @param sourceEntity - entity loaded by viewer
124
+ * @param queryContext - query context in which to perform the check
125
+ */
126
+ export async function canViewerDeleteAsync<
127
+ TFields extends object,
128
+ TID extends NonNullable<TFields[TSelectedFields]>,
129
+ TMViewerContext extends ViewerContext,
130
+ TEntity extends Entity<TFields, TID, TMViewerContext, TSelectedFields>,
131
+ TPrivacyPolicy extends EntityPrivacyPolicy<
132
+ TFields,
133
+ TID,
134
+ TMViewerContext,
135
+ TEntity,
136
+ TSelectedFields
137
+ >,
138
+ TSelectedFields extends keyof TFields = keyof TFields,
139
+ >(
140
+ entityClass: IEntityClass<
141
+ TFields,
142
+ TID,
143
+ TMViewerContext,
144
+ TEntity,
145
+ TPrivacyPolicy,
146
+ TSelectedFields
147
+ >,
148
+ sourceEntity: TEntity,
149
+ queryContext: EntityQueryContext = sourceEntity
150
+ .getViewerContext()
151
+ .getViewerScopedEntityCompanionForClass(entityClass)
152
+ .getQueryContextProvider()
153
+ .getQueryContext(),
154
+ ): Promise<boolean> {
155
+ return await canViewerDeleteInternalAsync(
156
+ entityClass,
157
+ sourceEntity,
158
+ /* cascadingDeleteCause */ null,
159
+ queryContext,
160
+ );
161
+ }
162
+
163
+ async function canViewerDeleteInternalAsync<
164
+ TFields extends object,
165
+ TID extends NonNullable<TFields[TSelectedFields]>,
166
+ TMViewerContext extends ViewerContext,
167
+ TEntity extends Entity<TFields, TID, TMViewerContext, TSelectedFields>,
168
+ TPrivacyPolicy extends EntityPrivacyPolicy<
169
+ TFields,
170
+ TID,
171
+ TMViewerContext,
172
+ TEntity,
173
+ TSelectedFields
174
+ >,
175
+ TSelectedFields extends keyof TFields = keyof TFields,
176
+ >(
177
+ entityClass: IEntityClass<
178
+ TFields,
179
+ TID,
180
+ TMViewerContext,
181
+ TEntity,
182
+ TPrivacyPolicy,
183
+ TSelectedFields
184
+ >,
185
+ sourceEntity: TEntity,
186
+ cascadingDeleteCause: EntityCascadingDeletionInfo | null,
187
+ queryContext: EntityQueryContext,
188
+ ): Promise<boolean> {
189
+ const viewerContext = sourceEntity.getViewerContext();
190
+ const entityCompanionProvider = viewerContext.entityCompanionProvider;
191
+ const viewerScopedCompanion = sourceEntity
192
+ .getViewerContext()
193
+ .getViewerScopedEntityCompanionForClass(entityClass);
194
+
195
+ const privacyPolicy = viewerScopedCompanion.entityCompanion.privacyPolicy;
196
+ const evaluationResult = await asyncResult(
197
+ privacyPolicy.authorizeDeleteAsync(
198
+ sourceEntity.getViewerContext(),
199
+ queryContext,
200
+ { previousValue: null, cascadingDeleteCause },
201
+ sourceEntity,
202
+ viewerScopedCompanion.getMetricsAdapter(),
203
+ ),
204
+ );
205
+ if (!evaluationResult.ok) {
206
+ if (evaluationResult.reason instanceof EntityNotAuthorizedError) {
207
+ return false;
208
+ } else {
209
+ throw evaluationResult.reason;
210
+ }
211
+ }
212
+
213
+ const newCascadingDeleteCause = {
214
+ entity: sourceEntity,
215
+ cascadingDeleteCause,
216
+ };
217
+
218
+ // Take entity X which is proposed to be deleted, look at inbound edges (entities that reference X).
219
+ // These inbound edges are the entities that will either get deleted or have their references
220
+ // to X nullified based on the EntityEdgeDeletionBehavior when entity X is deleted.
221
+ // For each of these inboundEdge entities Y, look at the field(s) on Y that reference X.
222
+ // For each of the field(s) on Y that reference X,
223
+ // - if EntityEdgeDeletionBehavior is cascade set null, check if user can update Y
224
+ // - if EntityEdgeDeletionBehavior is cascade delete, recursively run canViewerDeleteAsync on Y
225
+ // Return the conjunction (returning eagerly when false) of all checks recursively.
226
+
227
+ const entityConfiguration =
228
+ viewerScopedCompanion.entityCompanion.entityCompanionDefinition.entityConfiguration;
229
+ const inboundEdges = entityConfiguration.inboundEdges;
230
+
231
+ for (const inboundEdge of inboundEdges) {
232
+ const configurationForInboundEdge =
233
+ entityCompanionProvider.getCompanionForEntity(inboundEdge).entityCompanionDefinition
234
+ .entityConfiguration;
235
+
236
+ const loader = viewerContext
237
+ .getViewerScopedEntityCompanionForClass(inboundEdge)
238
+ .getLoaderFactory()
239
+ .forLoad(queryContext, {
240
+ previousValue: null,
241
+ cascadingDeleteCause: newCascadingDeleteCause,
242
+ });
243
+
244
+ for (const [fieldName, fieldDefinition] of configurationForInboundEdge.schema) {
245
+ const association = fieldDefinition.association;
246
+ if (!association) {
247
+ continue;
248
+ }
249
+
250
+ const associatedConfiguration = entityCompanionProvider.getCompanionForEntity(
251
+ association.associatedEntityClass,
252
+ ).entityCompanionDefinition.entityConfiguration;
253
+ if (associatedConfiguration !== entityConfiguration) {
254
+ continue;
255
+ }
256
+
257
+ const entityResultsForInboundEdge = await loader
258
+ .withAuthorizationResults()
259
+ .loadManyByFieldEqualingAsync(
260
+ fieldName,
261
+ association.associatedEntityLookupByField
262
+ ? sourceEntity.getField(association.associatedEntityLookupByField as any)
263
+ : sourceEntity.getID(),
264
+ );
265
+
266
+ const failedEntityLoadResults = failedResults(entityResultsForInboundEdge);
267
+ for (const failedResult of failedEntityLoadResults) {
268
+ if (failedResult.reason instanceof EntityNotAuthorizedError) {
269
+ return false;
270
+ } else {
271
+ throw failedResult.reason;
272
+ }
273
+ }
274
+
275
+ // all results should be success at this point due to check above
276
+ const entitiesForInboundEdge = entityResultsForInboundEdge.map((r) => r.enforceValue());
277
+
278
+ switch (association.edgeDeletionBehavior) {
279
+ case EntityEdgeDeletionBehavior.CASCADE_DELETE:
280
+ case EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY: {
281
+ const canDeleteAll = (
282
+ await Promise.all(
283
+ entitiesForInboundEdge.map((entity) =>
284
+ canViewerDeleteInternalAsync(
285
+ inboundEdge,
286
+ entity,
287
+ newCascadingDeleteCause,
288
+ queryContext,
289
+ ),
290
+ ),
291
+ )
292
+ ).every((b) => b);
293
+
294
+ if (!canDeleteAll) {
295
+ return false;
296
+ }
297
+ break;
298
+ }
299
+
300
+ case EntityEdgeDeletionBehavior.SET_NULL:
301
+ case EntityEdgeDeletionBehavior.SET_NULL_INVALIDATE_CACHE_ONLY: {
302
+ const canUpdateAll = (
303
+ await Promise.all(
304
+ entitiesForInboundEdge.map((entity) =>
305
+ canViewerUpdateInternalAsync(
306
+ inboundEdge,
307
+ entity,
308
+ newCascadingDeleteCause,
309
+ queryContext,
310
+ ),
311
+ ),
312
+ )
313
+ ).every((b) => b);
314
+
315
+ if (!canUpdateAll) {
316
+ return false;
317
+ }
318
+ break;
319
+ }
320
+ }
321
+ }
322
+ }
323
+
324
+ return true;
325
+ }