@expo/entity 0.39.0 → 0.41.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 (175) hide show
  1. package/build/AuthorizationResultBasedEntityAssociationLoader.d.ts +99 -0
  2. package/build/AuthorizationResultBasedEntityAssociationLoader.js +122 -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 +26 -8
  22. package/build/Entity.js +38 -25
  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/EntityCreator.d.ts +27 -0
  28. package/build/EntityCreator.js +39 -0
  29. package/build/EntityCreator.js.map +1 -0
  30. package/build/EntityDeleter.d.ts +27 -0
  31. package/build/EntityDeleter.js +40 -0
  32. package/build/EntityDeleter.js.map +1 -0
  33. package/build/EntityLoader.d.ts +4 -14
  34. package/build/EntityLoader.js +7 -20
  35. package/build/EntityLoader.js.map +1 -1
  36. package/build/EntityLoaderFactory.d.ts +2 -2
  37. package/build/EntityLoaderFactory.js +4 -2
  38. package/build/EntityLoaderFactory.js.map +1 -1
  39. package/build/EntityMutatorFactory.d.ts +4 -4
  40. package/build/EntityMutatorFactory.js +4 -4
  41. package/build/EntityMutatorFactory.js.map +1 -1
  42. package/build/EntitySecondaryCacheLoader.d.ts +3 -3
  43. package/build/EntitySecondaryCacheLoader.js +1 -3
  44. package/build/EntitySecondaryCacheLoader.js.map +1 -1
  45. package/build/EntityUpdater.d.ts +27 -0
  46. package/build/EntityUpdater.js +40 -0
  47. package/build/EntityUpdater.js.map +1 -0
  48. package/build/ReadonlyEntity.d.ts +24 -5
  49. package/build/ReadonlyEntity.js +33 -7
  50. package/build/ReadonlyEntity.js.map +1 -1
  51. package/build/ViewerScopedEntityLoaderFactory.d.ts +2 -2
  52. package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
  53. package/build/ViewerScopedEntityMutatorFactory.d.ts +4 -4
  54. package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
  55. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.d.ts +1 -0
  56. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js +242 -0
  57. package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js.map +1 -0
  58. package/build/__tests__/{EntityLoader-constructor-test.js → AuthorizationResultBasedEntityLoader-constructor-test.js} +10 -10
  59. package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js.map +1 -0
  60. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.d.ts +1 -0
  61. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js +401 -0
  62. package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js.map +1 -0
  63. package/build/__tests__/EnforcingEntityAssociationLoader-test.d.ts +1 -0
  64. package/build/__tests__/EnforcingEntityAssociationLoader-test.js +115 -0
  65. package/build/__tests__/EnforcingEntityAssociationLoader-test.js.map +1 -0
  66. package/build/__tests__/Entity-test.js +63 -5
  67. package/build/__tests__/Entity-test.js.map +1 -1
  68. package/build/__tests__/EntityAssociationLoader-test.js +14 -184
  69. package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
  70. package/build/__tests__/EntityCommonUseCases-test.js +34 -20
  71. package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
  72. package/build/__tests__/EntityCompanion-test.js +17 -7
  73. package/build/__tests__/EntityCompanion-test.js.map +1 -1
  74. package/build/__tests__/EntityEdges-test.js +57 -71
  75. package/build/__tests__/EntityEdges-test.js.map +1 -1
  76. package/build/__tests__/EntityLoader-test.js +22 -386
  77. package/build/__tests__/EntityLoader-test.js.map +1 -1
  78. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +6 -9
  79. package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
  80. package/build/__tests__/EntityMutator-test.js +67 -70
  81. package/build/__tests__/EntityMutator-test.js.map +1 -1
  82. package/build/__tests__/EntityPrivacyPolicy-test.js +17 -7
  83. package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
  84. package/build/__tests__/EntitySecondaryCacheLoader-test.js +7 -7
  85. package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
  86. package/build/__tests__/EntitySelfReferentialEdges-test.js +47 -81
  87. package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
  88. package/build/__tests__/ReadonlyEntity-test.js +40 -7
  89. package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
  90. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +6 -10
  91. package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
  92. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +10 -22
  93. package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
  94. package/build/errors/EntityCacheAdapterError.js +17 -7
  95. package/build/errors/EntityCacheAdapterError.js.map +1 -1
  96. package/build/errors/EntityDatabaseAdapterError.js +17 -7
  97. package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
  98. package/build/errors/EntityInvalidFieldValueError.js +17 -7
  99. package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
  100. package/build/errors/EntityNotAuthorizedError.js +17 -7
  101. package/build/errors/EntityNotAuthorizedError.js.map +1 -1
  102. package/build/errors/EntityNotFoundError.js +17 -7
  103. package/build/errors/EntityNotFoundError.js.map +1 -1
  104. package/build/index.d.ts +19 -11
  105. package/build/index.js +24 -7
  106. package/build/index.js.map +1 -1
  107. package/build/internal/__tests__/EntityDataManager-test.js +42 -32
  108. package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
  109. package/build/internal/__tests__/ReadThroughEntityCache-test.js +17 -7
  110. package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
  111. package/build/rules/AlwaysAllowPrivacyPolicyRule.js +17 -7
  112. package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
  113. package/build/rules/AlwaysDenyPrivacyPolicyRule.js +17 -7
  114. package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
  115. package/build/rules/AlwaysSkipPrivacyPolicyRule.js +17 -7
  116. package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
  117. package/build/utils/EntityPrivacyUtils.js +4 -8
  118. package/build/utils/EntityPrivacyUtils.js.map +1 -1
  119. package/build/utils/__tests__/EntityPrivacyUtils-test.js +38 -28
  120. package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -1
  121. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js +5 -5
  122. package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js.map +1 -1
  123. package/build/utils/testing/StubDatabaseAdapter.js +17 -7
  124. package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
  125. package/build/utils/testing/StubQueryContextProvider.d.ts +1 -3
  126. package/build/utils/testing/StubQueryContextProvider.js +1 -3
  127. package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
  128. package/build/utils/testing/createUnitTestEntityCompanionProvider.js +2 -1
  129. package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +1 -1
  130. package/package.json +19 -3
  131. package/src/AuthorizationResultBasedEntityAssociationLoader.ts +490 -0
  132. package/src/AuthorizationResultBasedEntityLoader.ts +1 -1
  133. package/src/{EntityMutator.ts → AuthorizationResultBasedEntityMutator.ts} +62 -58
  134. package/src/EnforcingEntityAssociationLoader.ts +390 -0
  135. package/src/EnforcingEntityCreator.ts +55 -0
  136. package/src/EnforcingEntityDeleter.ts +44 -0
  137. package/src/EnforcingEntityUpdater.ts +55 -0
  138. package/src/Entity.ts +140 -29
  139. package/src/EntityAssociationLoader.ts +38 -495
  140. package/src/EntityCreator.ts +73 -0
  141. package/src/EntityDeleter.ts +73 -0
  142. package/src/EntityLoader.ts +10 -49
  143. package/src/EntityLoaderFactory.ts +20 -3
  144. package/src/EntityMutatorFactory.ts +32 -7
  145. package/src/EntitySecondaryCacheLoader.ts +5 -7
  146. package/src/EntityUpdater.ts +73 -0
  147. package/src/ReadonlyEntity.ts +121 -7
  148. package/src/ViewerScopedEntityLoaderFactory.ts +9 -2
  149. package/src/ViewerScopedEntityMutatorFactory.ts +29 -4
  150. package/src/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.ts +323 -0
  151. package/src/__tests__/{EntityLoader-constructor-test.ts → AuthorizationResultBasedEntityLoader-constructor-test.ts} +16 -9
  152. package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +730 -0
  153. package/src/__tests__/EnforcingEntityAssociationLoader-test.ts +253 -0
  154. package/src/__tests__/Entity-test.ts +77 -5
  155. package/src/__tests__/EntityAssociationLoader-test.ts +15 -260
  156. package/src/__tests__/EntityCommonUseCases-test.ts +24 -15
  157. package/src/__tests__/EntityEdges-test.ts +44 -64
  158. package/src/__tests__/EntityLoader-test.ts +29 -681
  159. package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +8 -9
  160. package/src/__tests__/EntityMutator-test.ts +116 -103
  161. package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
  162. package/src/__tests__/EntitySelfReferentialEdges-test.ts +65 -81
  163. package/src/__tests__/ReadonlyEntity-test.ts +47 -7
  164. package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +15 -15
  165. package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +19 -22
  166. package/src/index.ts +19 -11
  167. package/src/internal/__tests__/EntityDataManager-test.ts +25 -25
  168. package/src/utils/EntityPrivacyUtils.ts +10 -13
  169. package/src/utils/__tests__/EntityPrivacyUtils-test.ts +21 -23
  170. package/src/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.ts +5 -5
  171. package/src/utils/testing/StubQueryContextProvider.ts +1 -3
  172. package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +3 -1
  173. package/build/EntityMutator.js.map +0 -1
  174. package/build/__tests__/EntityLoader-constructor-test.js.map +0 -1
  175. /package/build/__tests__/{EntityLoader-constructor-test.d.ts → AuthorizationResultBasedEntityLoader-constructor-test.d.ts} +0 -0
