@expo/entity 0.38.0 → 0.40.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 (206) hide show
  1. package/build/AuthorizationResultBasedEntityAssociationLoader.d.ts +99 -0
  2. package/build/AuthorizationResultBasedEntityAssociationLoader.js +124 -0
  3. package/build/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -0
  4. package/build/AuthorizationResultBasedEntityLoader.d.ts +1 -1
  5. package/build/AuthorizationResultBasedEntityLoader.js.map +1 -1
  6. package/build/{EntityMutator.d.ts → AuthorizationResultBasedEntityMutator.d.ts} +5 -17
  7. package/build/{EntityMutator.js → AuthorizationResultBasedEntityMutator.js} +22 -48
  8. package/build/AuthorizationResultBasedEntityMutator.js.map +1 -0
  9. package/build/EnforcingEntityAssociationLoader.d.ts +79 -0
  10. package/build/EnforcingEntityAssociationLoader.js +62 -0
  11. package/build/EnforcingEntityAssociationLoader.js.map +1 -0
  12. package/build/EnforcingEntityCreator.d.ts +24 -0
  13. package/build/EnforcingEntityCreator.js +32 -0
  14. package/build/EnforcingEntityCreator.js.map +1 -0
  15. package/build/EnforcingEntityDeleter.d.ts +17 -0
  16. package/build/EnforcingEntityDeleter.js +22 -0
  17. package/build/EnforcingEntityDeleter.js.map +1 -0
  18. package/build/EnforcingEntityUpdater.d.ts +24 -0
  19. package/build/EnforcingEntityUpdater.js +32 -0
  20. package/build/EnforcingEntityUpdater.js.map +1 -0
  21. package/build/Entity.d.ts +8 -12
  22. package/build/Entity.js +9 -34
  23. package/build/Entity.js.map +1 -1
  24. package/build/EntityAssociationLoader.d.ts +12 -91
  25. package/build/EntityAssociationLoader.js +20 -126
  26. package/build/EntityAssociationLoader.js.map +1 -1
  27. package/build/EntityCompanionProvider.d.ts +2 -2
  28. package/build/EntityCompanionProvider.js.map +1 -1
  29. package/build/EntityCreator.d.ts +27 -0
  30. package/build/EntityCreator.js +39 -0
  31. package/build/EntityCreator.js.map +1 -0
  32. package/build/EntityDatabaseAdapter.js +2 -2
  33. package/build/EntityDatabaseAdapter.js.map +1 -1
  34. package/build/EntityDeleter.d.ts +27 -0
  35. package/build/EntityDeleter.js +40 -0
  36. package/build/EntityDeleter.js.map +1 -0
  37. package/build/EntityLoader.d.ts +4 -14
  38. package/build/EntityLoader.js +7 -20
  39. package/build/EntityLoader.js.map +1 -1
  40. package/build/EntityLoaderFactory.d.ts +2 -2
  41. package/build/EntityLoaderFactory.js +4 -2
  42. package/build/EntityLoaderFactory.js.map +1 -1
  43. package/build/EntityMutatorFactory.d.ts +4 -4
  44. package/build/EntityMutatorFactory.js +4 -4
  45. package/build/EntityMutatorFactory.js.map +1 -1
  46. package/build/EntitySecondaryCacheLoader.d.ts +3 -3
  47. package/build/EntitySecondaryCacheLoader.js +1 -3
  48. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  49. package/build/EntityUpdater.d.ts +27 -0
  50. package/build/EntityUpdater.js +40 -0
  51. package/build/EntityUpdater.js.map +1 -0
  52. package/build/ReadonlyEntity.d.ts +2 -2
  53. package/build/ReadonlyEntity.js +4 -6
  54. package/build/ReadonlyEntity.js.map +1 -1
  55. package/build/ViewerScopedEntityLoaderFactory.d.ts +2 -2
  56. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  57. package/build/ViewerScopedEntityMutatorFactory.d.ts +4 -4
  58. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  59. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.d.ts +1 -0
  60. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js +273 -0
  61. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js.map +1 -0
  62. package/build/__tests__/{EntityLoader-constructor-test.js → AuthorizationResultBasedEntityLoader-constructor-test.js} +11 -11
  63. package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js.map +1 -0
  64. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.d.ts +1 -0
  65. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js +401 -0
  66. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js.map +1 -0
  67. package/build/__tests__/EnforcingEntityAssociationLoader-test.d.ts +1 -0
  68. package/build/__tests__/EnforcingEntityAssociationLoader-test.js +115 -0
  69. package/build/__tests__/EnforcingEntityAssociationLoader-test.js.map +1 -0
  70. package/build/__tests__/Entity-test.js +23 -5
  71. package/build/__tests__/Entity-test.js.map +1 -1
  72. package/build/__tests__/EntityAssociationLoader-test.js +14 -184
  73. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  74. package/build/__tests__/EntityCommonUseCases-test.js +34 -12
  75. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  76. package/build/__tests__/EntityCompanion-test.js +17 -7
  77. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  78. package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
  79. package/build/__tests__/EntityEdges-test.js +41 -23
  80. package/build/__tests__/EntityEdges-test.js.map +1 -1
  81. package/build/__tests__/EntityLoader-test.js +22 -386
  82. package/build/__tests__/EntityLoader-test.js.map +1 -1
  83. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +4 -3
  84. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  85. package/build/__tests__/EntityMutator-test.js +67 -70
  86. package/build/__tests__/EntityMutator-test.js.map +1 -1
  87. package/build/__tests__/EntityPrivacyPolicy-test.js +17 -7
  88. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  89. package/build/__tests__/EntitySecondaryCacheLoader-test.js +7 -7
  90. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
  91. package/build/__tests__/EntitySelfReferentialEdges-test.js +36 -24
  92. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  93. package/build/__tests__/ReadonlyEntity-test.js +1 -1
  94. package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
  95. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +4 -2
  96. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  97. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +7 -4
  98. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  99. package/build/__tests__/entityUtils-test.js +8 -0
  100. package/build/__tests__/entityUtils-test.js.map +1 -1
  101. package/build/entityUtils.d.ts +7 -0
  102. package/build/entityUtils.js +20 -10
  103. package/build/entityUtils.js.map +1 -1
  104. package/build/errors/EntityCacheAdapterError.js +17 -7
  105. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  106. package/build/errors/EntityDatabaseAdapterError.js +17 -7
  107. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  108. package/build/errors/EntityInvalidFieldValueError.js +17 -7
  109. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  110. package/build/errors/EntityNotAuthorizedError.js +17 -7
  111. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  112. package/build/errors/EntityNotFoundError.js +17 -7
  113. package/build/errors/EntityNotFoundError.js.map +1 -1
  114. package/build/index.d.ts +19 -11
  115. package/build/index.js +24 -7
  116. package/build/index.js.map +1 -1
  117. package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
  118. package/build/internal/__tests__/EntityDataManager-test.js +42 -32
  119. package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
  120. package/build/internal/__tests__/ReadThroughEntityCache-test.js +17 -7
  121. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  122. package/build/rules/AlwaysAllowPrivacyPolicyRule.js +17 -7
  123. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  124. package/build/rules/AlwaysDenyPrivacyPolicyRule.js +17 -7
  125. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  126. package/build/rules/AlwaysSkipPrivacyPolicyRule.js +17 -7
  127. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  128. package/build/utils/EntityPrivacyUtils.d.ts +32 -4
  129. package/build/utils/EntityPrivacyUtils.js +68 -24
  130. package/build/utils/EntityPrivacyUtils.js.map +1 -1
  131. package/build/utils/__tests__/EntityPrivacyUtils-test.js +148 -23
  132. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -1
  133. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js +8 -5
  134. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js.map +1 -1
  135. package/build/utils/collections/__tests__/maps-test.js +1 -1
  136. package/build/utils/collections/__tests__/maps-test.js.map +1 -1
  137. package/build/utils/collections/maps.js +2 -2
  138. package/build/utils/collections/maps.js.map +1 -1
  139. package/build/utils/mergeEntityMutationTriggerConfigurations.js +1 -2
  140. package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -1
  141. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +1 -1
  142. package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
  143. package/build/utils/testing/StubDatabaseAdapter.js +17 -7
  144. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  145. package/build/utils/testing/StubQueryContextProvider.d.ts +1 -3
  146. package/build/utils/testing/StubQueryContextProvider.js +1 -3
  147. package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
  148. package/build/utils/testing/createUnitTestEntityCompanionProvider.js +2 -1
  149. package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +1 -1
  150. package/build/utils/testing/describeFieldTestCase.js +1 -1
  151. package/build/utils/testing/describeFieldTestCase.js.map +1 -1
  152. package/package.json +19 -3
  153. package/src/AuthorizationResultBasedEntityAssociationLoader.ts +492 -0
  154. package/src/AuthorizationResultBasedEntityLoader.ts +2 -2
  155. package/src/{EntityMutator.ts → AuthorizationResultBasedEntityMutator.ts} +62 -58
  156. package/src/EnforcingEntityAssociationLoader.ts +390 -0
  157. package/src/EnforcingEntityCreator.ts +55 -0
  158. package/src/EnforcingEntityDeleter.ts +44 -0
  159. package/src/EnforcingEntityUpdater.ts +55 -0
  160. package/src/Entity.ts +20 -65
  161. package/src/EntityAssociationLoader.ts +38 -495
  162. package/src/EntityCompanionProvider.ts +5 -2
  163. package/src/EntityCreator.ts +73 -0
  164. package/src/EntityDeleter.ts +73 -0
  165. package/src/EntityLoader.ts +10 -49
  166. package/src/EntityLoaderFactory.ts +20 -3
  167. package/src/EntityMutatorFactory.ts +32 -7
  168. package/src/EntitySecondaryCacheLoader.ts +5 -7
  169. package/src/EntityUpdater.ts +73 -0
  170. package/src/ReadonlyEntity.ts +14 -13
  171. package/src/ViewerScopedEntityLoaderFactory.ts +9 -2
  172. package/src/ViewerScopedEntityMutatorFactory.ts +29 -4
  173. package/src/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.ts +354 -0
  174. package/src/__tests__/{EntityLoader-constructor-test.ts → AuthorizationResultBasedEntityLoader-constructor-test.ts} +17 -10
  175. package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +730 -0
  176. package/src/__tests__/EnforcingEntityAssociationLoader-test.ts +253 -0
  177. package/src/__tests__/Entity-test.ts +24 -5
  178. package/src/__tests__/EntityAssociationLoader-test.ts +16 -259
  179. package/src/__tests__/EntityCommonUseCases-test.ts +20 -8
  180. package/src/__tests__/EntityCompanion-test.ts +1 -1
  181. package/src/__tests__/EntityDatabaseAdapter-test.ts +6 -6
  182. package/src/__tests__/EntityEdges-test.ts +24 -16
  183. package/src/__tests__/EntityLoader-test.ts +25 -675
  184. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +4 -3
  185. package/src/__tests__/EntityMutator-test.ts +116 -103
  186. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
  187. package/src/__tests__/EntitySelfReferentialEdges-test.ts +36 -24
  188. package/src/__tests__/ReadonlyEntity-test.ts +1 -1
  189. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +4 -2
  190. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +7 -4
  191. package/src/__tests__/entityUtils-test.ts +12 -0
  192. package/src/entityUtils.ts +24 -9
  193. package/src/index.ts +19 -11
  194. package/src/internal/EntityFieldTransformationUtils.ts +2 -2
  195. package/src/internal/__tests__/EntityDataManager-test.ts +29 -29
  196. package/src/utils/EntityPrivacyUtils.ts +188 -107
  197. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +169 -29
  198. package/src/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.ts +8 -5
  199. package/src/utils/collections/__tests__/maps-test.ts +1 -1
  200. package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +1 -1
  201. package/src/utils/testing/StubDatabaseAdapter.ts +1 -1
  202. package/src/utils/testing/StubQueryContextProvider.ts +1 -3
  203. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +3 -1
  204. package/build/EntityMutator.js.map +0 -1
  205. package/build/__tests__/EntityLoader-constructor-test.js.map +0 -1
  206. /package/build/__tests__/{EntityLoader-constructor-test.d.ts → AuthorizationResultBasedEntityLoader-constructor-test.d.ts} +0 -0
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StubQueryContextProvider = void 0;
7
6
  const EntityQueryContextProvider_1 = __importDefault(require("../../EntityQueryContextProvider"));
