@expo/entity 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/build/AuthorizationResultBasedEntityLoader.d.ts +128 -0
  2. package/build/AuthorizationResultBasedEntityLoader.js +196 -0
  3. package/build/AuthorizationResultBasedEntityLoader.js.map +1 -0
  4. package/build/ComposedEntityCacheAdapter.js +1 -0
  5. package/build/ComposedEntityCacheAdapter.js.map +1 -1
  6. package/build/ComposedSecondaryEntityCache.js +1 -0
  7. package/build/ComposedSecondaryEntityCache.js.map +1 -1
  8. package/build/EnforcingEntityLoader.d.ts +5 -4
  9. package/build/EnforcingEntityLoader.js +4 -2
  10. package/build/EnforcingEntityLoader.js.map +1 -1
  11. package/build/Entity.d.ts +0 -27
  12. package/build/Entity.js +0 -50
  13. package/build/Entity.js.map +1 -1
  14. package/build/EntityAssociationLoader.d.ts +1 -1
  15. package/build/EntityAssociationLoader.js +17 -8
  16. package/build/EntityAssociationLoader.js.map +1 -1
  17. package/build/EntityCompanion.js +9 -1
  18. package/build/EntityCompanion.js.map +1 -1
  19. package/build/EntityCompanionProvider.d.ts +3 -1
  20. package/build/EntityCompanionProvider.js +10 -4
  21. package/build/EntityCompanionProvider.js.map +1 -1
  22. package/build/EntityConfiguration.d.ts +2 -1
  23. package/build/EntityConfiguration.js +19 -1
  24. package/build/EntityConfiguration.js.map +1 -1
  25. package/build/EntityDatabaseAdapter.d.ts +2 -2
  26. package/build/EntityDatabaseAdapter.js +5 -3
  27. package/build/EntityDatabaseAdapter.js.map +1 -1
  28. package/build/EntityFieldDefinition.d.ts +21 -10
  29. package/build/EntityFieldDefinition.js +8 -9
  30. package/build/EntityFieldDefinition.js.map +1 -1
  31. package/build/EntityFields.d.ts +10 -0
  32. package/build/EntityFields.js +15 -1
  33. package/build/EntityFields.js.map +1 -1
  34. package/build/EntityLoader.d.ts +12 -125
  35. package/build/EntityLoader.js +24 -239
  36. package/build/EntityLoader.js.map +1 -1
  37. package/build/EntityLoaderFactory.d.ts +1 -1
  38. package/build/EntityLoaderFactory.js +3 -0
  39. package/build/EntityLoaderFactory.js.map +1 -1
  40. package/build/EntityLoaderUtils.d.ts +58 -0
  41. package/build/EntityLoaderUtils.js +109 -0
  42. package/build/EntityLoaderUtils.js.map +1 -0
  43. package/build/EntityMutator.d.ts +1 -0
  44. package/build/EntityMutator.js +71 -56
  45. package/build/EntityMutator.js.map +1 -1
  46. package/build/EntityMutatorFactory.js +9 -0
  47. package/build/EntityMutatorFactory.js.map +1 -1
  48. package/build/EntityPrivacyPolicy.d.ts +11 -5
  49. package/build/EntityPrivacyPolicy.js +5 -7
  50. package/build/EntityPrivacyPolicy.js.map +1 -1
  51. package/build/EntityQueryContext.d.ts +2 -1
  52. package/build/EntityQueryContext.js +11 -6
  53. package/build/EntityQueryContext.js.map +1 -1
  54. package/build/EntitySecondaryCacheLoader.js +5 -1
  55. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  56. package/build/GenericEntityCacheAdapter.js +1 -0
  57. package/build/GenericEntityCacheAdapter.js.map +1 -1
  58. package/build/GenericSecondaryEntityCache.js +2 -0
  59. package/build/GenericSecondaryEntityCache.js.map +1 -1
  60. package/build/IEntityCacheAdapterProvider.d.ts +1 -1
  61. package/build/IEntityDatabaseAdapterProvider.d.ts +1 -1
  62. package/build/ReadonlyEntity.js +5 -1
  63. package/build/ReadonlyEntity.js.map +1 -1
  64. package/build/ViewerContext.js +2 -0
  65. package/build/ViewerContext.js.map +1 -1
  66. package/build/ViewerScopedEntityCompanion.js +2 -0
  67. package/build/ViewerScopedEntityCompanion.js.map +1 -1
  68. package/build/ViewerScopedEntityCompanionProvider.d.ts +0 -1
  69. package/build/ViewerScopedEntityCompanionProvider.js +2 -1
  70. package/build/ViewerScopedEntityCompanionProvider.js.map +1 -1
  71. package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
  72. package/build/ViewerScopedEntityLoaderFactory.js +2 -0
  73. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  74. package/build/ViewerScopedEntityMutatorFactory.js +2 -0
  75. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  76. package/build/__tests__/ComposedCacheAdapter-test.js +2 -0
  77. package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
  78. package/build/__tests__/ComposedSecondaryEntityCache-test.js +1 -0
  79. package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +1 -1
  80. package/build/__tests__/EnforcingEntityLoader-test.js +101 -113
  81. package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
  82. package/build/__tests__/Entity-test.js +0 -132
  83. package/build/__tests__/Entity-test.js.map +1 -1
  84. package/build/__tests__/EntityAssociationLoader-test.js +6 -2
  85. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  86. package/build/__tests__/EntityCommonUseCases-test.js +24 -22
  87. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  88. package/build/__tests__/EntityCompanion-test.js +26 -3
  89. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  90. package/build/__tests__/EntityConfiguration-test.js +103 -0
  91. package/build/__tests__/EntityConfiguration-test.js.map +1 -0
  92. package/build/__tests__/EntityDatabaseAdapter-test.js +6 -0
  93. package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
  94. package/build/__tests__/EntityEdges-test.js +61 -20
  95. package/build/__tests__/EntityEdges-test.js.map +1 -1
  96. package/build/__tests__/EntityFields-test.js +6 -0
  97. package/build/__tests__/EntityFields-test.js.map +1 -1
  98. package/build/__tests__/EntityLoader-constructor-test.js +16 -17
  99. package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
  100. package/build/__tests__/EntityLoader-test.js +74 -22
  101. package/build/__tests__/EntityLoader-test.js.map +1 -1
  102. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +12 -15
  103. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  104. package/build/__tests__/EntityMutator-test.js +54 -9
  105. package/build/__tests__/EntityMutator-test.js.map +1 -1
  106. package/build/__tests__/EntityPrivacyPolicy-test.js +77 -59
  107. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  108. package/build/__tests__/EntityQueryContext-test.js +9 -0
  109. package/build/__tests__/EntityQueryContext-test.js.map +1 -1
  110. package/build/__tests__/EntitySelfReferentialEdges-test.js +42 -25
  111. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  112. package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
  113. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +20 -18
  114. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  115. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +12 -15
  116. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  117. package/build/entityUtils.d.ts +1 -1
  118. package/build/entityUtils.js.map +1 -1
  119. package/build/errors/EntityCacheAdapterError.js +2 -5
  120. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  121. package/build/errors/EntityDatabaseAdapterError.js +14 -35
  122. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  123. package/build/errors/EntityError.js +1 -0
  124. package/build/errors/EntityError.js.map +1 -1
  125. package/build/errors/EntityInvalidFieldValueError.js +2 -2
  126. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  127. package/build/errors/EntityNotAuthorizedError.js +3 -2
  128. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  129. package/build/errors/EntityNotFoundError.js +2 -2
  130. package/build/errors/EntityNotFoundError.js.map +1 -1
  131. package/build/index.d.ts +26 -20
  132. package/build/index.js +38 -28
  133. package/build/index.js.map +1 -1
  134. package/build/internal/EntityDataManager.d.ts +1 -1
  135. package/build/internal/EntityDataManager.js +6 -1
  136. package/build/internal/EntityDataManager.js.map +1 -1
  137. package/build/internal/EntityFieldTransformationUtils.d.ts +5 -5
  138. package/build/internal/EntityFieldTransformationUtils.js +5 -8
  139. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  140. package/build/internal/EntityTableDataCoordinator.d.ts +1 -1
  141. package/build/internal/EntityTableDataCoordinator.js +5 -0
  142. package/build/internal/EntityTableDataCoordinator.js.map +1 -1
  143. package/build/internal/ReadThroughEntityCache.d.ts +1 -1
  144. package/build/internal/ReadThroughEntityCache.js +2 -0
  145. package/build/internal/ReadThroughEntityCache.js.map +1 -1
  146. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +6 -2
  147. package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
  148. package/build/internal/__tests__/ReadThroughEntityCache-test.js +33 -0
  149. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  150. package/build/metrics/IEntityMetricsAdapter.d.ts +1 -1
  151. package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +1 -1
  152. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  153. package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +1 -1
  154. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  155. package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +1 -1
  156. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  157. package/build/rules/PrivacyPolicyRule.d.ts +1 -1
  158. package/build/rules/PrivacyPolicyRule.js.map +1 -1
  159. package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
  160. package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
  161. package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
  162. package/build/testfixtures/DateIDTestEntity.js +12 -15
  163. package/build/testfixtures/DateIDTestEntity.js.map +1 -1
  164. package/build/testfixtures/SimpleTestEntity.js +12 -15
  165. package/build/testfixtures/SimpleTestEntity.js.map +1 -1
  166. package/build/testfixtures/TestEntity.js +12 -15
  167. package/build/testfixtures/TestEntity.js.map +1 -1
  168. package/build/testfixtures/TestEntity2.js +12 -15
  169. package/build/testfixtures/TestEntity2.js.map +1 -1
  170. package/build/testfixtures/TestEntityNumberKey.js +12 -15
  171. package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
  172. package/build/testfixtures/TestEntityWithMutationTriggers.d.ts +36 -0
  173. package/build/testfixtures/TestEntityWithMutationTriggers.js +82 -0
  174. package/build/testfixtures/TestEntityWithMutationTriggers.js.map +1 -0
  175. package/build/utils/EntityPrivacyUtils.d.ts +34 -0
  176. package/build/utils/EntityPrivacyUtils.js +160 -0
  177. package/build/utils/EntityPrivacyUtils.js.map +1 -0
  178. package/build/utils/__tests__/EntityPrivacyUtils-test.d.ts +1 -0
  179. package/build/utils/__tests__/EntityPrivacyUtils-test.js +395 -0
  180. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -0
  181. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.d.ts +1 -0
  182. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js +26 -0
  183. package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js.map +1 -0
  184. package/build/utils/collections/maps.js.map +1 -1
  185. package/build/utils/mergeEntityMutationTriggerConfigurations.d.ts +4 -0
  186. package/build/utils/mergeEntityMutationTriggerConfigurations.js +28 -0
  187. package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -0
  188. package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -1
  189. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
  190. package/build/utils/testing/StubCacheAdapter.d.ts +3 -3
  191. package/build/utils/testing/StubCacheAdapter.js +3 -3
  192. package/build/utils/testing/StubCacheAdapter.js.map +1 -1
  193. package/build/utils/testing/StubDatabaseAdapter.d.ts +2 -2
  194. package/build/utils/testing/StubDatabaseAdapter.js +4 -2
  195. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  196. package/build/utils/testing/StubDatabaseAdapterProvider.d.ts +1 -1
  197. package/build/utils/testing/StubDatabaseAdapterProvider.js +1 -3
  198. package/build/utils/testing/StubDatabaseAdapterProvider.js.map +1 -1
  199. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.d.ts +1 -0
  200. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js +42 -0
  201. package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js.map +1 -0
  202. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +53 -0
  203. package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
  204. package/build/utils/testing/describeFieldTestCase.js.map +1 -1
  205. package/package.json +5 -4
  206. package/src/AuthorizationResultBasedEntityLoader.ts +297 -0
  207. package/src/ComposedEntityCacheAdapter.ts +6 -6
  208. package/src/ComposedSecondaryEntityCache.ts +8 -8
  209. package/src/EnforcingEntityLoader.ts +20 -19
  210. package/src/Entity.ts +11 -126
  211. package/src/EntityAssociationLoader.ts +40 -41
  212. package/src/EntityCompanion.ts +8 -4
  213. package/src/EntityCompanionProvider.ts +24 -16
  214. package/src/EntityConfiguration.ts +18 -7
  215. package/src/EntityDatabaseAdapter.ts +41 -41
  216. package/src/EntityFieldDefinition.ts +28 -18
  217. package/src/EntityFields.ts +15 -0
  218. package/src/EntityLoader.ts +63 -357
  219. package/src/EntityLoaderFactory.ts +10 -4
  220. package/src/EntityLoaderUtils.ts +149 -0
  221. package/src/EntityMutationInfo.ts +2 -2
  222. package/src/EntityMutationTriggerConfiguration.ts +5 -5
  223. package/src/EntityMutationValidator.ts +2 -2
  224. package/src/EntityMutator.ts +146 -144
  225. package/src/EntityMutatorFactory.ts +8 -8
  226. package/src/EntityPrivacyPolicy.ts +78 -28
  227. package/src/EntityQueryContext.ts +14 -13
  228. package/src/EntityQueryContextProvider.ts +5 -5
  229. package/src/EntitySecondaryCacheLoader.ts +13 -11
  230. package/src/GenericEntityCacheAdapter.ts +10 -10
  231. package/src/GenericSecondaryEntityCache.ts +6 -6
  232. package/src/IEntityCacheAdapter.ts +4 -4
  233. package/src/IEntityCacheAdapterProvider.ts +2 -2
  234. package/src/IEntityDatabaseAdapterProvider.ts +2 -2
  235. package/src/ReadonlyEntity.ts +5 -5
  236. package/src/ViewerContext.ts +5 -5
  237. package/src/ViewerScopedEntityCompanion.ts +4 -4
  238. package/src/ViewerScopedEntityCompanionProvider.ts +4 -5
  239. package/src/ViewerScopedEntityLoaderFactory.ts +10 -4
  240. package/src/ViewerScopedEntityMutatorFactory.ts +5 -5
  241. package/src/__tests__/ComposedCacheAdapter-test.ts +12 -10
  242. package/src/__tests__/ComposedSecondaryEntityCache-test.ts +8 -8
  243. package/src/__tests__/EnforcingEntityLoader-test.ts +236 -159
  244. package/src/__tests__/Entity-test.ts +0 -202
  245. package/src/__tests__/EntityAssociationLoader-test.ts +29 -25
  246. package/src/__tests__/EntityCommonUseCases-test.ts +29 -13
  247. package/src/__tests__/EntityCompanion-test.ts +57 -5
  248. package/src/__tests__/EntityConfiguration-test.ts +118 -0
  249. package/src/__tests__/EntityDatabaseAdapter-test.ts +11 -11
  250. package/src/__tests__/EntityEdges-test.ts +108 -36
  251. package/src/__tests__/EntityFields-test.ts +14 -2
  252. package/src/__tests__/EntityLoader-constructor-test.ts +20 -7
  253. package/src/__tests__/EntityLoader-test.ts +214 -86
  254. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +2 -2
  255. package/src/__tests__/EntityMutator-test.ts +281 -96
  256. package/src/__tests__/EntityPrivacyPolicy-test.ts +166 -53
  257. package/src/__tests__/EntityQueryContext-test.ts +30 -12
  258. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
  259. package/src/__tests__/EntitySelfReferentialEdges-test.ts +46 -26
  260. package/src/__tests__/GenericEntityCacheAdapter-test.ts +2 -2
  261. package/src/__tests__/ViewerContext-test.ts +1 -1
  262. package/src/__tests__/ViewerScopedEntityCompanion-test.ts +2 -2
  263. package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +2 -2
  264. package/src/__tests__/ViewerScopedEntityLoaderFactory-test.ts +2 -1
  265. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +19 -19
  266. package/src/__tests__/entityUtils-test.ts +2 -2
  267. package/src/entityUtils.ts +4 -4
  268. package/src/errors/EntityError.ts +4 -1
  269. package/src/errors/EntityInvalidFieldValueError.ts +2 -2
  270. package/src/errors/EntityNotAuthorizedError.ts +3 -3
  271. package/src/errors/EntityNotFoundError.ts +2 -2
  272. package/src/index.ts +26 -20
  273. package/src/internal/EntityDataManager.ts +24 -24
  274. package/src/internal/EntityFieldTransformationUtils.ts +39 -32
  275. package/src/internal/EntityTableDataCoordinator.ts +3 -3
  276. package/src/internal/ReadThroughEntityCache.ts +9 -9
  277. package/src/internal/__tests__/EntityDataManager-test.ts +51 -51
  278. package/src/internal/__tests__/EntityFieldTransformationUtils-test.ts +14 -10
  279. package/src/internal/__tests__/ReadThroughEntityCache-test.ts +74 -18
  280. package/src/metrics/EntityMetricsUtils.ts +4 -4
  281. package/src/metrics/IEntityMetricsAdapter.ts +1 -1
  282. package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +9 -3
  283. package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +9 -3
  284. package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +9 -3
  285. package/src/rules/PrivacyPolicyRule.ts +9 -3
  286. package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -1
  287. package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -1
  288. package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -1
  289. package/src/testfixtures/TestEntity.ts +1 -1
  290. package/src/testfixtures/TestEntityWithMutationTriggers.ts +156 -0
  291. package/src/utils/EntityPrivacyUtils.ts +325 -0
  292. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +570 -0
  293. package/src/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.ts +29 -0
  294. package/src/utils/collections/__tests__/maps-test.ts +2 -2
  295. package/src/utils/collections/maps.ts +11 -11
  296. package/src/utils/mergeEntityMutationTriggerConfigurations.ts +44 -0
  297. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +25 -22
  298. package/src/utils/testing/StubCacheAdapter.ts +17 -15
  299. package/src/utils/testing/StubDatabaseAdapter.ts +35 -30
  300. package/src/utils/testing/StubDatabaseAdapterProvider.ts +2 -2
  301. package/src/utils/testing/StubQueryContextProvider.ts +2 -2
  302. package/src/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.ts +42 -0
  303. package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +111 -29
  304. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +2 -2
  305. package/src/utils/testing/describeFieldTestCase.ts +1 -1
  306. package/build/__tests__/EntityDataConfiguration-test.js +0 -68
  307. package/build/__tests__/EntityDataConfiguration-test.js.map +0 -1
  308. package/src/__tests__/EntityDataConfiguration-test.ts +0 -77
  309. /package/build/__tests__/{EntityDataConfiguration-test.d.ts → EntityConfiguration-test.d.ts} +0 -0
