@expo/entity 0.31.0 → 0.32.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 (257) hide show
  1. package/build/ComposedEntityCacheAdapter.d.ts +4 -6
  2. package/build/ComposedEntityCacheAdapter.js +3 -6
  3. package/build/ComposedEntityCacheAdapter.js.map +1 -1
  4. package/build/EnforcingEntityLoader.d.ts +6 -1
  5. package/build/EnforcingEntityLoader.js +8 -0
  6. package/build/EnforcingEntityLoader.js.map +1 -1
  7. package/build/Entity.d.ts +20 -10
  8. package/build/Entity.js +2 -2
  9. package/build/Entity.js.map +1 -1
  10. package/build/EntityAssociationLoader.d.ts +9 -9
  11. package/build/EntityCompanion.d.ts +6 -5
  12. package/build/EntityCompanion.js +6 -4
  13. package/build/EntityCompanion.js.map +1 -1
  14. package/build/EntityCompanionProvider.d.ts +28 -36
  15. package/build/EntityCompanionProvider.js +4 -19
  16. package/build/EntityCompanionProvider.js.map +1 -1
  17. package/build/EntityConfiguration.d.ts +3 -3
  18. package/build/EntityConfiguration.js +2 -2
  19. package/build/EntityConfiguration.js.map +1 -1
  20. package/build/EntityDatabaseAdapter.d.ts +1 -1
  21. package/build/EntityDatabaseAdapter.js +1 -1
  22. package/build/EntityDatabaseAdapter.js.map +1 -1
  23. package/build/EntityFieldDefinition.d.ts +2 -2
  24. package/build/EntityFieldDefinition.js +1 -1
  25. package/build/EntityFieldDefinition.js.map +1 -1
  26. package/build/EntityLoader.d.ts +19 -2
  27. package/build/EntityLoader.js +41 -5
  28. package/build/EntityLoader.js.map +1 -1
  29. package/build/EntityLoaderFactory.d.ts +4 -7
  30. package/build/EntityLoaderFactory.js +3 -5
  31. package/build/EntityLoaderFactory.js.map +1 -1
  32. package/build/EntityMutationInfo.d.ts +3 -3
  33. package/build/EntityMutationInfo.js +1 -1
  34. package/build/EntityMutationInfo.js.map +1 -1
  35. package/build/EntityMutationTriggerConfiguration.d.ts +3 -3
  36. package/build/EntityMutationValidator.d.ts +1 -1
  37. package/build/EntityMutator.d.ts +9 -7
  38. package/build/EntityMutator.js +21 -21
  39. package/build/EntityMutator.js.map +1 -1
  40. package/build/EntityMutatorFactory.d.ts +4 -2
  41. package/build/EntityMutatorFactory.js +5 -4
  42. package/build/EntityMutatorFactory.js.map +1 -1
  43. package/build/EntityPrivacyPolicy.d.ts +3 -3
  44. package/build/EntityPrivacyPolicy.js +2 -2
  45. package/build/EntityPrivacyPolicy.js.map +1 -1
  46. package/build/EntityQueryContext.d.ts +13 -5
  47. package/build/EntityQueryContext.js +11 -4
  48. package/build/EntityQueryContext.js.map +1 -1
  49. package/build/EntityQueryContextProvider.d.ts +3 -3
  50. package/build/EntityQueryContextProvider.js +2 -2
  51. package/build/EntityQueryContextProvider.js.map +1 -1
  52. package/build/EntitySecondaryCacheLoader.d.ts +1 -1
  53. package/build/EntitySecondaryCacheLoader.js +1 -1
  54. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  55. package/build/GenericEntityCacheAdapter.d.ts +14 -0
  56. package/build/GenericEntityCacheAdapter.js +38 -0
  57. package/build/GenericEntityCacheAdapter.js.map +1 -0
  58. package/build/{EntityCacheAdapter.d.ts → IEntityCacheAdapter.d.ts} +5 -8
  59. package/build/IEntityCacheAdapter.js +3 -0
  60. package/build/IEntityCacheAdapter.js.map +1 -0
  61. package/build/IEntityCacheAdapterProvider.d.ts +2 -2
  62. package/build/IEntityGenericCacher.d.ts +31 -2
  63. package/build/ReadonlyEntity.d.ts +19 -7
  64. package/build/ReadonlyEntity.js +15 -13
  65. package/build/ReadonlyEntity.js.map +1 -1
  66. package/build/ViewerContext.d.ts +3 -3
  67. package/build/ViewerContext.js +3 -3
  68. package/build/ViewerContext.js.map +1 -1
  69. package/build/ViewerScopedEntityCompanion.d.ts +2 -2
  70. package/build/ViewerScopedEntityCompanion.js.map +1 -1
  71. package/build/ViewerScopedEntityCompanionProvider.d.ts +3 -3
  72. package/build/ViewerScopedEntityCompanionProvider.js +3 -3
  73. package/build/ViewerScopedEntityCompanionProvider.js.map +1 -1
  74. package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
  75. package/build/ViewerScopedEntityMutatorFactory.d.ts +1 -1
  76. package/build/__tests__/ComposedCacheAdapter-test.js +4 -8
  77. package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
  78. package/build/__tests__/EnforcingEntityLoader-test.js +26 -0
  79. package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
  80. package/build/__tests__/Entity-test.js +42 -20
  81. package/build/__tests__/Entity-test.js.map +1 -1
  82. package/build/__tests__/EntityAssociationLoader-test.js +6 -6
  83. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  84. package/build/__tests__/EntityCommonUseCases-test.js +20 -22
  85. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  86. package/build/__tests__/EntityCompanion-test.js +2 -1
  87. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  88. package/build/__tests__/EntityCompanionProvider-test.js +15 -40
  89. package/build/__tests__/EntityCompanionProvider-test.js.map +1 -1
  90. package/build/__tests__/EntityEdges-test.js +48 -54
  91. package/build/__tests__/EntityEdges-test.js.map +1 -1
  92. package/build/__tests__/EntityLoader-constructor-test.d.ts +9 -5
  93. package/build/__tests__/EntityLoader-constructor-test.js +13 -14
  94. package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
  95. package/build/__tests__/EntityLoader-test.js +80 -10
  96. package/build/__tests__/EntityLoader-test.js.map +1 -1
  97. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +20 -22
  98. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  99. package/build/__tests__/EntityMutator-test.js +67 -14
  100. package/build/__tests__/EntityMutator-test.js.map +1 -1
  101. package/build/__tests__/EntityPrivacyPolicy-test.js +82 -29
  102. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  103. package/build/__tests__/EntityQueryContext-test.js +12 -0
  104. package/build/__tests__/EntityQueryContext-test.js.map +1 -1
  105. package/build/__tests__/EntitySecondaryCacheLoader-test.js +1 -2
  106. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
  107. package/build/__tests__/EntitySelfReferentialEdges-test.js +16 -20
  108. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  109. package/build/__tests__/GenericEntityCacheAdapter-test.d.ts +1 -0
  110. package/build/__tests__/GenericEntityCacheAdapter-test.js +80 -0
  111. package/build/__tests__/GenericEntityCacheAdapter-test.js.map +1 -0
  112. package/build/__tests__/ReadonlyEntity-test.js +79 -13
  113. package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
  114. package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js +2 -25
  115. package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js.map +1 -1
  116. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +20 -23
  117. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  118. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +17 -20
  119. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  120. package/build/errors/EntityError.js +2 -2
  121. package/build/errors/EntityError.js.map +1 -1
  122. package/build/errors/EntityInvalidFieldValueError.d.ts +2 -2
  123. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  124. package/build/errors/EntityNotAuthorizedError.d.ts +2 -2
  125. package/build/errors/EntityNotAuthorizedError.js +1 -1
  126. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  127. package/build/errors/EntityNotFoundError.d.ts +2 -2
  128. package/build/errors/EntityNotFoundError.js.map +1 -1
  129. package/build/index.d.ts +2 -1
  130. package/build/index.js +3 -3
  131. package/build/index.js.map +1 -1
  132. package/build/internal/EntityDataManager.d.ts +1 -1
  133. package/build/internal/EntityDataManager.js +1 -1
  134. package/build/internal/EntityDataManager.js.map +1 -1
  135. package/build/internal/EntityFieldTransformationUtils.d.ts +1 -1
  136. package/build/internal/EntityFieldTransformationUtils.js +4 -4
  137. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  138. package/build/internal/EntityTableDataCoordinator.d.ts +3 -3
  139. package/build/internal/EntityTableDataCoordinator.js.map +1 -1
  140. package/build/internal/ReadThroughEntityCache.d.ts +3 -3
  141. package/build/internal/ReadThroughEntityCache.js +1 -1
  142. package/build/internal/ReadThroughEntityCache.js.map +1 -1
  143. package/build/internal/__tests__/EntityDataManager-test.js +1 -1
  144. package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
  145. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  146. package/build/metrics/EntityMetricsUtils.js.map +1 -1
  147. package/build/metrics/IEntityMetricsAdapter.js +4 -4
  148. package/build/metrics/IEntityMetricsAdapter.js.map +1 -1
  149. package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +2 -2
  150. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  151. package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +2 -2
  152. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  153. package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +2 -2
  154. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  155. package/build/rules/PrivacyPolicyRule.d.ts +1 -1
  156. package/build/rules/PrivacyPolicyRule.js +1 -1
  157. package/build/rules/PrivacyPolicyRule.js.map +1 -1
  158. package/build/testfixtures/DateIDTestEntity.d.ts +2 -3
  159. package/build/testfixtures/DateIDTestEntity.js +7 -9
  160. package/build/testfixtures/DateIDTestEntity.js.map +1 -1
  161. package/build/testfixtures/SimpleTestEntity.d.ts +3 -4
  162. package/build/testfixtures/SimpleTestEntity.js +7 -9
  163. package/build/testfixtures/SimpleTestEntity.js.map +1 -1
  164. package/build/testfixtures/TestEntity.d.ts +2 -3
  165. package/build/testfixtures/TestEntity.js +14 -10
  166. package/build/testfixtures/TestEntity.js.map +1 -1
  167. package/build/testfixtures/TestEntity2.d.ts +2 -3
  168. package/build/testfixtures/TestEntity2.js +7 -9
  169. package/build/testfixtures/TestEntity2.js.map +1 -1
  170. package/build/testfixtures/TestEntityNumberKey.d.ts +2 -3
  171. package/build/testfixtures/TestEntityNumberKey.js +7 -9
  172. package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
  173. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +4 -4
  174. package/build/utils/testing/StubCacheAdapter.d.ts +6 -5
  175. package/build/utils/testing/StubCacheAdapter.js +5 -6
  176. package/build/utils/testing/StubCacheAdapter.js.map +1 -1
  177. package/build/utils/testing/StubDatabaseAdapterProvider.js.map +1 -1
  178. package/build/utils/testing/StubQueryContextProvider.d.ts +2 -1
  179. package/build/utils/testing/StubQueryContextProvider.js +1 -1
  180. package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
  181. package/build/utils/testing/createUnitTestEntityCompanionProvider.js +2 -2
  182. package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +1 -1
  183. package/package.json +3 -3
  184. package/src/ComposedEntityCacheAdapter.ts +4 -11
  185. package/src/EnforcingEntityLoader.ts +17 -1
  186. package/src/Entity.ts +23 -12
  187. package/src/EntityAssociationLoader.ts +12 -12
  188. package/src/EntityCompanion.ts +13 -32
  189. package/src/EntityCompanionProvider.ts +41 -80
  190. package/src/EntityConfiguration.ts +4 -5
  191. package/src/EntityFieldDefinition.ts +2 -2
  192. package/src/EntityLoader.ts +45 -2
  193. package/src/EntityLoaderFactory.ts +7 -9
  194. package/src/EntityMutationInfo.ts +2 -2
  195. package/src/EntityMutationTriggerConfiguration.ts +3 -3
  196. package/src/EntityMutationValidator.ts +1 -1
  197. package/src/EntityMutator.ts +38 -31
  198. package/src/EntityMutatorFactory.ts +6 -1
  199. package/src/EntityPrivacyPolicy.ts +2 -2
  200. package/src/EntityQueryContext.ts +24 -4
  201. package/src/EntityQueryContextProvider.ts +7 -5
  202. package/src/EntitySecondaryCacheLoader.ts +1 -1
  203. package/src/GenericEntityCacheAdapter.ts +65 -0
  204. package/src/{EntityCacheAdapter.ts → IEntityCacheAdapter.ts} +5 -8
  205. package/src/IEntityCacheAdapterProvider.ts +2 -2
  206. package/src/IEntityGenericCacher.ts +32 -2
  207. package/src/ReadonlyEntity.ts +32 -32
  208. package/src/ViewerContext.ts +10 -8
  209. package/src/ViewerScopedEntityCompanion.ts +2 -2
  210. package/src/ViewerScopedEntityCompanionProvider.ts +4 -12
  211. package/src/ViewerScopedEntityLoaderFactory.ts +1 -1
  212. package/src/ViewerScopedEntityMutatorFactory.ts +1 -1
  213. package/src/__tests__/ComposedCacheAdapter-test.ts +6 -11
  214. package/src/__tests__/EnforcingEntityLoader-test.ts +41 -0
  215. package/src/__tests__/Entity-test.ts +42 -21
  216. package/src/__tests__/EntityCommonUseCases-test.ts +20 -22
  217. package/src/__tests__/EntityCompanion-test.ts +6 -9
  218. package/src/__tests__/EntityCompanionProvider-test.ts +14 -26
  219. package/src/__tests__/EntityEdges-test.ts +43 -49
  220. package/src/__tests__/EntityLoader-constructor-test.ts +16 -12
  221. package/src/__tests__/EntityLoader-test.ts +105 -0
  222. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +20 -22
  223. package/src/__tests__/EntityMutator-test.ts +119 -19
  224. package/src/__tests__/EntityPrivacyPolicy-test.ts +82 -29
  225. package/src/__tests__/EntityQueryContext-test.ts +23 -1
  226. package/src/__tests__/EntitySelfReferentialEdges-test.ts +8 -10
  227. package/src/__tests__/GenericEntityCacheAdapter-test.ts +102 -0
  228. package/src/__tests__/ReadonlyEntity-test.ts +79 -13
  229. package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +2 -5
  230. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +30 -24
  231. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +14 -18
  232. package/src/errors/EntityInvalidFieldValueError.ts +2 -2
  233. package/src/errors/EntityNotAuthorizedError.ts +2 -2
  234. package/src/errors/EntityNotFoundError.ts +2 -2
  235. package/src/index.ts +2 -1
  236. package/src/internal/EntityDataManager.ts +1 -1
  237. package/src/internal/EntityTableDataCoordinator.ts +4 -4
  238. package/src/internal/ReadThroughEntityCache.ts +2 -2
  239. package/src/internal/__tests__/EntityDataManager-test.ts +2 -1
  240. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +8 -8
  241. package/src/metrics/EntityMetricsUtils.ts +1 -1
  242. package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +2 -2
  243. package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +2 -2
  244. package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +2 -2
  245. package/src/rules/PrivacyPolicyRule.ts +1 -1
  246. package/src/testfixtures/DateIDTestEntity.ts +6 -8
  247. package/src/testfixtures/SimpleTestEntity.ts +6 -8
  248. package/src/testfixtures/TestEntity.ts +19 -15
  249. package/src/testfixtures/TestEntity2.ts +6 -8
  250. package/src/testfixtures/TestEntityNumberKey.ts +6 -8
  251. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +4 -4
  252. package/src/utils/testing/StubCacheAdapter.ts +9 -11
  253. package/src/utils/testing/StubDatabaseAdapterProvider.ts +1 -1
  254. package/src/utils/testing/StubQueryContextProvider.ts +4 -3
  255. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +3 -3
  256. package/build/EntityCacheAdapter.js +0 -13
  257. package/build/EntityCacheAdapter.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { Result, asyncResult, result } from '@expo/results';