@@ -1,14 +1,11 @@
1
1
  import AuthorizationResultBasedEntityLoader from './AuthorizationResultBasedEntityLoader';
2
2
  import EnforcingEntityLoader from './EnforcingEntityLoader';
3
3
  import { IEntityClass } from './Entity';
4
- import EntityConfiguration from './EntityConfiguration';
5
4
  import EntityLoaderUtils from './EntityLoaderUtils';
6
- import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
5
+ import EntityPrivacyPolicy from './EntityPrivacyPolicy';
7
6
  import { EntityQueryContext } from './EntityQueryContext';
8
7
  import ReadonlyEntity from './ReadonlyEntity';
9
8
  import ViewerContext from './ViewerContext';
10
- import EntityDataManager from './internal/EntityDataManager';
11
- import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
12
9
 
13
10
  /**
14
11
  * The primary interface for loading entities. All normal loads are batched,
@@ -18,6 +15,7 @@ export default class EntityLoader<
18
15
  TFields extends object,
19
16
  TID extends NonNullable<TFields[TSelectedFields]>,
20
17
  TViewerContext extends ViewerContext,
18
+ TViewerContext2 extends TViewerContext,
21
19
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
22
20
  TPrivacyPolicy extends EntityPrivacyPolicy<
23
21
  TFields,
@@ -28,26 +26,9 @@ export default class EntityLoader<
28
26
  >,
29
27
  TSelectedFields extends keyof TFields,
30
28
  > {
31
- private readonly utilsPrivate: EntityLoaderUtils<
32
- TFields,
33
- TID,
34
- TViewerContext,
35
- TEntity,
36
- TPrivacyPolicy,
37
- TSelectedFields
38
- >;
39
-
40
29
  constructor(
41
- private readonly viewerContext: TViewerContext,
30
+ private readonly viewerContext: TViewerContext2,
42
31
  private readonly queryContext: EntityQueryContext,
43
- private readonly privacyPolicyEvaluationContext: EntityPrivacyPolicyEvaluationContext<
44
- TFields,
45
- TID,
46
- TViewerContext,
47
- TEntity,
48
- TSelectedFields
49
- >,
50
- private readonly entityConfiguration: EntityConfiguration<TFields>,
51
32
  private readonly entityClass: IEntityClass<
52
33
  TFields,
53
34
  TID,
@@ -56,23 +37,7 @@ export default class EntityLoader<
56
37
  TPrivacyPolicy,
57
38
  TSelectedFields
58
39
  >,
59
- private readonly entitySelectedFields: TSelectedFields[] | undefined,
60
- private readonly privacyPolicy: TPrivacyPolicy,
61
- private readonly dataManager: EntityDataManager<TFields>,
62
- protected readonly metricsAdapter: IEntityMetricsAdapter,
63
- ) {
64
- this.utilsPrivate = new EntityLoaderUtils(
65
- this.viewerContext,
66
- this.queryContext,
67
- this.privacyPolicyEvaluationContext,
68
- this.entityConfiguration,
69
- this.entityClass,
70
- this.entitySelectedFields,
71
- this.privacyPolicy,
72
- this.dataManager,
73
- this.metricsAdapter,
74
- );
75
- }
40
+ ) {}
76
41
 
77
42
  /**
78
43
  * Enforcing entity loader. All loads through this loader are
@@ -92,7 +57,7 @@ export default class EntityLoader<
92
57
 
93
58
  /**
94
59
  * Authorization-result-based entity loader. All loads through this
95
- * loader are are results (or null for some loader methods), where an unsuccessful result
60
+ * loader are results (or null for some loader methods), where an unsuccessful result
96
61
  * means an authorization error or entity construction error occurred. Other errors are thrown.
97
62
  */