@@ -65,7 +65,7 @@ describe(EntityDataManager, () => {
65
65
  const objects = getObjects();
66
66
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
67
67
  testEntityConfiguration,
68
- objects
68
+ objects,
69
69
  );
70
70
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
71
71
  const cacheAdapterProvider = new NoCacheStubCacheAdapterProvider();
@@ -76,7 +76,7 @@ describe(EntityDataManager, () => {
76
76
  entityCache,
77
77
  StubQueryContextProvider,
78
78
  new NoOpEntityMetricsAdapter(),
79
- TestEntity.name
79
+ TestEntity.name,
80
80
  );
81
81
  const queryContext = StubQueryContextProvider.getQueryContext();
82
82
 
@@ -86,7 +86,7 @@ describe(EntityDataManager, () => {
86
86
  const entityDatas = await entityDataManager.loadManyByFieldEqualingAsync(
87
87
  queryContext,
88
88
  'customIdField',
89
- ['2']
89
+ ['2'],
90
90
  );
91
91
  expect(entityDatas.get('2')).toHaveLength(1);
92
92
 
@@ -98,7 +98,7 @@ describe(EntityDataManager, () => {
98
98
  const entityDatas2 = await entityDataManager.loadManyByFieldEqualingAsync(
99
99
  queryContext,
100
100
  'testIndexedField',
101
- ['unique2', 'unique3']
101
+ ['unique2', 'unique3'],
102
102
  );
103
103
  expect(entityDatas2.get('unique2')).toHaveLength(1);
104
104
  expect(entityDatas2.get('unique3')).toHaveLength(1);
@@ -113,7 +113,7 @@ describe(EntityDataManager, () => {
113
113
  const objects = getObjects();
114
114
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
115
115
  testEntityConfiguration,
116
- objects
116
+ objects,
117
117
  );
118
118
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
119
119
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -124,7 +124,7 @@ describe(EntityDataManager, () => {
124
124
  entityCache,
125
125
  StubQueryContextProvider,
126
126
  new NoOpEntityMetricsAdapter(),
127
- TestEntity.name
127
+ TestEntity.name,
128
128
  );
129
129
  const queryContext = StubQueryContextProvider.getQueryContext();
130
130
 
@@ -134,7 +134,7 @@ describe(EntityDataManager, () => {
134
134
  const entityDatas = await entityDataManager.loadManyByFieldEqualingAsync(
135
135
  queryContext,
136
136
  'customIdField',
137
- ['1']
137
+ ['1'],
138
138
  );
139
139
  expect(entityDatas.get('1')).toHaveLength(1);
140
140
 
@@ -146,7 +146,7 @@ describe(EntityDataManager, () => {
146
146
  const entityDatas2 = await entityDataManager.loadManyByFieldEqualingAsync(
147
147
  queryContext,
148
148
  'testIndexedField',
149
- ['unique2', 'unique3']
149
+ ['unique2', 'unique3'],
150
150
  );
151
151
  expect(entityDatas2.get('unique2')).toHaveLength(1);
152
152
  expect(entityDatas2.get('unique3')).toHaveLength(1);
@@ -161,7 +161,7 @@ describe(EntityDataManager, () => {
161
161
  const objects = getObjects();
162
162
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
163
163
  testEntityConfiguration,
164
- objects
164
+ objects,
165
165
  );
166
166
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
167
167
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -172,7 +172,7 @@ describe(EntityDataManager, () => {
172
172
  entityCache,
173
173
  StubQueryContextProvider,
174
174
  new NoOpEntityMetricsAdapter(),
175
- TestEntity.name
175
+ TestEntity.name,
176
176
  );
177
177
  const queryContext = StubQueryContextProvider.getQueryContext();
178
178
  // use second data manager to ensure that cache is hit instead of data loader
@@ -181,7 +181,7 @@ describe(EntityDataManager, () => {
181
181
  entityCache,
182
182
  StubQueryContextProvider,
183
183
  new NoOpEntityMetricsAdapter(),
184
- TestEntity.name
184
+ TestEntity.name,
185
185
  );
186
186
 
187
187
  const dbSpy = jest.spyOn(databaseAdapter, 'fetchManyWhereAsync');
@@ -205,7 +205,7 @@ describe(EntityDataManager, () => {
205
205
  const objects = getObjects();
206
206
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
207
207
  testEntityConfiguration,
208
- objects
208
+ objects,
209
209
  );
210
210
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
211
211
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -216,7 +216,7 @@ describe(EntityDataManager, () => {
216
216
  entityCache,
217
217
  StubQueryContextProvider,
218
218
  new NoOpEntityMetricsAdapter(),
219
- TestEntity.name
219
+ TestEntity.name,
220
220
  );
221
221
  const queryContext = StubQueryContextProvider.getQueryContext();
222
222
 
@@ -241,7 +241,7 @@ describe(EntityDataManager, () => {
241
241
  const objects = getObjects();
242
242
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
243
243
  testEntityConfiguration,
244
- objects
244
+ objects,
245
245
  );
246
246
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
247
247
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -252,7 +252,7 @@ describe(EntityDataManager, () => {
252
252
  entityCache,
253
253
  StubQueryContextProvider,
254
254
  new NoOpEntityMetricsAdapter(),
255
- TestEntity.name
255
+ TestEntity.name,
256
256
  );
257
257
  const queryContext = StubQueryContextProvider.getQueryContext();
258
258
 
@@ -262,12 +262,12 @@ describe(EntityDataManager, () => {
262
262
  const entityData = await entityDataManager.loadManyByFieldEqualingAsync(
263
263
  queryContext,
264
264
  'stringField',
265
- ['hello', 'world']
265
+ ['hello', 'world'],
266
266
  );
267
267
  const entityData2 = await entityDataManager.loadManyByFieldEqualingAsync(
268
268
  queryContext,
269
269
  'stringField',
270
- ['hello', 'world']
270
+ ['hello', 'world'],
271
271
  );
272
272
 
273
273
  expect(dbSpy).toHaveBeenCalledTimes(1);
@@ -285,7 +285,7 @@ describe(EntityDataManager, () => {
285
285
  const objects = getObjects();
286
286
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
287
287
  testEntityConfiguration,
288
- objects
288
+ objects,
289
289
  );
290
290
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
291
291
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -296,7 +296,7 @@ describe(EntityDataManager, () => {
296
296
  entityCache,
297
297
  StubQueryContextProvider,
298
298
  new NoOpEntityMetricsAdapter(),
299
- TestEntity.name
299
+ TestEntity.name,
300
300
  );
301
301
  const queryContext = StubQueryContextProvider.getQueryContext();
302
302
 
@@ -324,7 +324,7 @@ describe(EntityDataManager, () => {
324
324
  const objects = getObjects();
325
325
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
326
326
  testEntityConfiguration,
327
- objects
327
+ objects,
328
328
  );
329
329
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
330
330
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -335,7 +335,7 @@ describe(EntityDataManager, () => {
335
335
  entityCache,
336
336
  StubQueryContextProvider,
337
337
  new NoOpEntityMetricsAdapter(),
338
- TestEntity.name
338
+ TestEntity.name,
339
339
  );
340
340
  const queryContext = StubQueryContextProvider.getQueryContext();
341
341
 
@@ -363,7 +363,7 @@ describe(EntityDataManager, () => {
363
363
  const objects = getObjects();
364
364
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
365
365
  testEntityConfiguration,
366
- objects
366
+ objects,
367
367
  );
368
368
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
369
369
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -374,7 +374,7 @@ describe(EntityDataManager, () => {
374
374
  entityCache,
375
375
  StubQueryContextProvider,
376
376
  new NoOpEntityMetricsAdapter(),
377
- TestEntity.name
377
+ TestEntity.name,
378
378
  );
379
379
 
380
380
  const dbSpy = jest.spyOn(databaseAdapter, 'fetchManyWhereAsync');
@@ -386,7 +386,7 @@ describe(EntityDataManager, () => {
386
386
  '1',
387
387
  ]);
388
388
  },
389
- {}
389
+ {},
390
390
  );
391
391
 
392
392
  expect(entityDatas.get('1')).toHaveLength(1);
@@ -402,7 +402,7 @@ describe(EntityDataManager, () => {
402
402
  const objects = getObjects();
403
403
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
404
404
  testEntityConfiguration,
405
- objects
405
+ objects,
406
406
  );
407
407
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
408
408
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -413,7 +413,7 @@ describe(EntityDataManager, () => {
413
413
  entityCache,
414
414
  StubQueryContextProvider,
415
415
  new NoOpEntityMetricsAdapter(),
416
- TestEntity.name
416
+ TestEntity.name,
417
417
  );
418
418
  const queryContext = StubQueryContextProvider.getQueryContext();
419
419
 
@@ -432,7 +432,7 @@ describe(EntityDataManager, () => {
432
432
  fieldValue: 1,
433
433
  },
434
434
  ],
435
- {}
435
+ {},
436
436
  );
437
437
 
438
438
  expect(entityDatas).toHaveLength(2);
@@ -447,7 +447,7 @@ describe(EntityDataManager, () => {
447
447
  it('handles DB errors as expected', async () => {
448
448
  const databaseAdapterMock = mock<EntityDatabaseAdapter<TestFields>>();
449
449
  when(databaseAdapterMock.fetchManyWhereAsync(anything(), anything(), anything())).thenReject(
450
- new Error('DB query failed')
450
+ new Error('DB query failed'),
451
451
  );
452
452
 
453
453
  const databaseAdapter = instance(databaseAdapterMock);
@@ -459,12 +459,12 @@ describe(EntityDataManager, () => {
459
459
  entityCache,
460
460
  StubQueryContextProvider,
461
461
  new NoOpEntityMetricsAdapter(),
462
- TestEntity.name
462
+ TestEntity.name,
463
463
  );
464
464
  const queryContext = StubQueryContextProvider.getQueryContext();
465
465
 
466
466
  await expect(
467
- entityDataManager.loadManyByFieldEqualingAsync(queryContext, 'customIdField', ['2'])
467
+ entityDataManager.loadManyByFieldEqualingAsync(queryContext, 'customIdField', ['2']),
468
468
  ).rejects.toThrow();
469
469
  });
470
470
 
@@ -475,7 +475,7 @@ describe(EntityDataManager, () => {
475
475
  const objects = getObjects();
476
476
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
477
477
  testEntityConfiguration,
478
- objects
478
+ objects,
479
479
  );
480
480
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
481
481
  const cacheAdapterProvider = new InMemoryFullCacheStubCacheAdapterProvider();
@@ -486,7 +486,7 @@ describe(EntityDataManager, () => {
486
486
  entityCache,
487
487
  StubQueryContextProvider,
488
488
  metricsAdapter,
489
- TestEntity.name
489
+ TestEntity.name,
490
490
  );
491
491
  const queryContext = StubQueryContextProvider.getQueryContext();
492
492
 
@@ -497,8 +497,8 @@ describe(EntityDataManager, () => {
497
497
  type: EntityMetricsLoadType.LOAD_MANY,
498
498
  entityClassName: TestEntity.name,
499
499
  count: 1,
500
- })
501
- )
500
+ }),
501
+ ),
502
502
  ).once();
503
503
 
504
504
  await entityDataManager.loadManyByFieldEqualityConjunctionAsync(
@@ -509,7 +509,7 @@ describe(EntityDataManager, () => {
509
509
  fieldValue: '1',
510
510
  },
511
511
  ],
512
- {}
512
+ {},
513
513
  );
514
514
  verify(
515
515
  metricsAdapterMock.logDataManagerLoadEvent(
@@ -517,8 +517,8 @@ describe(EntityDataManager, () => {
517
517
  type: EntityMetricsLoadType.LOAD_MANY_EQUALITY_CONJUNCTION,
518
518
  entityClassName: TestEntity.name,
519
519
  count: 1,
520
- })
521
- )
520
+ }),
521
+ ),
522
522
  ).once();
523
523
 
524
524
  verify(
@@ -527,8 +527,8 @@ describe(EntityDataManager, () => {
527
527
  type: IncrementLoadCountEventType.DATALOADER,
528
528
  fieldValueCount: 1,
529
529
  entityClassName: TestEntity.name,
530
- })
531
- )
530
+ }),
531
+ ),
532
532
  ).once();
533
533
  verify(
534
534
  metricsAdapterMock.incrementDataManagerLoadCount(
@@ -536,8 +536,8 @@ describe(EntityDataManager, () => {
536
536
  type: IncrementLoadCountEventType.CACHE,
537
537
  fieldValueCount: 1,
538
538
  entityClassName: TestEntity.name,
539
- })
540
- )
539
+ }),
540
+ ),
541
541
  ).once();
542
542
  verify(
543
543
  metricsAdapterMock.incrementDataManagerLoadCount(
@@ -545,8 +545,8 @@ describe(EntityDataManager, () => {
545
545
  type: IncrementLoadCountEventType.DATABASE,
546
546
  fieldValueCount: 1,
547
547
  entityClassName: TestEntity.name,
548
- })
549
- )
548
+ }),
549
+ ),
550
550
  ).once();
551
551
 
552
552
  resetCalls(metricsAdapterMock);
@@ -557,8 +557,8 @@ describe(EntityDataManager, () => {
557
557
  anything(),
558
558
  anyString(),
559
559
  anything(),
560
- anything()
561
- )
560
+ anything(),
561
+ ),
562
562
  ).thenResolve([]);
563
563
  await entityDataManager.loadManyByRawWhereClauseAsync(queryContext, '', [], {});
564
564
  verify(
@@ -567,8 +567,8 @@ describe(EntityDataManager, () => {
567
567
  type: EntityMetricsLoadType.LOAD_MANY_RAW,
568
568
  entityClassName: TestEntity.name,
569
569
  count: 0,
570
- })
571
- )
570
+ }),
571
+ ),
572
572
  ).once();
573
573
 
574
574
  verify(metricsAdapterMock.incrementDataManagerLoadCount(anything())).never();
@@ -578,7 +578,7 @@ describe(EntityDataManager, () => {
578
578
  const objects = getObjects();
579
579
  const dataStore = StubDatabaseAdapter.convertFieldObjectsToDataStore(
580
580
  testEntityConfiguration,
581
- objects
581
+ objects,
582
582
  );
583
583
  const databaseAdapter = new StubDatabaseAdapter<TestFields>(testEntityConfiguration, dataStore);
584
584
  const cacheAdapterProvider = new NoCacheStubCacheAdapterProvider();
@@ -589,18 +589,18 @@ describe(EntityDataManager, () => {
589
589
  entityCache,
590
590
  StubQueryContextProvider,
591
591
  new NoOpEntityMetricsAdapter(),
592
- TestEntity.name
592
+ TestEntity.name,
593
593
  );
594
594
  const queryContext = StubQueryContextProvider.getQueryContext();
595
595
 
596
596
  await expect(
597
- entityDataManager.loadManyByFieldEqualingAsync(queryContext, 'nullableField', [null as any])
597
+ entityDataManager.loadManyByFieldEqualingAsync(queryContext, 'nullableField', [null as any]),
598
598
  ).rejects.toThrowError('Invalid load: TestEntity (nullableField = null)');
599
599
 
600
600
  await expect(
601
601
  entityDataManager.loadManyByFieldEqualingAsync(queryContext, 'nullableField', [
602
602
  undefined as any,
603
- ])
603
+ ]),
604
604
  ).rejects.toThrowError('Invalid load: TestEntity (nullableField = undefined)');
605
605
  });
606
606
  });
@@ -44,10 +44,10 @@ const blahEntityConfiguration = new EntityConfiguration<BlahT>({
44
44
  describe(getDatabaseFieldForEntityField, () => {
45
45
  it('returns correct mapping', () => {
46
46
  expect(getDatabaseFieldForEntityField(blahEntityConfiguration, 'cacheable')).toEqual(
47
- 'cacheable'
47
+ 'cacheable',
48
48
  );
49
49
  expect(
50
- getDatabaseFieldForEntityField(blahEntityConfiguration, 'uniqueButNotCacheable')
50
+ getDatabaseFieldForEntityField(blahEntityConfiguration, 'uniqueButNotCacheable'),
51
51
  ).toEqual('unique_but_not_cacheable');
52
52
  });
53
53
  });
@@ -59,7 +59,7 @@ describe(transformDatabaseObjectToFields, () => {
59
59
  id: 'blah',
60
60
  unique_but_not_cacheable: 'wat',
61
61
  who: 'why',
62
- })
62
+ }),
63
63
  ).toEqual({
64
64
  id: 'blah',
65
65
  uniqueButNotCacheable: 'wat',
@@ -79,7 +79,7 @@ describe(transformDatabaseObjectToFields, () => {
79
79
  expect(
80
80
  transformDatabaseObjectToFields(blahEntityConfiguration, fieldTransformMap, {
81
81
  transform_read: 'wat',
82
- })
82
+ }),
83
83
  ).toEqual({
84
84
  transformRead: 'wat-read-transformed',
85
85
  });
@@ -93,7 +93,7 @@ describe(transformFieldsToDatabaseObject, () => {
93
93
  id: 'blah',
94
94
  cacheable: 'wat',
95
95
  uniqueButNotCacheable: 'wat',
96
- })
96
+ }),
97
97
  ).toEqual({
98
98
  id: 'blah',
99
99
  cacheable: 'wat',
@@ -114,7 +114,7 @@ describe(transformFieldsToDatabaseObject, () => {
114
114
  expect(
115
115
  transformFieldsToDatabaseObject(blahEntityConfiguration, fieldTransformMap, {
116
116
  transformWrite: 'wat',
117
- })
117
+ }),
118
118
  ).toEqual({
119
119
  transform_write: 'wat-write-transformed',
120
120
  });
@@ -122,7 +122,7 @@ describe(transformFieldsToDatabaseObject, () => {
122
122
  });
123
123
 
124
124
  describe(transformCacheObjectToFields, () => {
125
- it('does field read transformation', () => {
125
+ it('does field read transformation, keeping unknown fields for cache version inconsistencies', () => {
126
126
  const fieldTransformMap = new Map([
127
127
  [
128
128
  StringField.name,
@@ -136,16 +136,18 @@ describe(transformCacheObjectToFields, () => {
136
136
  transformCacheObjectToFields(blahEntityConfiguration, fieldTransformMap, {
137
137
  id: 'hello',
138
138
  transformRead: 'wat',
139
- })
139
+ unknownField: 'who',
140
+ }),
140
141
  ).toEqual({
141
142
  id: 'hello',
142
143
  transformRead: 'wat-read-transformed-cache',
144
+ unknownField: 'who',
143
145
  });
144
146
  });
145
147
  });
146
148
 
147
149
  describe(transformFieldsToCacheObject, () => {
148
- it('does field write transformation', () => {
150
+ it('does field write transformation, keeping unknown fields at runtime for cache version inconsistencies', () => {
149
151
  const fieldTransformMap = new Map([
150
152
  [
151
153
  StringField.name,
@@ -159,10 +161,12 @@ describe(transformFieldsToCacheObject, () => {
159
161
  transformFieldsToCacheObject(blahEntityConfiguration, fieldTransformMap, {
160
162
  id: 'hello',
161
163
  transformWrite: 'wat',
162
- })
164
+ unknownField: 'who',
165
+ } as any),
163
166
  ).toEqual({
164
167
  id: 'hello',
165
168
  transformWrite: 'wat-write-transformed-cache',
169
+ unknownField: 'who',
166
170
  });
167
171
  });
168
172
  });
@@ -23,7 +23,7 @@ const makeEntityConfiguration = (cacheIdField: boolean): EntityConfiguration<Bla
23
23
  const createIdFetcher =
24
24
  (ids: string[]) =>
25
25
  async <N extends keyof BlahFields>(
26
- fetcherFieldValues: readonly NonNullable<BlahFields[N]>[]
26
+ fetcherFieldValues: readonly NonNullable<BlahFields[N]>[],
27
27
  ): Promise<ReadonlyMap<NonNullable<BlahFields[N]>, readonly Readonly<BlahFields>[]>> => {
28
28
  const results = new Map();
29
29
  fetcherFieldValues.forEach((v) => {
@@ -36,6 +36,22 @@ const createIdFetcher =
36
36
  return results;
37
37
  };
38
38
 
39
+ const createFetcherNonUnique =
40
+ (ids: string[]) =>
41
+ async <N extends keyof BlahFields>(
42
+ fetcherFieldValues: readonly NonNullable<BlahFields[N]>[],
43
+ ): Promise<ReadonlyMap<NonNullable<BlahFields[N]>, readonly Readonly<BlahFields>[]>> => {
44
+ const results = new Map();
45
+ fetcherFieldValues.forEach((v) => {
46
+ if (ids.includes(v)) {
47
+ results.set(v, [{ id: v }, { id: v + '2' }]);
48
+ } else {
49
+ results.set(v, []);
50
+ }
51
+ });
52
+ return results;
53
+ };
54
+
39
55
  describe(ReadThroughEntityCache, () => {
40
56
  describe('readManyThroughAsync', () => {
41
57
  it('fetches from DB upon cache miss and caches the result', async () => {
@@ -48,7 +64,7 @@ describe(ReadThroughEntityCache, () => {
48
64
  new Map([
49
65
  ['wat', { status: CacheStatus.MISS }],
50
66
  ['who', { status: CacheStatus.MISS }],
51
- ])
67
+ ]),
52
68
  );
53
69
 
54
70
  const result = await entityCache.readManyThroughAsync('id', ['wat', 'who'], fetcher);
@@ -61,16 +77,16 @@ describe(ReadThroughEntityCache, () => {
61
77
  new Map([
62
78
  ['wat', { id: 'wat' }],
63
79
  ['who', { id: 'who' }],
64
- ])
65
- )
66
- )
80
+ ]),
81
+ ),
82
+ ),
67
83
  ).once();
68
84
  verify(cacheAdapterMock.cacheDBMissesAsync('id', deepEqual([]))).once();
69
85
  expect(result).toEqual(
70
86
  new Map([
71
87
  ['wat', [{ id: 'wat' }]],
72
88
  ['who', [{ id: 'who' }]],
73
- ])
89
+ ]),
74
90
  );
75
91
  });
76
92
 
@@ -84,7 +100,7 @@ describe(ReadThroughEntityCache, () => {
84
100
  new Map([
85
101
  ['wat', { status: CacheStatus.HIT, item: { id: 'wat' } }],
86
102
  ['who', { status: CacheStatus.HIT, item: { id: 'who' } }],
87
- ])
103
+ ]),
88
104
  );
89
105
 
90
106
  const result = await entityCache.readManyThroughAsync('id', ['wat', 'who'], fetcher);
@@ -97,16 +113,16 @@ describe(ReadThroughEntityCache, () => {
97
113
  new Map([
98
114
  ['wat', { id: 'wat' }],
99
115
  ['who', { id: 'who' }],
100
- ])
101
- )
102
- )
116
+ ]),
117
+ ),
118
+ ),
103
119
  ).never();
104
120
  verify(cacheAdapterMock.cacheDBMissesAsync('id', deepEqual([]))).never();
105
121
  expect(result).toEqual(
106
122
  new Map([
107
123
  ['wat', [{ id: 'wat' }]],
108
124
  ['who', [{ id: 'who' }]],
109
- ])
125
+ ]),
110
126
  );
111
127
  });
112
128
 
@@ -119,7 +135,7 @@ describe(ReadThroughEntityCache, () => {
119
135
  const fetcher = createIdFetcher(['wat', 'who']);
120
136
 
121
137
  when(cacheAdapterMock.loadManyAsync('id', deepEqual(['why']))).thenResolve(
122
- new Map([['why', { status: CacheStatus.MISS }]])
138
+ new Map([['why', { status: CacheStatus.MISS }]]),
123
139
  );
124
140
 
125
141
  const result = await entityCache.readManyThroughAsync('id', ['why'], fetcher);
@@ -137,7 +153,7 @@ describe(ReadThroughEntityCache, () => {
137
153
  const fetcher = createIdFetcher([]);
138
154
 
139
155
  when(cacheAdapterMock.loadManyAsync('id', deepEqual(['why']))).thenResolve(
140
- new Map([['why', { status: CacheStatus.NEGATIVE }]])
156
+ new Map([['why', { status: CacheStatus.NEGATIVE }]]),
141
157
  );
142
158
 
143
159
  const result = await entityCache.readManyThroughAsync('id', ['why'], fetcher);
@@ -154,31 +170,31 @@ describe(ReadThroughEntityCache, () => {
154
170
  const fetcher = createIdFetcher(['wat', 'who', 'why']);
155
171
 
156
172
  when(
157
- cacheAdapterMock.loadManyAsync('id', deepEqual(['wat', 'who', 'why', 'how']))
173
+ cacheAdapterMock.loadManyAsync('id', deepEqual(['wat', 'who', 'why', 'how'])),
158
174
  ).thenResolve(
159
175
  new Map([
160
176
  ['wat', { status: CacheStatus.MISS }],
161
177
  ['who', { status: CacheStatus.NEGATIVE }],
162
178
  ['why', { status: CacheStatus.HIT, item: { id: 'why' } }],
163
179
  ['how', { status: CacheStatus.MISS }],
164
- ])
180
+ ]),
165
181
  );
166
182
 
167
183
  const result = await entityCache.readManyThroughAsync(
168
184
  'id',
169
185
  ['wat', 'who', 'why', 'how'],
170
- fetcher
186
+ fetcher,
171
187
  );
172
188
  verify(cacheAdapterMock.loadManyAsync('id', deepEqual(['wat', 'who', 'why', 'how']))).once();
173
189
  verify(
174
- cacheAdapterMock.cacheManyAsync('id', deepEqual(new Map([['wat', { id: 'wat' }]])))
190
+ cacheAdapterMock.cacheManyAsync('id', deepEqual(new Map([['wat', { id: 'wat' }]]))),
175
191
  ).once();
176
192
  verify(cacheAdapterMock.cacheDBMissesAsync('id', deepEqual(['how']))).once();
177
193
  expect(result).toEqual(
178
194
  new Map([
179
195
  ['wat', [{ id: 'wat' }]],
180
196
  ['why', [{ id: 'why' }]],
181
- ])
197
+ ]),
182
198
  );
183
199
  });
184
200
 
@@ -191,6 +207,46 @@ describe(ReadThroughEntityCache, () => {
191
207
  verify(cacheAdapterMock.loadManyAsync('id', anything())).never();
192
208
  expect(result).toEqual(new Map([['wat', [{ id: 'wat' }]]]));
193
209
  });
210
+
211
+ it('does not cache when DB returns multiple objects for what is supposed to be unique and returns empty', async () => {
212
+ const consoleSpy = jest.spyOn(console, 'warn');
213
+
214
+ const cacheAdapterMock = mock<IEntityCacheAdapter<BlahFields>>();
215
+ const cacheAdapter = instance(cacheAdapterMock);
216
+ const entityCache = new ReadThroughEntityCache(makeEntityConfiguration(true), cacheAdapter);
217
+ const fetcher = createFetcherNonUnique(['wat', 'who']);
218
+
219
+ when(cacheAdapterMock.loadManyAsync('id', deepEqual(['wat', 'who']))).thenResolve(
220
+ new Map([
221
+ ['wat', { status: CacheStatus.MISS }],
222
+ ['who', { status: CacheStatus.MISS }],
223
+ ]),
224
+ );
225
+
226
+ const result = await entityCache.readManyThroughAsync('id', ['wat', 'who'], fetcher);
227
+
228
+ verify(cacheAdapterMock.loadManyAsync('id', deepEqual(['wat', 'who']))).once();
229
+ verify(
230
+ cacheAdapterMock.cacheManyAsync(
231
+ 'id',
232
+ deepEqual(
233
+ new Map([
234
+ ['wat', { id: 'wat' }],
235
+ ['who', { id: 'who' }],
236
+ ]),
237
+ ),
238
+ ),
239
+ ).never();
240
+ verify(cacheAdapterMock.cacheDBMissesAsync('id', deepEqual([]))).once();
241
+ expect(result).toEqual(new Map());
242
+
243
+ expect(consoleSpy).toHaveBeenCalledWith(
244
+ 'unique key id in blah returned multiple rows for wat',
245
+ );
246
+ expect(consoleSpy).toHaveBeenCalledWith(
247
+ 'unique key id in blah returned multiple rows for who',
248
+ );
249
+ });
194
250
  });
195
251
 
196
252
  describe('invalidateManyAsync', () => {