@expo/entity 0.41.0 → 0.43.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 (430) hide show
  1. package/build/AuthorizationResultBasedEntityAssociationLoader.d.ts +16 -16
  2. package/build/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -1
  3. package/build/AuthorizationResultBasedEntityLoader.d.ts +39 -67
  4. package/build/AuthorizationResultBasedEntityLoader.js +85 -62
  5. package/build/AuthorizationResultBasedEntityLoader.js.map +1 -1
  6. package/build/AuthorizationResultBasedEntityMutator.d.ts +16 -16
  7. package/build/AuthorizationResultBasedEntityMutator.js.map +1 -1
  8. package/build/ComposedEntityCacheAdapter.d.ts +7 -6
  9. package/build/ComposedEntityCacheAdapter.js +28 -28
  10. package/build/ComposedEntityCacheAdapter.js.map +1 -1
  11. package/build/ComposedSecondaryEntityCache.d.ts +1 -1
  12. package/build/ComposedSecondaryEntityCache.js.map +1 -1
  13. package/build/EnforcingEntityAssociationLoader.d.ts +15 -15
  14. package/build/EnforcingEntityAssociationLoader.js.map +1 -1
  15. package/build/EnforcingEntityCreator.d.ts +2 -2
  16. package/build/EnforcingEntityDeleter.d.ts +2 -2
  17. package/build/EnforcingEntityLoader.d.ts +104 -18
  18. package/build/EnforcingEntityLoader.js +113 -12
  19. package/build/EnforcingEntityLoader.js.map +1 -1
  20. package/build/EnforcingEntityUpdater.d.ts +2 -2
  21. package/build/Entity.d.ts +10 -10
  22. package/build/Entity.js.map +1 -1
  23. package/build/EntityAssociationLoader.d.ts +3 -3
  24. package/build/EntityCompanion.d.ts +5 -5
  25. package/build/EntityCompanion.js.map +1 -1
  26. package/build/EntityCompanionProvider.d.ts +6 -6
  27. package/build/EntityCompanionProvider.js.map +1 -1
  28. package/build/EntityConfiguration.d.ts +46 -5
  29. package/build/EntityConfiguration.js +39 -1
  30. package/build/EntityConfiguration.js.map +1 -1
  31. package/build/EntityCreator.d.ts +4 -4
  32. package/build/EntityDatabaseAdapter.d.ts +15 -14
  33. package/build/EntityDatabaseAdapter.js +20 -12
  34. package/build/EntityDatabaseAdapter.js.map +1 -1
  35. package/build/EntityDeleter.d.ts +4 -4
  36. package/build/EntityFieldDefinition.d.ts +20 -10
  37. package/build/EntityFieldDefinition.js +3 -1
  38. package/build/EntityFieldDefinition.js.map +1 -1
  39. package/build/EntityFields.d.ts +14 -12
  40. package/build/EntityFields.js.map +1 -1
  41. package/build/EntityLoader.d.ts +5 -5
  42. package/build/EntityLoaderFactory.d.ts +3 -3
  43. package/build/EntityLoaderFactory.js.map +1 -1
  44. package/build/EntityLoaderUtils.d.ts +2 -2
  45. package/build/EntityLoaderUtils.js +27 -1
  46. package/build/EntityLoaderUtils.js.map +1 -1
  47. package/build/EntityMutationInfo.d.ts +2 -2
  48. package/build/EntityMutationTriggerConfiguration.d.ts +14 -14
  49. package/build/EntityMutationTriggerConfiguration.js.map +1 -1
  50. package/build/EntityMutationValidator.d.ts +2 -2
  51. package/build/EntityMutatorFactory.d.ts +5 -5
  52. package/build/EntityMutatorFactory.js.map +1 -1
  53. package/build/EntityPrivacyPolicy.d.ts +14 -14
  54. package/build/EntityPrivacyPolicy.js.map +1 -1
  55. package/build/EntitySecondaryCacheLoader.d.ts +4 -4
  56. package/build/EntityUpdater.d.ts +4 -4
  57. package/build/GenericEntityCacheAdapter.d.ts +7 -6
  58. package/build/GenericEntityCacheAdapter.js +13 -14
  59. package/build/GenericEntityCacheAdapter.js.map +1 -1
  60. package/build/GenericSecondaryEntityCache.d.ts +3 -3
  61. package/build/GenericSecondaryEntityCache.js.map +1 -1
  62. package/build/IEntityCacheAdapter.d.ts +17 -16
  63. package/build/IEntityCacheAdapterProvider.d.ts +1 -1
  64. package/build/IEntityDatabaseAdapterProvider.d.ts +1 -1
  65. package/build/IEntityGenericCacher.d.ts +15 -5
  66. package/build/ReadonlyEntity.d.ts +8 -8
  67. package/build/ReadonlyEntity.js.map +1 -1
  68. package/build/ViewerContext.d.ts +1 -1
  69. package/build/ViewerScopedEntityCompanion.d.ts +5 -5
  70. package/build/ViewerScopedEntityCompanionProvider.d.ts +1 -1
  71. package/build/ViewerScopedEntityLoaderFactory.d.ts +3 -3
  72. package/build/ViewerScopedEntityMutatorFactory.d.ts +5 -5
  73. package/build/entityUtils.d.ts +1 -1
  74. package/build/entityUtils.js.map +1 -1
  75. package/build/errors/EntityInvalidFieldValueError.d.ts +2 -2
  76. package/build/errors/EntityNotAuthorizedError.d.ts +1 -1
  77. package/build/errors/EntityNotFoundError.d.ts +2 -2
  78. package/build/index.d.ts +7 -7
  79. package/build/index.js +8 -13
  80. package/build/index.js.map +1 -1
  81. package/build/internal/CompositeFieldHolder.d.ts +48 -0
  82. package/build/internal/CompositeFieldHolder.js +116 -0
  83. package/build/internal/CompositeFieldHolder.js.map +1 -0
  84. package/build/internal/CompositeFieldValueMap.d.ts +15 -0
  85. package/build/internal/CompositeFieldValueMap.js +51 -0
  86. package/build/internal/CompositeFieldValueMap.js.map +1 -0
  87. package/build/internal/EntityDataManager.d.ts +16 -16
  88. package/build/internal/EntityDataManager.js +42 -45
  89. package/build/internal/EntityDataManager.js.map +1 -1
  90. package/build/internal/EntityFieldTransformationUtils.d.ts +5 -5
  91. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  92. package/build/internal/EntityLoadInterfaces.d.ts +104 -0
  93. package/build/internal/EntityLoadInterfaces.js +25 -0
  94. package/build/internal/EntityLoadInterfaces.js.map +1 -0
  95. package/build/internal/EntityTableDataCoordinator.d.ts +6 -6
  96. package/build/internal/EntityTableDataCoordinator.js.map +1 -1
  97. package/build/internal/ReadThroughEntityCache.d.ts +17 -16
  98. package/build/internal/ReadThroughEntityCache.js +36 -36
  99. package/build/internal/ReadThroughEntityCache.js.map +1 -1
  100. package/build/internal/SingleFieldHolder.d.ts +34 -0
  101. package/build/internal/SingleFieldHolder.js +90 -0
  102. package/build/internal/SingleFieldHolder.js.map +1 -0
  103. package/build/metrics/EntityMetricsUtils.d.ts +2 -1
  104. package/build/metrics/EntityMetricsUtils.js.map +1 -1
  105. package/build/metrics/IEntityMetricsAdapter.d.ts +5 -0
  106. package/build/metrics/IEntityMetricsAdapter.js.map +1 -1
  107. package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +2 -2
  108. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  109. package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +2 -2
  110. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  111. package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +2 -2
  112. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  113. package/build/rules/PrivacyPolicyRule.d.ts +2 -2
  114. package/build/tsconfig.build.tsbuildinfo +1 -0
  115. package/build/utils/EntityPrivacyUtils.d.ts +4 -4
  116. package/build/utils/EntityPrivacyUtils.js.map +1 -1
  117. package/build/utils/collections/SerializableKeyMap.d.ts +27 -0
  118. package/build/utils/collections/SerializableKeyMap.js +60 -0
  119. package/build/utils/collections/SerializableKeyMap.js.map +1 -0
  120. package/build/utils/collections/maps.js +1 -2
  121. package/build/utils/collections/maps.js.map +1 -1
  122. package/build/utils/collections/sets.d.ts +1 -0
  123. package/build/utils/collections/sets.js +7 -0
  124. package/build/utils/collections/sets.js.map +1 -0
  125. package/build/utils/mergeEntityMutationTriggerConfigurations.d.ts +1 -1
  126. package/package.json +8 -5
  127. package/src/AuthorizationResultBasedEntityAssociationLoader.ts +56 -49
  128. package/src/AuthorizationResultBasedEntityLoader.ts +194 -81
  129. package/src/AuthorizationResultBasedEntityMutator.ts +71 -45
  130. package/src/ComposedEntityCacheAdapter.ts +55 -46
  131. package/src/ComposedSecondaryEntityCache.ts +5 -2
  132. package/src/EnforcingEntityAssociationLoader.ts +52 -44
  133. package/src/EnforcingEntityCreator.ts +5 -5
  134. package/src/EnforcingEntityDeleter.ts +5 -5
  135. package/src/EnforcingEntityLoader.ts +158 -21
  136. package/src/EnforcingEntityUpdater.ts +5 -5
  137. package/src/Entity.ts +39 -39
  138. package/src/EntityAssociationLoader.ts +6 -6
  139. package/src/EntityCompanion.ts +11 -11
  140. package/src/EntityCompanionProvider.ts +21 -18
  141. package/src/EntityConfiguration.ts +123 -9
  142. package/src/EntityCreator.ts +7 -7
  143. package/src/EntityDatabaseAdapter.ts +51 -28
  144. package/src/EntityDeleter.ts +7 -7
  145. package/src/EntityFieldDefinition.ts +32 -12
  146. package/src/EntityFields.ts +49 -12
  147. package/src/EntityLoader.ts +8 -8
  148. package/src/EntityLoaderFactory.ts +8 -8
  149. package/src/EntityLoaderUtils.ts +39 -10
  150. package/src/EntityMutationInfo.ts +6 -6
  151. package/src/EntityMutationTriggerConfiguration.ts +68 -20
  152. package/src/EntityMutationValidator.ts +4 -4
  153. package/src/EntityMutatorFactory.ts +13 -13
  154. package/src/EntityPrivacyPolicy.ts +50 -26
  155. package/src/EntitySecondaryCacheLoader.ts +6 -6
  156. package/src/EntityUpdater.ts +7 -7
  157. package/src/GenericEntityCacheAdapter.ts +39 -28
  158. package/src/GenericSecondaryEntityCache.ts +6 -3
  159. package/src/IEntityCacheAdapter.ts +45 -25
  160. package/src/IEntityCacheAdapterProvider.ts +3 -3
  161. package/src/IEntityDatabaseAdapterProvider.ts +3 -3
  162. package/src/IEntityGenericCacher.ts +33 -5
  163. package/src/ReadonlyEntity.ts +24 -24
  164. package/src/ViewerContext.ts +5 -5
  165. package/src/ViewerScopedEntityCompanion.ts +7 -7
  166. package/src/ViewerScopedEntityCompanionProvider.ts +6 -6
  167. package/src/ViewerScopedEntityLoaderFactory.ts +7 -7
  168. package/src/ViewerScopedEntityMutatorFactory.ts +8 -8
  169. package/src/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.ts +4 -4
  170. package/src/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.ts +14 -13
  171. package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +367 -69
  172. package/src/__tests__/ComposedCacheAdapter-test.ts +235 -117
  173. package/src/__tests__/EnforcingEntityLoader-test.ts +135 -1
  174. package/src/__tests__/Entity-test.ts +2 -2
  175. package/src/__tests__/EntityAssociationLoader-test.ts +2 -2
  176. package/src/__tests__/EntityCommonUseCases-test.ts +11 -11
  177. package/src/__tests__/EntityCompanion-test.ts +4 -4
  178. package/src/__tests__/EntityCompanionProvider-test.ts +9 -8
  179. package/src/__tests__/EntityConfiguration-test.ts +85 -6
  180. package/src/__tests__/EntityDatabaseAdapter-test.ts +113 -17
  181. package/src/__tests__/EntityEdges-test.ts +97 -72
  182. package/src/__tests__/EntityFields-test.ts +2 -2
  183. package/src/__tests__/EntityLoader-test.ts +2 -2
  184. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +11 -11
  185. package/src/__tests__/EntityMutator-SingleCompositeFieldCacheConsistency-test.ts +73 -0
  186. package/src/__tests__/EntityMutator-test.ts +74 -46
  187. package/src/__tests__/EntityPrivacyPolicy-test.ts +51 -74
  188. package/src/__tests__/EntityQueryContext-test.ts +1 -1
  189. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +3 -3
  190. package/src/__tests__/EntitySelfReferentialEdges-test.ts +64 -39
  191. package/src/__tests__/GenericEntityCacheAdapter-test.ts +83 -28
  192. package/src/__tests__/ReadonlyEntity-test.ts +3 -3
  193. package/src/__tests__/ViewerContext-test.ts +1 -1
  194. package/src/__tests__/ViewerScopedEntityCompanion-test.ts +5 -2
  195. package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +1 -1
  196. package/src/__tests__/ViewerScopedEntityMutatorFactory-test.ts +12 -3
  197. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +12 -12
  198. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +12 -12
  199. package/src/entityUtils.ts +4 -1
  200. package/src/errors/EntityInvalidFieldValueError.ts +5 -5
  201. package/src/errors/EntityNotAuthorizedError.ts +3 -3
  202. package/src/errors/EntityNotFoundError.ts +5 -5
  203. package/src/index.ts +7 -7
  204. package/src/internal/CompositeFieldHolder.ts +218 -0
  205. package/src/internal/CompositeFieldValueMap.ts +78 -0
  206. package/src/internal/EntityDataManager.ts +107 -96
  207. package/src/internal/EntityFieldTransformationUtils.ts +33 -14
  208. package/src/internal/EntityLoadInterfaces.ts +143 -0
  209. package/src/internal/EntityTableDataCoordinator.ts +8 -5
  210. package/src/internal/ReadThroughEntityCache.ts +63 -50
  211. package/src/internal/SingleFieldHolder.ts +131 -0
  212. package/src/internal/__tests__/CompositeFieldHolder-test.ts +25 -0
  213. package/src/internal/__tests__/CompositeFieldValueMap-test.ts +43 -0
  214. package/src/internal/__tests__/EntityDataManager-test.ts +308 -91
  215. package/src/internal/__tests__/EntityFieldTransformationUtils-test.ts +3 -2
  216. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +315 -107
  217. package/src/metrics/EntityMetricsUtils.ts +7 -2
  218. package/src/metrics/IEntityMetricsAdapter.ts +6 -0
  219. package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +5 -5
  220. package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +5 -5
  221. package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +5 -5
  222. package/src/rules/PrivacyPolicyRule.ts +4 -4
  223. package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +1 -1
  224. package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +1 -1
  225. package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +1 -1
  226. package/src/utils/EntityPrivacyUtils.ts +72 -30
  227. package/src/utils/{testing → __testfixtures__}/PrivacyPolicyRuleTestUtils.ts +26 -26
  228. package/src/{testfixtures → utils/__testfixtures__}/SimpleTestEntity.ts +16 -15
  229. package/src/utils/__testfixtures__/StubCacheAdapter.ts +164 -0
  230. package/src/utils/{testing → __testfixtures__}/StubDatabaseAdapter.ts +19 -12
  231. package/src/utils/{testing → __testfixtures__}/StubDatabaseAdapterProvider.ts +4 -4
  232. package/src/utils/__testfixtures__/TSMockitoExtensions.ts +69 -0
  233. package/src/{testfixtures → utils/__testfixtures__}/TestEntity.ts +21 -15
  234. package/src/{testfixtures → utils/__testfixtures__}/TestEntity2.ts +16 -15
  235. package/src/{testfixtures → utils/__testfixtures__}/TestEntityWithMutationTriggers.ts +23 -22
  236. package/src/{testfixtures → utils/__testfixtures__}/TestViewerContext.ts +1 -1
  237. package/src/utils/{testing → __testfixtures__}/describeFieldTestCase.ts +1 -1
  238. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +62 -66
  239. package/src/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.ts +29 -25
  240. package/src/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.ts +1 -1
  241. package/src/utils/collections/SerializableKeyMap.ts +84 -0
  242. package/src/utils/collections/__tests__/SerializableKeyMap-test.ts +119 -0
  243. package/src/utils/collections/__tests__/sets-test.ts +17 -0
  244. package/src/utils/collections/maps.ts +7 -8
  245. package/src/utils/collections/sets.ts +3 -0
  246. package/src/utils/mergeEntityMutationTriggerConfigurations.ts +5 -5
  247. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.d.ts +0 -1
  248. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js +0 -242
  249. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js.map +0 -1
  250. package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.d.ts +0 -26
  251. package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js +0 -110
  252. package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js.map +0 -1
  253. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.d.ts +0 -1
  254. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js +0 -401
  255. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js.map +0 -1
  256. package/build/__tests__/ComposedCacheAdapter-test.d.ts +0 -1
  257. package/build/__tests__/ComposedCacheAdapter-test.js +0 -229
  258. package/build/__tests__/ComposedCacheAdapter-test.js.map +0 -1
  259. package/build/__tests__/ComposedSecondaryEntityCache-test.d.ts +0 -1
  260. package/build/__tests__/ComposedSecondaryEntityCache-test.js +0 -66
  261. package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +0 -1
  262. package/build/__tests__/EnforcingEntityAssociationLoader-test.d.ts +0 -1
  263. package/build/__tests__/EnforcingEntityAssociationLoader-test.js +0 -115
  264. package/build/__tests__/EnforcingEntityAssociationLoader-test.js.map +0 -1
  265. package/build/__tests__/EnforcingEntityLoader-test.d.ts +0 -1
  266. package/build/__tests__/EnforcingEntityLoader-test.js +0 -253
  267. package/build/__tests__/EnforcingEntityLoader-test.js.map +0 -1
  268. package/build/__tests__/Entity-test.d.ts +0 -1
  269. package/build/__tests__/Entity-test.js +0 -94
  270. package/build/__tests__/Entity-test.js.map +0 -1
  271. package/build/__tests__/EntityAssociationLoader-test.d.ts +0 -1
  272. package/build/__tests__/EntityAssociationLoader-test.js +0 -30
  273. package/build/__tests__/EntityAssociationLoader-test.js.map +0 -1
  274. package/build/__tests__/EntityCommonUseCases-test.d.ts +0 -1
  275. package/build/__tests__/EntityCommonUseCases-test.js +0 -146
  276. package/build/__tests__/EntityCommonUseCases-test.js.map +0 -1
  277. package/build/__tests__/EntityCompanion-test.d.ts +0 -1
  278. package/build/__tests__/EntityCompanion-test.js +0 -77
  279. package/build/__tests__/EntityCompanion-test.js.map +0 -1
  280. package/build/__tests__/EntityCompanionProvider-test.d.ts +0 -1
  281. package/build/__tests__/EntityCompanionProvider-test.js +0 -54
  282. package/build/__tests__/EntityCompanionProvider-test.js.map +0 -1
  283. package/build/__tests__/EntityConfiguration-test.d.ts +0 -1
  284. package/build/__tests__/EntityConfiguration-test.js +0 -103
  285. package/build/__tests__/EntityConfiguration-test.js.map +0 -1
  286. package/build/__tests__/EntityDatabaseAdapter-test.d.ts +0 -1
  287. package/build/__tests__/EntityDatabaseAdapter-test.js +0 -146
  288. package/build/__tests__/EntityDatabaseAdapter-test.js.map +0 -1
  289. package/build/__tests__/EntityEdges-test.d.ts +0 -1
  290. package/build/__tests__/EntityEdges-test.js +0 -723
  291. package/build/__tests__/EntityEdges-test.js.map +0 -1
  292. package/build/__tests__/EntityFields-test.d.ts +0 -1
  293. package/build/__tests__/EntityFields-test.js +0 -63
  294. package/build/__tests__/EntityFields-test.js.map +0 -1
  295. package/build/__tests__/EntityLoader-test.d.ts +0 -1
  296. package/build/__tests__/EntityLoader-test.js +0 -36
  297. package/build/__tests__/EntityLoader-test.js.map +0 -1
  298. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.d.ts +0 -1
  299. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +0 -73
  300. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +0 -1
  301. package/build/__tests__/EntityMutator-test.d.ts +0 -1
  302. package/build/__tests__/EntityMutator-test.js +0 -741
  303. package/build/__tests__/EntityMutator-test.js.map +0 -1
  304. package/build/__tests__/EntityPrivacyPolicy-test.d.ts +0 -1
  305. package/build/__tests__/EntityPrivacyPolicy-test.js +0 -463
  306. package/build/__tests__/EntityPrivacyPolicy-test.js.map +0 -1
  307. package/build/__tests__/EntityQueryContext-test.d.ts +0 -1
  308. package/build/__tests__/EntityQueryContext-test.js +0 -116
  309. package/build/__tests__/EntityQueryContext-test.js.map +0 -1
  310. package/build/__tests__/EntitySecondaryCacheLoader-test.d.ts +0 -1
  311. package/build/__tests__/EntitySecondaryCacheLoader-test.js +0 -60
  312. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +0 -1
  313. package/build/__tests__/EntitySelfReferentialEdges-test.d.ts +0 -1
  314. package/build/__tests__/EntitySelfReferentialEdges-test.js +0 -201
  315. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +0 -1
  316. package/build/__tests__/GenericEntityCacheAdapter-test.d.ts +0 -1
  317. package/build/__tests__/GenericEntityCacheAdapter-test.js +0 -80
  318. package/build/__tests__/GenericEntityCacheAdapter-test.js.map +0 -1
  319. package/build/__tests__/ReadonlyEntity-test.d.ts +0 -1
  320. package/build/__tests__/ReadonlyEntity-test.js +0 -211
  321. package/build/__tests__/ReadonlyEntity-test.js.map +0 -1
  322. package/build/__tests__/ViewerContext-test.d.ts +0 -1
  323. package/build/__tests__/ViewerContext-test.js +0 -30
  324. package/build/__tests__/ViewerContext-test.js.map +0 -1
  325. package/build/__tests__/ViewerScopedEntityCompanion-test.d.ts +0 -1
  326. package/build/__tests__/ViewerScopedEntityCompanion-test.js +0 -20
  327. package/build/__tests__/ViewerScopedEntityCompanion-test.js.map +0 -1
  328. package/build/__tests__/ViewerScopedEntityCompanionProvider-test.d.ts +0 -1
  329. package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js +0 -20
  330. package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js.map +0 -1
  331. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.d.ts +0 -1
  332. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js +0 -23
  333. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +0 -1
  334. package/build/__tests__/ViewerScopedEntityMutatorFactory-test.d.ts +0 -1
  335. package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js +0 -22
  336. package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js.map +0 -1
  337. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.d.ts +0 -1
  338. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +0 -123
  339. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +0 -1
  340. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.d.ts +0 -1
  341. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +0 -121
  342. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +0 -1
  343. package/build/__tests__/entityUtils-test.d.ts +0 -1
  344. package/build/__tests__/entityUtils-test.js +0 -87
  345. package/build/__tests__/entityUtils-test.js.map +0 -1
  346. package/build/internal/__tests__/EntityDataManager-test.d.ts +0 -1
  347. package/build/internal/__tests__/EntityDataManager-test.js +0 -373
  348. package/build/internal/__tests__/EntityDataManager-test.js.map +0 -1
  349. package/build/internal/__tests__/EntityFieldTransformationUtils-test.d.ts +0 -1
  350. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +0 -136
  351. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +0 -1
  352. package/build/internal/__tests__/ReadThroughEntityCache-test.d.ts +0 -1
  353. package/build/internal/__tests__/ReadThroughEntityCache-test.js +0 -206
  354. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +0 -1
  355. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.d.ts +0 -1
  356. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js +0 -21
  357. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +0 -1
  358. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.d.ts +0 -1
  359. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js +0 -21
  360. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +0 -1
  361. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.d.ts +0 -1
  362. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js +0 -21
  363. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +0 -1
  364. package/build/testfixtures/DateIDTestEntity.d.ts +0 -19
  365. package/build/testfixtures/DateIDTestEntity.js +0 -48
  366. package/build/testfixtures/DateIDTestEntity.js.map +0 -1
  367. package/build/testfixtures/SimpleTestEntity.d.ts +0 -20
  368. package/build/testfixtures/SimpleTestEntity.js +0 -48
  369. package/build/testfixtures/SimpleTestEntity.js.map +0 -1
  370. package/build/testfixtures/TestEntity.d.ts +0 -30
  371. package/build/testfixtures/TestEntity.js +0 -93
  372. package/build/testfixtures/TestEntity.js.map +0 -1
  373. package/build/testfixtures/TestEntity2.d.ts +0 -20
  374. package/build/testfixtures/TestEntity2.js +0 -51
  375. package/build/testfixtures/TestEntity2.js.map +0 -1
  376. package/build/testfixtures/TestEntityNumberKey.d.ts +0 -19
  377. package/build/testfixtures/TestEntityNumberKey.js +0 -48
  378. package/build/testfixtures/TestEntityNumberKey.js.map +0 -1
  379. package/build/testfixtures/TestEntityWithMutationTriggers.d.ts +0 -36
  380. package/build/testfixtures/TestEntityWithMutationTriggers.js +0 -82
  381. package/build/testfixtures/TestEntityWithMutationTriggers.js.map +0 -1
  382. package/build/testfixtures/TestViewerContext.d.ts +0 -3
  383. package/build/testfixtures/TestViewerContext.js +0 -10
  384. package/build/testfixtures/TestViewerContext.js.map +0 -1
  385. package/build/utils/__tests__/EntityPrivacyUtils-test.d.ts +0 -1
  386. package/build/utils/__tests__/EntityPrivacyUtils-test.js +0 -486
  387. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +0 -1
  388. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.d.ts +0 -1
  389. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js +0 -178
  390. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js.map +0 -1
  391. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.d.ts +0 -1
  392. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js +0 -26
  393. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js.map +0 -1
  394. package/build/utils/collections/__tests__/maps-test.d.ts +0 -1
  395. package/build/utils/collections/__tests__/maps-test.js +0 -120
  396. package/build/utils/collections/__tests__/maps-test.js.map +0 -1
  397. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +0 -28
  398. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +0 -52
  399. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +0 -1
  400. package/build/utils/testing/StubCacheAdapter.d.ts +0 -27
  401. package/build/utils/testing/StubCacheAdapter.js +0 -86
  402. package/build/utils/testing/StubCacheAdapter.js.map +0 -1
  403. package/build/utils/testing/StubDatabaseAdapter.d.ts +0 -25
  404. package/build/utils/testing/StubDatabaseAdapter.js +0 -191
  405. package/build/utils/testing/StubDatabaseAdapter.js.map +0 -1
  406. package/build/utils/testing/StubDatabaseAdapterProvider.d.ts +0 -7
  407. package/build/utils/testing/StubDatabaseAdapterProvider.js +0 -14
  408. package/build/utils/testing/StubDatabaseAdapterProvider.js.map +0 -1
  409. package/build/utils/testing/StubQueryContextProvider.d.ts +0 -7
  410. package/build/utils/testing/StubQueryContextProvider.js +0 -19
  411. package/build/utils/testing/StubQueryContextProvider.js.map +0 -1
  412. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.d.ts +0 -1
  413. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js +0 -42
  414. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js.map +0 -1
  415. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.d.ts +0 -1
  416. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +0 -402
  417. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +0 -1
  418. package/build/utils/testing/createUnitTestEntityCompanionProvider.d.ts +0 -7
  419. package/build/utils/testing/createUnitTestEntityCompanionProvider.js +0 -36
  420. package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +0 -1
  421. package/build/utils/testing/describeFieldTestCase.d.ts +0 -2
  422. package/build/utils/testing/describeFieldTestCase.js +0 -18
  423. package/build/utils/testing/describeFieldTestCase.js.map +0 -1
  424. package/src/testfixtures/DateIDTestEntity.ts +0 -59
  425. package/src/testfixtures/TestEntityNumberKey.ts +0 -59
  426. package/src/utils/testing/StubCacheAdapter.ts +0 -122
  427. package/src/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.ts +0 -42
  428. package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +0 -548
  429. /package/src/utils/{testing → __testfixtures__}/StubQueryContextProvider.ts +0 -0
  430. /package/src/utils/{testing → __testfixtures__}/createUnitTestEntityCompanionProvider.ts +0 -0