98
63
  withAuthorizationResults(): AuthorizationResultBasedEntityLoader<
@@ -103,14 +68,10 @@ export default class EntityLoader<
103
68
  TPrivacyPolicy,
104
69
  TSelectedFields
105
70
  > {
106
- return new AuthorizationResultBasedEntityLoader(
107
- this.queryContext,
108
- this.entityConfiguration,
109
- this.entityClass,
110
- this.dataManager,
111
- this.metricsAdapter,
112
- this.utilsPrivate,
113
- );
71
+ return this.viewerContext
72
+ .getViewerScopedEntityCompanionForClass(this.entityClass)
73
+ .getLoaderFactory()
74
+ .forLoad(this.queryContext, { previousValue: null, cascadingDeleteCause: null });
114
75
  }
115
76
 
116
77
  /**
@@ -125,6 +86,6 @@ export default class EntityLoader<
125
86
  TPrivacyPolicy,
126
87
  TSelectedFields
127
88
  > {
128
- return this.utilsPrivate;
89
+ return this.withAuthorizationResults().utils;
129
90
  }
130
91
  }
@@ -1,5 +1,6 @@
1
+ import AuthorizationResultBasedEntityLoader from './AuthorizationResultBasedEntityLoader';
1
2
  import EntityCompanion from './EntityCompanion';
2
- import EntityLoader from './EntityLoader';
3
+ import EntityLoaderUtils from './EntityLoaderUtils';
3
4
  import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
4
5
  import { EntityQueryContext } from './EntityQueryContext';
5
6
  import ReadonlyEntity from './ReadonlyEntity';
@@ -52,8 +53,15 @@ export default class EntityLoaderFactory<
52
53
  TEntity,
53
54
  TSelectedFields
54
55
  >,
55
- ): EntityLoader<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
56
- return new EntityLoader(
56
+ ): AuthorizationResultBasedEntityLoader<
57
+ TFields,
58
+ TID,
59
+ TViewerContext,
60
+ TEntity,
61
+ TPrivacyPolicy,
62
+ TSelectedFields
63
+ > {
64
+ const utils = new EntityLoaderUtils(
57
65
  viewerContext,
58
66
  queryContext,
59
67
  privacyPolicyEvaluationContext,
@@ -64,5 +72,14 @@ export default class EntityLoaderFactory<
64
72
  this.dataManager,
65
73
  this.metricsAdapter,
66
74
  );
75
+
76
+ return new AuthorizationResultBasedEntityLoader(
77
+ queryContext,
78
+ this.entityCompanion.entityCompanionDefinition.entityConfiguration,
79
+ this.entityCompanion.entityCompanionDefinition.entityClass,
80
+ this.dataManager,
81
+ this.metricsAdapter,
82
+ utils,
83
+ );
67
84
  }
68
85
  }
@@ -1,3 +1,8 @@
1
+ import {
2
+ AuthorizationResultBasedCreateMutator,
3
+ AuthorizationResultBasedUpdateMutator,
4
+ AuthorizationResultBasedDeleteMutator,
5
+ } from './AuthorizationResultBasedEntityMutator';
1
6
  import Entity, { IEntityClass } from './Entity';
2
7
  import EntityCompanionProvider from './EntityCompanionProvider';
3
8
  import EntityConfiguration from './EntityConfiguration';
@@ -5,7 +10,6 @@ import EntityDatabaseAdapter from './EntityDatabaseAdapter';
5
10
  import EntityLoaderFactory from './EntityLoaderFactory';
6
11
  import EntityMutationTriggerConfiguration from './EntityMutationTriggerConfiguration';
7
12
  import EntityMutationValidator from './EntityMutationValidator';
8
- import { CreateMutator, UpdateMutator, DeleteMutator } from './EntityMutator';
9
13
  import EntityPrivacyPolicy from './EntityPrivacyPolicy';
10
14
  import { EntityQueryContext } from './EntityQueryContext';
11
15
  import ViewerContext from './ViewerContext';
@@ -75,8 +79,15 @@ export default class EntityMutatorFactory<
75
79
  forCreate(
76
80
  viewerContext: TViewerContext,
77
81
  queryContext: EntityQueryContext,
78
- ): CreateMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
79
- return new CreateMutator(
82
+ ): AuthorizationResultBasedCreateMutator<
83
+ TFields,
84
+ TID,
85
+ TViewerContext,
86
+ TEntity,
87
+ TPrivacyPolicy,
88
+ TSelectedFields
89
+ > {
90
+ return new AuthorizationResultBasedCreateMutator(
80
91
  this.entityCompanionProvider,
81
92
  viewerContext,
82
93
  queryContext,
@@ -100,8 +111,15 @@ export default class EntityMutatorFactory<
100
111
  forUpdate(
101
112
  existingEntity: TEntity,
102
113
  queryContext: EntityQueryContext,
103
- ): UpdateMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
104
- return new UpdateMutator(
114
+ ): AuthorizationResultBasedUpdateMutator<
115
+ TFields,
116
+ TID,
117
+ TViewerContext,
118
+ TEntity,
119
+ TPrivacyPolicy,
120
+ TSelectedFields
121
+ > {
122
+ return new AuthorizationResultBasedUpdateMutator(
105
123
  this.entityCompanionProvider,
106
124
  existingEntity.getViewerContext(),
107
125
  queryContext,
@@ -125,8 +143,15 @@ export default class EntityMutatorFactory<
125
143
  forDelete(
126
144
  existingEntity: TEntity,
127
145
  queryContext: EntityQueryContext,
128
- ): DeleteMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
129
- return new DeleteMutator(
146
+ ): AuthorizationResultBasedDeleteMutator<
147
+ TFields,
148
+ TID,
149
+ TViewerContext,
150
+ TEntity,
151
+ TPrivacyPolicy,
152
+ TSelectedFields
153
+ > {
154
+ return new AuthorizationResultBasedDeleteMutator(
130
155
  this.entityCompanionProvider,
131
156
  existingEntity.getViewerContext(),
132
157
  queryContext,
@@ -1,6 +1,6 @@
1
1
  import { Result } from '@expo/results';
2
2
 
3
- import EntityLoader from './EntityLoader';
3
+ import AuthorizationResultBasedEntityLoader from './AuthorizationResultBasedEntityLoader';
4
4
  import EntityPrivacyPolicy from './EntityPrivacyPolicy';
5
5
  import ReadonlyEntity from './ReadonlyEntity';
6
6
  import ViewerContext from './ViewerContext';
@@ -60,7 +60,7 @@ export default abstract class EntitySecondaryCacheLoader<
60
60
  > {
61
61
  constructor(
62
62
  private readonly secondaryEntityCache: ISecondaryEntityCache<TFields, TLoadParams>,
63
- protected readonly entityLoader: EntityLoader<
63
+ protected readonly entityLoader: AuthorizationResultBasedEntityLoader<
64
64
  TFields,
65
65
  TID,
66
66
  TViewerContext,
@@ -84,11 +84,9 @@ export default abstract class EntitySecondaryCacheLoader<
84
84
  );
85
85
 
86
86
  // convert value to and from array to reuse complex code
87
- const entitiesMap = await this.entityLoader
88
- .utils()
89
- .constructAndAuthorizeEntitiesAsync(
90
- mapMap(loadParamsToFieldObjects, (fieldObject) => (fieldObject ? [fieldObject] : [])),
91
- );
87
+ const entitiesMap = await this.entityLoader.utils.constructAndAuthorizeEntitiesAsync(
88
+ mapMap(loadParamsToFieldObjects, (fieldObject) => (fieldObject ? [fieldObject] : [])),
89
+ );
92
90
  return mapMap(entitiesMap, (fieldObjects) => fieldObjects[0] ?? null);
93
91
  }
94
92
 
@@ -0,0 +1,73 @@
1
+ import { AuthorizationResultBasedUpdateMutator } from './AuthorizationResultBasedEntityMutator';
2
+ import EnforcingEntityUpdater from './EnforcingEntityUpdater';
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
+ * The primary interface for updating entities.
11
+ */
12
+ export default class EntityUpdater<
13
+ TFields extends object,
14
+ TID extends NonNullable<TFields[TSelectedFields]>,
15
+ TViewerContext extends ViewerContext,
16
+ TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
17
+ TPrivacyPolicy extends EntityPrivacyPolicy<
18
+ TFields,
19
+ TID,
20
+ TViewerContext,
21
+ TEntity,
22
+ TSelectedFields
23
+ >,
24
+ TSelectedFields extends keyof TFields,
25
+ > {
26
+ constructor(
27
+ private readonly existingEntity: TEntity,
28
+ private readonly queryContext: EntityQueryContext,
29
+ private readonly entityClass: IEntityClass<
30
+ TFields,
31
+ TID,
32
+ TViewerContext,
33
+ TEntity,
34
+ TPrivacyPolicy,
35
+ TSelectedFields
36
+ >,
37
+ ) {}
38
+
39
+ /**
40
+ * Enforcing entity updater. All updates through this updater are
41
+ * guaranteed to be successful and will throw otherwise.
42
+ */
43
+ enforcing(): EnforcingEntityUpdater<
44
+ TFields,
45
+ TID,
46
+ TViewerContext,
47
+ TEntity,
48
+ TPrivacyPolicy,
49
+ TSelectedFields
50
+ > {
51
+ return new EnforcingEntityUpdater(this.withAuthorizationResults());
52
+ }
53
+
54
+ /**
55
+ * Authorization-result-based entity updater. All updates through this
56
+ * updater are results, where an unsuccessful result means an authorization
57
+ * error or entity construction error occurred. Other errors are thrown.
58
+ */
59
+ withAuthorizationResults(): AuthorizationResultBasedUpdateMutator<
60
+ TFields,
61
+ TID,
62
+ TViewerContext,
63
+ TEntity,
64
+ TPrivacyPolicy,
65
+ TSelectedFields
66
+ > {
67
+ return this.existingEntity
68
+ .getViewerContext()
69
+ .getViewerScopedEntityCompanionForClass(this.entityClass)
70
+ .getMutatorFactory()
71
+ .forUpdate(this.existingEntity, this.queryContext);
72
+ }
73
+ }
@@ -1,8 +1,13 @@
1
1
  import invariant from 'invariant';
