@expo/entity 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +1 -0
  132. package/build/index.js +1 -0
  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 +4 -3
  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 +1 -0
  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
@@ -61,7 +61,7 @@ export interface EntityCompanionDefinition<
61
61
  TEntity,
62
62
  TSelectedFields
63
63
  >,
64
- TSelectedFields extends keyof TFields = keyof TFields
64
+ TSelectedFields extends keyof TFields = keyof TFields,
65
65
  > {
66
66
  /**
67
67
  * The concrete Entity class for which this is the definition.
@@ -139,6 +139,7 @@ export default class EntityCompanionProvider {
139
139
  * @param metricsAdapter - An IEntityMetricsAdapter for collecting metrics on this instance
140
140
  * @param databaseAdapterFlavors - Database adapter configurations for this instance
141
141
  * @param cacheAdapterFlavors - Cache adapter configurations for this instance
142
+ * @param globalMutationTriggers - Optional set of EntityMutationTrigger to run for all entity mutations systemwide.
142
143
  */
143
144
  constructor(
144
145
  public readonly metricsAdapter: IEntityMetricsAdapter,
@@ -146,7 +147,14 @@ export default class EntityCompanionProvider {
146
147
  DatabaseAdapterFlavor,
147
148
  DatabaseAdapterFlavorDefinition
148
149
  >,
149
- private cacheAdapterFlavors: ReadonlyMap<CacheAdapterFlavor, CacheAdapterFlavorDefinition>
150
+ private cacheAdapterFlavors: ReadonlyMap<CacheAdapterFlavor, CacheAdapterFlavorDefinition>,
151
+ readonly globalMutationTriggers: EntityMutationTriggerConfiguration<
152
+ any,
153
+ any,
154
+ any,
155
+ any,
156
+ any
157
+ > = {},
150
158
  ) {}
151
159
 
152
160
  /**
@@ -167,7 +175,7 @@ export default class EntityCompanionProvider {
167
175
  TEntity,
168
176
  TSelectedFields
169
177
  >,
170
- TSelectedFields extends keyof TFields
178
+ TSelectedFields extends keyof TFields,
171
179
  >(
172
180
  entityClass: IEntityClass<
173
181
  TFields,
@@ -176,58 +184,58 @@ export default class EntityCompanionProvider {
176
184
  TEntity,
177
185
  TPrivacyPolicy,
178
186
  TSelectedFields
179
- >
187
+ >,
180
188
  ): EntityCompanion<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
181
189
  const entityCompanionDefinition = computeIfAbsent(
182
190
  this.companionDefinitionMap,
183
191
  entityClass.name,
184
- () => entityClass.defineCompanionDefinition()
192
+ () => entityClass.defineCompanionDefinition(),
185
193
  );
186
194
  const tableDataCoordinator = this.getTableDataCoordinatorForEntity(
187
195
  entityCompanionDefinition.entityConfiguration,
188
- entityClass.name
196
+ entityClass.name,
189
197
  );
190
198
  return computeIfAbsent(this.companionMap, entityClass.name, () => {
191
199
  return new EntityCompanion(
192
200
  this,
193
201
  entityCompanionDefinition,
194
202
  tableDataCoordinator,
195
- this.metricsAdapter
203
+ this.metricsAdapter,
196
204
  );
197
205
  });
198
206
  }
199
207
 
200
208
  getQueryContextProviderForDatabaseAdaptorFlavor(
201
- databaseAdapterFlavor: DatabaseAdapterFlavor
209
+ databaseAdapterFlavor: DatabaseAdapterFlavor,
202
210
  ): EntityQueryContextProvider {
203
211
  const entityDatabaseAdapterFlavor = this.databaseAdapterFlavors.get(databaseAdapterFlavor);
204
212
  invariant(
205
213
  entityDatabaseAdapterFlavor,
206
- `No database adaptor configuration found for flavor: ${databaseAdapterFlavor}`
214
+ `No database adaptor configuration found for flavor: ${databaseAdapterFlavor}`,
207
215
  );
208
216
 
209
217
  return entityDatabaseAdapterFlavor.queryContextProvider;
210
218
  }
211
219
 
212
- private getTableDataCoordinatorForEntity<TFields>(
220
+ private getTableDataCoordinatorForEntity<TFields extends Record<string, any>>(
213
221
  entityConfiguration: EntityConfiguration<TFields>,
214
- entityClassName: string
222
+ entityClassName: string,
215
223
  ): EntityTableDataCoordinator<TFields> {
216
224
  return computeIfAbsent(this.tableDataCoordinatorMap, entityConfiguration.tableName, () => {
217
225
  const entityDatabaseAdapterFlavor = this.databaseAdapterFlavors.get(
218
- entityConfiguration.databaseAdapterFlavor
226
+ entityConfiguration.databaseAdapterFlavor,
219
227
  );
220
228
  invariant(
221
229
  entityDatabaseAdapterFlavor,
222
- `No database adaptor configuration found for flavor: ${entityConfiguration.databaseAdapterFlavor}`
230
+ `No database adaptor configuration found for flavor: ${entityConfiguration.databaseAdapterFlavor}`,
223
231
  );
224
232
 
225
233
  const entityCacheAdapterFlavor = this.cacheAdapterFlavors.get(
226
- entityConfiguration.cacheAdapterFlavor
234
+ entityConfiguration.cacheAdapterFlavor,
227
235
  );
228
236
  invariant(
229
237
  entityCacheAdapterFlavor,
230
- `No cache adaptor configuration found for flavor: ${entityConfiguration.cacheAdapterFlavor}`
238
+ `No cache adaptor configuration found for flavor: ${entityConfiguration.cacheAdapterFlavor}`,
231
239
  );
232
240
 
233
241
  return new EntityTableDataCoordinator(
@@ -236,7 +244,7 @@ export default class EntityCompanionProvider {
236
244
  entityCacheAdapterFlavor.cacheAdapterProvider,
237
245
  entityDatabaseAdapterFlavor.queryContextProvider,
238
246
  this.metricsAdapter,
239
- entityClassName
247
+ entityClassName,
240
248
  );
241
249
  });
242
250
  }
@@ -7,7 +7,7 @@ import { mapMap, invertMap, reduceMap } from './utils/collections/maps';
7
7
  * The data storage configuration for a type of Entity. Contains information relating to IDs,
8
8
  * cachable fields, field mappings, and types of cache and database adapter.
9
9
  */
10
- export default class EntityConfiguration<TFields> {
10
+ export default class EntityConfiguration<TFields extends Record<string, any>> {
11
11
  readonly idField: keyof TFields;
12
12
  readonly tableName: string;
13
13
  readonly cacheableKeys: ReadonlySet<keyof TFields>;
@@ -75,18 +75,29 @@ export default class EntityConfiguration<TFields> {
75
75
 
76
76
  // external schema is a Record to typecheck that all fields have FieldDefinitions,
77
77
  // but internally the most useful representation is a map for lookups
78
- // TODO(wschurman): validate schema
79
- this.schema = new Map(Object.entries(schema) as any);
78
+ EntityConfiguration.validateSchema(schema);
79
+ this.schema = new Map(Object.entries(schema));
80
80
 
81
81
  this.cacheableKeys = EntityConfiguration.computeCacheableKeys(this.schema);
82
82
  this.entityToDBFieldsKeyMapping = EntityConfiguration.computeEntityToDBFieldsKeyMapping(
83
- this.schema
83
+ this.schema,
84
84
  );
85
85
  this.dbToEntityFieldsKeyMapping = invertMap(this.entityToDBFieldsKeyMapping);
86
86
  }
87
87
 
88
+ private static validateSchema<TFields extends Record<string, any>>(schema: TFields): void {
89
+ const disallowedFieldsKeys = Object.getOwnPropertyNames(Object.prototype);
90
+ for (const disallowedFieldsKey of disallowedFieldsKeys) {
91
+ if (Object.hasOwn(schema, disallowedFieldsKey)) {
92
+ throw new Error(
93
+ `Entity field name not allowed to prevent conflicts with standard Object prototype fields: ${disallowedFieldsKey}`,
94
+ );
95
+ }
96
+ }
97
+ }
98
+
88
99
  private static computeCacheableKeys<TFields>(
89
- schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any>>
100
+ schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any>>,
90
101
  ): ReadonlySet<keyof TFields> {
91
102
  return reduceMap(
92
103
  schema,
@@ -96,12 +107,12 @@ export default class EntityConfiguration<TFields> {
96
107
  }
97
108
  return acc;
98
109
  },
99
- new Set<keyof TFields>()
110
+ new Set<keyof TFields>(),
100
111
  );
101
112
  }
102
113
 
103
114
  private static computeEntityToDBFieldsKeyMapping<TFields>(
104
- schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any>>
115
+ schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any>>,
105
116
  ): ReadonlyMap<keyof TFields, string> {
106
117
  return mapMap(schema, (v) => v.columnName);
107
118
  }
@@ -12,7 +12,7 @@ import {
12
12
  */
13
13
  export interface SingleValueFieldEqualityCondition<
14
14
  TFields,
15
- N extends keyof TFields = keyof TFields
15
+ N extends keyof TFields = keyof TFields,
16
16
  > {
17
17
  fieldName: N;
18
18
  fieldValue: TFields[N];
@@ -23,7 +23,7 @@ export interface SingleValueFieldEqualityCondition<
23
23
  */
24
24
  export interface MultiValueFieldEqualityCondition<
25
25
  TFields,
26
- N extends keyof TFields = keyof TFields
26
+ N extends keyof TFields = keyof TFields,
27
27
  > {
28
28
  fieldName: N;
29
29
  fieldValues: readonly TFields[N][];
@@ -39,9 +39,9 @@ export type FieldEqualityCondition<TFields, N extends keyof TFields = keyof TFie
39
39
 
40
40
  export function isSingleValueFieldEqualityCondition<
41
41
  TFields,
42
- N extends keyof TFields = keyof TFields
42
+ N extends keyof TFields = keyof TFields,
43
43
  >(
44
- condition: FieldEqualityCondition<TFields, N>
44
+ condition: FieldEqualityCondition<TFields, N>,
45
45
  ): condition is SingleValueFieldEqualityCondition<TFields, N> {
46
46
  return (condition as SingleValueFieldEqualityCondition<TFields, N>).fieldValue !== undefined;
47
47
  }
@@ -113,7 +113,7 @@ export interface TableQuerySelectionModifiersWithOrderByRaw extends TableQuerySe
113
113
  * handles all entity field transformation. Subclasses are responsible for
114
114
  * implementing database-specific logic for a type of database.
115
115
  */
116
- export default abstract class EntityDatabaseAdapter<TFields> {
116
+ export default abstract class EntityDatabaseAdapter<TFields extends Record<string, any>> {
117
117
  private readonly fieldTransformerMap: FieldTransformerMap;
118
118
 
119
119
  constructor(private readonly entityConfiguration: EntityConfiguration<TFields>) {
@@ -137,18 +137,18 @@ export default abstract class EntityDatabaseAdapter<TFields> {
137
137
  */
138
138
  async fetchManyWhereAsync<K extends keyof TFields>(
139
139
  queryContext: EntityQueryContext,
140
- field: K,
141
- fieldValues: readonly NonNullable<TFields[K]>[]
140
+ fieldName: K,
141
+ fieldValues: readonly NonNullable<TFields[K]>[],
142
142
  ): Promise<ReadonlyMap<NonNullable<TFields[K]>, readonly Readonly<TFields>[]>> {
143
- const fieldColumn = getDatabaseFieldForEntityField(this.entityConfiguration, field);
143
+ const fieldColumn = getDatabaseFieldForEntityField(this.entityConfiguration, fieldName);
144
144
  const results = await this.fetchManyWhereInternalAsync(
145
145
  queryContext.getQueryInterface(),
146
146
  this.entityConfiguration.tableName,
147
147
  fieldColumn,
148
- fieldValues
148
+ fieldValues,
149
149
  );
150
150
  const objects = results.map((result) =>
151
- transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result)
151
+ transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result),
152
152
  );
153
153
 
154
154
  const objectMap = new Map();
@@ -157,7 +157,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
157
157
  }
158
158
 
159
159
  objects.forEach((object) => {
160
- const objectFieldValue = object[field];
160
+ const objectFieldValue = object[fieldName];
161
161
  objectMap.get(objectFieldValue).push(object);
162
162
  });
163
163
 
@@ -168,7 +168,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
168
168
  queryInterface: any,
169
169
  tableName: string,
170
170
  tableField: string,
171
- tableValues: readonly any[]
171
+ tableValues: readonly any[],
172
172
  ): Promise<object[]>;
173
173
 
174
174
  /**
@@ -183,7 +183,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
183
183
  async fetchManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(
184
184
  queryContext: EntityQueryContext,
185
185
  fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
186
- querySelectionModifiers: QuerySelectionModifiers<TFields>
186
+ querySelectionModifiers: QuerySelectionModifiers<TFields>,
187
187
  ): Promise<readonly Readonly<TFields>[]> {
188
188
  const tableFieldSingleValueOperands: TableFieldSingleValueEqualityCondition[] = [];
189
189
  const tableFieldMultipleValueOperands: TableFieldMultiValueEqualityCondition[] = [];
@@ -206,11 +206,11 @@ export default abstract class EntityDatabaseAdapter<TFields> {
206
206
  this.entityConfiguration.tableName,
207
207
  tableFieldSingleValueOperands,
208
208
  tableFieldMultipleValueOperands,
209
- this.convertToTableQueryModifiers(querySelectionModifiers)
209
+ this.convertToTableQueryModifiers(querySelectionModifiers),
210
210
  );
211
211
 
212
212
  return results.map((result) =>
213
- transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result)
213
+ transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result),
214
214
  );
215
215
  }
216
216
 
@@ -219,7 +219,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
219
219
  tableName: string,
220
220
  tableFieldSingleValueEqualityOperands: TableFieldSingleValueEqualityCondition[],
221
221
  tableFieldMultiValueEqualityOperands: TableFieldMultiValueEqualityCondition[],
222
- querySelectionModifiers: TableQuerySelectionModifiers
222
+ querySelectionModifiers: TableQuerySelectionModifiers,
223
223
  ): Promise<object[]>;
224
224
 
225
225
  /**
@@ -235,18 +235,18 @@ export default abstract class EntityDatabaseAdapter<TFields> {
235
235
  queryContext: EntityQueryContext,
236
236
  rawWhereClause: string,
237
237
  bindings: any[] | object,
238
- querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>
238
+ querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>,
239
239
  ): Promise<readonly Readonly<TFields>[]> {
240
240
  const results = await this.fetchManyByRawWhereClauseInternalAsync(
241
241
  queryContext.getQueryInterface(),
242
242
  this.entityConfiguration.tableName,
243
243
  rawWhereClause,
244
244
  bindings,
245
- this.convertToTableQueryModifiersWithOrderByRaw(querySelectionModifiers)
245
+ this.convertToTableQueryModifiersWithOrderByRaw(querySelectionModifiers),
246
246
  );
247
247
 
248
248
  return results.map((result) =>
249
- transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result)
249
+ transformDatabaseObjectToFields(this.entityConfiguration, this.fieldTransformerMap, result),
250
250
  );
251
251
  }
252
252
 
@@ -255,7 +255,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
255
255
  tableName: string,
256
256
  rawWhereClause: string,
257
257
  bindings: any[] | object,
258
- querySelectionModifiers: TableQuerySelectionModifiersWithOrderByRaw
258
+ querySelectionModifiers: TableQuerySelectionModifiersWithOrderByRaw,
259
259
  ): Promise<object[]>;
260
260
 
261
261
  /**
@@ -267,40 +267,40 @@ export default abstract class EntityDatabaseAdapter<TFields> {
267
267
  */
268
268
  async insertAsync(
269
269
  queryContext: EntityQueryContext,
270
- object: Readonly<Partial<TFields>>
270
+ object: Readonly<Partial<TFields>>,
271
271
  ): Promise<Readonly<TFields>> {
272
272
  const dbObject = transformFieldsToDatabaseObject(
273
273
  this.entityConfiguration,
274
274
  this.fieldTransformerMap,
275
- object
275
+ object,
276
276
  );
277
277
  const results = await this.insertInternalAsync(
278
278
  queryContext.getQueryInterface(),
279
279
  this.entityConfiguration.tableName,
280
- dbObject
280
+ dbObject,
281
281
  );
282
282
 
283
283
  if (results.length > 1) {
284
284
  throw new Error(
285
- `Excessive results from database adapter insert: ${this.entityConfiguration.tableName}`
285
+ `Excessive results from database adapter insert: ${this.entityConfiguration.tableName}`,
286
286
  );
287
287
  } else if (results.length === 0) {
288
288
  throw new Error(
289
- `Empty results from database adapter insert: ${this.entityConfiguration.tableName}`
289
+ `Empty results from database adapter insert: ${this.entityConfiguration.tableName}`,
290
290
  );
291
291
  }
292
292
 
293
293
  return transformDatabaseObjectToFields(
294
294
  this.entityConfiguration,
295
295
  this.fieldTransformerMap,
296
- results[0]!
296
+ results[0]!,
297
297
  );
298
298
  }
299
299
 
300
300
  protected abstract insertInternalAsync(
301
301
  queryInterface: any,
302
302
  tableName: string,
303
- object: object
303
+ object: object,
304
304
  ): Promise<object[]>;
305
305
 
306
306
  /**
@@ -316,36 +316,36 @@ export default abstract class EntityDatabaseAdapter<TFields> {
316
316
  queryContext: EntityQueryContext,
317
317
  idField: K,
318
318
  id: any,
319
- object: Readonly<Partial<TFields>>
319
+ object: Readonly<Partial<TFields>>,
320
320
  ): Promise<Readonly<TFields>> {
321
321
  const idColumn = getDatabaseFieldForEntityField(this.entityConfiguration, idField);
322
322
  const dbObject = transformFieldsToDatabaseObject(
323
323
  this.entityConfiguration,
324
324
  this.fieldTransformerMap,
325
- object
325
+ object,
326
326
  );
327
327
  const results = await this.updateInternalAsync(
328
328
  queryContext.getQueryInterface(),
329
329
  this.entityConfiguration.tableName,
330
330
  idColumn,
331
331
  id,
332
- dbObject
332
+ dbObject,
333
333
  );
334
334
 
335
335
  if (results.length > 1) {
336
336
  throw new Error(
337
- `Excessive results from database adapter update: ${this.entityConfiguration.tableName}(id = ${id})`
337
+ `Excessive results from database adapter update: ${this.entityConfiguration.tableName}(id = ${id})`,
338
338
  );
339
339
  } else if (results.length === 0) {
340
340
  throw new Error(
341
- `Empty results from database adapter update: ${this.entityConfiguration.tableName}(id = ${id})`
341
+ `Empty results from database adapter update: ${this.entityConfiguration.tableName}(id = ${id})`,
342
342
  );
343
343
  }
344
344
 
345
345
  return transformDatabaseObjectToFields(
346
346
  this.entityConfiguration,
347
347
  this.fieldTransformerMap,
348
- results[0]!
348
+ results[0]!,
349
349
  );
350
350
  }
351
351
 
@@ -354,7 +354,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
354
354
  tableName: string,
355
355
  tableIdField: string,
356
356
  id: any,
357
- object: object
357
+ object: object,
358
358
  ): Promise<object[]>;
359
359
 
360
360
  /**
@@ -367,19 +367,19 @@ export default abstract class EntityDatabaseAdapter<TFields> {
367
367
  async deleteAsync<K extends keyof TFields>(
368
368
  queryContext: EntityQueryContext,
369
369
  idField: K,
370
- id: any
370
+ id: any,
371
371
  ): Promise<void> {
372
372
  const idColumn = getDatabaseFieldForEntityField(this.entityConfiguration, idField);
373
373
  const numDeleted = await this.deleteInternalAsync(
374
374
  queryContext.getQueryInterface(),
375
375
  this.entityConfiguration.tableName,
376
376
  idColumn,
377
- id
377
+ id,
378
378
  );
379
379
 
380
380
  if (numDeleted > 1) {
381
381
  throw new Error(
382
- `Excessive deletions from database adapter delete: ${this.entityConfiguration.tableName}(id = ${id})`
382
+ `Excessive deletions from database adapter delete: ${this.entityConfiguration.tableName}(id = ${id})`,
383
383
  );
384
384
  }
385
385
  }
@@ -388,11 +388,11 @@ export default abstract class EntityDatabaseAdapter<TFields> {
388
388
  queryInterface: any,
389
389
  tableName: string,
390
390
  tableIdField: string,
391
- id: any
391
+ id: any,
392
392
  ): Promise<number>;
393
393
 
394
394
  private convertToTableQueryModifiersWithOrderByRaw(
395
- querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>
395
+ querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>,
396
396
  ): TableQuerySelectionModifiersWithOrderByRaw {
397
397
  return {
398
398
  ...this.convertToTableQueryModifiers(querySelectionModifiers),
@@ -401,7 +401,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
401
401
  }
402
402
 
403
403
  private convertToTableQueryModifiers(
404
- querySelectionModifiers: QuerySelectionModifiers<TFields>
404
+ querySelectionModifiers: QuerySelectionModifiers<TFields>,
405
405
  ): TableQuerySelectionModifiers {
406
406
  const orderBy = querySelectionModifiers.orderBy;
407
407
  return {
@@ -410,7 +410,7 @@ export default abstract class EntityDatabaseAdapter<TFields> {
410
410
  ? orderBy.map((orderBySpecification) => ({
411
411
  columnName: getDatabaseFieldForEntityField(
412
412
  this.entityConfiguration,
413
- orderBySpecification.fieldName
413
+ orderBySpecification.fieldName,
414
414
  ),
415
415
  order: orderBySpecification.order,
416
416
  }))
@@ -56,7 +56,7 @@ export interface EntityAssociationDefinition<
56
56
  TAssociatedEntity,
57
57
  TAssociatedSelectedFields
58
58
  >,
59
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
59
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
60
60
  > {
61
61
  /**
62
62
  * Class of entity on the other end of this edge.
@@ -95,6 +95,28 @@ export interface EntityAssociationDefinition<
95
95
  edgeDeletionBehavior: EntityEdgeDeletionBehavior;
96
96
  }
97
97
 
98
+ /**
99
+ * Options for EntityFieldDefinition
100
+ */
101
+ export interface EntityFieldDefinitionOptions {
102
+ /**
103
+ * Column name in the database.
104
+ */
105
+ columnName: string;
106
+
107
+ /**
108
+ * Whether or not to cache loaded instances of the entity by this field. The column name is
109
+ * used to derive a cache key for the cache entry. If true, this column must be able uniquely
110
+ * identify the entity.
111
+ */
112
+ cache?: boolean;
113
+
114
+ /**
115
+ * Defines the association behavior for an entity that this column references.
116
+ */
117
+ association?: EntityAssociationDefinition<any, any, any, any, any, any>;
118
+ }
119
+
98
120
  /**
99
121
  * Definition for a field referencing a column in the underlying database. Specifies things like
100
122
  * cache behavior and associations, and handles input validation.
@@ -105,24 +127,12 @@ export abstract class EntityFieldDefinition<T> {
105
127
  readonly association: EntityAssociationDefinition<any, any, any, any, any, any> | undefined;
106
128
  /**
107
129
  *
108
- * @param columnName - Column name in the database.
109
- * @param cache - Whether or not to cache loaded instances of the entity by this field. The column name is
110
- * used to derive a cache key for the cache entry. If true, this column must be able uniquely
111
- * identify the entity.
112
- * @param association - Defines the association behavior for an entity that this column references.
130
+ * @param options - options for this field definition
113
131
  */
114
- constructor({
115
- columnName,
116
- cache = false,
117
- association,
118
- }: {
119
- columnName: string;
120
- cache?: boolean;
121
- association?: EntityAssociationDefinition<any, any, any, any, any, any>;
122
- }) {
123
- this.columnName = columnName;
124
- this.cache = cache;
125
- this.association = association;
132
+ constructor(options: EntityFieldDefinitionOptions) {
133
+ this.columnName = options.columnName;
134
+ this.cache = options.cache ?? false;
135
+ this.association = options.association;
126
136
  }
127
137
 
128
138
  /**
@@ -88,3 +88,18 @@ export class EnumField extends EntityFieldDefinition<string | number> {
88
88
  return typeof value === 'number' || typeof value === 'string';
89
89
  }
90
90
  }
91
+
92
+ /**
93
+ * EntityFieldDefinition for a enum column with a strict typescript enum type.
94
+ */
95
+ export class StrictEnumField<T extends object> extends EnumField {
96
+ private readonly enum: T;
97
+ constructor(options: ConstructorParameters<typeof EnumField>[0] & { enum: T }) {
98
+ super(options);
99
+ this.enum = options.enum;
100
+ }
101
+
102
+ protected override validateInputValueInternal(value: string | number): boolean {
103
+ return super.validateInputValueInternal(value) && Object.values(this.enum).includes(value);
104
+ }
105
+ }