2
2
  import invariant from 'invariant';
3
+ import nullthrows from 'nullthrows';
3
4
 
4
5
  import EnforcingEntityLoader from './EnforcingEntityLoader';
5
6
  import { IEntityClass } from './Entity';
@@ -14,6 +15,7 @@ import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './Ent
14
15
  import { EntityQueryContext } from './EntityQueryContext';
15
16
  import ReadonlyEntity from './ReadonlyEntity';
16
17
  import ViewerContext from './ViewerContext';
18
+ import { pick } from './entityUtils';
17
19
  import EntityInvalidFieldValueError from './errors/EntityInvalidFieldValueError';
18
20
  import EntityNotFoundError from './errors/EntityNotFoundError';
19
21
  import EntityDataManager from './internal/EntityDataManager';
@@ -25,7 +27,7 @@ import { mapMap, mapMapAsync } from './utils/collections/maps';
25
27
  * cached, and authorized against the entity's EntityPrivacyPolicy.
26
28
  */
27
29
  export default class EntityLoader<
28
- TFields,
30
+ TFields extends object,
29
31
  TID extends NonNullable<TFields[TSelectedFields]>,
30
32
  TViewerContext extends ViewerContext,
31
33
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -51,6 +53,7 @@ export default class EntityLoader<
51
53
  TPrivacyPolicy,