2
2
 
3
+ import AuthorizationResultBasedEntityAssociationLoader from './AuthorizationResultBasedEntityAssociationLoader';
4
+ import AuthorizationResultBasedEntityLoader from './AuthorizationResultBasedEntityLoader';
5
+ import EnforcingEntityAssociationLoader from './EnforcingEntityAssociationLoader';
6
+ import EnforcingEntityLoader from './EnforcingEntityLoader';
3
7
  import { IEntityClass } from './Entity';
4
8
  import EntityAssociationLoader from './EntityAssociationLoader';
5
9
  import EntityLoader from './EntityLoader';
10
+ import EntityLoaderUtils from './EntityLoaderUtils';
6
11
  import EntityPrivacyPolicy from './EntityPrivacyPolicy';
7
12
  import { EntityQueryContext } from './EntityQueryContext';
8
13
  import ViewerContext from './ViewerContext';
@@ -82,16 +87,33 @@ export default abstract class ReadonlyEntity<
82
87
  }
83
88
 
84
89
  /**
85
- * @returns EntityAssociationLoader for this entity
90
+ * @returns EnforcingEntityAssociationLoader for this entity
86
91
  */
87
- associationLoader(): EntityAssociationLoader<
92
+ associationLoader(
93
+ queryContext?: EntityQueryContext,
94
+ ): EnforcingEntityAssociationLoader<TFields, TID, TViewerContext, this, TSelectedFields> {
95
+ return new EntityAssociationLoader<TFields, TID, TViewerContext, this, TSelectedFields>(
96
+ this,
97
+ queryContext,
98
+ ).enforcing();
99
+ }
100
+
101
+ /**
102
+ * @returns AuthorizationResultBasedEntityAssociationLoader for this entity
103
+ */
104
+ associationLoaderWithAuthorizationResults(
105
+ queryContext?: EntityQueryContext,
106
+ ): AuthorizationResultBasedEntityAssociationLoader<
88
107
  TFields,
