@expo/entity 0.31.1 → 0.33.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 +10 -2
  27. package/build/EntityLoader.js +32 -7
  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 +28 -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 +22 -12
  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 +10 -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 +36 -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 +44 -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 +14 -1
  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
@@ -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>;
@@ -1,5 +1,5 @@
1
- import EntityCacheAdapter from './EntityCacheAdapter';
2
1
  import EntityConfiguration from './EntityConfiguration';
2
+ import IEntityCacheAdapter from './IEntityCacheAdapter';
3
3
 
4
4
  /**
5
5
  * A cache adapter provider vends cache adapters for a particular cache adapter type.
@@ -11,5 +11,5 @@ export default interface IEntityCacheAdapterProvider {
11
11
  */
12
12
  getCacheAdapter<TFields>(
13
13
  entityConfiguration: EntityConfiguration<TFields>
14
- ): EntityCacheAdapter<TFields>;
14
+ ): IEntityCacheAdapter<TFields>;
15
15
  }
@@ -1,15 +1,45 @@
1
1
  import { CacheLoadResult } from './internal/ReadThroughEntityCache';
2
2
 
3
3
  /**
4
- * A cacher stores and loads key-value pairs. It also supports negative caching - it stores the absence
5
- * of keys that don't exist in the backing datastore.
4
+ * A generic cacher stores and loads key-value pairs. It also supports negative caching - it stores the absence
5
+ * of keys that don't exist in the backing datastore. It is also responsible for cache key creation.
6
6
  */
7
7
  export default interface IEntityGenericCacher<TFields> {
8
+ /**
9
+ * Load many keys from the cache. Return info in a format that is useful for read-through caching and
10
+ * negative caching.
11
+ *
12
+ * @param keys - cache keys to load
13
+ */
8
14
  loadManyAsync(keys: readonly string[]): Promise<ReadonlyMap<string, CacheLoadResult<TFields>>>;
9
15
 
16
+ /**
17
+ * Cache many objects for specified keys.
18
+ *
19
+ * @param objectMap - map from cache key to object to cache for key
20
+ */
10
21
  cacheManyAsync(objectMap: ReadonlyMap<string, Readonly<TFields>>): Promise<void>;
11
22
 
23
+ /**
24
+ * Negatively-cache specified keys. Subsequent loads for these keys (without calling invalidate) may
25
+ * return a negative CacheLoadResult
26
+ *
27
+ * @param keys - keys to cache negatively
28
+ */
12
29
  cacheDBMissesAsync(keys: readonly string[]): Promise<void>;
13
30
 
31
+ /**
32
+ * Invalidate specified keys in cache. Subsequent loads for these keys may return a cache miss.
33
+ *
34
+ * @param keys - keys to invalidate
35
+ */
14
36
  invalidateManyAsync(keys: readonly string[]): Promise<void>;
37
+
38
+ /**
39
+ * Create a cache key for a field and value of a object being cached or invalidated.
40
+ *
41
+ * @param fieldName - name of the object field for this cache key
42
+ * @param fieldValue - value of the obejct field for this cache key
43
+ */
44
+ makeCacheKey<N extends keyof TFields>(fieldName: N, fieldValue: NonNullable<TFields[N]>): string;
15
45
  }
@@ -2,12 +2,10 @@ import invariant from 'invariant';
2
2
 
3
3
  import { IEntityClass } from './Entity';
4
4
  import EntityAssociationLoader from './EntityAssociationLoader';
5
- import { EntityCompanionDefinition } from './EntityCompanionProvider';
6
5
  import EntityLoader from './EntityLoader';
7
6
  import EntityPrivacyPolicy from './EntityPrivacyPolicy';
8
7
  import { EntityQueryContext } from './EntityQueryContext';
9
8
  import ViewerContext from './ViewerContext';
10
- import { pick } from './entityUtils';
11
9
 
12
10
  /**
13
11
  * A readonly entity exposes only the read functionality of an Entity. Used as the base
@@ -18,45 +16,47 @@ import { pick } from './entityUtils';
18
16
  * - Entities representing immutable tables.
19
17
  */
20
18
  export default abstract class ReadonlyEntity<