52
54
  TSelectedFields
53
55
  >,
56
+ private readonly entitySelectedFields: TSelectedFields[] | undefined,
54
57
  private readonly privacyPolicy: TPrivacyPolicy,
55
58
  private readonly dataManager: EntityDataManager<TFields>,
56
59
  protected readonly metricsAdapter: IEntityMetricsAdapter
@@ -182,6 +185,32 @@ export default class EntityLoader<
182
185
  });
183
186
  }
184
187
 
188
+ /**
189
+ * Loads the first entity matching the selection constructed from the conjunction of specified
190
+ * operands, or null if no matching entity exists. Entities loaded using this method are not
191
+ * batched or cached.
192
+ *
193
+ * This is a convenience method for {@link loadManyByFieldEqualityConjunctionAsync}. However, the
194
+ * `orderBy` option must be specified to define what "first" means. If ordering doesn't matter,
195
+ * explicitly pass in an empty array.
196
+ *
197
+ * @param fieldEqualityOperands - list of field equality selection operand specifications
198
+ * @param querySelectionModifiers - orderBy and optional offset for the query
199
+ * @returns the first entity results that matches the query, where result error can be
200
+ * UnauthorizedError
201
+ */
202
+ async loadFirstByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
203
+ fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
204
+ querySelectionModifiers: Omit<QuerySelectionModifiers<TFields>, 'limit'> &
205
+ Required<Pick<QuerySelectionModifiers<TFields>, 'orderBy'>>
206
+ ): Promise<Result<TEntity> | null> {
207
+ const results = await this.loadManyByFieldEqualityConjunctionAsync(fieldEqualityOperands, {
208
+ ...querySelectionModifiers,
209
+ limit: 1,
210
+ });
211
+ return results[0] ?? null;
212
+ }
213
+
185
214
  /**
186
215
  * Loads many entities matching the selection constructed from the conjunction of specified operands.
187
216
  * Entities loaded using this method are not batched or cached.
@@ -306,7 +335,7 @@ export default class EntityLoader<
306
335
  private tryConstructEntities(fieldsObjects: readonly TFields[]): readonly Result<TEntity>[] {
307
336
  return fieldsObjects.map((fieldsObject) => {
308
337
  try {
309
- return result(new this.entityClass(this.viewerContext, fieldsObject));
338
+ return result(this.constructEntity(fieldsObject));
310
339
  } catch (e) {
311
340
  if (!(e instanceof Error)) {
312
341
  throw e;
@@ -316,6 +345,20 @@ export default class EntityLoader<
316
345
  });
317
346
  }
318
347
 
348
+ public constructEntity(fieldsObject: TFields): TEntity {
349
+ const idField = this.entityConfiguration.idField;
350
+ const id = nullthrows(fieldsObject[idField], 'must provide ID to create an entity');
351
+ const entitySelectedFields =
352
+ this.entitySelectedFields ?? Array.from(this.entityConfiguration.schema.keys());
353
+ const selectedFields = pick(fieldsObject, entitySelectedFields);
354
+ return new this.entityClass({
355
+ viewerContext: this.viewerContext,
356
+ id: id as TID,
357
+ databaseFields: fieldsObject,
358
+ selectedFields,
359
+ });
360
+ }
361
+
319
362
  /**
320
363
  * Construct and authorize entities from fields map, returning error results for entities that fail
321
364
  * to construct or fail to authorize.
@@ -1,5 +1,4 @@
1
- import { IEntityClass } from './Entity';
2
- import EntityConfiguration from './EntityConfiguration';
1
+ import EntityCompanion from './EntityCompanion';
3
2
  import EntityLoader from './EntityLoader';
4
3
  import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
5
4
  import { EntityQueryContext } from './EntityQueryContext';
@@ -12,7 +11,7 @@ import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
12
11
  * The primary entry point for loading entities.
13
12
  */