8
7
  class StubQueryContextProvider extends EntityQueryContextProvider_1.default {
9
8
  getQueryInterface() {
@@ -16,6 +15,5 @@ class StubQueryContextProvider extends EntityQueryContextProvider_1.default {
16
15
  return (transactionScope) => Promise.resolve(transactionScope({}));
17
16
  }
18
17
  }
19
- exports.StubQueryContextProvider = StubQueryContextProvider;
20
- exports.default = new StubQueryContextProvider();
18
+ exports.default = StubQueryContextProvider;
21
19
  //# sourceMappingURL=StubQueryContextProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StubQueryContextProvider.js","sourceRoot":"","sources":["../../../src/utils/testing/StubQueryContextProvider.ts"],"names":[],"mappings":";;;;;;AACA,kGAA0E;AAE1E,MAAa,wBAAyB,SAAQ,oCAA0B;IAC5D,iBAAiB;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAES,uBAAuB,CAC/B,kBAAsC;QAEtC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;IAES,6BAA6B,CACrC,oBAAyB;QAEzB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;CACF;AAhBD,4DAgBC;AAED,kBAAe,IAAI,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"StubQueryContextProvider.js","sourceRoot":"","sources":["../../../src/utils/testing/StubQueryContextProvider.ts"],"names":[],"mappings":";;;;;AACA,kGAA0E;AAE1E,MAAqB,wBAAyB,SAAQ,oCAA0B;IACpE,iBAAiB;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAES,uBAAuB,CAC/B,kBAAsC;QAEtC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;IAES,6BAA6B,CACrC,oBAAyB;QAEzB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;CACF;AAhBD,2CAgBC"}
@@ -9,6 +9,7 @@ const StubDatabaseAdapterProvider_1 = __importDefault(require("./StubDatabaseAda
9
9
  const StubQueryContextProvider_1 = __importDefault(require("./StubQueryContextProvider"));
10
10
  const EntityCompanionProvider_1 = __importDefault(require("../../EntityCompanionProvider"));
11
11
  const NoOpEntityMetricsAdapter_1 = __importDefault(require("../../metrics/NoOpEntityMetricsAdapter"));
12
+ const queryContextProvider = new StubQueryContextProvider_1.default();
12
13
  /**
13
14
  * Entity companion provider for use in unit tests. All database and cache implementations
14
15
  * are replaced with in-memory simulations.
@@ -19,7 +20,7 @@ const createUnitTestEntityCompanionProvider = (metricsAdapter = new NoOpEntityMe
19
20
  'postgres',
20
21
  {
21
22
  adapterProvider: new StubDatabaseAdapterProvider_1.default(),
22
- queryContextProvider: StubQueryContextProvider_1.default,
23
+ queryContextProvider,
23
24
  },
24
25
  ],
25
26
  ]), new Map([
@@ -1 +1 @@
1
- {"version":3,"file":"createUnitTestEntityCompanionProvider.js","sourceRoot":"","sources":["../../../src/utils/testing/createUnitTestEntityCompanionProvider.ts"],"names":[],"mappings":";;;;;;AAAA,yDAA+E;AAC/E,gGAAwE;AACxE,0FAAkE;AAClE,4FAAoE;AAEpE,sGAA8E;AAE9E;;;GAGG;AACI,MAAM,qCAAqC,GAAG,CACnD,iBAAwC,IAAI,kCAAwB,EAAE,EAC7C,EAAE;IAC3B,OAAO,IAAI,iCAAuB,CAChC,cAAc,EACd,IAAI,GAAG,CAAC;QACN;YACE,UAAU;YACV;gBACE,eAAe,EAAE,IAAI,qCAA2B,EAAE;gBAClD,oBAAoB,EAAE,kCAAwB;aAC/C;SACF;KACF,CAAC,EACF,IAAI,GAAG,CAAC;QACN;YACE,OAAO;YACP;gBACE,oBAAoB,EAAE,IAAI,4DAAyC,EAAE;aACtE;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC,CAAC;AAvBW,QAAA,qCAAqC,yCAuBhD"}
1
+ {"version":3,"file":"createUnitTestEntityCompanionProvider.js","sourceRoot":"","sources":["../../../src/utils/testing/createUnitTestEntityCompanionProvider.ts"],"names":[],"mappings":";;;;;;AAAA,yDAA+E;AAC/E,gGAAwE;AACxE,0FAAkE;AAClE,4FAAoE;AAEpE,sGAA8E;AAE9E,MAAM,oBAAoB,GAAG,IAAI,kCAAwB,EAAE,CAAC;AAE5D;;;GAGG;AACI,MAAM,qCAAqC,GAAG,CACnD,iBAAwC,IAAI,kCAAwB,EAAE,EAC7C,EAAE;IAC3B,OAAO,IAAI,iCAAuB,CAChC,cAAc,EACd,IAAI,GAAG,CAAC;QACN;YACE,UAAU;YACV;gBACE,eAAe,EAAE,IAAI,qCAA2B,EAAE;gBAClD,oBAAoB;aACrB;SACF;KACF,CAAC,EACF,IAAI,GAAG,CAAC;QACN;YACE,OAAO;YACP;gBACE,oBAAoB,EAAE,IAAI,4DAAyC,EAAE;aACtE;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC,CAAC;AAvBW,QAAA,qCAAqC,yCAuBhD"}
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = describeFieldTestCase;
3
4
  function describeFieldTestCase(fieldDefinition, validValues, invalidValues) {
4
5
  describe(fieldDefinition.constructor.name, () => {
5
6
  if (validValues.length > 0) {
@@ -14,5 +15,4 @@ function describeFieldTestCase(fieldDefinition, validValues, invalidValues) {
14
15
  }
15
16
  });
16
17
  }
17
- exports.default = describeFieldTestCase;
18
18
  //# sourceMappingURL=describeFieldTestCase.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"describeFieldTestCase.js","sourceRoot":"","sources":["../../../src/utils/testing/describeFieldTestCase.ts"],"names":[],"mappings":";;AAEA,SAAwB,qBAAqB,CAC3C,eAAyC,EACzC,WAAgB,EAChB,aAAoB;IAEpB,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE;QAC9C,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC/E,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/D,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnF,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAlBD,wCAkBC"}
1
+ {"version":3,"file":"describeFieldTestCase.js","sourceRoot":"","sources":["../../../src/utils/testing/describeFieldTestCase.ts"],"names":[],"mappings":";;AAEA,wCAkBC;AAlBD,SAAwB,qBAAqB,CAC3C,eAAyC,EACzC,WAAgB,EAChB,aAAoB;IAEpB,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,EAAE;QAC9C,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC/E,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/D,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnF,MAAM,CAAC,eAAe,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/entity",
3
- "version": "0.38.0",
3
+ "version": "0.40.0",
4
4
  "description": "A privacy-first data model",
5
5
  "files": [
6
6
  "build",
@@ -16,7 +16,7 @@
16
16
  "test": "jest --rootDir . --config ../../resources/jest.config.js",
17
17
  "integration": "../../resources/run-with-docker yarn integration-no-setup",
18
18
  "integration-no-setup": "jest --config ../../resources/jest-integration.config.js --rootDir . --runInBand --passWithNoTests",
19
- "barrelsby": "barrelsby --config ../../.barrelsby.json"
19
+ "ctix": "ctix build --config ../../.ctirc && ../../resources/prepend-barrel.sh '@expo/entity'"
20
20
  },
21
21
  "engines": {
22
22
  "node": ">=16"
@@ -34,5 +34,21 @@
34
34
  "uuid": "^8.3.0",
35
35
  "uuidv7": "^1.0.0"
36
36
  },
37
- "gitHead": "d7cc0c23b983eccca9ca4e7ca620a5aaef6846c4"
37
+ "devDependencies": {
38
+ "@types/invariant": "^2.2.37",
39
+ "@types/jest": "^29.5.12",
40
+ "@types/node": "^20.14.1",
41
+ "@types/uuid": "^8.3.0",
42
+ "ctix": "^2.7.0",
43
+ "eslint": "^8.57.1",
44
+ "eslint-config-universe": "^14.0.0",
45
+ "eslint-plugin-tsdoc": "^0.3.0",
46
+ "jest": "^29.7.0",
47
+ "prettier": "^3.3.3",
48
+ "prettier-plugin-organize-imports": "^4.1.0",
49
+ "ts-jest": "^29.2.5",
50
+ "ts-mockito": "^2.6.1",
51
+ "typescript": "^5.7.3"
52
+ },
53
+ "gitHead": "74c396255c8177a87cf80da2608072f5989dd519"
38
54
  }
@@ -0,0 +1,492 @@
1
+ import { Result, result } from '@expo/results';
2
+
3
+ import { IEntityClass } from './Entity';
4
+ import EntityPrivacyPolicy from './EntityPrivacyPolicy';
5
+ import { EntityQueryContext } from './EntityQueryContext';
6
+ import ReadonlyEntity from './ReadonlyEntity';
7
+ import ViewerContext from './ViewerContext';
8
+
9
+ /**
10
+ * An association loader is a set of convenience methods for loading entities
11
+ * associated with an entity. In relational databases, these entities are often referenced
12
+ * by foreign keys.
13
+ */
14
+ export default class AuthorizationResultBasedEntityAssociationLoader<
15
+ TFields extends object,
16
+ TID extends NonNullable<TFields[TSelectedFields]>,
17
+ TViewerContext extends ViewerContext,
18
+ TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
19
+ TSelectedFields extends keyof TFields,
20
+ > {
21
+ constructor(
22
+ private readonly entity: TEntity,
23
+ private readonly queryContext: EntityQueryContext,
24
+ ) {}
25
+
26
+ /**
27
+ * Load an associated entity identified by a field value of this entity. In a relational database,
28
+ * the field in this entity is a foreign key to the ID of the associated entity.
29
+ * @param fieldIdentifyingAssociatedEntity - field of this entity containing the ID of the associated entity
30
+ * @param associatedEntityClass - class of the associated entity
31
+ */
32
+ async loadAssociatedEntityAsync<
33
+ TIdentifyingField extends keyof Pick<TFields, TSelectedFields>,
34
+ TAssociatedFields extends object,
35
+ TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
36
+ TAssociatedEntity extends ReadonlyEntity<
37
+ TAssociatedFields,
38
+ TAssociatedID,
39
+ TViewerContext,
40
+ TAssociatedSelectedFields
41
+ >,
42
+ TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
43
+ TAssociatedFields,
44
+ TAssociatedID,
45
+ TViewerContext,
46
+ TAssociatedEntity,
47
+ TAssociatedSelectedFields
48
+ >,
49
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
50
+ >(
51
+ fieldIdentifyingAssociatedEntity: TIdentifyingField,
52
+ associatedEntityClass: IEntityClass<
53
+ TAssociatedFields,
54
+ TAssociatedID,
55
+ TViewerContext,
56
+ TAssociatedEntity,
57
+ TAssociatedPrivacyPolicy,
58
+ TAssociatedSelectedFields
59
+ >,
60
+ ): Promise<
61
+ Result<null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity>
62
+ > {
63
+ const associatedEntityID = this.entity.getField(fieldIdentifyingAssociatedEntity);
64
+ if (!associatedEntityID) {
65
+ return result(null) as Result<
66
+ null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
67
+ >;
68
+ }
69
+
70
+ const loader = this.entity
71
+ .getViewerContext()
72
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
73
+ .getLoaderFactory()
74
+ .forLoad(this.queryContext, { previousValue: null, cascadingDeleteCause: null });
75
+
76
+ return (await loader.loadByIDAsync(associatedEntityID as unknown as TAssociatedID)) as Result<
77
+ null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
78
+ >;
79
+ }
80
+
81
+ /**
82
+ * Load many entities associated with this entity, often referred to as entites belonging
83
+ * to this entity. In a relational database, the field in the foreign entity is a
84
+ * foreign key to the ID of this entity. Also commonly referred to as a has many relationship,
85
+ * where this entity has many associated entities.
86
+ * @param associatedEntityClass - class of the associated entities
87
+ * @param associatedEntityFieldContainingThisID - field of associated entity which contains the ID of this entity
88
+ */
89
+ async loadManyAssociatedEntitiesAsync<
90
+ TAssociatedFields extends object,
91
+ TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
92
+ TAssociatedEntity extends ReadonlyEntity<
93
+ TAssociatedFields,
94
+ TAssociatedID,
95
+ TViewerContext,
96
+ TAssociatedSelectedFields
97
+ >,
98
+ TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
99
+ TAssociatedFields,
100
+ TAssociatedID,
101
+ TViewerContext,
102
+ TAssociatedEntity,
103
+ TAssociatedSelectedFields
104
+ >,
105
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
106
+ >(
107
+ associatedEntityClass: IEntityClass<
108
+ TAssociatedFields,
109
+ TAssociatedID,
110
+ TViewerContext,
111
+ TAssociatedEntity,
112
+ TAssociatedPrivacyPolicy,
113
+ TAssociatedSelectedFields
114
+ >,
115
+ associatedEntityFieldContainingThisID: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
116
+ ): Promise<readonly Result<TAssociatedEntity>[]> {
117
+ const thisID = this.entity.getID();
118
+ const loader = this.entity
119
+ .getViewerContext()
120
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
121
+ .getLoaderFactory()
122
+ .forLoad(this.queryContext, { previousValue: null, cascadingDeleteCause: null });
123
+ return await loader.loadManyByFieldEqualingAsync(
124
+ associatedEntityFieldContainingThisID,
125
+ thisID as any,
126
+ );
127
+ }
128
+
129
+ /**
130
+ * Load an associated entity identified by a field value of this entity. In a relational database,
131
+ * the field in this entity is a foreign key to a unique field of the associated entity.
132
+ * @param fieldIdentifyingAssociatedEntity - field of this entity containing the value with which to look up associated entity
133
+ * @param associatedEntityClass - class of the associated entity
134
+ * @param associatedEntityLookupByField - field of associated entity with which to look up the associated entity
135
+ */
136
+ async loadAssociatedEntityByFieldEqualingAsync<
137
+ TAssociatedFields extends object,
138
+ TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
139
+ TAssociatedEntity extends ReadonlyEntity<
140
+ TAssociatedFields,
141
+ TAssociatedID,
142
+ TViewerContext,
143
+ TAssociatedSelectedFields
144
+ >,
145
+ TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
146
+ TAssociatedFields,
147
+ TAssociatedID,
148
+ TViewerContext,
149
+ TAssociatedEntity,
150
+ TAssociatedSelectedFields
151
+ >,
152
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
153
+ >(
154
+ fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
155
+ associatedEntityClass: IEntityClass<
156
+ TAssociatedFields,
157
+ TAssociatedID,
158
+ TViewerContext,
159
+ TAssociatedEntity,
160
+ TAssociatedPrivacyPolicy,
161
+ TAssociatedSelectedFields
162
+ >,
163
+ associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
164
+ ): Promise<Result<TAssociatedEntity> | null> {
165
+ const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
166
+ if (!associatedFieldValue) {
167
+ return null;
168
+ }
169
+ const loader = this.entity
170
+ .getViewerContext()
171
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
172
+ .getLoaderFactory()
173
+ .forLoad(this.queryContext, { previousValue: null, cascadingDeleteCause: null });
174
+ return await loader.loadByFieldEqualingAsync(
175
+ associatedEntityLookupByField,
176
+ associatedFieldValue as any,
177
+ );
178
+ }
179
+
180
+ /**
181
+ * Load many associated entities identified by a field value of this entity. In a relational database,
182
+ * the field in this entity refers to a field of the associated entity.
183
+ * @param fieldIdentifyingAssociatedEntity - field of this entity containing the value with which to look up associated entities
184
+ * @param associatedEntityClass - class of the associated entities
185
+ * @param associatedEntityLookupByField - field of associated entities with which to look up the associated entities
186
+ */
187
+ async loadManyAssociatedEntitiesByFieldEqualingAsync<
188
+ TAssociatedFields extends object,
189
+ TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
190
+ TAssociatedEntity extends ReadonlyEntity<
191
+ TAssociatedFields,
192
+ TAssociatedID,
193
+ TViewerContext,
194
+ TAssociatedSelectedFields
195
+ >,
196
+ TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
197
+ TAssociatedFields,
198
+ TAssociatedID,
199
+ TViewerContext,
200
+ TAssociatedEntity,
201
+ TAssociatedSelectedFields
202
+ >,
203
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
204
+ >(
205
+ fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
206
+ associatedEntityClass: IEntityClass<
207
+ TAssociatedFields,
208
+ TAssociatedID,
209
+ TViewerContext,
210
+ TAssociatedEntity,
211
+ TAssociatedPrivacyPolicy,
212
+ TAssociatedSelectedFields
213
+ >,
214
+ associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
215
+ ): Promise<readonly Result<TAssociatedEntity>[]> {
216
+ const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
217
+ if (!associatedFieldValue) {
218
+ return [];
219
+ }
220
+
221
+ const loader = this.entity
222
+ .getViewerContext()
223
+ .getViewerScopedEntityCompanionForClass(associatedEntityClass)
224
+ .getLoaderFactory()
225
+ .forLoad(this.queryContext, { previousValue: null, cascadingDeleteCause: null });
226
+ return await loader.loadManyByFieldEqualingAsync(
227
+ associatedEntityLookupByField,
228
+ associatedFieldValue as any,
229
+ );
230
+ }
231
+
232
+ /**
233
+ * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
234
+ * fold step, load an associated entity identified by a field value of the current fold value.
235
+ * @param loadDirectives - associated entity load directives instructing each step of the folds
236
+ */
237
+ async loadAssociatedEntityThroughAsync<
238
+ TFields2 extends object,
239
+ TID2 extends NonNullable<TFields2[TSelectedFields2]>,
240
+ TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
241
+ TPrivacyPolicy2 extends EntityPrivacyPolicy<
242
+ TFields2,
243
+ TID2,
244
+ TViewerContext,
245
+ TEntity2,
246
+ TSelectedFields2
247
+ >,
248
+ TSelectedFields2 extends keyof TFields2 = keyof TFields2,
249
+ >(
250
+ loadDirectives: [
251
+ EntityLoadThroughDirective<
252
+ TViewerContext,
253
+ TFields,
254
+ TFields2,
255
+ TID2,
256
+ TEntity2,
257
+ TPrivacyPolicy2,
258
+ TSelectedFields,
259
+ TSelectedFields2
260
+ >,
261
+ ],
262
+ ): Promise<Result<TEntity2> | null>;
263
+
264
+ /**
265
+ * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
266
+ * fold step, load an associated entity identified by a field value of the current fold value.
267
+ * @param loadDirectives - associated entity load directives instructing each step of the folds
268
+ */
269
+ async loadAssociatedEntityThroughAsync<
270
+ TFields2 extends object,
271
+ TID2 extends NonNullable<TFields2[TSelectedFields2]>,
272
+ TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
273
+ TPrivacyPolicy2 extends EntityPrivacyPolicy<
274
+ TFields2,
275
+ TID2,
276
+ TViewerContext,
277
+ TEntity2,
278
+ TSelectedFields2
279
+ >,
280
+ TFields3 extends object,
281
+ TID3 extends NonNullable<TFields3[TSelectedFields3]>,
282
+ TEntity3 extends ReadonlyEntity<TFields3, TID3, TViewerContext, TSelectedFields3>,
283
+ TPrivacyPolicy3 extends EntityPrivacyPolicy<
284
+ TFields3,
285
+ TID3,
286
+ TViewerContext,
287
+ TEntity3,
288
+ TSelectedFields3
289
+ >,
290
+ TSelectedFields2 extends keyof TFields2 = keyof TFields2,
291
+ TSelectedFields3 extends keyof TFields3 = keyof TFields3,
292
+ >(
293
+ loadDirectives: [
294
+ EntityLoadThroughDirective<
295
+ TViewerContext,
296
+ TFields,
297
+ TFields2,
298
+ TID2,
299
+ TEntity2,
300
+ TPrivacyPolicy2,
301
+ TSelectedFields,
302
+ TSelectedFields2
303
+ >,
304
+ EntityLoadThroughDirective<
305
+ TViewerContext,
306
+ TFields2,
307
+ TFields3,
308
+ TID3,
309
+ TEntity3,
310
+ TPrivacyPolicy3,
311
+ TSelectedFields2,
312
+ TSelectedFields3
313
+ >,
314
+ ],
315
+ ): Promise<Result<TEntity3> | null>;
316
+
317
+ /**
318
+ * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
319
+ * fold step, load an associated entity identified by a field value of the current fold value.
320
+ * @param loadDirectives - associated entity load directives instructing each step of the folds
321
+ */
322
+ async loadAssociatedEntityThroughAsync<
323
+ TFields2 extends object,
324
+ TID2 extends NonNullable<TFields2[TSelectedFields2]>,
325
+ TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
326
+ TPrivacyPolicy2 extends EntityPrivacyPolicy<
327
+ TFields2,
328
+ TID2,
329
+ TViewerContext,
330
+ TEntity2,
331
+ TSelectedFields2
332
+ >,
333
+ TFields3 extends object,
334
+ TID3 extends NonNullable<TFields3[TSelectedFields3]>,
335
+ TEntity3 extends ReadonlyEntity<TFields3, TID3, TViewerContext, TSelectedFields3>,
336
+ TPrivacyPolicy3 extends EntityPrivacyPolicy<
337
+ TFields3,
338
+ TID3,
339
+ TViewerContext,
340
+ TEntity3,
341
+ TSelectedFields3
342
+ >,
343
+ TFields4 extends object,
344
+ TID4 extends NonNullable<TFields4[TSelectedFields4]>,
345
+ TEntity4 extends ReadonlyEntity<TFields4, TID4, TViewerContext, TSelectedFields4>,
346
+ TPrivacyPolicy4 extends EntityPrivacyPolicy<
347
+ TFields4,
348
+ TID4,
349
+ TViewerContext,
350
+ TEntity4,
351
+ TSelectedFields4
352
+ >,
353
+ TSelectedFields2 extends keyof TFields2 = keyof TFields2,
354
+ TSelectedFields3 extends keyof TFields3 = keyof TFields3,
355
+ TSelectedFields4 extends keyof TFields4 = keyof TFields4,
356
+ >(
357
+ loadDirectives: [
358
+ EntityLoadThroughDirective<
359
+ TViewerContext,
360
+ TFields,
361
+ TFields2,
362
+ TID2,
363
+ TEntity2,
364
+ TPrivacyPolicy2,
365
+ TSelectedFields,
366
+ TSelectedFields2
367
+ >,
368
+ EntityLoadThroughDirective<
369
+ TViewerContext,
370
+ TFields2,
371
+ TFields3,
372
+ TID3,
373
+ TEntity3,
374
+ TPrivacyPolicy3,
375
+ TSelectedFields2,
376
+ TSelectedFields3
377
+ >,
378
+ EntityLoadThroughDirective<
379
+ TViewerContext,
380
+ TFields3,
381
+ TFields4,
382
+ TID4,
383
+ TEntity4,
384
+ TPrivacyPolicy4,
385
+ TSelectedFields3,
386
+ TSelectedFields4
387
+ >,
388
+ ],
389
+ ): Promise<Result<TEntity4> | null>;
390
+
391
+ /**
392
+ * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
393
+ * fold step, load an associated entity identified by a field value of the current fold value.
394
+ * @param loadDirectives - associated entity load directives instructing each step of the folds
395
+ */
396
+ async loadAssociatedEntityThroughAsync(
397
+ loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
398
+ ): Promise<Result<ReadonlyEntity<any, any, any, any>> | null>;
399
+
400
+ async loadAssociatedEntityThroughAsync(
401
+ loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
402
+ ): Promise<Result<ReadonlyEntity<any, any, any, any>> | null> {
403
+ let currentEntity: ReadonlyEntity<any, any, any, any> = this.entity;
404
+ for (const loadDirective of loadDirectives) {
405
+ const {
406
+ associatedEntityClass,
407
+ fieldIdentifyingAssociatedEntity,
408
+ associatedEntityLookupByField,
409
+ } = loadDirective;
410
+ let associatedEntityResult: Result<ReadonlyEntity<any, any, any, any>> | null;
411
+ if (associatedEntityLookupByField) {
412
+ associatedEntityResult = await currentEntity
413
+ .associationLoader(this.queryContext)
414
+ .withAuthorizationResults()
415
+ .loadAssociatedEntityByFieldEqualingAsync(
416
+ fieldIdentifyingAssociatedEntity,
417
+ associatedEntityClass,
418
+ associatedEntityLookupByField,
419
+ );
420
+ } else {
421
+ const associatedEntityResultLocal = await currentEntity
422
+ .associationLoader(this.queryContext)
423
+ .withAuthorizationResults()
424
+ .loadAssociatedEntityAsync(fieldIdentifyingAssociatedEntity, associatedEntityClass);
425
+
426
+ if (associatedEntityResultLocal.ok && associatedEntityResultLocal.value === null) {
427
+ associatedEntityResult = null;
428
+ } else {
429
+ associatedEntityResult = associatedEntityResultLocal;
430
+ }
431
+ }
432
+
433
+ if (!associatedEntityResult) {
434
+ return null;
435
+ }
436
+
437
+ if (!associatedEntityResult.ok) {
438
+ return result(associatedEntityResult.reason);
439
+ }
440
+ currentEntity = associatedEntityResult.value;
441
+ }
442
+ return result(currentEntity);
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Instruction for each step of a load-associated-through method.
448
+ */
449
+ export interface EntityLoadThroughDirective<
450
+ TViewerContext extends ViewerContext,
451
+ TFields,
452
+ TAssociatedFields extends object,
453
+ TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
454
+ TAssociatedEntity extends ReadonlyEntity<
455
+ TAssociatedFields,
456
+ TAssociatedID,
457
+ TViewerContext,
458
+ TAssociatedSelectedFields
459
+ >,
460
+ TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
461
+ TAssociatedFields,
462
+ TAssociatedID,
463
+ TViewerContext,
464
+ TAssociatedEntity,
465
+ TAssociatedSelectedFields
466
+ >,
467
+ TSelectedFields extends keyof TFields = keyof TFields,
468
+ TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
469
+ > {
470
+ /**
471
+ * Class of entity to load at this step.
472
+ */
473
+ associatedEntityClass: IEntityClass<
474
+ TAssociatedFields,
475
+ TAssociatedID,
476
+ TViewerContext,
477
+ TAssociatedEntity,
478
+ TAssociatedPrivacyPolicy,
479
+ TAssociatedSelectedFields
480
+ >;
481
+
482
+ /**
483
+ * Field of the current entity with which to load an instance of associatedEntityClass.
484
+ */
485
+ fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>;
486
+
487
+ /**
488
+ * Field by which to load the instance of associatedEntityClass. If not provided, the
489
+ * associatedEntityClass instance is fetched by its ID.
490
+ */
491
+ associatedEntityLookupByField?: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>;
492
+ }
@@ -54,7 +54,7 @@ export default class AuthorizationResultBasedEntityLoader<
54
54
  >,
55
55
  private readonly dataManager: EntityDataManager<TFields>,
56
56
  protected readonly metricsAdapter: IEntityMetricsAdapter,
57
- private readonly utils: EntityLoaderUtils<
57
+ public readonly utils: EntityLoaderUtils<
58
58
  TFields,
59
59
  TID,
60
60
  TViewerContext,
@@ -102,7 +102,7 @@ export default class AuthorizationResultBasedEntityLoader<
102
102
  entityResultsForFieldValue !== undefined,
103
103
  `${fieldValue} should be guaranteed to be present in returned map of entities`,
104
104
  );
105
- return entityResultsForFieldValue!;
105
+ return entityResultsForFieldValue;
106
106
  }
107
107
 
108
108
  /**