21
- TFields,
19
+ TFields extends object,
22
20
  TID extends NonNullable<TFields[TSelectedFields]>,
23
21
  TViewerContext extends ViewerContext,
24
22
  TSelectedFields extends keyof TFields = keyof TFields
25
23
  > {
24
+ private readonly viewerContext: TViewerContext;
26
25
  private readonly id: TID;
27
- private readonly rawFields: Readonly<Pick<TFields, TSelectedFields>>;
26
+ private readonly databaseFields: Readonly<TFields>;
27
+ private readonly selectedFields: Readonly<Pick<TFields, TSelectedFields>>;
28
28
 
29
29
  /**
30
30
  * Constructs an instance of an Entity.
31
- * @param viewerContext - the ViewerContext reading this entity
32
- * @param rawFields - all underlying fields for this entity's data
31
+ *
32
+ * @param constructorParam - data needed to construct an instance of an entity
33
+ * viewerContext - the ViewerContext reading this entity
34
+ * id - the ID of this entity
35
+ * databaseFields - all underlying fields for this entity's data
36
+ * selectedFields - selected fields for this entity from TSelectedFields type
37
+ *
38
+ * This should only be overridden in cases where additional data validation is needed.
39
+ * The params should not be modified when calling super during constructions.
33
40
  *
34
41
  * @internal
35
42
  */
36
- constructor(
37
- private readonly viewerContext: TViewerContext,
38
- private readonly databaseFields: Readonly<TFields>
39
- ) {
40
- const companionDefinition = (
41
- this.constructor as any
42
- ).getCompanionDefinition() as EntityCompanionDefinition<
43
- TFields,
44
- TID,
45
- TViewerContext,
46
- this,
47
- EntityPrivacyPolicy<TFields, TID, TViewerContext, this, TSelectedFields>,
48
- TSelectedFields
49
- >;
50
- const idField = companionDefinition.entityConfiguration.idField as keyof Pick<
51
- TFields,
52
- TSelectedFields
53
- >;
54
- const id = databaseFields[idField];
55
- invariant(id, 'must provide ID to create an entity');
56
- this.id = id as any;
43
+ constructor({
44
+ viewerContext,
45
+ id,
46
+ databaseFields,
47
+ selectedFields,
48
+ }: {
49
+ viewerContext: TViewerContext;
50
+ id: TID;
51
+ databaseFields: Readonly<TFields>;
52
+ selectedFields: Readonly<Pick<TFields, TSelectedFields>>;
53
+ }) {
54
+ invariant(id !== null && id !== undefined, 'id must be non-null');
57
55
 
58
- const entitySelectedFields = companionDefinition.entitySelectedFields as (keyof TFields)[];
59
- this.rawFields = pick(databaseFields, entitySelectedFields);
56
+ this.viewerContext = viewerContext;
57
+ this.id = id;
58
+ this.databaseFields = databaseFields;
59
+ this.selectedFields = selectedFields;
60
60
  }
61
61
 
62
62
  toString(): string {
@@ -102,14 +102,14 @@ export default abstract class ReadonlyEntity<
102
102
  getField<K extends keyof Pick<TFields, TSelectedFields>>(
103
103
  fieldName: K
104
104
  ): Pick<TFields, TSelectedFields>[K] {
105
- return this.rawFields[fieldName];
105
+ return this.selectedFields[fieldName];
106
106
  }
107
107
 
108
108
  /**
109
109
  * @returns all underlying fields from this entity's data
110
110
  */
111
111
  getAllFields(): Readonly<Pick<TFields, TSelectedFields>> {
112
- return { ...this.rawFields };
112
+ return { ...this.selectedFields };
113
113
  }
114
114
 
115
115
  /**
@@ -125,7 +125,7 @@ export default abstract class ReadonlyEntity<
125
125
  * @param queryContext - query context in which to perform the load
126
126
  */
127
127
  static loader<
128
- TMFields,
128
+ TMFields extends object,
129
129
  TMID extends NonNullable<TMFields[TMSelectedFields]>,
130
130
  TMViewerContext extends ViewerContext,
131
131
  TMViewerContext2 extends TMViewerContext,