@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
@@ -39,21 +39,25 @@ class CategoryPrivacyPolicy extends EntityPrivacyPolicy<
39
39
  // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
40
40
  const makeEntityClass = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) => {
41
41
  class CategoryEntity extends Entity<CategoryFields, string, TestViewerContext> {
42
- static getCompanionDefinition(): EntityCompanionDefinition<
42
+ static defineCompanionDefinition(): EntityCompanionDefinition<
43
43
  CategoryFields,
44
44
  string,
45
45
  TestViewerContext,
46
46
  CategoryEntity,
47
47
  CategoryPrivacyPolicy
48
48
  > {
49
- return categoryEntityCompanion;
49
+ return {
50
+ entityClass: CategoryEntity,
51
+ entityConfiguration: categoryEntityConfiguration,
52
+ privacyPolicyClass: CategoryPrivacyPolicy,
53
+ };
50
54
  }
51
55
  }
52
56
 
53
57
  const categoryEntityConfiguration = new EntityConfiguration<CategoryFields>({
54
58
  idField: 'id',
55
59
  tableName: 'categories',
56
- getInboundEdges: () => [CategoryEntity],
60
+ inboundEdges: [CategoryEntity],
57
61
  schema: {
58
62
  id: new UUIDField({
59
63
  columnName: 'id',
@@ -63,7 +67,7 @@ const makeEntityClass = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) => {
63
67
  columnName: 'parent_category_id',
64
68
  cache: true,
65
69
  association: {
66
- getAssociatedEntityClass: () => CategoryEntity,
70
+ associatedEntityClass: CategoryEntity,
67
71
  edgeDeletionBehavior,
68
72
  },
69
73
  }),
@@ -72,12 +76,6 @@ const makeEntityClass = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) => {
72
76
  cacheAdapterFlavor: 'redis',
73
77
  });
74
78
 
75
- const categoryEntityCompanion = new EntityCompanionDefinition({
76
- entityClass: CategoryEntity,
77
- entityConfiguration: categoryEntityConfiguration,
78
- privacyPolicyClass: CategoryPrivacyPolicy,
79
- });
80
-
81
79
  return {
82
80
  CategoryEntity,
83
81
  };
@@ -0,0 +1,102 @@
1
+ import { mock, when, instance, anything, verify, anyString, deepEqual } from 'ts-mockito';
2
+
3
+ import GenericEntityCacheAdapter from '../GenericEntityCacheAdapter';
4
+ import IEntityGenericCacher from '../IEntityGenericCacher';
5
+ import { CacheStatus } from '../internal/ReadThroughEntityCache';
6
+
7
+ type BlahFields = {
8
+ id: string;
9
+ };
10
+
11
+ describe(GenericEntityCacheAdapter, () => {
12
+ describe('loadManyAsync', () => {
13
+ it('returns appropriate cache results', async () => {
14
+ const mockGenericCacher = mock<IEntityGenericCacher<BlahFields>>();
15
+ when(mockGenericCacher.makeCacheKey('id', anyString())).thenCall((fieldName, fieldValue) => {
16
+ return `${fieldName}.${fieldValue}`;
17
+ });
18
+ when(mockGenericCacher.loadManyAsync(deepEqual(['id.wat', 'id.who', 'id.why']))).thenResolve(
19
+ new Map([
20
+ ['id.wat', { status: CacheStatus.HIT, item: { id: 'wat' } }],
21
+ ['id.who', { status: CacheStatus.NEGATIVE }],
22
+ ['id.why', { status: CacheStatus.MISS }],
23
+ ])
24
+ );
25
+
26
+ const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
27
+
28
+ const results = await cacheAdapter.loadManyAsync('id', ['wat', 'who', 'why']);
29
+ expect(results.get('wat')).toMatchObject({ status: CacheStatus.HIT, item: { id: 'wat' } });
30
+ expect(results.get('who')).toMatchObject({ status: CacheStatus.NEGATIVE });
31
+ expect(results.get('why')).toMatchObject({ status: CacheStatus.MISS });
32
+ expect(results.size).toBe(3);
33
+
34
+ verify(mockGenericCacher.loadManyAsync(anything())).once();
35
+ });
36
+
37
+ it('returns empty map when passed empty array of fieldValues', async () => {
38
+ const mockGenericCacher = mock<IEntityGenericCacher<BlahFields>>();
39
+ when(mockGenericCacher.loadManyAsync(deepEqual([]))).thenResolve(new Map([]));
40
+
41
+ const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
42
+ const results = await cacheAdapter.loadManyAsync('id', []);
43
+ expect(results).toEqual(new Map());
44
+ });
45
+ });
46
+
47
+ describe('cacheManyAsync', () => {
48
+ it('correctly caches all objects', async () => {
49
+ const mockGenericCacher = mock<IEntityGenericCacher<BlahFields>>();
50
+ when(mockGenericCacher.makeCacheKey('id', anyString())).thenCall((fieldName, fieldValue) => {
51
+ return `${fieldName}.${fieldValue}`;
52
+ });
53
+
54
+ const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
55
+ await cacheAdapter.cacheManyAsync('id', new Map([['wat', { id: 'wat' }]]));
56
+
57
+ verify(
58
+ mockGenericCacher.cacheManyAsync(deepEqual(new Map([['id.wat', { id: 'wat' }]])))
59
+ ).once();
60
+ });
61
+ });
62
+
63
+ describe('cacheDBMissesAsync', () => {
64
+ it('correctly caches misses', async () => {
65
+ const mockGenericCacher = mock<IEntityGenericCacher<BlahFields>>();
66
+ when(mockGenericCacher.makeCacheKey('id', anyString())).thenCall((fieldName, fieldValue) => {
67
+ return `${fieldName}.${fieldValue}`;
68
+ });
69
+
70
+ const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
71
+ await cacheAdapter.cacheDBMissesAsync('id', ['wat']);
72
+
73
+ verify(mockGenericCacher.cacheDBMissesAsync(deepEqual(['id.wat']))).once();
74
+ });
75
+ });
76
+
77
+ describe('invalidateManyAsync', () => {
78
+ it('invalidates correctly', async () => {
79
+ const mockGenericCacher = mock<IEntityGenericCacher<BlahFields>>();
80
+ when(mockGenericCacher.makeCacheKey('id', anyString())).thenCall((fieldName, fieldValue) => {
81
+ return `${fieldName}.${fieldValue}`;
82
+ });
83
+
84
+ const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
85
+ await cacheAdapter.invalidateManyAsync('id', ['wat']);
86
+
87
+ verify(mockGenericCacher.invalidateManyAsync(deepEqual(['id.wat']))).once();
88
+ });
89
+
90
+ it('returns when passed empty array of fieldValues', async () => {
91
+ const mockGenericCacher = mock<IEntityGenericCacher<BlahFields>>();
92
+ when(mockGenericCacher.makeCacheKey('id', anyString())).thenCall((fieldName, fieldValue) => {
93
+ return `${fieldName}.${fieldValue}`;
94
+ });
95
+
96
+ const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
97
+ await cacheAdapter.invalidateManyAsync('id', []);
98
+
99
+ verify(mockGenericCacher.invalidateManyAsync(deepEqual([]))).once();
100
+ });
101
+ });
102
+ });
@@ -15,7 +15,12 @@ describe(ReadonlyEntity, () => {
15
15
  const data = {
16
16
  id: 'what',
17
17
  };
18
- const testEntity = new SimpleTestEntity(viewerContext, data);
18
+ const testEntity = new SimpleTestEntity({
19
+ viewerContext,
20
+ id: 'what',
21
+ databaseFields: data,
22
+ selectedFields: data,
23
+ });
19
24
  expect(testEntity.getID()).toEqual('what');
20
25
  });
21
26
  });
