@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
@@ -1,7 +1,6 @@
1
- import { Result, result } from '@expo/results';
2
-
1
+ import AuthorizationResultBasedEntityAssociationLoader from './AuthorizationResultBasedEntityAssociationLoader';
2
+ import EnforcingEntityAssociationLoader from './EnforcingEntityAssociationLoader';
3
3
  import { IEntityClass } from './Entity';
4
- import EntityPrivacyPolicy from './EntityPrivacyPolicy';
5
4
  import { EntityQueryContext } from './EntityQueryContext';
6
5
  import ReadonlyEntity from './ReadonlyEntity';
7
6
  import ViewerContext from './ViewerContext';
@@ -18,507 +17,51 @@ export default class EntityAssociationLoader<
18
17
  TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
19
18
  TSelectedFields extends keyof TFields,
20
19
  > {
21
- constructor(private readonly entity: TEntity) {}
22
-
23
- /**
24
- * Load an associated entity identified by a field value of this entity. In a relational database,
25
- * the field in this entity is a foreign key to the ID of the associated entity.
26
- * @param fieldIdentifyingAssociatedEntity - field of this entity containing the ID of the associated entity
27
- * @param associatedEntityClass - class of the associated entity
28
- * @param queryContext - query context in which to perform the load
29
- */
30
- async loadAssociatedEntityAsync<
31
- TIdentifyingField extends keyof Pick<TFields, TSelectedFields>,
32
- TAssociatedFields extends object,
33
- TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
34
- TAssociatedEntity extends ReadonlyEntity<
35
- TAssociatedFields,
36
- TAssociatedID,
37
- TViewerContext,
38
- TAssociatedSelectedFields
39
- >,
40
- TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
41
- TAssociatedFields,
42
- TAssociatedID,
43
- TViewerContext,
44
- TAssociatedEntity,
45
- TAssociatedSelectedFields
46
- >,
47
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
48
- >(
49
- fieldIdentifyingAssociatedEntity: TIdentifyingField,
50
- associatedEntityClass: IEntityClass<
51
- TAssociatedFields,
52
- TAssociatedID,
53
- TViewerContext,
54
- TAssociatedEntity,
55
- TAssociatedPrivacyPolicy,
56
- TAssociatedSelectedFields
57
- >,
58
- queryContext: EntityQueryContext = this.entity
59
- .getViewerContext()
60
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
61
- .getQueryContextProvider()
62
- .getQueryContext(),
63
- ): Promise<
64
- Result<null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity>
65
- > {
66
- const associatedEntityID = this.entity.getField(fieldIdentifyingAssociatedEntity);
67
- if (!associatedEntityID) {
68
- return result(null) as Result<
69
- null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
70
- >;
71
- }
72
-
73
- const loader = this.entity
74
- .getViewerContext()
75
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
76
- .getLoaderFactory()
77
- .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
78
-
79
- return (await loader
80
- .withAuthorizationResults()
81
- .loadByIDAsync(associatedEntityID as unknown as TAssociatedID)) as Result<
82
- null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
83
- >;
84
- }
85
-
86
- /**
87
- * Load many entities associated with this entity, often referred to as entites belonging
88
- * to this entity. In a relational database, the field in the foreign entity is a
89
- * foreign key to the ID of this entity. Also commonly referred to as a has many relationship,
90
- * where this entity has many associated entities.
91
- * @param associatedEntityClass - class of the associated entities
92
- * @param associatedEntityFieldContainingThisID - field of associated entity which contains the ID of this entity
93
- * @param queryContext - query context in which to perform the load
94
- */
95
- async loadManyAssociatedEntitiesAsync<
96
- TAssociatedFields extends object,
97
- TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
98
- TAssociatedEntity extends ReadonlyEntity<
99
- TAssociatedFields,
100
- TAssociatedID,
101
- TViewerContext,
102
- TAssociatedSelectedFields
103
- >,
104
- TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
105
- TAssociatedFields,
106
- TAssociatedID,
107
- TViewerContext,
108
- TAssociatedEntity,
109
- TAssociatedSelectedFields
110
- >,
111
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
112
- >(
113
- associatedEntityClass: IEntityClass<
114
- TAssociatedFields,
115
- TAssociatedID,
116
- TViewerContext,
117
- TAssociatedEntity,
118
- TAssociatedPrivacyPolicy,
119
- TAssociatedSelectedFields
120
- >,
121
- associatedEntityFieldContainingThisID: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
122
- queryContext: EntityQueryContext = this.entity
123
- .getViewerContext()
124
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
125
- .getQueryContextProvider()
126
- .getQueryContext(),
127
- ): Promise<readonly Result<TAssociatedEntity>[]> {
128
- const thisID = this.entity.getID();
129
- const loader = this.entity
130
- .getViewerContext()
131
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
132
- .getLoaderFactory()
133
- .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
134
- return await loader
135
- .withAuthorizationResults()
136
- .loadManyByFieldEqualingAsync(associatedEntityFieldContainingThisID, thisID as any);
137
- }
138
-
139
- /**
140
- * Load an associated entity identified by a field value of this entity. In a relational database,
141
- * the field in this entity is a foreign key to a unique field of the associated entity.
142
- * @param fieldIdentifyingAssociatedEntity - field of this entity containing the value with which to look up associated entity
143
- * @param associatedEntityClass - class of the associated entity
144
- * @param associatedEntityLookupByField - field of associated entity with which to look up the associated entity
145
- * @param queryContext - query context in which to perform the load
146
- */
147
- async loadAssociatedEntityByFieldEqualingAsync<
148
- TAssociatedFields extends object,
149
- TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
150
- TAssociatedEntity extends ReadonlyEntity<
151
- TAssociatedFields,
152
- TAssociatedID,
153
- TViewerContext,
154
- TAssociatedSelectedFields
155
- >,
156
- TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
157
- TAssociatedFields,
158
- TAssociatedID,
159
- TViewerContext,
160
- TAssociatedEntity,
161
- TAssociatedSelectedFields
162
- >,
163
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
164
- >(
165
- fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
166
- associatedEntityClass: IEntityClass<
167
- TAssociatedFields,
168
- TAssociatedID,
169
- TViewerContext,
170
- TAssociatedEntity,
171
- TAssociatedPrivacyPolicy,
172
- TAssociatedSelectedFields
173
- >,
174
- associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
175
- queryContext: EntityQueryContext = this.entity
176
- .getViewerContext()
177
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
178
- .getQueryContextProvider()
179
- .getQueryContext(),
180
- ): Promise<Result<TAssociatedEntity> | null> {
181
- const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
182
- if (!associatedFieldValue) {
183
- return null;
184
- }
185
- const loader = this.entity
186
- .getViewerContext()
187
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
188
- .getLoaderFactory()
189
- .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
190
- return await loader
191
- .withAuthorizationResults()
192
- .loadByFieldEqualingAsync(associatedEntityLookupByField, associatedFieldValue as any);
193
- }
194
-
195
- /**
196
- * Load many associated entities identified by a field value of this entity. In a relational database,
197
- * the field in this entity refers to a field of the associated entity.
198
- * @param fieldIdentifyingAssociatedEntity - field of this entity containing the value with which to look up associated entities
199
- * @param associatedEntityClass - class of the associated entities
200
- * @param associatedEntityLookupByField - field of associated entities with which to look up the associated entities
201
- * @param queryContext - query context in which to perform the load
202
- */
203
- async loadManyAssociatedEntitiesByFieldEqualingAsync<
204
- TAssociatedFields extends object,
205
- TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
206
- TAssociatedEntity extends ReadonlyEntity<
207
- TAssociatedFields,
208
- TAssociatedID,
209
- TViewerContext,
210
- TAssociatedSelectedFields
211
- >,
212
- TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
213
- TAssociatedFields,
214
- TAssociatedID,
215
- TViewerContext,
216
- TAssociatedEntity,
217
- TAssociatedSelectedFields
218
- >,
219
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
220
- >(
221
- fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
222
- associatedEntityClass: IEntityClass<
223
- TAssociatedFields,
224
- TAssociatedID,
225
- TViewerContext,
226
- TAssociatedEntity,
227
- TAssociatedPrivacyPolicy,
228
- TAssociatedSelectedFields
229
- >,
230
- associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
231
- queryContext: EntityQueryContext = this.entity
20
+ constructor(
21
+ private readonly entity: TEntity,
22
+ private readonly queryContext: EntityQueryContext = entity
232
23
  .getViewerContext()
233
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
24
+ .getViewerScopedEntityCompanionForClass(
25
+ entity.constructor as IEntityClass<
26
+ TFields,
27
+ TID,
28
+ TViewerContext,
29
+ TEntity,
30
+ any,
31
+ TSelectedFields
32
+ >,
33
+ )
234
34
  .getQueryContextProvider()
235
35
  .getQueryContext(),
236
- ): Promise<readonly Result<TAssociatedEntity>[]> {
237
- const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
238
- if (!associatedFieldValue) {
239
- return [];
240
- }
241
-
242
- const loader = this.entity
243
- .getViewerContext()
244
- .getViewerScopedEntityCompanionForClass(associatedEntityClass)
245
- .getLoaderFactory()
246
- .forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
247
- return await loader
248
- .withAuthorizationResults()
249
- .loadManyByFieldEqualingAsync(associatedEntityLookupByField, associatedFieldValue as any);
250
- }
251
-
252
- /**
253
- * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
254
- * fold step, load an associated entity identified by a field value of the current fold value.
255
- * @param loadDirectives - associated entity load directives instructing each step of the fold
256
- * @param queryContext - query context in which to perform the loads
257
- */
258
- async loadAssociatedEntityThroughAsync<
259
- TFields2 extends object,
260
- TID2 extends NonNullable<TFields2[TSelectedFields2]>,
261
- TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
262
- TPrivacyPolicy2 extends EntityPrivacyPolicy<
263
- TFields2,
264
- TID2,
265
- TViewerContext,
266
- TEntity2,
267
- TSelectedFields2
268
- >,
269
- TSelectedFields2 extends keyof TFields2 = keyof TFields2,
270
- >(
271
- loadDirectives: [
272
- EntityLoadThroughDirective<
273
- TViewerContext,
274
- TFields,
275
- TFields2,
276
- TID2,
277
- TEntity2,
278
- TPrivacyPolicy2,
279
- TSelectedFields,
280
- TSelectedFields2
281
- >,
282
- ],
283
- queryContext?: EntityQueryContext,
284
- ): Promise<Result<TEntity2> | null>;
285
-
286
- /**
287
- * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
288
- * fold step, load an associated entity identified by a field value of the current fold value.
289
- * @param loadDirectives - associated entity load directives instructing each step of the fold
290
- * @param queryContext - query context in which to perform the loads
291
- */
292
- async loadAssociatedEntityThroughAsync<
293
- TFields2 extends object,
294
- TID2 extends NonNullable<TFields2[TSelectedFields2]>,
295
- TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
296
- TPrivacyPolicy2 extends EntityPrivacyPolicy<
297
- TFields2,
298
- TID2,
299
- TViewerContext,
300
- TEntity2,
301
- TSelectedFields2
302
- >,
303
- TFields3 extends object,
304
- TID3 extends NonNullable<TFields3[TSelectedFields3]>,
305
- TEntity3 extends ReadonlyEntity<TFields3, TID3, TViewerContext, TSelectedFields3>,
306
- TPrivacyPolicy3 extends EntityPrivacyPolicy<
307
- TFields3,
308
- TID3,
309
- TViewerContext,
310
- TEntity3,
311
- TSelectedFields3
312
- >,
313
- TSelectedFields2 extends keyof TFields2 = keyof TFields2,
314
- TSelectedFields3 extends keyof TFields3 = keyof TFields3,
315
- >(
316
- loadDirectives: [
317
- EntityLoadThroughDirective<
318
- TViewerContext,
319
- TFields,
320
- TFields2,
321
- TID2,
322
- TEntity2,
323
- TPrivacyPolicy2,
324
- TSelectedFields,
325
- TSelectedFields2
326
- >,
327
- EntityLoadThroughDirective<
328
- TViewerContext,
329
- TFields2,
330
- TFields3,
331
- TID3,
332
- TEntity3,
333
- TPrivacyPolicy3,
334
- TSelectedFields2,
335
- TSelectedFields3
336
- >,
337
- ],
338
- queryContext?: EntityQueryContext,
339
- ): Promise<Result<TEntity3> | null>;
36
+ ) {}
340
37
 
341
38
  /**
342
- * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
343
- * fold step, load an associated entity identified by a field value of the current fold value.
344
- * @param loadDirectives - associated entity load directives instructing each step of the fold
345
- * @param queryContext - query context in which to perform the loads
39
+ * Enforcing entity association loader. All loads through this loader are
40
+ * guaranteed to be the values of successful results (or null for some loader methods),
41
+ * and will throw otherwise.
346
42
  */
347
- async loadAssociatedEntityThroughAsync<
348
- TFields2 extends object,
349
- TID2 extends NonNullable<TFields2[TSelectedFields2]>,
350
- TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
351
- TPrivacyPolicy2 extends EntityPrivacyPolicy<
352
- TFields2,
353
- TID2,
354
- TViewerContext,
355
- TEntity2,
356
- TSelectedFields2
357
- >,
358
- TFields3 extends object,
359
- TID3 extends NonNullable<TFields3[TSelectedFields3]>,
360
- TEntity3 extends ReadonlyEntity<TFields3, TID3, TViewerContext, TSelectedFields3>,
361
- TPrivacyPolicy3 extends EntityPrivacyPolicy<
362
- TFields3,
363
- TID3,
364
- TViewerContext,
365
- TEntity3,
366
- TSelectedFields3
367
- >,
368
- TFields4 extends object,
369
- TID4 extends NonNullable<TFields4[TSelectedFields4]>,
370
- TEntity4 extends ReadonlyEntity<TFields4, TID4, TViewerContext, TSelectedFields4>,
371
- TPrivacyPolicy4 extends EntityPrivacyPolicy<
372
- TFields4,
373
- TID4,
374
- TViewerContext,
375
- TEntity4,
376
- TSelectedFields4
377
- >,
378
- TSelectedFields2 extends keyof TFields2 = keyof TFields2,
379
- TSelectedFields3 extends keyof TFields3 = keyof TFields3,
380
- TSelectedFields4 extends keyof TFields4 = keyof TFields4,
381
- >(
382
- loadDirectives: [
383
- EntityLoadThroughDirective<
384
- TViewerContext,
385
- TFields,
386
- TFields2,
387
- TID2,
388
- TEntity2,
389
- TPrivacyPolicy2,
390
- TSelectedFields,
391
- TSelectedFields2
392
- >,
393
- EntityLoadThroughDirective<
394
- TViewerContext,
395
- TFields2,
396
- TFields3,
397
- TID3,
398
- TEntity3,
399
- TPrivacyPolicy3,
400
- TSelectedFields2,
401
- TSelectedFields3
402
- >,
403
- EntityLoadThroughDirective<
404
- TViewerContext,
405
- TFields3,
406
- TFields4,
407
- TID4,
408
- TEntity4,
409
- TPrivacyPolicy4,
410
- TSelectedFields3,
411
- TSelectedFields4
412
- >,
413
- ],
414
- queryContext?: EntityQueryContext,
415
- ): Promise<Result<TEntity4> | null>;
416
-
417
- /**
418
- * Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
419
- * fold step, load an associated entity identified by a field value of the current fold value.
420
- * @param loadDirectives - associated entity load directives instructing each step of the fold
421
- * @param queryContext - query context in which to perform the loads
422
- */
423
- async loadAssociatedEntityThroughAsync(
424
- loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
425
- queryContext?: EntityQueryContext,
426
- ): Promise<Result<ReadonlyEntity<any, any, any, any>> | null>;
427
-
428
- async loadAssociatedEntityThroughAsync(
429
- loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
430
- queryContext?: EntityQueryContext,
431
- ): Promise<Result<ReadonlyEntity<any, any, any, any>> | null> {
432
- let currentEntity: ReadonlyEntity<any, any, any, any> = this.entity;
433
- for (const loadDirective of loadDirectives) {
434
- const {
435
- associatedEntityClass,
436
- fieldIdentifyingAssociatedEntity,
437
- associatedEntityLookupByField,
438
- } = loadDirective;
439
- let associatedEntityResult: Result<ReadonlyEntity<any, any, any, any>> | null;
440
- if (associatedEntityLookupByField) {
441
- associatedEntityResult = await currentEntity
442
- .associationLoader()
443
- .loadAssociatedEntityByFieldEqualingAsync(
444
- fieldIdentifyingAssociatedEntity,
445
- associatedEntityClass,
446
- associatedEntityLookupByField,
447
- queryContext,
448
- );
449
- } else {
450
- const associatedEntityResultLocal = await currentEntity
451
- .associationLoader()
452
- .loadAssociatedEntityAsync(
453
- fieldIdentifyingAssociatedEntity,
454
- associatedEntityClass,
455
- queryContext,
456
- );
457
-
458
- if (associatedEntityResultLocal.ok && associatedEntityResultLocal.value === null) {
459
- associatedEntityResult = null;
460
- } else {
461
- associatedEntityResult = associatedEntityResultLocal;
462
- }
463
- }
464
-
465
- if (!associatedEntityResult) {
466
- return null;
467
- }
468
-
469
- if (!associatedEntityResult.ok) {
470
- return result(associatedEntityResult.reason);
471
- }
472
- currentEntity = associatedEntityResult.value;
473
- }
474
- return result(currentEntity);
43
+ enforcing(): EnforcingEntityAssociationLoader<
44
+ TFields,
45
+ TID,
46
+ TViewerContext,
47
+ TEntity,
48
+ TSelectedFields
49
+ > {
50
+ return new EnforcingEntityAssociationLoader(this.withAuthorizationResults());
475
51
  }
476
- }
477
52
 
478
- /**
479
- * Instruction for each step of a load-associated-through method.
480
- */
481
- export interface EntityLoadThroughDirective<
482
- TViewerContext extends ViewerContext,
483
- TFields,
484
- TAssociatedFields extends object,
485
- TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
486
- TAssociatedEntity extends ReadonlyEntity<
487
- TAssociatedFields,
488
- TAssociatedID,
489
- TViewerContext,
490
- TAssociatedSelectedFields
491
- >,
492
- TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
493
- TAssociatedFields,
494
- TAssociatedID,
495
- TViewerContext,
496
- TAssociatedEntity,
497
- TAssociatedSelectedFields
498
- >,
499
- TSelectedFields extends keyof TFields = keyof TFields,
500
- TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
501
- > {
502
53
  /**
503
- * Class of entity to load at this step.
54
+ * Authorization-result-based entity loader. All loads through this
55
+ * loader are results, where an unsuccessful result
56
+ * means an authorization error or entity construction error occurred. Other errors are thrown.
504
57
  */
505
- associatedEntityClass: IEntityClass<
506
- TAssociatedFields,
507
- TAssociatedID,
58
+ withAuthorizationResults(): AuthorizationResultBasedEntityAssociationLoader<
59
+ TFields,
60
+ TID,
508
61
  TViewerContext,
509
- TAssociatedEntity,
510
- TAssociatedPrivacyPolicy,
511
- TAssociatedSelectedFields
512
- >;
513
-
514
- /**
515
- * Field of the current entity with which to load an instance of associatedEntityClass.
516
- */
517
- fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>;
518
-
519
- /**
520
- * Field by which to load the instance of associatedEntityClass. If not provided, the
521
- * associatedEntityClass instance is fetched by its ID.
522
- */
523
- associatedEntityLookupByField?: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>;
62
+ TEntity,
63
+ TSelectedFields
64
+ > {
65
+ return new AuthorizationResultBasedEntityAssociationLoader(this.entity, this.queryContext);
66
+ }
524
67
  }
@@ -143,11 +143,14 @@ export default class EntityCompanionProvider {
143
143
  */
144
144
  constructor(
145
145
  public readonly metricsAdapter: IEntityMetricsAdapter,
146
- private databaseAdapterFlavors: ReadonlyMap<
146
+ private readonly databaseAdapterFlavors: ReadonlyMap<
147
147
  DatabaseAdapterFlavor,
148
148
  DatabaseAdapterFlavorDefinition
149
149
  >,
150
- private cacheAdapterFlavors: ReadonlyMap<CacheAdapterFlavor, CacheAdapterFlavorDefinition>,
150
+ private readonly cacheAdapterFlavors: ReadonlyMap<
151
+ CacheAdapterFlavor,
152
+ CacheAdapterFlavorDefinition
153
+ >,
151
154
  readonly globalMutationTriggers: EntityMutationTriggerConfiguration<
152
155
  any,
153
156
  any,
@@ -0,0 +1,73 @@
1
+ import { AuthorizationResultBasedCreateMutator } from './AuthorizationResultBasedEntityMutator';
2
+ import EnforcingEntityCreator from './EnforcingEntityCreator';
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 creating entities.
11
+ */
12
+ export default class EntityCreator<
13
+ TFields extends object,
14
+ TID extends NonNullable<TFields[TSelectedFields]>,
15
+ TViewerContext extends ViewerContext,
16
+ TViewerContext2 extends TViewerContext,
17
+ TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
18
+ TPrivacyPolicy extends EntityPrivacyPolicy<
19
+ TFields,
20
+ TID,
21
+ TViewerContext,
22
+ TEntity,
23
+ TSelectedFields
24
+ >,
25
+ TSelectedFields extends keyof TFields,
26
+ > {
27
+ constructor(
28
+ private readonly viewerContext: TViewerContext2,
29
+ private readonly queryContext: EntityQueryContext,
30
+ private readonly entityClass: IEntityClass<
31
+ TFields,
32
+ TID,
33
+ TViewerContext,
34
+ TEntity,
35
+ TPrivacyPolicy,
36
+ TSelectedFields
37
+ >,
38
+ ) {}
39
+
40
+ /**
41
+ * Enforcing entity creator. All creates through this creator are
42
+ * guaranteed to be successful and will throw otherwise.
43
+ */
44
+ enforcing(): EnforcingEntityCreator<
45
+ TFields,
46
+ TID,
47
+ TViewerContext,
48
+ TEntity,
49
+ TPrivacyPolicy,
50
+ TSelectedFields
51
+ > {
52
+ return new EnforcingEntityCreator(this.withAuthorizationResults());
53
+ }
54
+
55
+ /**
56
+ * Authorization-result-based entity creator. All creates through this
57
+ * creator are results, where an unsuccessful result means an authorization
58
+ * error or entity construction error occurred. Other errors are thrown.
59
+ */
60
+ withAuthorizationResults(): AuthorizationResultBasedCreateMutator<
61
+ TFields,
62
+ TID,
63
+ TViewerContext,
64
+ TEntity,
65
+ TPrivacyPolicy,
66
+ TSelectedFields
67
+ > {
68
+ return this.viewerContext
69
+ .getViewerScopedEntityCompanionForClass(this.entityClass)
70
+ .getMutatorFactory()
71
+ .forCreate(this.queryContext);
72
+ }
73
+ }