14
13
  export default class EntityLoaderFactory<
15
- TFields,
14
+ TFields extends object,
16
15
  TID extends NonNullable<TFields[TSelectedFields]>,
17
16
  TViewerContext extends ViewerContext,
18
17
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -26,8 +25,7 @@ export default class EntityLoaderFactory<
26
25
  TSelectedFields extends keyof TFields
27
26
  > {
28
27
  constructor(
29
- private readonly entityConfiguration: EntityConfiguration<TFields>,
30
- private readonly entityClass: IEntityClass<
28
+ private readonly entityCompanion: EntityCompanion<
31
29
  TFields,
32
30
  TID,
33
31
  TViewerContext,
@@ -35,7 +33,6 @@ export default class EntityLoaderFactory<
35
33
  TPrivacyPolicy,
36
34
  TSelectedFields
37
35
  >,
38
- private readonly privacyPolicyClass: TPrivacyPolicy,
39
36
  private readonly dataManager: EntityDataManager<TFields>,
40
37
  protected readonly metricsAdapter: IEntityMetricsAdapter
41
38
  ) {}
@@ -54,9 +51,10 @@ export default class EntityLoaderFactory<
54
51
  viewerContext,
55
52
  queryContext,
56
53
  privacyPolicyEvaluationContext,
57
- this.entityConfiguration,
58
- this.entityClass,
59
- this.privacyPolicyClass,
54
+ this.entityCompanion.entityCompanionDefinition.entityConfiguration,
55
+ this.entityCompanion.entityCompanionDefinition.entityClass,
56
+ this.entityCompanion.entityCompanionDefinition.entitySelectedFields,
57
+ this.entityCompanion.privacyPolicy,
60
58
  this.dataManager,
61
59
  this.metricsAdapter
62
60
  );
@@ -8,7 +8,7 @@ export enum EntityMutationType {
8
8
  }
9
9
 
10
10
  export type EntityValidatorMutationInfo<
11
- TFields,
11
+ TFields extends object,
12
12
  TID extends NonNullable<TFields[TSelectedFields]>,
13
13
  TViewerContext extends ViewerContext,
14
14
  TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -39,7 +39,7 @@ export type EntityCascadingDeletionInfo = {
39
39
  };
40
40
 
41
41
  export type EntityTriggerMutationInfo<
42
- TFields,
42
+ TFields extends object,
43
43
  TID extends NonNullable<TFields[TSelectedFields]>,
44
44
  TViewerContext extends ViewerContext,