89
108
  TID,
90
109
  TViewerContext,
91
110
  this,
92
111
  TSelectedFields
93
112
  > {
94
- return new EntityAssociationLoader(this);
113
+ return new EntityAssociationLoader<TFields, TID, TViewerContext, this, TSelectedFields>(
114
+ this,
115
+ queryContext,
116
+ ).withAuthorizationResults();
95
117
  }
96
118
 
97
119
  /**
@@ -152,10 +174,102 @@ export default abstract class ReadonlyEntity<
152
174
  .getViewerScopedEntityCompanionForClass(this)
153
175
  .getQueryContextProvider()
154
176
  .getQueryContext(),
155
- ): EntityLoader<TMFields, TMID, TMViewerContext, TMEntity, TMPrivacyPolicy, TMSelectedFields> {
156
- return viewerContext
177
+ ): EnforcingEntityLoader<
178
+ TMFields,
179
+ TMID,
180
+ TMViewerContext,
181
+ TMEntity,
182
+ TMPrivacyPolicy,
183
+ TMSelectedFields
184
+ > {
185
+ return new EntityLoader(viewerContext, queryContext, this).enforcing();
186
+ }
187
+
188
+ /**
189
+ * Vend loader for loading an entity in a given query context.
190
+ * @param viewerContext - viewer context of loading user
191
+ * @param queryContext - query context in which to perform the load
192
+ */
193
+ static loaderWithAuthorizationResults<
194
+ TMFields extends object,
195
+ TMID extends NonNullable<TMFields[TMSelectedFields]>,
196
+ TMViewerContext extends ViewerContext,
197
+ TMViewerContext2 extends TMViewerContext,
198
+ TMEntity extends ReadonlyEntity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
199
+ TMPrivacyPolicy extends EntityPrivacyPolicy<
200
+ TMFields,
201
+ TMID,
202
+ TMViewerContext,
203
+ TMEntity,
204
+ TMSelectedFields
205
+ >,
206
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
207
+ >(
208
+ this: IEntityClass<
209
+ TMFields,
210
+ TMID,
211
+ TMViewerContext,
212
+ TMEntity,
213
+ TMPrivacyPolicy,
214
+ TMSelectedFields
215
+ >,
216
+ viewerContext: TMViewerContext2,
217
+ queryContext: EntityQueryContext = viewerContext
218
+ .getViewerScopedEntityCompanionForClass(this)
219
+ .getQueryContextProvider()
220
+ .getQueryContext(),
221
+ ): AuthorizationResultBasedEntityLoader<
222
+ TMFields,
223
+ TMID,
224
+ TMViewerContext,
225
+ TMEntity,
226
+ TMPrivacyPolicy,
227
+ TMSelectedFields
228
+ > {
229
+ return new EntityLoader(viewerContext, queryContext, this).withAuthorizationResults();
230
+ }
231
+
232
+ /**
233
+ * Vend loader for loading an entity in a given query context.
234
+ * @param viewerContext - viewer context of loading user
235
+ * @param queryContext - query context in which to perform the load
236
+ */
237
+ static loaderUtils<
238
+ TMFields extends object,
239
+ TMID extends NonNullable<TMFields[TMSelectedFields]>,
240
+ TMViewerContext extends ViewerContext,
241
+ TMViewerContext2 extends TMViewerContext,
242
+ TMEntity extends ReadonlyEntity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
243
+ TMPrivacyPolicy extends EntityPrivacyPolicy<
244
+ TMFields,
245
+ TMID,
246
+ TMViewerContext,
247
+ TMEntity,
248
+ TMSelectedFields
249
+ >,
250
+ TMSelectedFields extends keyof TMFields = keyof TMFields,
251
+ >(
252
+ this: IEntityClass<
253
+ TMFields,
254
+ TMID,
255
+ TMViewerContext,
256
+ TMEntity,
257
+ TMPrivacyPolicy,
258
+ TMSelectedFields
259
+ >,
260
+ viewerContext: TMViewerContext2,
261
+ queryContext: EntityQueryContext = viewerContext
157
262
  .getViewerScopedEntityCompanionForClass(this)
158
- .getLoaderFactory()
159
- .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
263
+ .getQueryContextProvider()
264
+ .getQueryContext(),
265
+ ): EntityLoaderUtils<
266
+ TMFields,
267
+ TMID,
268
+ TMViewerContext,
269
+ TMEntity,
270
+ TMPrivacyPolicy,
271
+ TMSelectedFields
272
+ > {
273
+ return new EntityLoader(viewerContext, queryContext, this).utils();
160
274
  }
