@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.
- package/build/AuthorizationResultBasedEntityAssociationLoader.d.ts +99 -0
- package/build/AuthorizationResultBasedEntityAssociationLoader.js +124 -0
- package/build/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -0
- package/build/AuthorizationResultBasedEntityLoader.d.ts +1 -1
- package/build/AuthorizationResultBasedEntityLoader.js.map +1 -1
- package/build/{EntityMutator.d.ts → AuthorizationResultBasedEntityMutator.d.ts} +5 -17
- package/build/{EntityMutator.js → AuthorizationResultBasedEntityMutator.js} +22 -48
- package/build/AuthorizationResultBasedEntityMutator.js.map +1 -0
- package/build/EnforcingEntityAssociationLoader.d.ts +79 -0
- package/build/EnforcingEntityAssociationLoader.js +62 -0
- package/build/EnforcingEntityAssociationLoader.js.map +1 -0
- package/build/EnforcingEntityCreator.d.ts +24 -0
- package/build/EnforcingEntityCreator.js +32 -0
- package/build/EnforcingEntityCreator.js.map +1 -0
- package/build/EnforcingEntityDeleter.d.ts +17 -0
- package/build/EnforcingEntityDeleter.js +22 -0
- package/build/EnforcingEntityDeleter.js.map +1 -0
- package/build/EnforcingEntityUpdater.d.ts +24 -0
- package/build/EnforcingEntityUpdater.js +32 -0
- package/build/EnforcingEntityUpdater.js.map +1 -0
- package/build/Entity.d.ts +8 -12
- package/build/Entity.js +9 -34
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.d.ts +12 -91
- package/build/EntityAssociationLoader.js +20 -126
- package/build/EntityAssociationLoader.js.map +1 -1
- package/build/EntityCompanionProvider.d.ts +2 -2
- package/build/EntityCompanionProvider.js.map +1 -1
- package/build/EntityCreator.d.ts +27 -0
- package/build/EntityCreator.js +39 -0
- package/build/EntityCreator.js.map +1 -0
- package/build/EntityDatabaseAdapter.js +2 -2
- package/build/EntityDatabaseAdapter.js.map +1 -1
- package/build/EntityDeleter.d.ts +27 -0
- package/build/EntityDeleter.js +40 -0
- package/build/EntityDeleter.js.map +1 -0
- package/build/EntityLoader.d.ts +4 -14
- package/build/EntityLoader.js +7 -20
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityLoaderFactory.d.ts +2 -2
- package/build/EntityLoaderFactory.js +4 -2
- package/build/EntityLoaderFactory.js.map +1 -1
- package/build/EntityMutatorFactory.d.ts +4 -4
- package/build/EntityMutatorFactory.js +4 -4
- package/build/EntityMutatorFactory.js.map +1 -1
- package/build/EntitySecondaryCacheLoader.d.ts +3 -3
- package/build/EntitySecondaryCacheLoader.js +1 -3
- package/build/EntitySecondaryCacheLoader.js.map +1 -1
- package/build/EntityUpdater.d.ts +27 -0
- package/build/EntityUpdater.js +40 -0
- package/build/EntityUpdater.js.map +1 -0
- package/build/ReadonlyEntity.d.ts +2 -2
- package/build/ReadonlyEntity.js +4 -6
- package/build/ReadonlyEntity.js.map +1 -1
- package/build/ViewerScopedEntityLoaderFactory.d.ts +2 -2
- package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
- package/build/ViewerScopedEntityMutatorFactory.d.ts +4 -4
- package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
- package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.d.ts +1 -0
- package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js +273 -0
- package/build/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.js.map +1 -0
- package/build/__tests__/{EntityLoader-constructor-test.js → AuthorizationResultBasedEntityLoader-constructor-test.js} +11 -11
- package/build/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.js.map +1 -0
- package/build/__tests__/AuthorizationResultBasedEntityLoader-test.d.ts +1 -0
- package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js +401 -0
- package/build/__tests__/AuthorizationResultBasedEntityLoader-test.js.map +1 -0
- package/build/__tests__/EnforcingEntityAssociationLoader-test.d.ts +1 -0
- package/build/__tests__/EnforcingEntityAssociationLoader-test.js +115 -0
- package/build/__tests__/EnforcingEntityAssociationLoader-test.js.map +1 -0
- package/build/__tests__/Entity-test.js +23 -5
- package/build/__tests__/Entity-test.js.map +1 -1
- package/build/__tests__/EntityAssociationLoader-test.js +14 -184
- package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js +34 -12
- package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
- package/build/__tests__/EntityCompanion-test.js +17 -7
- package/build/__tests__/EntityCompanion-test.js.map +1 -1
- package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
- package/build/__tests__/EntityEdges-test.js +41 -23
- package/build/__tests__/EntityEdges-test.js.map +1 -1
- package/build/__tests__/EntityLoader-test.js +22 -386
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +4 -3
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
- package/build/__tests__/EntityMutator-test.js +67 -70
- package/build/__tests__/EntityMutator-test.js.map +1 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js +17 -7
- package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
- package/build/__tests__/EntitySecondaryCacheLoader-test.js +7 -7
- package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
- package/build/__tests__/EntitySelfReferentialEdges-test.js +36 -24
- package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
- package/build/__tests__/ReadonlyEntity-test.js +1 -1
- package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +4 -2
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +7 -4
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
- package/build/__tests__/entityUtils-test.js +8 -0
- package/build/__tests__/entityUtils-test.js.map +1 -1
- package/build/entityUtils.d.ts +7 -0
- package/build/entityUtils.js +20 -10
- package/build/entityUtils.js.map +1 -1
- package/build/errors/EntityCacheAdapterError.js +17 -7
- package/build/errors/EntityCacheAdapterError.js.map +1 -1
- package/build/errors/EntityDatabaseAdapterError.js +17 -7
- package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
- package/build/errors/EntityInvalidFieldValueError.js +17 -7
- package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
- package/build/errors/EntityNotAuthorizedError.js +17 -7
- package/build/errors/EntityNotAuthorizedError.js.map +1 -1
- package/build/errors/EntityNotFoundError.js +17 -7
- package/build/errors/EntityNotFoundError.js.map +1 -1
- package/build/index.d.ts +19 -11
- package/build/index.js +24 -7
- package/build/index.js.map +1 -1
- package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/internal/__tests__/EntityDataManager-test.js +42 -32
- package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
- package/build/internal/__tests__/ReadThroughEntityCache-test.js +17 -7
- package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js +17 -7
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js +17 -7
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js +17 -7
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
- package/build/utils/EntityPrivacyUtils.d.ts +32 -4
- package/build/utils/EntityPrivacyUtils.js +68 -24
- package/build/utils/EntityPrivacyUtils.js.map +1 -1
- package/build/utils/__tests__/EntityPrivacyUtils-test.js +148 -23
- package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -1
- package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js +8 -5
- package/build/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.js.map +1 -1
- package/build/utils/collections/__tests__/maps-test.js +1 -1
- package/build/utils/collections/__tests__/maps-test.js.map +1 -1
- package/build/utils/collections/maps.js +2 -2
- package/build/utils/collections/maps.js.map +1 -1
- package/build/utils/mergeEntityMutationTriggerConfigurations.js +1 -2
- package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapter.js +17 -7
- package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
- package/build/utils/testing/StubQueryContextProvider.d.ts +1 -3
- package/build/utils/testing/StubQueryContextProvider.js +1 -3
- package/build/utils/testing/StubQueryContextProvider.js.map +1 -1
- package/build/utils/testing/createUnitTestEntityCompanionProvider.js +2 -1
- package/build/utils/testing/createUnitTestEntityCompanionProvider.js.map +1 -1
- package/build/utils/testing/describeFieldTestCase.js +1 -1
- package/build/utils/testing/describeFieldTestCase.js.map +1 -1
- package/package.json +19 -3
- package/src/AuthorizationResultBasedEntityAssociationLoader.ts +492 -0
- package/src/AuthorizationResultBasedEntityLoader.ts +2 -2
- package/src/{EntityMutator.ts → AuthorizationResultBasedEntityMutator.ts} +62 -58
- package/src/EnforcingEntityAssociationLoader.ts +390 -0
- package/src/EnforcingEntityCreator.ts +55 -0
- package/src/EnforcingEntityDeleter.ts +44 -0
- package/src/EnforcingEntityUpdater.ts +55 -0
- package/src/Entity.ts +20 -65
- package/src/EntityAssociationLoader.ts +38 -495
- package/src/EntityCompanionProvider.ts +5 -2
- package/src/EntityCreator.ts +73 -0
- package/src/EntityDeleter.ts +73 -0
- package/src/EntityLoader.ts +10 -49
- package/src/EntityLoaderFactory.ts +20 -3
- package/src/EntityMutatorFactory.ts +32 -7
- package/src/EntitySecondaryCacheLoader.ts +5 -7
- package/src/EntityUpdater.ts +73 -0
- package/src/ReadonlyEntity.ts +14 -13
- package/src/ViewerScopedEntityLoaderFactory.ts +9 -2
- package/src/ViewerScopedEntityMutatorFactory.ts +29 -4
- package/src/__tests__/AuthorizationResultBasedEntityAssociationLoader-test.ts +354 -0
- package/src/__tests__/{EntityLoader-constructor-test.ts → AuthorizationResultBasedEntityLoader-constructor-test.ts} +17 -10
- package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +730 -0
- package/src/__tests__/EnforcingEntityAssociationLoader-test.ts +253 -0
- package/src/__tests__/Entity-test.ts +24 -5
- package/src/__tests__/EntityAssociationLoader-test.ts +16 -259
- package/src/__tests__/EntityCommonUseCases-test.ts +20 -8
- package/src/__tests__/EntityCompanion-test.ts +1 -1
- package/src/__tests__/EntityDatabaseAdapter-test.ts +6 -6
- package/src/__tests__/EntityEdges-test.ts +24 -16
- package/src/__tests__/EntityLoader-test.ts +25 -675
- package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +4 -3
- package/src/__tests__/EntityMutator-test.ts +116 -103
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +36 -24
- package/src/__tests__/ReadonlyEntity-test.ts +1 -1
- package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +4 -2
- package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +7 -4
- package/src/__tests__/entityUtils-test.ts +12 -0
- package/src/entityUtils.ts +24 -9
- package/src/index.ts +19 -11
- package/src/internal/EntityFieldTransformationUtils.ts +2 -2
- package/src/internal/__tests__/EntityDataManager-test.ts +29 -29
- package/src/utils/EntityPrivacyUtils.ts +188 -107
- package/src/utils/__tests__/EntityPrivacyUtils-test.ts +169 -29
- package/src/utils/__tests__/canViewerDeleteAsync-edgeDeletionPermissionInferenceBehavior-test.ts +8 -5
- package/src/utils/collections/__tests__/maps-test.ts +1 -1
- package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +1 -1
- package/src/utils/testing/StubDatabaseAdapter.ts +1 -1
- package/src/utils/testing/StubQueryContextProvider.ts +1 -3
- package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +3 -1
- package/build/EntityMutator.js.map +0 -1
- package/build/__tests__/EntityLoader-constructor-test.js.map +0 -1
- /package/build/__tests__/{EntityLoader-constructor-test.d.ts → AuthorizationResultBasedEntityLoader-constructor-test.d.ts} +0 -0
|
@@ -21,12 +21,13 @@ import EntityMutationValidator from './EntityMutationValidator';
|
|
|
21
21
|
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
22
22
|
import { EntityQueryContext, EntityTransactionalQueryContext } from './EntityQueryContext';
|
|
23
23
|
import ViewerContext from './ViewerContext';
|
|
24
|
+
import { enforceResultsAsync } from './entityUtils';
|
|
24
25
|
import EntityInvalidFieldValueError from './errors/EntityInvalidFieldValueError';
|
|
25
26
|
import { timeAndLogMutationEventAsync } from './metrics/EntityMetricsUtils';
|
|
26
27
|
import IEntityMetricsAdapter, { EntityMetricsMutationType } from './metrics/IEntityMetricsAdapter';
|
|
27
28
|
import { mapMapAsync } from './utils/collections/maps';
|
|
28
29
|
|
|
29
|
-
abstract class
|
|
30
|
+
abstract class AuthorizationResultBasedBaseMutator<
|
|
30
31
|
TFields extends object,
|
|
31
32
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
32
33
|
TViewerContext extends ViewerContext,
|
|
@@ -154,7 +155,7 @@ abstract class BaseMutator<
|
|
|
154
155
|
/**
|
|
155
156
|
* Mutator for creating a new entity.
|
|
156
157
|
*/
|
|
157
|
-
export class
|
|
158
|
+
export class AuthorizationResultBasedCreateMutator<
|
|
158
159
|
TFields extends object,
|
|
159
160
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
160
161
|
TViewerContext extends ViewerContext,
|
|
@@ -167,12 +168,19 @@ export class CreateMutator<
|
|
|
167
168
|
TSelectedFields
|
|
168
169
|
>,
|
|
169
170
|
TSelectedFields extends keyof TFields,
|
|
170
|
-
> extends
|
|
171
|
+
> extends AuthorizationResultBasedBaseMutator<
|
|
172
|
+
TFields,
|
|
173
|
+
TID,
|
|
174
|
+
TViewerContext,
|
|
175
|
+
TEntity,
|
|
176
|
+
TPrivacyPolicy,
|
|
177
|
+
TSelectedFields
|
|
178
|
+
> {
|
|
171
179
|
private readonly fieldsForEntity: Partial<TFields> = {};
|
|
172
180
|
|
|
173
181
|
/**
|
|
174
182
|
* Set the value for entity field.
|
|
175
|
-
* @param fieldName - entity field being
|
|
183
|
+
* @param fieldName - entity field being set
|
|
176
184
|
* @param value - value for entity field
|
|
177
185
|
*/
|
|
178
186
|
setField<K extends keyof Pick<TFields, TSelectedFields>>(fieldName: K, value: TFields[K]): this {
|
|
@@ -193,13 +201,6 @@ export class CreateMutator<
|
|
|
193
201
|
)(this.createInTransactionAsync());
|
|
194
202
|
}
|
|
195
203
|
|
|
196
|
-
/**
|
|
197
|
-
* Convenience method that returns the new entity or throws upon create failure.
|
|
198
|
-
*/
|
|
199
|
-
async enforceCreateAsync(): Promise<TEntity> {
|
|
200
|
-
return await enforceAsyncResult(this.createAsync());
|
|
201
|
-
}
|
|
202
|
-
|
|
203
204
|
private async createInTransactionAsync(): Promise<Result<TEntity>> {
|
|
204
205
|
return await this.queryContext.runInTransactionIfNotInTransactionAsync((innerQueryContext) =>
|
|
205
206
|
this.createInternalAsync(innerQueryContext),
|
|
@@ -216,7 +217,7 @@ export class CreateMutator<
|
|
|
216
217
|
cascadingDeleteCause: null,
|
|
217
218
|
});
|
|
218
219
|
|
|
219
|
-
const temporaryEntityForPrivacyCheck = entityLoader.utils
|
|
220
|
+
const temporaryEntityForPrivacyCheck = entityLoader.utils.constructEntity({
|
|
220
221
|
[this.entityConfiguration.idField]: '00000000-0000-0000-0000-000000000000', // zero UUID
|
|
221
222
|
...this.fieldsForEntity,
|
|
222
223
|
} as unknown as TFields);
|
|
@@ -256,13 +257,13 @@ export class CreateMutator<
|
|
|
256
257
|
const insertResult = await this.databaseAdapter.insertAsync(queryContext, this.fieldsForEntity);
|
|
257
258
|
|
|
258
259
|
queryContext.appendPostCommitInvalidationCallback(
|
|
259
|
-
entityLoader.utils
|
|
260
|
+
entityLoader.utils.invalidateFieldsAsync.bind(entityLoader, insertResult),
|
|
260
261
|
);
|
|
261
262
|
|
|
262
|
-
const unauthorizedEntityAfterInsert = entityLoader.utils
|
|
263
|
-
const newEntity = await
|
|
264
|
-
.
|
|
265
|
-
|
|
263
|
+
const unauthorizedEntityAfterInsert = entityLoader.utils.constructEntity(insertResult);
|
|
264
|
+
const newEntity = await enforceAsyncResult(
|
|
265
|
+
entityLoader.loadByIDAsync(unauthorizedEntityAfterInsert.getID()),
|
|
266
|
+
);
|
|
266
267
|
|
|
267
268
|
await this.executeMutationTriggersAsync(
|
|
268
269
|
this.mutationTriggers.afterCreate,
|
|
@@ -293,7 +294,7 @@ export class CreateMutator<
|
|
|
293
294
|
/**
|
|
294
295
|
* Mutator for updating an existing entity.
|
|
295
296
|
*/
|
|
296
|
-
export class
|
|
297
|
+
export class AuthorizationResultBasedUpdateMutator<
|
|
297
298
|
TFields extends object,
|
|
298
299
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
299
300
|
TViewerContext extends ViewerContext,
|
|
@@ -306,7 +307,14 @@ export class UpdateMutator<
|
|
|
306
307
|
TSelectedFields
|
|
307
308
|
>,
|
|
308
309
|
TSelectedFields extends keyof TFields,
|
|
309
|
-
> extends
|
|
310
|
+
> extends AuthorizationResultBasedBaseMutator<
|
|
311
|
+
TFields,
|
|
312
|
+
TID,
|
|
313
|
+
TViewerContext,
|
|
314
|
+
TEntity,
|
|
315
|
+
TPrivacyPolicy,
|
|
316
|
+
TSelectedFields
|
|
317
|
+
> {
|
|
310
318
|
private readonly originalEntity: TEntity;
|
|
311
319
|
private readonly fieldsForEntity: TFields;
|
|
312
320
|
private readonly updatedFields: Partial<TFields> = {};
|
|
@@ -392,13 +400,6 @@ export class UpdateMutator<
|
|
|
392
400
|
)(this.updateInTransactionAsync(false, null));
|
|
393
401
|
}
|
|
394
402
|
|
|
395
|
-
/**
|
|
396
|
-
* Convenience method that returns the updated entity or throws upon update failure.
|
|
397
|
-
*/
|
|
398
|
-
async enforceUpdateAsync(): Promise<TEntity> {
|
|
399
|
-
return await enforceAsyncResult(this.updateAsync());
|
|
400
|
-
}
|
|
401
|
-
|
|
402
403
|
private async updateInTransactionAsync(
|
|
403
404
|
skipDatabaseUpdate: true,
|
|
404
405
|
cascadingDeleteCause: EntityCascadingDeletionInfo,
|
|
@@ -429,7 +430,7 @@ export class UpdateMutator<
|
|
|
429
430
|
cascadingDeleteCause,
|
|
430
431
|
});
|
|
431
432
|
|
|
432
|
-
const entityAboutToBeUpdated = entityLoader.utils
|
|
433
|
+
const entityAboutToBeUpdated = entityLoader.utils.constructEntity(this.fieldsForEntity);
|
|
433
434
|
const authorizeUpdateResult = await asyncResult(
|
|
434
435
|
this.privacyPolicy.authorizeUpdateAsync(
|
|
435
436
|
this.viewerContext,
|
|
@@ -473,17 +474,18 @@ export class UpdateMutator<
|
|
|
473
474
|
}
|
|
474
475
|
|
|
475
476
|
queryContext.appendPostCommitInvalidationCallback(
|
|
476
|
-
entityLoader
|
|
477
|
-
|
|
478
|
-
|
|
477
|
+
entityLoader.utils.invalidateFieldsAsync.bind(
|
|
478
|
+
entityLoader,
|
|
479
|
+
this.originalEntity.getAllDatabaseFields(),
|
|
480
|
+
),
|
|
479
481
|
);
|
|
480
482
|
queryContext.appendPostCommitInvalidationCallback(
|
|
481
|
-
entityLoader.utils
|
|
483
|
+
entityLoader.utils.invalidateFieldsAsync.bind(entityLoader, this.fieldsForEntity),
|
|
482
484
|
);
|
|
483
485
|
|
|
484
|
-
const updatedEntity = await
|
|
485
|
-
.
|
|
486
|
-
|
|
486
|
+
const updatedEntity = await enforceAsyncResult(
|
|
487
|
+
entityLoader.loadByIDAsync(entityAboutToBeUpdated.getID()),
|
|
488
|
+
); // ID is guaranteed to be stable by ensureStableIDField
|
|
487
489
|
|
|
488
490
|
await this.executeMutationTriggersAsync(
|
|
489
491
|
this.mutationTriggers.afterUpdate,
|
|
@@ -526,7 +528,7 @@ export class UpdateMutator<
|
|
|
526
528
|
/**
|
|
527
529
|
* Mutator for deleting an existing entity.
|
|
528
530
|
*/
|
|
529
|
-
export class
|
|
531
|
+
export class AuthorizationResultBasedDeleteMutator<
|
|
530
532
|
TFields extends object,
|
|
531
533
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
532
534
|
TViewerContext extends ViewerContext,
|
|
@@ -539,7 +541,14 @@ export class DeleteMutator<
|
|
|
539
541
|
TSelectedFields
|
|
540
542
|
>,
|
|
541
543
|
TSelectedFields extends keyof TFields,
|
|
542
|
-
> extends
|
|
544
|
+
> extends AuthorizationResultBasedBaseMutator<
|
|
545
|
+
TFields,
|
|
546
|
+
TID,
|
|
547
|
+
TViewerContext,
|
|
548
|
+
TEntity,
|
|
549
|
+
TPrivacyPolicy,
|
|
550
|
+
TSelectedFields
|
|
551
|
+
> {
|
|
543
552
|
constructor(
|
|
544
553
|
companionProvider: EntityCompanionProvider,
|
|
545
554
|
viewerContext: TViewerContext,
|
|
@@ -607,13 +616,6 @@ export class DeleteMutator<
|
|
|
607
616
|
)(this.deleteInTransactionAsync(new Set(), false, null));
|
|
608
617
|
}
|
|
609
618
|
|
|
610
|
-
/**
|
|
611
|
-
* Convenience method that throws upon delete failure.
|
|
612
|
-
*/
|
|
613
|
-
async enforceDeleteAsync(): Promise<void> {
|
|
614
|
-
return await enforceAsyncResult(this.deleteAsync());
|
|
615
|
-
}
|
|
616
|
-
|
|
617
619
|
private async deleteInTransactionAsync(
|
|
618
620
|
processedEntityIdentifiersFromTransitiveDeletions: Set<string>,
|
|
619
621
|
skipDatabaseDeletion: boolean,
|
|
@@ -681,9 +683,10 @@ export class DeleteMutator<
|
|
|
681
683
|
cascadingDeleteCause,
|
|
682
684
|
});
|
|
683
685
|
queryContext.appendPostCommitInvalidationCallback(
|
|
684
|
-
entityLoader
|
|
685
|
-
|
|
686
|
-
|
|
686
|
+
entityLoader.utils.invalidateFieldsAsync.bind(
|
|
687
|
+
entityLoader,
|
|
688
|
+
this.entity.getAllDatabaseFields(),
|
|
689
|
+
),
|
|
687
690
|
);
|
|
688
691
|
|
|
689
692
|
await this.executeMutationTriggersAsync(
|
|
@@ -782,18 +785,19 @@ export class DeleteMutator<
|
|
|
782
785
|
return;
|
|
783
786
|
}
|
|
784
787
|
|
|
785
|
-
const inboundReferenceEntities = await
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
788
|
+
const inboundReferenceEntities = await enforceResultsAsync(
|
|
789
|
+
loaderFactory
|
|
790
|
+
.forLoad(queryContext, {
|
|
791
|
+
previousValue: null,
|
|
792
|
+
cascadingDeleteCause: newCascadingDeleteCause,
|
|
793
|
+
})
|
|
794
|
+
.loadManyByFieldEqualingAsync(
|
|
795
|
+
fieldName,
|
|
796
|
+
association.associatedEntityLookupByField
|
|
797
|
+
? entity.getField(association.associatedEntityLookupByField as any)
|
|
798
|
+
: entity.getID(),
|
|
799
|
+
),
|
|
800
|
+
);
|
|
797
801
|
|
|
798
802
|
switch (association.edgeDeletionBehavior) {
|
|
799
803
|
case EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY: {
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { enforceAsyncResult } from '@expo/results';
|
|
2
|
+
|
|
3
|
+
import AuthorizationResultBasedEntityAssociationLoader, {
|
|
4
|
+
EntityLoadThroughDirective,
|
|
5
|
+
} from './AuthorizationResultBasedEntityAssociationLoader';
|
|
6
|
+
import { IEntityClass } from './Entity';
|
|
7
|
+
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
8
|
+
import ReadonlyEntity from './ReadonlyEntity';
|
|
9
|
+
import ViewerContext from './ViewerContext';
|
|
10
|
+
import { enforceResultsAsync } from './entityUtils';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* An association loader is a set of convenience methods for loading entities
|
|
14
|
+
* associated with an entity. In relational databases, these entities are often referenced
|
|
15
|
+
* by foreign keys.
|
|
16
|
+
*/
|
|
17
|
+
export default class EnforcingEntityAssociationLoader<
|
|
18
|
+
TFields extends object,
|
|
19
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
20
|
+
TViewerContext extends ViewerContext,
|
|
21
|
+
TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
22
|
+
TSelectedFields extends keyof TFields,
|
|
23
|
+
> {
|
|
24
|
+
constructor(
|
|
25
|
+
private readonly authorizationResultBasedEntityAssociationLoader: AuthorizationResultBasedEntityAssociationLoader<
|
|
26
|
+
TFields,
|
|
27
|
+
TID,
|
|
28
|
+
TViewerContext,
|
|
29
|
+
TEntity,
|
|
30
|
+
TSelectedFields
|
|
31
|
+
>,
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Load an associated entity identified by a field value of this entity. In a relational database,
|
|
36
|
+
* the field in this entity is a foreign key to the ID of the associated entity.
|
|
37
|
+
* @param fieldIdentifyingAssociatedEntity - field of this entity containing the ID of the associated entity
|
|
38
|
+
* @param associatedEntityClass - class of the associated entity
|
|
39
|
+
*/
|
|
40
|
+
async loadAssociatedEntityAsync<
|
|
41
|
+
TIdentifyingField extends keyof Pick<TFields, TSelectedFields>,
|
|
42
|
+
TAssociatedFields extends object,
|
|
43
|
+
TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
|
|
44
|
+
TAssociatedEntity extends ReadonlyEntity<
|
|
45
|
+
TAssociatedFields,
|
|
46
|
+
TAssociatedID,
|
|
47
|
+
TViewerContext,
|
|
48
|
+
TAssociatedSelectedFields
|
|
49
|
+
>,
|
|
50
|
+
TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
|
|
51
|
+
TAssociatedFields,
|
|
52
|
+
TAssociatedID,
|
|
53
|
+
TViewerContext,
|
|
54
|
+
TAssociatedEntity,
|
|
55
|
+
TAssociatedSelectedFields
|
|
56
|
+
>,
|
|
57
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
58
|
+
>(
|
|
59
|
+
fieldIdentifyingAssociatedEntity: TIdentifyingField,
|
|
60
|
+
associatedEntityClass: IEntityClass<
|
|
61
|
+
TAssociatedFields,
|
|
62
|
+
TAssociatedID,
|
|
63
|
+
TViewerContext,
|
|
64
|
+
TAssociatedEntity,
|
|
65
|
+
TAssociatedPrivacyPolicy,
|
|
66
|
+
TAssociatedSelectedFields
|
|
67
|
+
>,
|
|
68
|
+
): Promise<
|
|
69
|
+
null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
|
|
70
|
+
> {
|
|
71
|
+
return await enforceAsyncResult(
|
|
72
|
+
this.authorizationResultBasedEntityAssociationLoader.loadAssociatedEntityAsync(
|
|
73
|
+
fieldIdentifyingAssociatedEntity,
|
|
74
|
+
associatedEntityClass,
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Load many entities associated with this entity, often referred to as entites belonging
|
|
81
|
+
* to this entity. In a relational database, the field in the foreign entity is a
|
|
82
|
+
* foreign key to the ID of this entity. Also commonly referred to as a has many relationship,
|
|
83
|
+
* where this entity has many associated entities.
|
|
84
|
+
* @param associatedEntityClass - class of the associated entities
|
|
85
|
+
* @param associatedEntityFieldContainingThisID - field of associated entity which contains the ID of this entity
|
|
86
|
+
*/
|
|
87
|
+
async loadManyAssociatedEntitiesAsync<
|
|
88
|
+
TAssociatedFields extends object,
|
|
89
|
+
TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
|
|
90
|
+
TAssociatedEntity extends ReadonlyEntity<
|
|
91
|
+
TAssociatedFields,
|
|
92
|
+
TAssociatedID,
|
|
93
|
+
TViewerContext,
|
|
94
|
+
TAssociatedSelectedFields
|
|
95
|
+
>,
|
|
96
|
+
TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
|
|
97
|
+
TAssociatedFields,
|
|
98
|
+
TAssociatedID,
|
|
99
|
+
TViewerContext,
|
|
100
|
+
TAssociatedEntity,
|
|
101
|
+
TAssociatedSelectedFields
|
|
102
|
+
>,
|
|
103
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
104
|
+
>(
|
|
105
|
+
associatedEntityClass: IEntityClass<
|
|
106
|
+
TAssociatedFields,
|
|
107
|
+
TAssociatedID,
|
|
108
|
+
TViewerContext,
|
|
109
|
+
TAssociatedEntity,
|
|
110
|
+
TAssociatedPrivacyPolicy,
|
|
111
|
+
TAssociatedSelectedFields
|
|
112
|
+
>,
|
|
113
|
+
associatedEntityFieldContainingThisID: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
|
|
114
|
+
): Promise<readonly TAssociatedEntity[]> {
|
|
115
|
+
return await enforceResultsAsync(
|
|
116
|
+
this.authorizationResultBasedEntityAssociationLoader.loadManyAssociatedEntitiesAsync(
|
|
117
|
+
associatedEntityClass,
|
|
118
|
+
associatedEntityFieldContainingThisID,
|
|
119
|
+
),
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Load an associated entity identified by a field value of this entity. In a relational database,
|
|
125
|
+
* the field in this entity is a foreign key to a unique field of the associated entity.
|
|
126
|
+
* @param fieldIdentifyingAssociatedEntity - field of this entity containing the value with which to look up associated entity
|
|
127
|
+
* @param associatedEntityClass - class of the associated entity
|
|
128
|
+
* @param associatedEntityLookupByField - field of associated entity with which to look up the associated entity
|
|
129
|
+
*/
|
|
130
|
+
async loadAssociatedEntityByFieldEqualingAsync<
|
|
131
|
+
TAssociatedFields extends object,
|
|
132
|
+
TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
|
|
133
|
+
TAssociatedEntity extends ReadonlyEntity<
|
|
134
|
+
TAssociatedFields,
|
|
135
|
+
TAssociatedID,
|
|
136
|
+
TViewerContext,
|
|
137
|
+
TAssociatedSelectedFields
|
|
138
|
+
>,
|
|
139
|
+
TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
|
|
140
|
+
TAssociatedFields,
|
|
141
|
+
TAssociatedID,
|
|
142
|
+
TViewerContext,
|
|
143
|
+
TAssociatedEntity,
|
|
144
|
+
TAssociatedSelectedFields
|
|
145
|
+
>,
|
|
146
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
147
|
+
>(
|
|
148
|
+
fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
|
|
149
|
+
associatedEntityClass: IEntityClass<
|
|
150
|
+
TAssociatedFields,
|
|
151
|
+
TAssociatedID,
|
|
152
|
+
TViewerContext,
|
|
153
|
+
TAssociatedEntity,
|
|
154
|
+
TAssociatedPrivacyPolicy,
|
|
155
|
+
TAssociatedSelectedFields
|
|
156
|
+
>,
|
|
157
|
+
associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
|
|
158
|
+
): Promise<TAssociatedEntity | null> {
|
|
159
|
+
const result =
|
|
160
|
+
await this.authorizationResultBasedEntityAssociationLoader.loadAssociatedEntityByFieldEqualingAsync(
|
|
161
|
+
fieldIdentifyingAssociatedEntity,
|
|
162
|
+
associatedEntityClass,
|
|
163
|
+
associatedEntityLookupByField,
|
|
164
|
+
);
|
|
165
|
+
return result?.enforceValue() ?? null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Load many associated entities identified by a field value of this entity. In a relational database,
|
|
170
|
+
* the field in this entity refers to a field of the associated entity.
|
|
171
|
+
* @param fieldIdentifyingAssociatedEntity - field of this entity containing the value with which to look up associated entities
|
|
172
|
+
* @param associatedEntityClass - class of the associated entities
|
|
173
|
+
* @param associatedEntityLookupByField - field of associated entities with which to look up the associated entities
|
|
174
|
+
*/
|
|
175
|
+
async loadManyAssociatedEntitiesByFieldEqualingAsync<
|
|
176
|
+
TAssociatedFields extends object,
|
|
177
|
+
TAssociatedID extends NonNullable<TAssociatedFields[TAssociatedSelectedFields]>,
|
|
178
|
+
TAssociatedEntity extends ReadonlyEntity<
|
|
179
|
+
TAssociatedFields,
|
|
180
|
+
TAssociatedID,
|
|
181
|
+
TViewerContext,
|
|
182
|
+
TAssociatedSelectedFields
|
|
183
|
+
>,
|
|
184
|
+
TAssociatedPrivacyPolicy extends EntityPrivacyPolicy<
|
|
185
|
+
TAssociatedFields,
|
|
186
|
+
TAssociatedID,
|
|
187
|
+
TViewerContext,
|
|
188
|
+
TAssociatedEntity,
|
|
189
|
+
TAssociatedSelectedFields
|
|
190
|
+
>,
|
|
191
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
192
|
+
>(
|
|
193
|
+
fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
|
|
194
|
+
associatedEntityClass: IEntityClass<
|
|
195
|
+
TAssociatedFields,
|
|
196
|
+
TAssociatedID,
|
|
197
|
+
TViewerContext,
|
|
198
|
+
TAssociatedEntity,
|
|
199
|
+
TAssociatedPrivacyPolicy,
|
|
200
|
+
TAssociatedSelectedFields
|
|
201
|
+
>,
|
|
202
|
+
associatedEntityLookupByField: keyof Pick<TAssociatedFields, TAssociatedSelectedFields>,
|
|
203
|
+
): Promise<readonly TAssociatedEntity[]> {
|
|
204
|
+
return await enforceResultsAsync(
|
|
205
|
+
this.authorizationResultBasedEntityAssociationLoader.loadManyAssociatedEntitiesByFieldEqualingAsync(
|
|
206
|
+
fieldIdentifyingAssociatedEntity,
|
|
207
|
+
associatedEntityClass,
|
|
208
|
+
associatedEntityLookupByField,
|
|
209
|
+
),
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
215
|
+
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
216
|
+
* @param loadDirectives - associated entity load directives instructing each step of the folds
|
|
217
|
+
*/
|
|
218
|
+
async loadAssociatedEntityThroughAsync<
|
|
219
|
+
TFields2 extends object,
|
|
220
|
+
TID2 extends NonNullable<TFields2[TSelectedFields2]>,
|
|
221
|
+
TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
|
|
222
|
+
TPrivacyPolicy2 extends EntityPrivacyPolicy<
|
|
223
|
+
TFields2,
|
|
224
|
+
TID2,
|
|
225
|
+
TViewerContext,
|
|
226
|
+
TEntity2,
|
|
227
|
+
TSelectedFields2
|
|
228
|
+
>,
|
|
229
|
+
TSelectedFields2 extends keyof TFields2 = keyof TFields2,
|
|
230
|
+
>(
|
|
231
|
+
loadDirectives: [
|
|
232
|
+
EntityLoadThroughDirective<
|
|
233
|
+
TViewerContext,
|
|
234
|
+
TFields,
|
|
235
|
+
TFields2,
|
|
236
|
+
TID2,
|
|
237
|
+
TEntity2,
|
|
238
|
+
TPrivacyPolicy2,
|
|
239
|
+
TSelectedFields,
|
|
240
|
+
TSelectedFields2
|
|
241
|
+
>,
|
|
242
|
+
],
|
|
243
|
+
): Promise<TEntity2 | null>;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
247
|
+
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
248
|
+
* @param loadDirectives - associated entity load directives instructing each step of the folds
|
|
249
|
+
*/
|
|
250
|
+
async loadAssociatedEntityThroughAsync<
|
|
251
|
+
TFields2 extends object,
|
|
252
|
+
TID2 extends NonNullable<TFields2[TSelectedFields2]>,
|
|
253
|
+
TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
|
|
254
|
+
TPrivacyPolicy2 extends EntityPrivacyPolicy<
|
|
255
|
+
TFields2,
|
|
256
|
+
TID2,
|
|
257
|
+
TViewerContext,
|
|
258
|
+
TEntity2,
|
|
259
|
+
TSelectedFields2
|
|
260
|
+
>,
|
|
261
|
+
TFields3 extends object,
|
|
262
|
+
TID3 extends NonNullable<TFields3[TSelectedFields3]>,
|
|
263
|
+
TEntity3 extends ReadonlyEntity<TFields3, TID3, TViewerContext, TSelectedFields3>,
|
|
264
|
+
TPrivacyPolicy3 extends EntityPrivacyPolicy<
|
|
265
|
+
TFields3,
|
|
266
|
+
TID3,
|
|
267
|
+
TViewerContext,
|
|
268
|
+
TEntity3,
|
|
269
|
+
TSelectedFields3
|
|
270
|
+
>,
|
|
271
|
+
TSelectedFields2 extends keyof TFields2 = keyof TFields2,
|
|
272
|
+
TSelectedFields3 extends keyof TFields3 = keyof TFields3,
|
|
273
|
+
>(
|
|
274
|
+
loadDirectives: [
|
|
275
|
+
EntityLoadThroughDirective<
|
|
276
|
+
TViewerContext,
|
|
277
|
+
TFields,
|
|
278
|
+
TFields2,
|
|
279
|
+
TID2,
|
|
280
|
+
TEntity2,
|
|
281
|
+
TPrivacyPolicy2,
|
|
282
|
+
TSelectedFields,
|
|
283
|
+
TSelectedFields2
|
|
284
|
+
>,
|
|
285
|
+
EntityLoadThroughDirective<
|
|
286
|
+
TViewerContext,
|
|
287
|
+
TFields2,
|
|
288
|
+
TFields3,
|
|
289
|
+
TID3,
|
|
290
|
+
TEntity3,
|
|
291
|
+
TPrivacyPolicy3,
|
|
292
|
+
TSelectedFields2,
|
|
293
|
+
TSelectedFields3
|
|
294
|
+
>,
|
|
295
|
+
],
|
|
296
|
+
): Promise<TEntity3 | null>;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
300
|
+
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
301
|
+
* @param loadDirectives - associated entity load directives instructing each step of the folds
|
|
302
|
+
*/
|
|
303
|
+
async loadAssociatedEntityThroughAsync<
|
|
304
|
+
TFields2 extends object,
|
|
305
|
+
TID2 extends NonNullable<TFields2[TSelectedFields2]>,
|
|
306
|
+
TEntity2 extends ReadonlyEntity<TFields2, TID2, TViewerContext, TSelectedFields2>,
|
|
307
|
+
TPrivacyPolicy2 extends EntityPrivacyPolicy<
|
|
308
|
+
TFields2,
|
|
309
|
+
TID2,
|
|
310
|
+
TViewerContext,
|
|
311
|
+
TEntity2,
|
|
312
|
+
TSelectedFields2
|
|
313
|
+
>,
|
|
314
|
+
TFields3 extends object,
|
|
315
|
+
TID3 extends NonNullable<TFields3[TSelectedFields3]>,
|
|
316
|
+
TEntity3 extends ReadonlyEntity<TFields3, TID3, TViewerContext, TSelectedFields3>,
|
|
317
|
+
TPrivacyPolicy3 extends EntityPrivacyPolicy<
|
|
318
|
+
TFields3,
|
|
319
|
+
TID3,
|
|
320
|
+
TViewerContext,
|
|
321
|
+
TEntity3,
|
|
322
|
+
TSelectedFields3
|
|
323
|
+
>,
|
|
324
|
+
TFields4 extends object,
|
|
325
|
+
TID4 extends NonNullable<TFields4[TSelectedFields4]>,
|
|
326
|
+
TEntity4 extends ReadonlyEntity<TFields4, TID4, TViewerContext, TSelectedFields4>,
|
|
327
|
+
TPrivacyPolicy4 extends EntityPrivacyPolicy<
|
|
328
|
+
TFields4,
|
|
329
|
+
TID4,
|
|
330
|
+
TViewerContext,
|
|
331
|
+
TEntity4,
|
|
332
|
+
TSelectedFields4
|
|
333
|
+
>,
|
|
334
|
+
TSelectedFields2 extends keyof TFields2 = keyof TFields2,
|
|
335
|
+
TSelectedFields3 extends keyof TFields3 = keyof TFields3,
|
|
336
|
+
TSelectedFields4 extends keyof TFields4 = keyof TFields4,
|
|
337
|
+
>(
|
|
338
|
+
loadDirectives: [
|
|
339
|
+
EntityLoadThroughDirective<
|
|
340
|
+
TViewerContext,
|
|
341
|
+
TFields,
|
|
342
|
+
TFields2,
|
|
343
|
+
TID2,
|
|
344
|
+
TEntity2,
|
|
345
|
+
TPrivacyPolicy2,
|
|
346
|
+
TSelectedFields,
|
|
347
|
+
TSelectedFields2
|
|
348
|
+
>,
|
|
349
|
+
EntityLoadThroughDirective<
|
|
350
|
+
TViewerContext,
|
|
351
|
+
TFields2,
|
|
352
|
+
TFields3,
|
|
353
|
+
TID3,
|
|
354
|
+
TEntity3,
|
|
355
|
+
TPrivacyPolicy3,
|
|
356
|
+
TSelectedFields2,
|
|
357
|
+
TSelectedFields3
|
|
358
|
+
>,
|
|
359
|
+
EntityLoadThroughDirective<
|
|
360
|
+
TViewerContext,
|
|
361
|
+
TFields3,
|
|
362
|
+
TFields4,
|
|
363
|
+
TID4,
|
|
364
|
+
TEntity4,
|
|
365
|
+
TPrivacyPolicy4,
|
|
366
|
+
TSelectedFields3,
|
|
367
|
+
TSelectedFields4
|
|
368
|
+
>,
|
|
369
|
+
],
|
|
370
|
+
): Promise<TEntity4 | null>;
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Load an associated entity by folding a sequence of EntityLoadThroughDirective. At each
|
|
374
|
+
* fold step, load an associated entity identified by a field value of the current fold value.
|
|
375
|
+
* @param loadDirectives - associated entity load directives instructing each step of the folds
|
|
376
|
+
*/
|
|
377
|
+
async loadAssociatedEntityThroughAsync(
|
|
378
|
+
loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
|
|
379
|
+
): Promise<ReadonlyEntity<any, any, any, any> | null>;
|
|
380
|
+
|
|
381
|
+
async loadAssociatedEntityThroughAsync(
|
|
382
|
+
loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
|
|
383
|
+
): Promise<ReadonlyEntity<any, any, any, any> | null> {
|
|
384
|
+
const result =
|
|
385
|
+
await this.authorizationResultBasedEntityAssociationLoader.loadAssociatedEntityThroughAsync(
|
|
386
|
+
loadDirectives,
|
|
387
|
+
);
|
|
388
|
+
return result?.enforceValue() ?? null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { enforceAsyncResult } from '@expo/results';
|
|
2
|
+
|
|
3
|
+
import { AuthorizationResultBasedCreateMutator } from './AuthorizationResultBasedEntityMutator';
|
|
4
|
+
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
5
|
+
import ReadonlyEntity from './ReadonlyEntity';
|
|
6
|
+
import ViewerContext from './ViewerContext';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Enforcing entity creator. All updates
|
|
10
|
+
* through this creator will throw if authorization is not successful.
|
|
11
|
+
*/
|
|
12
|
+
export default class EnforcingEntityCreator<
|
|
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 entityCreator: AuthorizationResultBasedCreateMutator<
|
|
28
|
+
TFields,
|
|
29
|
+
TID,
|
|
30
|
+
TViewerContext,
|
|
31
|
+
TEntity,
|
|
32
|
+
TPrivacyPolicy,
|
|
33
|
+
TSelectedFields
|
|
34
|
+
>,
|
|
35
|
+
) {}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Set the value for entity field.
|
|
39
|
+
* @param fieldName - entity field being updated
|
|
40
|
+
* @param value - value for entity field
|
|
41
|
+
*/
|
|
42
|
+
setField<K extends keyof Pick<TFields, TSelectedFields>>(fieldName: K, value: TFields[K]): this {
|
|
43
|
+
this.entityCreator.setField(fieldName, value);
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Commit the new entity after authorizing against creation privacy rules. Invalidates all caches for
|
|
49
|
+
* queries that would return new entity.
|
|
50
|
+
* @returns authorized, cached, newly-created entity, throwing if unsuccessful
|
|
51
|
+
*/
|
|
52
|
+
async createAsync(): Promise<TEntity> {
|
|
53
|
+
return await enforceAsyncResult(this.entityCreator.createAsync());
|
|
54
|
+
}
|
|
55
|
+
}
|