45
45
  TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -7,7 +7,7 @@ import ViewerContext from './ViewerContext';
7
7
  * Interface to define trigger behavior for entities.
8
8
  */
9
9
  export default interface EntityMutationTriggerConfiguration<
10
- TFields,
10
+ TFields extends object,
11
11
  TID extends NonNullable<TFields[TSelectedFields]>,
12
12
  TViewerContext extends ViewerContext,
13
13
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -70,7 +70,7 @@ export default interface EntityMutationTriggerConfiguration<
70
70
  * the transaction if a transaction is supplied.
71
71
  */
72
72
  export abstract class EntityMutationTrigger<
73
- TFields,
73
+ TFields extends object,
74
74
  TID extends NonNullable<TFields[TSelectedFields]>,
75
75
  TViewerContext extends ViewerContext,
76
76
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -89,7 +89,7 @@ export abstract class EntityMutationTrigger<
89
89
  * since they explicitly occur outside of the transaction.
90
90
  */
91
91
  export abstract class EntityNonTransactionalMutationTrigger<
92
- TFields,
92
+ TFields extends object,
93
93
  TID extends NonNullable<TFields[TSelectedFields]>,
94
94
  TViewerContext extends ViewerContext,
95
95
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -8,7 +8,7 @@ import ViewerContext from './ViewerContext';
8
8
  * same transaction as the mutation itself before creating or updating an entity.
9
9
  */
10
10
  export default abstract class EntityMutationValidator<
11
- TFields,
11
+ TFields extends object,
12
12
  TID extends NonNullable<TFields[TSelectedFields]>,
13
13
  TViewerContext extends ViewerContext,
14
14
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -2,7 +2,7 @@ import { Result, asyncResult, result, enforceAsyncResult } from '@expo/results';
2
2
  import invariant from 'invariant';
3
3
 
4
4
  import Entity, { IEntityClass } from './Entity';
5
- import { EntityCompanionDefinition } from './EntityCompanionProvider';
5
+ import EntityCompanionProvider from './EntityCompanionProvider';
6
6
  import EntityConfiguration from './EntityConfiguration';
7
7
  import EntityDatabaseAdapter from './EntityDatabaseAdapter';
8
8
  import { EntityEdgeDeletionBehavior } from './EntityFieldDefinition';
@@ -28,7 +28,7 @@ import IEntityMetricsAdapter, { EntityMetricsMutationType } from './metrics/IEnt
28
28
  import { mapMapAsync } from './utils/collections/maps';
29
29
 
30
30
  abstract class BaseMutator<
31
- TFields,
31
+ TFields extends object,
32
32
  TID extends NonNullable<TFields[TSelectedFields]>,
33
33
  TViewerContext extends ViewerContext,
34
34
  TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -42,6 +42,7 @@ abstract class BaseMutator<
42
42
  TSelectedFields extends keyof TFields