161
275
  }
@@ -1,4 +1,4 @@
1
- import EntityLoader from './EntityLoader';
1
+ import AuthorizationResultBasedEntityLoader from './AuthorizationResultBasedEntityLoader';
2
2
  import EntityLoaderFactory from './EntityLoaderFactory';
3
3
  import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
4
4
  import { EntityQueryContext } from './EntityQueryContext';
@@ -43,7 +43,14 @@ export default class ViewerScopedEntityLoaderFactory<
43
43
  TEntity,
44
44
  TSelectedFields
45
45
  >,
46
- ): EntityLoader<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
46
+ ): AuthorizationResultBasedEntityLoader<
47
+ TFields,
48
+ TID,
49
+ TViewerContext,
50
+ TEntity,
51
+ TPrivacyPolicy,
52
+ TSelectedFields
53
+ > {
47
54
  return this.entityLoaderFactory.forLoad(
48
55
  this.viewerContext,
49
56
  queryContext,
@@ -1,4 +1,8 @@
1
- import { CreateMutator, UpdateMutator, DeleteMutator } from './EntityMutator';
1
+ import {
2
+ AuthorizationResultBasedCreateMutator,
3
+ AuthorizationResultBasedUpdateMutator,
4
+ AuthorizationResultBasedDeleteMutator,
5
+ } from './AuthorizationResultBasedEntityMutator';
2
6
  import EntityMutatorFactory from './EntityMutatorFactory';
3
7
  import EntityPrivacyPolicy from './EntityPrivacyPolicy';
4
8
  import { EntityQueryContext } from './EntityQueryContext';
@@ -36,21 +40,42 @@ export default class ViewerScopedEntityMutatorFactory<
36
40
 
37
41
  forCreate(
38
42
  queryContext: EntityQueryContext,
39
- ): CreateMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
43
+ ): AuthorizationResultBasedCreateMutator<
44
+ TFields,
45
+ TID,
46
+ TViewerContext,
47
+ TEntity,
48
+ TPrivacyPolicy,
49
+ TSelectedFields
50
+ > {
40
51
  return this.entityMutatorFactory.forCreate(this.viewerContext, queryContext);
41
52
  }
42
53
 
43
54
  forUpdate(
44
55
  existingEntity: TEntity,
45
56
  queryContext: EntityQueryContext,
46
- ): UpdateMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
57
+ ): AuthorizationResultBasedUpdateMutator<
58
+ TFields,
59
+ TID,
60
+ TViewerContext,
61
+ TEntity,
62
+ TPrivacyPolicy,
63
+ TSelectedFields
64
+ > {
47
65
  return this.entityMutatorFactory.forUpdate(existingEntity, queryContext);
48
66
  }
49
67
 
50
68
  forDelete(
51
69
  existingEntity: TEntity,
52
70
  queryContext: EntityQueryContext,
53
- ): DeleteMutator<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
71
+ ): AuthorizationResultBasedDeleteMutator<
72
+ TFields,
73
+ TID,
74
+ TViewerContext,
75
+ TEntity,
76
+ TPrivacyPolicy,
77
+ TSelectedFields
78
+ > {
54
79
  return this.entityMutatorFactory.forDelete(existingEntity, queryContext);
55
80
  }
56
81
  }