@@ -26,7 +31,12 @@ describe(ReadonlyEntity, () => {
26
31
  const data = {
27
32
  id: 'what',
28
33
  };
29
- const testEntity = new SimpleTestEntity(viewerContext, data);
34
+ const testEntity = new SimpleTestEntity({
35
+ viewerContext,
36
+ id: 'what',
37
+ databaseFields: data,
38
+ selectedFields: data,
39
+ });
30
40
  expect(testEntity.toString()).toEqual('SimpleTestEntity[what]');
31
41
  });
32
42
  });
@@ -34,11 +44,25 @@ describe(ReadonlyEntity, () => {
34
44
  describe('getUniqueIdentifier', () => {
35
45
  it('returns a different value for two different entities of the same type', () => {
36
46
  const viewerContext = instance(mock(ViewerContext));
37
- const testEntity = new SimpleTestEntity(viewerContext, {
47
+ const testEntity = new SimpleTestEntity({
48
+ viewerContext,
38
49
  id: '1',
50
+ databaseFields: {
51
+ id: '1',
52
+ },
53
+ selectedFields: {
54
+ id: '1',
55
+ },
39
56
  });
40
- const testEntity2 = new SimpleTestEntity(viewerContext, {
57
+ const testEntity2 = new SimpleTestEntity({
58
+ viewerContext,
41
59
  id: '2',
60
+ databaseFields: {
61
+ id: '2',
62
+ },
63
+ selectedFields: {
64
+ id: '2',
65
+ },
42
66
  });
43
67
  expect(testEntity.getUniqueIdentifier()).not.toEqual(testEntity2.getUniqueIdentifier());
44
68
  });
@@ -47,22 +71,43 @@ describe(ReadonlyEntity, () => {
47
71
  const viewerContext = instance(mock(ViewerContext));
48
72
  const viewerContext2 = instance(mock(ViewerContext));
49
73
  const data = { id: '1' };
50
- const testEntity = new SimpleTestEntity(viewerContext, data);
51
- const testEntity2 = new SimpleTestEntity(viewerContext2, data);
74
+ const testEntity = new SimpleTestEntity({
75
+ viewerContext,
76
+ id: '1',
77
+ databaseFields: data,
78
+ selectedFields: data,
79
+ });
80
+ const testEntity2 = new SimpleTestEntity({
81
+ viewerContext: viewerContext2,
82
+ id: '1',
83
+ databaseFields: data,
84
+ selectedFields: data,
85
+ });
52
86
  expect(testEntity.getUniqueIdentifier()).toEqual(testEntity2.getUniqueIdentifier());
53
87
  });
54
88
 
55
89
  it('returns a different value for different entities even if same ID', () => {
56
90
  const viewerContext = instance(mock(ViewerContext));
57
91
  const data = { id: '1' };
58
- const testEntity = new SimpleTestEntity(viewerContext, data);
59
- const testEntity2 = new TestEntity(viewerContext, {
92
+ const testEntity = new SimpleTestEntity({
93
+ viewerContext,
94
+ id: 'what',
95
+ databaseFields: data,
96
+ selectedFields: data,
97
+ });
98
+ const data2 = {
60
99
  customIdField: '1',
61
100
  testIndexedField: '2',
62
101
  stringField: '3',
63
102
  intField: 4,
64
103
  dateField: new Date(),
65
104
  nullableField: null,
105
+ };
106
+ const testEntity2 = new TestEntity({
107
+ viewerContext,
108
+ id: '1',
109
+ databaseFields: data2,
110
+ selectedFields: data2,
66
111
  });
67
112
  expect(testEntity.getUniqueIdentifier()).not.toEqual(testEntity2.getUniqueIdentifier());
68
113
  });
@@ -72,16 +117,27 @@ describe(ReadonlyEntity, () => {
72
117
  const viewerContext = instance(mock(ViewerContext));
73
118
  const dataWithoutID = {};
74
119
  expect(() => {
75
- new SimpleTestEntity(viewerContext, dataWithoutID as any); // eslint-disable-line no-new
120
+ // eslint-disable-next-line no-new
121
+ new SimpleTestEntity({
122
+ viewerContext,
123
+ id: undefined as any,
124
+ databaseFields: dataWithoutID as any,
125
+ selectedFields: dataWithoutID as any,
126
+ });
76
127
  }).toThrow();
77
128
  });
78
129
 
79
- it('returns correct viewerContext from instantiation', () => {
130
+ it('returns correct viewerCo}ntext from instantiation', () => {
80
131
  const viewerContext = instance(mock(ViewerContext));
81
132
  const data = {
82
133
  id: 'what',
83
134
  };
84
- const testEntity = new SimpleTestEntity(viewerContext, data);
135
+ const testEntity = new SimpleTestEntity({
136
+ viewerContext,
137
+ id: 'what',
138
+ databaseFields: data,
139
+ selectedFields: data,
140
+ });
85
141
  expect(testEntity.getViewerContext()).toBe(viewerContext);
86
142
  });
87
143
 
@@ -90,7 +146,12 @@ describe(ReadonlyEntity, () => {
90
146
  const data = {
91
147
  id: 'what',
92
148
  };
93
- const testEntity = new SimpleTestEntity(viewerContext, data);
149
+ const testEntity = new SimpleTestEntity({
150
+ viewerContext,
151
+ id: 'what',
152
+ databaseFields: data,
153
+ selectedFields: data,
154
+ });
94
155
  expect(testEntity.getField('id')).toEqual('what');
95
156
  expect(testEntity.getAllFields()).toEqual(data);
96
157
  });
@@ -102,7 +163,12 @@ describe(ReadonlyEntity, () => {
102
163
  const data = {
103
164
  id: 'what',
104
165
  };
105
- const testEntity = new SimpleTestEntity(viewerContext, data);
166
+ const testEntity = new SimpleTestEntity({
167
+ viewerContext,
168
+ id: 'what',
169
+ databaseFields: data,
170
+ selectedFields: data,
171
+ });
106
172
  expect(testEntity.associationLoader()).toBeInstanceOf(EntityAssociationLoader);
107
173
  });
108
174
  });
@@ -4,7 +4,7 @@ import EntityCompanionProvider from '../EntityCompanionProvider';
4
4
  import ViewerContext from '../ViewerContext';
5
5
  import ViewerScopedEntityCompanion from '../ViewerScopedEntityCompanion';
6
6
  import ViewerScopedEntityCompanionProvider from '../ViewerScopedEntityCompanionProvider';
7
- import TestEntity, { testEntityCompanion } from '../testfixtures/TestEntity';
7
+ import TestEntity from '../testfixtures/TestEntity';
8
8
 
9
9
  describe(ViewerScopedEntityCompanionProvider, () => {
10
10
  it('returns viewer scoped entity companion', () => {
@@ -15,10 +15,7 @@ describe(ViewerScopedEntityCompanionProvider, () => {
15
15
  vc
16
16
  );
17
17
  expect(
18
- viewerScopedEntityCompanionProvider.getViewerScopedCompanionForEntity(
19
- TestEntity,
20
- testEntityCompanion
21
- )
18
+ viewerScopedEntityCompanionProvider.getViewerScopedCompanionForEntity(TestEntity)
22
19
  ).toBeInstanceOf(ViewerScopedEntityCompanion);
23
20
  });
24
21
  });
@@ -122,14 +122,19 @@ class TestEntityPrivacyPolicy extends EntityPrivacyPolicy<any, string, ViewerCon
122
122
  }
123
123
 
124
124
  class OneTestEntity extends Entity<TestFields, string, ViewerContext, OneTestFields> {
125
- constructor(viewerContext: ViewerContext, rawFields: Readonly<TestFields>) {
126
- if (rawFields.entity_type !== EntityType.ONE) {
125
+ constructor(constructorParams: {
126
+ viewerContext: ViewerContext;
127
+ id: string;
128
+ databaseFields: Readonly<TestFields>;
129
+ selectedFields: Readonly<Pick<TestFields, OneTestFields>>;
130
+ }) {
131
+ if (constructorParams.selectedFields.entity_type !== EntityType.ONE) {
127
132
  throw new Error('OneTestEntity must be instantiated with one data');
128
133
  }
129
- super(viewerContext, rawFields);
134
+ super(constructorParams);
130
135
  }
131
136
 
132
- static getCompanionDefinition(): EntityCompanionDefinition<
137
+ static defineCompanionDefinition(): EntityCompanionDefinition<
133
138
  TestFields,
134
139
  string,
135
140
  ViewerContext,
@@ -137,19 +142,29 @@ class OneTestEntity extends Entity<TestFields, string, ViewerContext, OneTestFie
137
142
  TestEntityPrivacyPolicy,
138
143
  OneTestFields
139
144
  > {
140
- return oneTestEntityCompanion;
145
+ return {
146
+ entityClass: OneTestEntity,
147
+ entityConfiguration: testEntityConfiguration,
148
+ privacyPolicyClass: TestEntityPrivacyPolicy,
149
+ entitySelectedFields: ['id', 'entity_type', 'common_other_field'],
150
+ };
141
151
  }
142
152
  }
143
153
 
144
154
  class TwoTestEntity extends Entity<TestFields, string, ViewerContext, TwoTestFields> {
145
- constructor(viewerContext: ViewerContext, rawFields: Readonly<TestFields>) {
146
- if (rawFields.entity_type !== EntityType.TWO) {
155
+ constructor(constructorParams: {
156
+ viewerContext: ViewerContext;
157
+ id: string;
158
+ databaseFields: Readonly<TestFields>;
159
+ selectedFields: Readonly<Pick<TestFields, TwoTestFields>>;
160
+ }) {
161
+ if (constructorParams.selectedFields.entity_type !== EntityType.TWO) {
147
162
  throw new Error('TwoTestEntity must be instantiated with two data');
148
163
  }
149
- super(viewerContext, rawFields);
164
+ super(constructorParams);
150
165
  }
151
166
 
152
- static getCompanionDefinition(): EntityCompanionDefinition<
167
+ static defineCompanionDefinition(): EntityCompanionDefinition<
153
168
  TestFields,
154
169
  string,
155
170
  ViewerContext,
@@ -157,20 +172,11 @@ class TwoTestEntity extends Entity<TestFields, string, ViewerContext, TwoTestFie
157
172
  TestEntityPrivacyPolicy,
158
173
  TwoTestFields
159
174
  > {
160
- return twoTestEntityCompanion;
175
+ return {
176
+ entityClass: TwoTestEntity,
177
+ entityConfiguration: testEntityConfiguration,
178
+ privacyPolicyClass: TestEntityPrivacyPolicy,
179
+ entitySelectedFields: ['id', 'other_field', 'common_other_field', 'entity_type'],
180
+ };
161
181
  }
162
182
  }
163
-
164
- const oneTestEntityCompanion = new EntityCompanionDefinition({
165
- entityClass: OneTestEntity,
166
- entityConfiguration: testEntityConfiguration,
167
- privacyPolicyClass: TestEntityPrivacyPolicy,
168
- entitySelectedFields: ['id', 'entity_type', 'common_other_field'],
169
- });
170
-
171
- const twoTestEntityCompanion = new EntityCompanionDefinition({
172
- entityClass: TwoTestEntity,
173
- entityConfiguration: testEntityConfiguration,
174
- privacyPolicyClass: TestEntityPrivacyPolicy,
175
- entitySelectedFields: ['id', 'other_field', 'common_other_field', 'entity_type'],
176
- });
@@ -130,7 +130,7 @@ class TestEntityPrivacyPolicy extends EntityPrivacyPolicy<any, string, ViewerCon
130
130
  }
131
131
 
132
132
  class OneTestEntity extends Entity<TestFields, string, ViewerContext, OneTestFields> {
133
- static getCompanionDefinition(): EntityCompanionDefinition<
133
+ static defineCompanionDefinition(): EntityCompanionDefinition<
134
134
  TestFields,
135
135
  string,
136
136
  ViewerContext,
@@ -138,12 +138,17 @@ class OneTestEntity extends Entity<TestFields, string, ViewerContext, OneTestFie
138
138
  TestEntityPrivacyPolicy,
139
139
  OneTestFields
140
140
  > {
141
- return oneTestEntityCompanion;
141
+ return {
142
+ entityClass: OneTestEntity,
143
+ entityConfiguration: testEntityConfiguration,
144
+ privacyPolicyClass: TestEntityPrivacyPolicy,
145
+ entitySelectedFields: ['id', 'fake_field'],
146
+ };
142
147
  }
143
148
  }
144
149
 
145
150
  class TwoTestEntity extends Entity<TestFields, string, ViewerContext, TwoTestFields> {
146
- static getCompanionDefinition(): EntityCompanionDefinition<
151
+ static defineCompanionDefinition(): EntityCompanionDefinition<
147
152
  TestFields,
148
153
  string,
149
154
  ViewerContext,
@@ -151,20 +156,11 @@ class TwoTestEntity extends Entity<TestFields, string, ViewerContext, TwoTestFie
151
156
  TestEntityPrivacyPolicy,
152
157
  TwoTestFields
153
158
  > {
154
- return twoTestEntityCompanion;
159
+ return {
160
+ entityClass: TwoTestEntity,
161
+ entityConfiguration: testEntityConfiguration,
162
+ privacyPolicyClass: TestEntityPrivacyPolicy,
163
+ entitySelectedFields: ['id', 'other_field', 'fake_field'],
164
+ };
155
165
  }
156
166
  }
157
-
158
- const oneTestEntityCompanion = new EntityCompanionDefinition({
159
- entityClass: OneTestEntity,
160
- entityConfiguration: testEntityConfiguration,
161
- privacyPolicyClass: TestEntityPrivacyPolicy,
162
- entitySelectedFields: ['id', 'fake_field'],
163
- });
164
-
165
- const twoTestEntityCompanion = new EntityCompanionDefinition({
166
- entityClass: TwoTestEntity,
167
- entityConfiguration: testEntityConfiguration,
168
- privacyPolicyClass: TestEntityPrivacyPolicy,
169
- entitySelectedFields: ['id', 'other_field', 'fake_field'],
170
- });
@@ -1,11 +1,11 @@
1
+ import EntityError, { EntityErrorCode, EntityErrorState } from './EntityError';
1
2
  import { IEntityClass } from '../Entity';
2
3
  import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
3
4
  import ReadonlyEntity from '../ReadonlyEntity';
4
5
  import ViewerContext from '../ViewerContext';
5
- import EntityError, { EntityErrorCode, EntityErrorState } from './EntityError';
6
6
 
7
7
  export default class EntityInvalidFieldValueError<
8
- TFields,
8
+ TFields extends object,
9
9
  TID extends NonNullable<TFields[TSelectedFields]>,
10
10
  TViewerContext extends ViewerContext,
11
11
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -1,10 +1,10 @@
1
+ import EntityError, { EntityErrorCode, EntityErrorState } from './EntityError';
1
2
  import { EntityAuthorizationAction } from '../EntityPrivacyPolicy';
2
3
  import ReadonlyEntity from '../ReadonlyEntity';
3
4
  import ViewerContext from '../ViewerContext';
4
- import EntityError, { EntityErrorCode, EntityErrorState } from './EntityError';
5
5
 
6
6
  export default class EntityNotAuthorizedError<
7
- TFields,
7
+ TFields extends object,
8
8
  TID extends NonNullable<TFields[TSelectedFields]>,
9
9
  TViewerContext extends ViewerContext,
10
10
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
@@ -1,11 +1,11 @@
1
+ import EntityError, { EntityErrorCode, EntityErrorState } from './EntityError';
1
2
  import { IEntityClass } from '../Entity';
2
3
  import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
3
4
  import ReadonlyEntity from '../ReadonlyEntity';
4
5
  import ViewerContext from '../ViewerContext';
5
- import EntityError, { EntityErrorCode, EntityErrorState } from './EntityError';
6
6
 
7
7
  export default class EntityNotFoundError<
8
- TFields,
8
+ TFields extends object,
9
9
  TID extends NonNullable<TFields[TSelectedFields]>,
10
10
  TViewerContext extends ViewerContext,
11
11
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
package/src/index.ts CHANGED
@@ -12,7 +12,8 @@ export { default as Entity } from './Entity';
12
12
  export * from './Entity';
13
13
  export { default as EntityAssociationLoader } from './EntityAssociationLoader';
14
14
  export * from './EntityAssociationLoader';
15
- export { default as EntityCacheAdapter } from './EntityCacheAdapter';
15
+ export { default as IEntityCacheAdapter } from './IEntityCacheAdapter';
16
+ export { default as GenericEntityCacheAdapter } from './GenericEntityCacheAdapter';
16
17
  export { default as EntityCompanion } from './EntityCompanion';
17
18
  export * from './EntityCompanion';
18
19
  export { default as EntityCompanionProvider } from './EntityCompanionProvider';
@@ -1,5 +1,6 @@
1
1
  import DataLoader from 'dataloader';
2
2
 
3
+ import ReadThroughEntityCache from './ReadThroughEntityCache';
3
4
  import EntityDatabaseAdapter, {
4
5
  FieldEqualityCondition,
5
6
  QuerySelectionModifiers,
@@ -17,7 +18,6 @@ import IEntityMetricsAdapter, {
17
18
  IncrementLoadCountEventType,
18
19
  } from '../metrics/IEntityMetricsAdapter';
19
20
  import { computeIfAbsent, zipToMap } from '../utils/collections/maps';
20
- import ReadThroughEntityCache from './ReadThroughEntityCache';
21
21
 
22
22
  /**
23
23
  * A data manager is responsible for orchestrating multiple sources of entity
@@ -1,12 +1,12 @@
1
- import EntityCacheAdapter from '../EntityCacheAdapter';
1
+ import EntityDataManager from './EntityDataManager';
2
+ import ReadThroughEntityCache from './ReadThroughEntityCache';
2
3
  import EntityConfiguration from '../EntityConfiguration';
3
4
  import EntityDatabaseAdapter from '../EntityDatabaseAdapter';
4
5
  import EntityQueryContextProvider from '../EntityQueryContextProvider';
6
+ import IEntityCacheAdapter from '../IEntityCacheAdapter';
5
7
  import IEntityCacheAdapterProvider from '../IEntityCacheAdapterProvider';
6
8
  import IEntityDatabaseAdapterProvider from '../IEntityDatabaseAdapterProvider';
7
9
  import IEntityMetricsAdapter from '../metrics/IEntityMetricsAdapter';
8
- import EntityDataManager from './EntityDataManager';
9
- import ReadThroughEntityCache from './ReadThroughEntityCache';
10
10
 
11
11
  /**
12
12
  * Responsible for orchestrating fetching and caching of entity data from a
@@ -15,7 +15,7 @@ import ReadThroughEntityCache from './ReadThroughEntityCache';
15
15
  */
16
16
  export default class EntityTableDataCoordinator<TFields> {
17
17
  readonly databaseAdapter: EntityDatabaseAdapter<TFields>;
18
- readonly cacheAdapter: EntityCacheAdapter<TFields>;
18
+ readonly cacheAdapter: IEntityCacheAdapter<TFields>;
19
19
  readonly dataManager: EntityDataManager<TFields>;
20
20
 
21
21
  constructor(
@@ -1,7 +1,7 @@
1
1
  import invariant from 'invariant';
2
2
 
3
- import EntityCacheAdapter from '../EntityCacheAdapter';
4
3
  import EntityConfiguration from '../EntityConfiguration';
4
+ import IEntityCacheAdapter from '../IEntityCacheAdapter';
5
5
  import { filterMap } from '../utils/collections/maps';
6
6
 
7
7
  export enum CacheStatus {
@@ -29,7 +29,7 @@ export type CacheLoadResult<TFields> =
29
29
  export default class ReadThroughEntityCache<TFields> {
30
30
  constructor(
31
31
  private readonly entityConfiguration: EntityConfiguration<TFields>,
32
- private readonly entityCacheAdapter: EntityCacheAdapter<TFields>
32
+ private readonly entityCacheAdapter: IEntityCacheAdapter<TFields>
33
33
  ) {}
34
34
 
35
35
  private isFieldCacheable<N extends keyof TFields>(fieldName: N): boolean {
@@ -385,7 +385,8 @@ describe(EntityDataManager, () => {
385
385
  return await entityDataManager.loadManyByFieldEqualingAsync(queryContext, 'customIdField', [
386
386
  '1',
387
387
  ]);
388
- }
388
+ },
389
+ {}
389
390
  );
390
391
 
391
392
  expect(entityDatas.get('1')).toHaveLength(1);