43
43
  > {
44
44
  constructor(
45
+ protected readonly companionProvider: EntityCompanionProvider,
45
46
  protected readonly viewerContext: TViewerContext,
46
47
  protected readonly queryContext: EntityQueryContext,
47
48
  protected readonly entityConfiguration: EntityConfiguration<TFields>,
@@ -155,7 +156,7 @@ abstract class BaseMutator<
155
156
  * Mutator for creating a new entity.
156
157
  */
157
158
  export class CreateMutator<
158
- TFields,
159
+ TFields extends object,
159
160
  TID extends NonNullable<TFields[TSelectedFields]>,
160
161
  TViewerContext extends ViewerContext,
161
162
  TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -211,7 +212,11 @@ export class CreateMutator<
211
212
  ): Promise<Result<TEntity>> {
212
213
  this.validateFields(this.fieldsForEntity);
213
214
 
214
- const temporaryEntityForPrivacyCheck = new this.entityClass(this.viewerContext, {
215
+ const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext, {
216
+ cascadingDeleteCause: null,
217
+ });
218
+
219
+ const temporaryEntityForPrivacyCheck = entityLoader.constructEntity({
215
220
  [this.entityConfiguration.idField]: '00000000-0000-0000-0000-000000000000', // zero UUID
216
221
  ...this.fieldsForEntity,
217
222
  } as unknown as TFields);
@@ -250,14 +255,11 @@ export class CreateMutator<
250
255
 
251
256
  const insertResult = await this.databaseAdapter.insertAsync(queryContext, this.fieldsForEntity);
252
257
 
253
- const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext, {
254
- cascadingDeleteCause: null,
255
- });
256
258
  queryContext.appendPostCommitInvalidationCallback(
257
259
  entityLoader.invalidateFieldsAsync.bind(entityLoader, insertResult)
258
260
  );
259
261
 
260
- const unauthorizedEntityAfterInsert = new this.entityClass(this.viewerContext, insertResult);
262
+ const unauthorizedEntityAfterInsert = entityLoader.constructEntity(insertResult);
261
263
  const newEntity = await entityLoader
262
264
  .enforcing()
263
265
  .loadByIDAsync(unauthorizedEntityAfterInsert.getID());
@@ -292,7 +294,7 @@ export class CreateMutator<
292
294
  * Mutator for updating an existing entity.
293
295
  */
294
296
  export class UpdateMutator<
295
- TFields,
297
+ TFields extends object,
296
298
  TID extends NonNullable<TFields[TSelectedFields]>,
297
299
  TViewerContext extends ViewerContext,
298
300
  TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -310,6 +312,7 @@ export class UpdateMutator<
310
312
  private readonly updatedFields: Partial<TFields> = {};
311
313
 
312
314
  constructor(
315
+ companionProvider: EntityCompanionProvider,
313
316
  viewerContext: TViewerContext,
314
317
  queryContext: EntityQueryContext,
315
318
  entityConfiguration: EntityConfiguration<TFields>,
@@ -349,6 +352,7 @@ export class UpdateMutator<
349
352
  originalEntity: TEntity
350
353
  ) {
351
354
  super(
355
+ companionProvider,
352
356
  viewerContext,
353
357
  queryContext,
354
358
  entityConfiguration,
@@ -419,7 +423,11 @@ export class UpdateMutator<
419
423
  ): Promise<Result<TEntity>> {
420
424
  this.validateFields(this.updatedFields);
421
425
 
422
- const entityAboutToBeUpdated = new this.entityClass(this.viewerContext, this.fieldsForEntity);
426
+ const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext, {
427
+ cascadingDeleteCause,
428
+ });
429
+
430
+ const entityAboutToBeUpdated = entityLoader.constructEntity(this.fieldsForEntity);
423
431
  const authorizeUpdateResult = await asyncResult(
424
432
  this.privacyPolicy.authorizeUpdateAsync(
425
433
  this.viewerContext,
@@ -462,10 +470,6 @@ export class UpdateMutator<
462
470
  this.updatedFields
463
471
  );
464
472
 
465
- const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext, {
466
- cascadingDeleteCause,
467
- });
468
-
469
473
  queryContext.appendPostCommitInvalidationCallback(
470
474
  entityLoader.invalidateFieldsAsync.bind(
471
475
  entityLoader,
@@ -481,7 +485,7 @@ export class UpdateMutator<
481
485
  const updatedEntity = updateResult
482
486
  ? await entityLoader
483
487
  .enforcing()
484
- .loadByIDAsync(new this.entityClass(this.viewerContext, updateResult).getID())
488
+ .loadByIDAsync(entityLoader.constructEntity(updateResult).getID())
485
489
  : entityAboutToBeUpdated;
486
490
 
487
491
  await this.executeMutationTriggersAsync(
@@ -518,7 +522,7 @@ export class UpdateMutator<
518
522
  * Mutator for deleting an existing entity.
519
523
  */
520
524
  export class DeleteMutator<
521
- TFields,
525
+ TFields extends object,
522
526
  TID extends NonNullable<TFields[TSelectedFields]>,
523
527
  TViewerContext extends ViewerContext,
524
528
  TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -532,6 +536,7 @@ export class DeleteMutator<
532
536
  TSelectedFields extends keyof TFields
533
537
  > extends BaseMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
534
538
  constructor(
539
+ companionProvider: EntityCompanionProvider,
535
540
  viewerContext: TViewerContext,
536
541
  queryContext: EntityQueryContext,
537
542
  entityConfiguration: EntityConfiguration<TFields>,
@@ -571,6 +576,7 @@ export class DeleteMutator<
571
576
  private readonly entity: TEntity
572
577
  ) {
573
578
  super(
579
+ companionProvider,
574
580
  viewerContext,
575
581
  queryContext,
576
582
  entityConfiguration,
@@ -723,31 +729,32 @@ export class DeleteMutator<
723
729
  }
724
730
  processedEntityIdentifiers.add(entity.getUniqueIdentifier());
725
731
 
726
- const companionDefinition = (
727
- entity.constructor as any
728
- ).getCompanionDefinition() as EntityCompanionDefinition<
729
- TFields,
730
- TID,
731
- TViewerContext,
732
- TEntity,
733
- TPrivacyPolicy,
734
- TSelectedFields
735
- >;
732
+ const companionDefinition = this.companionProvider.getCompanionForEntity(
733
+ entity.constructor as IEntityClass<
734
+ TFields,
735
+ TID,
736
+ TViewerContext,
737
+ TEntity,
738
+ TPrivacyPolicy,
739
+ TSelectedFields
740
+ >
741
+ ).entityCompanionDefinition;
736
742
  const entityConfiguration = companionDefinition.entityConfiguration;
737
- const inboundEdges = entityConfiguration.getInboundEdges();
743
+ const inboundEdges = entityConfiguration.inboundEdges;
738
744
  await Promise.all(
739
745
  inboundEdges.map(async (entityClass) => {
740
746
  return await mapMapAsync(
741
- entityClass.getCompanionDefinition().entityConfiguration.schema,
747
+ this.companionProvider.getCompanionForEntity(entityClass).entityCompanionDefinition
748
+ .entityConfiguration.schema,
742
749
  async (fieldDefinition, fieldName) => {
743
750
  const association = fieldDefinition.association;
744
751
  if (!association) {
745
752
  return;
746
753
  }
747
754
 
748
- const associatedConfiguration = association
749
- .getAssociatedEntityClass()
750
- .getCompanionDefinition().entityConfiguration;
755
+ const associatedConfiguration = this.companionProvider.getCompanionForEntity(
756
+ association.associatedEntityClass
757
+ ).entityCompanionDefinition.entityConfiguration;
751
758
  if (associatedConfiguration !== entityConfiguration) {
752
759
  return;
753
760
  }
@@ -1,4 +1,5 @@
1
1
  import Entity, { IEntityClass } from './Entity';
2
+ import EntityCompanionProvider from './EntityCompanionProvider';
2
3
  import EntityConfiguration from './EntityConfiguration';
3
4
  import EntityDatabaseAdapter from './EntityDatabaseAdapter';
4
5
  import EntityLoaderFactory from './EntityLoaderFactory';
@@ -14,7 +15,7 @@ import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
14
15
  * The primary interface for creating, mutating, and deleting entities.
15
16
  */
16
17
  export default class EntityMutatorFactory<
17
- TFields,
18
+ TFields extends object,
18
19
  TID extends NonNullable<TFields[TSelectedFields]>,
19
20
  TViewerContext extends ViewerContext,
20
21
  TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -28,6 +29,7 @@ export default class EntityMutatorFactory<
28
29
  TSelectedFields extends keyof TFields = keyof TFields
29
30
  > {
30
31
  constructor(
32
+ private readonly entityCompanionProvider: EntityCompanionProvider,
31
33
  private readonly entityConfiguration: EntityConfiguration<TFields>,
32
34
  private readonly entityClass: IEntityClass<
33
35
  TFields,
@@ -75,6 +77,7 @@ export default class EntityMutatorFactory<
75
77
  queryContext: EntityQueryContext
76
78
  ): CreateMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
77
79
  return new CreateMutator(
80
+ this.entityCompanionProvider,
78
81
  viewerContext,
79
82
  queryContext,
80
83
  this.entityConfiguration,
@@ -99,6 +102,7 @@ export default class EntityMutatorFactory<
99
102
  queryContext: EntityQueryContext
100
103
  ): UpdateMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
101
104
  return new UpdateMutator(
105
+ this.entityCompanionProvider,
102
106
  existingEntity.getViewerContext(),
103
107
  queryContext,
104
108
  this.entityConfiguration,
@@ -123,6 +127,7 @@ export default class EntityMutatorFactory<
123
127
  queryContext: EntityQueryContext
124
128
  ): DeleteMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
125
129
  return new DeleteMutator(
130
+ this.entityCompanionProvider,
126
131
  existingEntity.getViewerContext(),
127
132
  queryContext,
128
133
  this.entityConfiguration,
@@ -41,7 +41,7 @@ export enum EntityPrivacyPolicyEvaluationMode {
41
41
  }
42
42
 
43
43
  export type EntityPrivacyPolicyEvaluator<
44
- TFields,
44
+ TFields extends object,
45
45
  TID extends NonNullable<TFields[TSelectedFields]>,
46
46
  TViewerContext extends ViewerContext,
47
47
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -92,7 +92,7 @@ export enum EntityAuthorizationAction {
92
92
  * ```
93
93
  */
94
94
  export default abstract class EntityPrivacyPolicy<
95
- TFields,
95
+ TFields extends object,
96
96
  TID extends NonNullable<TFields[TSelectedFields]>,
97
97
  TViewerContext extends ViewerContext,
98
98
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -8,6 +8,16 @@ export type PreCommitCallback = (
8
8
  ...args: any
9
9
  ) => Promise<any>;
10
10
 
11
+ export enum TransactionIsolationLevel {
12
+ READ_COMMITTED = 'READ_COMMITTED',
13
+ REPEATABLE_READ = 'REPEATABLE_READ',
14
+ SERIALIZABLE = 'SERIALIZABLE',
15
+ }
16
+
17
+ export type TransactionConfig = {
18
+ isolationLevel?: TransactionIsolationLevel;
19
+ };
20
+
11
21
  /**
12
22
  * Entity framework representation of transactional and non-transactional database
13
23
  * query execution units.
@@ -25,7 +35,8 @@ export abstract class EntityQueryContext {
25
35
  }
26
36
 
27
37
  abstract runInTransactionIfNotInTransactionAsync<T>(
28
- transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>
38
+ transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>,
39
+ transactionConfig?: TransactionConfig
29
40
  ): Promise<T>;
30
41
  }
31
42
 
@@ -48,9 +59,13 @@ export class EntityNonTransactionalQueryContext extends EntityQueryContext {
48
59
  }
49
60
 
50
61
  async runInTransactionIfNotInTransactionAsync<T>(
51
- transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>
62
+ transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>,
63
+ transactionConfig?: TransactionConfig
52
64
  ): Promise<T> {
53
- return await this.entityQueryContextProvider.runInTransactionAsync(transactionScope);
65
+ return await this.entityQueryContextProvider.runInTransactionAsync(
66
+ transactionScope,
67
+ transactionConfig
68
+ );
54
69
  }
55
70
  }
56
71
 
@@ -132,8 +147,13 @@ export class EntityTransactionalQueryContext extends EntityQueryContext {
132
147
  }
133
148
 
134
149
  async runInTransactionIfNotInTransactionAsync<T>(
135
- transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>
150
+ transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>,
151
+ transactionConfig?: TransactionConfig
136
152
  ): Promise<T> {
153
+ assert(
154
+ transactionConfig === undefined,
155
+ 'Should not pass transactionConfig to a nested transaction'
156
+ );
137
157
  return await transactionScope(this);
138
158
  }
139
159
 
@@ -2,6 +2,7 @@ import {
2
2
  EntityTransactionalQueryContext,
3
3
  EntityNonTransactionalQueryContext,
4
4
  EntityNestedTransactionalQueryContext,
5
+ TransactionConfig,
5
6
  } from './EntityQueryContext';
6
7
 
7
8
  /**
@@ -23,9 +24,9 @@ export default abstract class EntityQueryContextProvider {
23
24
  /**
24
25
  * Vend a transaction runner for use in runInTransactionAsync.
25
26
  */
26
- protected abstract createTransactionRunner<T>(): (
27
- transactionScope: (queryInterface: any) => Promise<T>
28
- ) => Promise<T>;
27
+ protected abstract createTransactionRunner<T>(
28
+ transactionConfig?: TransactionConfig
29
+ ): (transactionScope: (queryInterface: any) => Promise<T>) => Promise<T>;
29
30
 
30
31
  protected abstract createNestedTransactionRunner<T>(
31
32
  outerQueryInterface: any
@@ -36,11 +37,12 @@ export default abstract class EntityQueryContextProvider {
36
37
  * @param transactionScope - async callback to execute within the transaction
37
38
  */
38
39
  async runInTransactionAsync<T>(
39
- transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>
40
+ transactionScope: (queryContext: EntityTransactionalQueryContext) => Promise<T>,
41
+ transactionConfig?: TransactionConfig
40
42
  ): Promise<T> {
41
43
  const [returnedValue, queryContext] = await this.createTransactionRunner<
42
44
  [T, EntityTransactionalQueryContext]
43
- >()(async (queryInterface) => {
45
+ >(transactionConfig)(async (queryInterface) => {
44
46
  const queryContext = new EntityTransactionalQueryContext(queryInterface, this);
45
47
  const result = await transactionScope(queryContext);
46
48
  await queryContext.runPreCommitCallbacksAsync();
@@ -45,7 +45,7 @@ export interface ISecondaryEntityCache<TFields, TLoadParams> {
45
45
  */
46
46
  export default abstract class EntitySecondaryCacheLoader<
47
47
  TLoadParams,
48
- TFields,
48
+ TFields extends object,
49
49
  TID extends NonNullable<TFields[TSelectedFields]>,
50
50
  TViewerContext extends ViewerContext,
51
51
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -0,0 +1,65 @@
1
+ import invariant from 'invariant';
2
+
3
+ import IEntityCacheAdapter from './IEntityCacheAdapter';
4
+ import IEntityGenericCacher from './IEntityGenericCacher';
5
+ import { CacheLoadResult } from './internal/ReadThroughEntityCache';
6
+ import { mapKeys } from './utils/collections/maps';
7
+
8
+ /**
9
+ * A standard IEntityCacheAdapter that coordinates caching through an IEntityGenericCacher.
10
+ */
11
+ export default class GenericEntityCacheAdapter<TFields> implements IEntityCacheAdapter<TFields> {
12
+ constructor(private readonly genericCacher: IEntityGenericCacher<TFields>) {}
13
+
14
+ public async loadManyAsync<N extends keyof TFields>(
15
+ fieldName: N,
16
+ fieldValues: readonly NonNullable<TFields[N]>[]
17
+ ): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>> {
18
+ const redisCacheKeyToFieldValueMapping = new Map(
19
+ fieldValues.map((fieldValue) => [
20
+ this.genericCacher.makeCacheKey(fieldName, fieldValue),
21
+ fieldValue,
22
+ ])
23
+ );
24
+ const cacheResults = await this.genericCacher.loadManyAsync(
25
+ Array.from(redisCacheKeyToFieldValueMapping.keys())
26
+ );
27
+
28
+ return mapKeys(cacheResults, (redisCacheKey) => {
29
+ const fieldValue = redisCacheKeyToFieldValueMapping.get(redisCacheKey);
30
+ invariant(
31
+ fieldValue !== undefined,
32
+ 'Unspecified cache key %s returned from generic cacher',
33
+ redisCacheKey
34
+ );
35
+ return fieldValue;
36
+ });
37
+ }
38
+
39
+ public async cacheManyAsync<N extends keyof TFields>(
40
+ fieldName: N,
41
+ objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
42
+ ): Promise<void> {
43
+ await this.genericCacher.cacheManyAsync(
44
+ mapKeys(objectMap, (fieldValue) => this.genericCacher.makeCacheKey(fieldName, fieldValue))
45
+ );
46
+ }
47
+
48
+ public async cacheDBMissesAsync<N extends keyof TFields>(
49
+ fieldName: N,
50
+ fieldValues: readonly NonNullable<TFields[N]>[]
51
+ ): Promise<void> {
52
+ await this.genericCacher.cacheDBMissesAsync(
53
+ fieldValues.map((fieldValue) => this.genericCacher.makeCacheKey(fieldName, fieldValue))
54
+ );
55
+ }
56
+
57
+ public async invalidateManyAsync<N extends keyof TFields>(
58
+ fieldName: N,
59
+ fieldValues: readonly NonNullable<TFields[N]>[]
60
+ ): Promise<void> {
61
+ await this.genericCacher.invalidateManyAsync(
62
+ fieldValues.map((fieldValue) => this.genericCacher.makeCacheKey(fieldName, fieldValue))
63
+ );
64
+ }
65
+ }
@@ -1,20 +1,17 @@
1
- import EntityConfiguration from './EntityConfiguration';
2
1
  import { CacheLoadResult } from './internal/ReadThroughEntityCache';
3
2
 
4
3
  /**
5
4
  * A cache adapter is an interface by which objects can be
6
5
  * cached, fetched from cache, and removed from cache (invalidated).
7
6
  */
8
- export default abstract class EntityCacheAdapter<TFields> {
9
- constructor(protected readonly entityConfiguration: EntityConfiguration<TFields>) {}
10
-
7
+ export default interface IEntityCacheAdapter<TFields> {
11
8
  /**
12
9
  * Load many objects from cache.
13
10
  * @param fieldName - object field being queried
14
11
  * @param fieldValues - fieldName field values being queried
15
12
  * @returns map from all field values to a CacheLoadResult for each input value
16
13
  */
17
- public abstract loadManyAsync<N extends keyof TFields>(
14
+ loadManyAsync<N extends keyof TFields>(
18
15
  fieldName: N,
19
16
  fieldValues: readonly NonNullable<TFields[N]>[]
20
17
  ): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>>;
@@ -24,7 +21,7 @@ export default abstract class EntityCacheAdapter<TFields> {
24
21
  * @param fieldName - object field being queried
25
22
  * @param objectMap - map from field value to object to cache
26
23
  */
27
- public abstract cacheManyAsync<N extends keyof TFields>(
24
+ cacheManyAsync<N extends keyof TFields>(
28
25
  fieldName: N,
29
26
  objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
30
27
  ): Promise<void>;
@@ -35,7 +32,7 @@ export default abstract class EntityCacheAdapter<TFields> {
35
32
  * @param fieldValues - fieldValues for objects reported as CacheStatus.NEGATIVE
36
33
  * in the cache and not found in the DB.
37
34
  */
38
- public abstract cacheDBMissesAsync<N extends keyof TFields>(
35
+ cacheDBMissesAsync<N extends keyof TFields>(
39
36
  fieldName: N,
40
37
  fieldValues: readonly NonNullable<TFields[N]>[]
41
38
  ): Promise<void>;
@@ -45,7 +42,7 @@ export default abstract class EntityCacheAdapter<TFields> {
45
42
  * @param fieldName - object field being queried
46
43
  * @param fieldValues - fieldName field values to be invalidated
47
44
  */
48
- public abstract invalidateManyAsync<N extends keyof TFields>(
45
+ invalidateManyAsync<N extends keyof TFields>(
49
46
  fieldName: N,
50
47
  fieldValues: readonly NonNullable<TFields[N]>[]
51
48
  ): Promise<void>;