@@ -20,8 +20,11 @@ export interface FieldTransformer<T> {
20
20
  */
21
21
  export type FieldTransformerMap = Map<string, FieldTransformer<any>>;
22
22
 
23
- export const getDatabaseFieldForEntityField = <TFields extends Record<string, any>>(
24
- entityConfiguration: EntityConfiguration<TFields>,
23
+ export const getDatabaseFieldForEntityField = <
24
+ TFields extends Record<string, any>,
25
+ TIDField extends keyof TFields,
26
+ >(
27
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
25
28
  entityField: keyof TFields,
26
29
  ): string => {
27
30
  const databaseField = entityConfiguration.entityToDBFieldsKeyMapping.get(entityField);
@@ -29,8 +32,11 @@ export const getDatabaseFieldForEntityField = <TFields extends Record<string, an
29
32
  return databaseField;
30
33
  };
31
34
 
32
- export const transformDatabaseObjectToFields = <TFields extends Record<string, any>>(
33
- entityConfiguration: EntityConfiguration<TFields>,
35
+ export const transformDatabaseObjectToFields = <
36
+ TFields extends Record<string, any>,
37
+ TIDField extends keyof TFields,
38
+ >(
39
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
34
40
  fieldTransformerMap: FieldTransformerMap,
35
41
  databaseObject: { [key: string]: any },
36
42
  ): Readonly<TFields> => {
@@ -50,8 +56,11 @@ export const transformDatabaseObjectToFields = <TFields extends Record<string, a
50
56
  return fields;
51
57
  };
52
58
 
53
- export const transformFieldsToDatabaseObject = <TFields extends Record<string, any>>(
54
- entityConfiguration: EntityConfiguration<TFields>,
59
+ export const transformFieldsToDatabaseObject = <
60
+ TFields extends Record<string, any>,
61
+ TIDField extends keyof TFields,
62
+ >(
63
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
55
64
  fieldTransformerMap: FieldTransformerMap,
56
65
  fields: Readonly<Partial<TFields>>,
57
66
  ): object => {
@@ -70,8 +79,11 @@ export const transformFieldsToDatabaseObject = <TFields extends Record<string, a
70
79
  return databaseObject;
71
80
  };
72
81
 
73
- export const transformCacheObjectToFields = <TFields extends Record<string, any>>(
74
- entityConfiguration: EntityConfiguration<TFields>,
82
+ export const transformCacheObjectToFields = <
83
+ TFields extends Record<string, any>,
84
+ TIDField extends keyof TFields,
85
+ >(
86
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
75
87
  fieldTransformerMap: FieldTransformerMap,
76
88
  cacheObject: { [key: string]: any },
77
89
  ): Readonly<TFields> => {
@@ -88,8 +100,11 @@ export const transformCacheObjectToFields = <TFields extends Record<string, any>
88
100
  return fields;
89
101
  };
90
102
 
91
- export const transformFieldsToCacheObject = <TFields extends Record<string, any>>(
92
- entityConfiguration: EntityConfiguration<TFields>,
103
+ export const transformFieldsToCacheObject = <
104
+ TFields extends Record<string, any>,
105
+ TIDField extends keyof TFields,
106
+ >(
107
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
93
108
  fieldTransformerMap: FieldTransformerMap,
94
109
  fields: Readonly<Partial<TFields>>,
95
110
  ): object => {
@@ -109,8 +124,9 @@ export const transformFieldsToCacheObject = <TFields extends Record<string, any>
109
124
  const maybeTransformDatabaseValueToFieldValue = <
110
125
  TFields extends Record<string, any>,
111
126
  N extends keyof TFields,
127
+ TIDField extends keyof TFields,
112
128
  >(
113
- entityConfiguration: EntityConfiguration<TFields>,
129
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
114
130
  fieldTransformerMap: FieldTransformerMap,
115
131
  fieldName: N,
116
132
  value: any,
@@ -126,8 +142,9 @@ const maybeTransformDatabaseValueToFieldValue = <
126
142
  const maybeTransformFieldValueToDatabaseValue = <
127
143
  TFields extends Record<string, any>,
128
144
  N extends keyof TFields,
145
+ TIDField extends keyof TFields,
129
146
  >(
130
- entityConfiguration: EntityConfiguration<TFields>,
147
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
131
148
  fieldTransformerMap: FieldTransformerMap,
132
149
  fieldName: N,
133
150
  value: TFields[N],
@@ -141,8 +158,9 @@ const maybeTransformFieldValueToDatabaseValue = <
141
158
  const maybeTransformCacheValueToFieldValue = <
142
159
  TFields extends Record<string, any>,
143
160
  N extends keyof TFields,
161
+ TIDField extends keyof TFields,
144
162
  >(
145
- entityConfiguration: EntityConfiguration<TFields>,
163
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
146
164
  fieldTransformerMap: FieldTransformerMap,
147
165
  fieldName: N,
148
166
  value: any,
@@ -160,8 +178,9 @@ const maybeTransformCacheValueToFieldValue = <
160
178
  const maybeTransformFieldValueToCacheValue = <
161
179
  TFields extends Record<string, any>,
162
180
  N extends keyof TFields,
181
+ TIDField extends keyof TFields,
163
182
  >(
164
- entityConfiguration: EntityConfiguration<TFields>,
183
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
165
184
  fieldTransformerMap: FieldTransformerMap,
166
185
  fieldName: N,
167
186
  value: TFields[N],
@@ -0,0 +1,143 @@
1
+ import EntityConfiguration from '../EntityConfiguration';
2
+ import { ISerializable, SerializableKeyMap } from '../utils/collections/SerializableKeyMap';
3
+
4
+ /**
5
+ * Load method type identifier of a load key. Used for keying data loaders and identification in metrics.
6
+ */
7
+ export enum EntityLoadMethodType {
8
+ /**
9
+ * Load method type for loading entities by single fieldName and fieldValue(s).
10
+ */
11
+ SINGLE = 'single',
12
+
13
+ /**
14
+ * Load method type for loading entities by composite field.
15
+ */
16
+ COMPOSITE = 'composite',
17
+ }
18
+
19
+ /**
20
+ * Interface responsible for defining how the key and corresponding load values behave in the data manager, cache adapter,
21
+ * and database adapter during entity field loading.
22
+ */
23
+ export interface IEntityLoadKey<
24
+ TFields extends Record<string, any>,
25
+ TIDField extends keyof TFields,
26
+ TSerializedLoadValue,
27
+ TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
28
+ > {
29
+ toString(): string;
30
+
31
+ /**
32
+ * Vends a new empty load value map with a key type corresponding to the load value type of this load key.
33
+ *
34
+ * @returns A new empty load value map.
35
+ */
36
+ vendNewLoadValueMap<V>(): LoadValueMap<TSerializedLoadValue, TLoadValue, V>;
37
+
38
+ /**
39
+ * Determines if this key is cacheable in cache adapters according to the entity configuration.
40
+ *
41
+ * @param entityConfiguration - The entity configuration to check.
42
+ * @returns Boolean indicating whether this key is cacheable.
43
+ */
44
+ isCacheable(entityConfiguration: EntityConfiguration<TFields, TIDField>): boolean;
45
+
46
+ /**
47
+ * Creates cache key parts for this key and a load value given an entity configuration.
48
+ * These parts will be included as part of the cache key.
49
+ *
50
+ * @param entityConfiguration - The entity configuration used to derive cache key parts.
51
+ * @param value - The load value for which to create cache key parts for.
52
+ * @returns An object containing the cache key type and parts.
53
+ */
54
+ createCacheKeyPartsForLoadValue(
55
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
56
+ value: TLoadValue,
57
+ ): readonly string[];
58
+
59
+ /**
60
+ * Gets the load method type of this key. Used as part of cache keys and data loader keys.
61
+ */
62
+ getLoadMethodType(): EntityLoadMethodType;
63
+
64
+ /**
65
+ * Gets the data loader key for this key. For single field keys, this is the field name. For composite keys, this is a
66
+ * unique identifier for the composite key.
67
+ */
68
+ getDataManagerDataLoaderKey(): string;
69
+
70
+ /**
71
+ * Serialize a load value for use in the data manager data loader as the dataloader value key.
72
+ */
73
+ serializeLoadValue(value: TLoadValue): TSerializedLoadValue;
74
+
75
+ /**
76
+ * Deserialize a load value for use in the data manager data loader as the dataloader value key.
77
+ */
78
+ deserializeLoadValue(value: TSerializedLoadValue): TLoadValue;
79
+
80
+ /**
81
+ * Validate that that the load values adhere to the typescript types at runtime in order to
82
+ * prevent inadvertently passing invalid values to the data loader, cache adapter, or database adapter.
83
+ * @param values - The load values to validate.
84
+ * @param entityClassName - The name of the entity class to which the load values belong (for error message only).
85
+ */
86
+ validateRuntimeLoadValuesForDataManagerDataLoader(
87
+ values: readonly TLoadValue[],
88
+ entityClassName: string,
89
+ ): void;
90
+
91
+ /**
92
+ * Get the database columns for this key given an entity configuration.
93
+ *
94
+ * @param entityConfiguration - The entity configuration.
95
+ * @returns An array of database column names.
96
+ */
97
+ getDatabaseColumns(
98
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
99
+ ): readonly string[];
100
+
101
+ /**
102
+ * Get the database values corresponding to the database columns for this key for a load value.
103
+ *
104
+ * @param value - The load value.
105
+ * @returns An array of database values.
106
+ */
107
+ getDatabaseValues(value: TLoadValue): readonly any[];
108
+
109
+ /**
110
+ * Get the load value for an entity fields object from the database.
111
+ *
112
+ * @param object - The entity fields object.
113
+ * @returns The load value for the object or null if the load value would be invalid for the object (for example, if the value is null).
114
+ */
115
+ getLoadValueForObject(object: Readonly<TFields>): TLoadValue | null;
116
+ }
117
+
118
+ /**
119
+ * Interface for a load value corresponding to a load key.
120
+ */
121
+ export interface IEntityLoadValue<TSerialized> extends ISerializable<TSerialized> {
122
+ toString(): string;
123
+ }
124
+
125
+ /**
126
+ * Map from load value interface to value.
127
+ */
128
+ export abstract class LoadValueMap<
129
+ TSerialized,
130
+ TLoadValue extends IEntityLoadValue<TSerialized>,
131
+ V,
132
+ > extends SerializableKeyMap<TSerialized, TLoadValue, V> {}
133
+
134
+ /**
135
+ * Load pair type for a load key and load value.
136
+ */
137
+ export type LoadPair<
138
+ TFields extends Record<string, any>,
139
+ TIDField extends keyof TFields,
140
+ TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
141
+ TSerializedLoadValue,
142
+ TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
143
+ > = readonly [TLoadKey, TLoadValue];
@@ -13,13 +13,16 @@ import IEntityMetricsAdapter from '../metrics/IEntityMetricsAdapter';
13
13
  * table. Note that one instance is shared amongst all entities that read from
14
14
  * the table to ensure cross-entity data consistency.
15
15
  */
16
- export default class EntityTableDataCoordinator<TFields extends Record<string, any>> {
17
- readonly databaseAdapter: EntityDatabaseAdapter<TFields>;
18
- readonly cacheAdapter: IEntityCacheAdapter<TFields>;
19
- readonly dataManager: EntityDataManager<TFields>;
16
+ export default class EntityTableDataCoordinator<
17
+ TFields extends Record<string, any>,
18
+ TIDField extends keyof TFields,
19
+ > {
20
+ readonly databaseAdapter: EntityDatabaseAdapter<TFields, TIDField>;
21
+ readonly cacheAdapter: IEntityCacheAdapter<TFields, TIDField>;
22
+ readonly dataManager: EntityDataManager<TFields, TIDField>;
20
23
 
21
24
  constructor(
22
- readonly entityConfiguration: EntityConfiguration<TFields>,
25
+ readonly entityConfiguration: EntityConfiguration<TFields, TIDField>,
23
26
  databaseAdapterProvider: IEntityDatabaseAdapterProvider,
24
27
  cacheAdapterProvider: IEntityCacheAdapterProvider,
25
28
  private readonly queryContextProvider: EntityQueryContextProvider,
@@ -2,6 +2,7 @@ import invariant from 'invariant';
2
2
 
3
3
  import EntityConfiguration from '../EntityConfiguration';
4
4
  import IEntityCacheAdapter from '../IEntityCacheAdapter';
5
+ import { IEntityLoadKey, IEntityLoadValue } from './EntityLoadInterfaces';
5
6
  import { filterMap } from '../utils/collections/maps';
6
7
 
7
8
  export enum CacheStatus {
@@ -10,7 +11,7 @@ export enum CacheStatus {
10
11
  NEGATIVE,
11
12
  }
12
13
 
13
- export type CacheLoadResult<TFields> =
14
+ export type CacheLoadResult<TFields extends Record<string, any>> =
14
15
  | {
15
16
  status: CacheStatus.HIT;
16
17
  item: Readonly<TFields>;
@@ -26,52 +27,63 @@ export type CacheLoadResult<TFields> =
26
27
  * A read-through entity cache is responsible for coordinating EntityDatabaseAdapter and
27
28
  * EntityCacheAdapter within the EntityDataManager.
28
29
  */
29
- export default class ReadThroughEntityCache<TFields extends Record<string, any>> {
30
+ export default class ReadThroughEntityCache<
31
+ TFields extends Record<string, any>,
32
+ TIDField extends keyof TFields,
33
+ > {
30
34
  constructor(
31
- private readonly entityConfiguration: EntityConfiguration<TFields>,
32
- private readonly entityCacheAdapter: IEntityCacheAdapter<TFields>,
35
+ private readonly entityConfiguration: EntityConfiguration<TFields, TIDField>,
36
+ private readonly entityCacheAdapter: IEntityCacheAdapter<TFields, TIDField>,
33
37
  ) {}
34
38
 
35
- private isFieldCacheable<N extends keyof TFields>(fieldName: N): boolean {
36
- return this.entityConfiguration.cacheableKeys.has(fieldName);
39
+ private isLoadKeyCacheable<
40
+ TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
41
+ TSerializedLoadValue,
42
+ TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
43
+ >(key: TLoadKey): boolean {
44
+ return key.isCacheable(this.entityConfiguration);
37
45
  }
38
46
 
39
47
  /**
40
48
  * Read-through cache function. Steps:
41
49
  *
42
- * 1. Check for cached (fieldName, fieldValue) objects
43
- * 2. Query the fetcher for fieldValues not in the cache
50
+ * 1. Check for cached (key, value) objects
51
+ * 2. Query the fetcher for values not in the cache
44
52
  * 3. Cache the results from the fetcher
45
53
  * 4. Negatively cache anything missing from the fetcher
46
54
  * 5. Return the full set of data for the query.
47
55
  *
48
- * If cache is not applicable for fieldName, return results from fetcher.
56
+ * If cache is not applicable for key, return results from fetcher.
49
57
  *
50
- * @param fieldName - object field being queried
51
- * @param fieldValues - fieldName field values being queried
52
- * @param fetcher - closure used to provide underlying data source objects for fieldName and fetcherFieldValues
53
- * @returns map from fieldValue to objects that match the query for that fieldValue
58
+ * @param key - load key being queried
59
+ * @param values - load values being queried
60
+ * @param fetcher - closure used to provide underlying data source objects for key and fetcherValues
61
+ * @returns map from value to objects that match the query for that value
54
62
  */
55
- public async readManyThroughAsync<N extends keyof TFields>(
56
- fieldName: N,
57
- fieldValues: readonly NonNullable<TFields[N]>[],
63
+ public async readManyThroughAsync<
64
+ TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
65
+ TSerializedLoadValue,
66
+ TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
67
+ >(
68
+ key: TLoadKey,
69
+ values: readonly TLoadValue[],
58
70
  fetcher: (
59
- fetcherFieldValues: readonly NonNullable<TFields[N]>[],
60
- ) => Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Readonly<TFields>[]>>,
61
- ): Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Readonly<TFields>[]>> {
62
- // return normal fetch when cache by fieldName not supported
63
- if (!this.isFieldCacheable(fieldName)) {
64
- return await fetcher(fieldValues);
71
+ fetcherValues: readonly TLoadValue[],
72
+ ) => Promise<ReadonlyMap<TLoadValue, readonly Readonly<TFields>[]>>,
73
+ ): Promise<ReadonlyMap<TLoadValue, readonly Readonly<TFields>[]>> {
74
+ // return normal fetch when cache by key not supported
75
+ if (!this.isLoadKeyCacheable(key)) {
76
+ return await fetcher(values);
65
77
  }
66
78
 
67
- const cacheLoadResults = await this.entityCacheAdapter.loadManyAsync(fieldName, fieldValues);
79
+ const cacheLoadResults = await this.entityCacheAdapter.loadManyAsync(key, values);
68
80
 
69
81
  invariant(
70
- cacheLoadResults.size === fieldValues.length,
71
- `${this.constructor.name} loadMany should return a result for each fieldValue`,
82
+ cacheLoadResults.size === values.length,
83
+ `${this.constructor.name} loadMany should return a result for each value`,
72
84
  );
73
85
 
74
- const fieldValuesToFetchFromDB = Array.from(
86
+ const valuesToFetchFromDB = Array.from(
75
87
  filterMap(
76
88
  cacheLoadResults,
77
89
  (cacheLoadResult) => cacheLoadResult.status === CacheStatus.MISS,
@@ -79,45 +91,45 @@ export default class ReadThroughEntityCache<TFields extends Record<string, any>>
79
91
  );
80
92
 
81
93
  // put transformed cache hits in result map
82
- const results: Map<NonNullable<TFields[N]>, readonly Readonly<TFields>[]> = new Map();
83
- cacheLoadResults.forEach((cacheLoadResult, fieldValue) => {
94
+ const results = key.vendNewLoadValueMap<readonly Readonly<TFields>[]>();
95
+ cacheLoadResults.forEach((cacheLoadResult, value) => {
84
96
  if (cacheLoadResult.status === CacheStatus.HIT) {
85
- results.set(fieldValue, [cacheLoadResult.item]);
97
+ results.set(value, [cacheLoadResult.item]);
86
98
  }
87
99
  });
88
100
 
89
101
  // fetch any misses from DB, add DB objects to results, cache DB results, inform cache of any missing DB results
90
- if (fieldValuesToFetchFromDB.length > 0) {
91
- const dbFetchResults = await fetcher(fieldValuesToFetchFromDB);
102
+ if (valuesToFetchFromDB.length > 0) {
103
+ const dbFetchResults = await fetcher(valuesToFetchFromDB);
92
104
 
93
- const fieldValueDBMisses = fieldValuesToFetchFromDB.filter((fv) => {
105
+ const valueDBMisses = valuesToFetchFromDB.filter((fv) => {
94
106
  const objectsFromFulfillerForFv = dbFetchResults.get(fv);
95
107
  return !objectsFromFulfillerForFv || objectsFromFulfillerForFv.length === 0;
96
108
  });
97
109
 
98
- const objectsToCache: Map<NonNullable<TFields[N]>, Readonly<TFields>> = new Map();
99
- for (const [fieldValue, objects] of dbFetchResults.entries()) {
110
+ const objectsToCache = key.vendNewLoadValueMap<Readonly<TFields>>();
111
+ for (const [value, objects] of dbFetchResults.entries()) {
100
112
  if (objects.length > 1) {
101
113
  // multiple objects received for what was supposed to be a unique query, don't add to return map nor cache
102
114
  // TODO(wschurman): emit or throw here since console may not be available
103
115
  // eslint-disable-next-line no-console
104
116
  console.warn(
105
- `unique key ${String(fieldName)} in ${
117
+ `unique key ${key} in table ${
106
118
  this.entityConfiguration.tableName
107
- } returned multiple rows for ${fieldValue}`,
119
+ } returned multiple rows for ${value}`,
108
120
  );
109
121
  continue;
110
122
  }
111
123
  const uniqueObject = objects[0];
112
124
  if (uniqueObject) {
113
- objectsToCache.set(fieldValue, uniqueObject);
114
- results.set(fieldValue, [uniqueObject]);
125
+ objectsToCache.set(value, uniqueObject);
126
+ results.set(value, [uniqueObject]);
115
127
  }
116
128
  }
117
129
 
118
130
  await Promise.all([
119
- this.entityCacheAdapter.cacheManyAsync(fieldName, objectsToCache),
120
- this.entityCacheAdapter.cacheDBMissesAsync(fieldName, fieldValueDBMisses),
131
+ this.entityCacheAdapter.cacheManyAsync(key, objectsToCache),
132
+ this.entityCacheAdapter.cacheDBMissesAsync(key, valueDBMisses),
121
133
  ]);
122
134
  }
123
135
 
@@ -125,20 +137,21 @@ export default class ReadThroughEntityCache<TFields extends Record<string, any>>
125
137
  }
126
138
 
127
139
  /**
128
- * Invalidate the cache for objects cached by (fieldName, fieldValue).
140
+ * Invalidate the cache for objects cached by (key, value).
129
141
  *
130
- * @param fieldName - object field being queried
131
- * @param fieldValues - fieldName field values to be invalidated
142
+ * @param key - load key to be invalidated
143
+ * @param values - load values to be invalidated for key
132
144
  */
133
- public async invalidateManyAsync<N extends keyof TFields>(
134
- fieldName: N,
135
- fieldValues: readonly NonNullable<TFields[N]>[],
136
- ): Promise<void> {
137
- // no-op when cache by fieldName not supported
138
- if (!this.isFieldCacheable(fieldName)) {
145
+ public async invalidateManyAsync<
146
+ TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
147
+ TSerializedLoadValue,
148
+ TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
149
+ >(key: TLoadKey, values: readonly TLoadValue[]): Promise<void> {
150
+ // no-op when cache by key not supported
151
+ if (!this.isLoadKeyCacheable(key)) {
139
152
  return;
140
153
  }
141
154
 
142
- await this.entityCacheAdapter.invalidateManyAsync(fieldName, fieldValues);
155
+ await this.entityCacheAdapter.invalidateManyAsync(key, values);
143
156
  }
144
157
  }
@@ -0,0 +1,131 @@
1
+ import invariant from 'invariant';
2
+
3
+ import EntityConfiguration from '../EntityConfiguration';
4
+ import { getDatabaseFieldForEntityField } from './EntityFieldTransformationUtils';
5
+ import {
6
+ EntityLoadMethodType,
7
+ IEntityLoadKey,
8
+ IEntityLoadValue,
9
+ LoadValueMap,
10
+ } from './EntityLoadInterfaces';
11
+
12
+ /**
13
+ * A load key that represents a single field (fieldName) on an entity.
14
+ */
15
+ export class SingleFieldHolder<
16
+ TFields extends Record<string, any>,
17
+ TIDField extends keyof TFields,
18
+ N extends keyof TFields,
19
+ > implements
20
+ IEntityLoadKey<TFields, TIDField, NonNullable<TFields[N]>, SingleFieldValueHolder<TFields, N>>
21
+ {
22
+ constructor(public readonly fieldName: N) {}
23
+
24
+ toString(): string {
25
+ return `SingleField(${String(this.fieldName)})`;
26
+ }
27
+
28
+ public isCacheable(entityConfiguration: EntityConfiguration<TFields, TIDField>): boolean {
29
+ return entityConfiguration.cacheableKeys.has(this.fieldName);
30
+ }
31
+
32
+ public getDatabaseColumns(entityConfiguration: EntityConfiguration<TFields, TIDField>): string[] {
33
+ return [getDatabaseFieldForEntityField(entityConfiguration, this.fieldName)];
34
+ }
35
+
36
+ getDatabaseValues(value: SingleFieldValueHolder<TFields, N>): readonly any[] {
37
+ return [value.fieldValue];
38
+ }
39
+
40
+ getLoadValueForObject(object: Readonly<TFields>): SingleFieldValueHolder<TFields, N> | null {
41
+ const value = object[this.fieldName];
42
+ if (value === null || value === undefined) {
43
+ return null;
44
+ }
45
+ return new SingleFieldValueHolder(value);
46
+ }
47
+
48
+ createCacheKeyPartsForLoadValue(
49
+ entityConfiguration: EntityConfiguration<TFields, TIDField>,
50
+ value: SingleFieldValueHolder<TFields, N>,
51
+ ): readonly string[] {
52
+ const columnName = entityConfiguration.entityToDBFieldsKeyMapping.get(this.fieldName);
53
+ invariant(columnName, `database field mapping missing for ${String(this.fieldName)}`);
54
+ return [columnName, String(value.fieldValue)];
55
+ }
56
+
57
+ getLoadMethodType(): EntityLoadMethodType {
58
+ return EntityLoadMethodType.SINGLE;
59
+ }
60
+
61
+ getDataManagerDataLoaderKey(): string {
62
+ return this.fieldName as string;
63
+ }
64
+
65
+ serializeLoadValue(value: SingleFieldValueHolder<TFields, N>): NonNullable<TFields[N]> {
66
+ return value.serialize();
67
+ }
68
+
69
+ deserializeLoadValue(value: NonNullable<TFields[N]>): SingleFieldValueHolder<TFields, N> {
70
+ return SingleFieldValueHolder.deserialize(value);
71
+ }
72
+
73
+ validateRuntimeLoadValuesForDataManagerDataLoader(
74
+ values: readonly SingleFieldValueHolder<TFields, N>[],
75
+ entityClassName: string,
76
+ ): void {
77
+ const nullOrUndefinedValueIndex = values.findIndex(
78
+ (value) => value.fieldValue === null || value.fieldValue === undefined,
79
+ );
80
+ if (nullOrUndefinedValueIndex >= 0) {
81
+ throw new Error(
82
+ `Invalid load: ${entityClassName} (${String(this.fieldName)} = ${
83
+ values[nullOrUndefinedValueIndex]?.fieldValue
84
+ })`,
85
+ );
86
+ }
87
+ }
88
+
89
+ vendNewLoadValueMap<V>(): LoadValueMap<
90
+ NonNullable<TFields[N]>,
91
+ SingleFieldValueHolder<TFields, N>,
92
+ V
93
+ > {
94
+ return new SingleFieldValueHolderMap();
95
+ }
96
+ }
97
+
98
+ /**
99
+ * A load value for a SingleFieldHolder.
100
+ */
101
+ export class SingleFieldValueHolder<TFields extends Record<string, any>, N extends keyof TFields>
102
+ implements IEntityLoadValue<NonNullable<TFields[N]>>
103
+ {
104
+ constructor(public readonly fieldValue: NonNullable<TFields[N]>) {}
105
+
106
+ toString(): string {
107
+ return `SingleFieldValue(${String(this.fieldValue)})`;
108
+ }
109
+
110
+ serialize(): NonNullable<TFields[N]> {
111
+ return this.fieldValue;
112
+ }
113
+
114
+ static deserialize<TFields extends Record<string, any>, N extends keyof TFields>(
115
+ fieldValue: NonNullable<TFields[N]>,
116
+ ): SingleFieldValueHolder<TFields, N> {
117
+ return new SingleFieldValueHolder(fieldValue);
118
+ }
119
+ }
120
+
121
+ export class SingleFieldValueHolderMap<
122
+ TFields extends Record<string, any>,
123
+ N extends keyof TFields,
124
+ V,
125
+ > extends LoadValueMap<NonNullable<TFields[N]>, SingleFieldValueHolder<TFields, N>, V> {
126
+ protected override deserializeKey(
127
+ serializedKey: NonNullable<TFields[N]>,
128
+ ): SingleFieldValueHolder<TFields, N> {
129
+ return SingleFieldValueHolder.deserialize(serializedKey);
130
+ }
131
+ }
@@ -0,0 +1,25 @@
1
+ import { CompositeFieldHolder, CompositeFieldValueHolder } from '../CompositeFieldHolder';
2
+
3
+ describe(CompositeFieldHolder, () => {
4
+ it('is order-agnostic for serialization', () => {
5
+ const compositeFieldHolder = new CompositeFieldHolder(['field1', 'field2']);
6
+ const compositeFieldHolder2 = new CompositeFieldHolder(['field2', 'field1']);
7
+
8
+ expect(compositeFieldHolder.serialize()).toEqual(compositeFieldHolder2.serialize());
9
+ });
10
+ });
11
+
12
+ describe(CompositeFieldValueHolder, () => {
13
+ it('is order-agnostic for serialization', () => {
14
+ const compositeFieldValueHolder = new CompositeFieldValueHolder({
15
+ field1: 'value1',
16
+ field2: 'value2',
17
+ });
18
+ const compositeFieldValueHolder2 = new CompositeFieldValueHolder({
19
+ field2: 'value2',
20
+ field1: 'value1',
21
+ });
22
+
23
+ expect(compositeFieldValueHolder.serialize()).toEqual(compositeFieldValueHolder2.serialize());
24
+ });
25
+ });
@@ -0,0 +1,43 @@
1
+ import { EntityCompositeFieldValue } from '../../EntityConfiguration';
2
+ import { CompositeFieldValueHolder } from '../CompositeFieldHolder';
3
+ import { CompositeFieldValueMap } from '../CompositeFieldValueMap';
4
+
5
+ describe(CompositeFieldValueMap, () => {
6
+ it('behaves like a ReadonlyMap', () => {
7
+ const map = new CompositeFieldValueMap([
8
+ [new CompositeFieldValueHolder({ a: 1, b: 'foo' }), 'foo'],
9
+ [new CompositeFieldValueHolder({ a: 2, b: 'bar' }), 'bar'],
10
+ ]);
11
+
12
+ expect(map.size).toBe(2);
13
+ expect(map.get({ a: 1, b: 'foo' })).toBe('foo');
14
+ expect(map.get({ a: 2, b: 'bar' })).toBe('bar');
15
+ expect(map.get({ a: 3, b: 'baz' })).toBeUndefined();
16
+ expect(map.has({ a: 1, b: 'foo' })).toBe(true);
17
+ expect(map.has({ a: 3, b: 'baz' })).toBe(false);
18
+
19
+ const keys = Array.from(map.keys());
20
+ expect(keys).toEqual([
21
+ { a: 1, b: 'foo' },
22
+ { a: 2, b: 'bar' },
23
+ ]);
24
+
25
+ const values = Array.from(map.values());
26
+ expect(values).toEqual(['foo', 'bar']);
27
+
28
+ const entries2 = Array.from(map.entries());
29
+ expect(entries2).toEqual([
30
+ [{ a: 1, b: 'foo' }, 'foo'],
31
+ [{ a: 2, b: 'bar' }, 'bar'],
32
+ ]);
33
+
34
+ const forEachEntries: [EntityCompositeFieldValue<any, any>, string, typeof map][] = [];
35
+ map.forEach((value, key, map) => {
36
+ forEachEntries.push([key, value, map]);
37
+ });
38
+ expect(forEachEntries).toEqual([
39
+ [{ a: 1, b: 'foo' }, 'foo', map],
40
+ [{ a: 2, b: 'bar' }, 'bar', map],
41
+ ]);
42
+ });
43
+ });