@expo/entity 0.35.0 → 0.36.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/AuthorizationResultBasedEntityLoader.d.ts +128 -0
- package/build/AuthorizationResultBasedEntityLoader.js +196 -0
- package/build/AuthorizationResultBasedEntityLoader.js.map +1 -0
- package/build/ComposedEntityCacheAdapter.js +1 -0
- package/build/ComposedEntityCacheAdapter.js.map +1 -1
- package/build/ComposedSecondaryEntityCache.js +1 -0
- package/build/ComposedSecondaryEntityCache.js.map +1 -1
- package/build/EnforcingEntityLoader.d.ts +5 -4
- package/build/EnforcingEntityLoader.js +4 -2
- package/build/EnforcingEntityLoader.js.map +1 -1
- package/build/Entity.d.ts +0 -27
- package/build/Entity.js +0 -50
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.d.ts +1 -1
- package/build/EntityAssociationLoader.js +17 -8
- package/build/EntityAssociationLoader.js.map +1 -1
- package/build/EntityCompanion.js +9 -1
- package/build/EntityCompanion.js.map +1 -1
- package/build/EntityCompanionProvider.d.ts +3 -1
- package/build/EntityCompanionProvider.js +10 -4
- package/build/EntityCompanionProvider.js.map +1 -1
- package/build/EntityConfiguration.d.ts +2 -1
- package/build/EntityConfiguration.js +19 -1
- package/build/EntityConfiguration.js.map +1 -1
- package/build/EntityDatabaseAdapter.d.ts +2 -2
- package/build/EntityDatabaseAdapter.js +5 -3
- package/build/EntityDatabaseAdapter.js.map +1 -1
- package/build/EntityFieldDefinition.d.ts +21 -10
- package/build/EntityFieldDefinition.js +8 -9
- package/build/EntityFieldDefinition.js.map +1 -1
- package/build/EntityFields.d.ts +10 -0
- package/build/EntityFields.js +15 -1
- package/build/EntityFields.js.map +1 -1
- package/build/EntityLoader.d.ts +12 -125
- package/build/EntityLoader.js +24 -239
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityLoaderFactory.d.ts +1 -1
- package/build/EntityLoaderFactory.js +3 -0
- package/build/EntityLoaderFactory.js.map +1 -1
- package/build/EntityLoaderUtils.d.ts +58 -0
- package/build/EntityLoaderUtils.js +109 -0
- package/build/EntityLoaderUtils.js.map +1 -0
- package/build/EntityMutator.d.ts +1 -0
- package/build/EntityMutator.js +71 -56
- package/build/EntityMutator.js.map +1 -1
- package/build/EntityMutatorFactory.js +9 -0
- package/build/EntityMutatorFactory.js.map +1 -1
- package/build/EntityPrivacyPolicy.d.ts +11 -5
- package/build/EntityPrivacyPolicy.js +5 -7
- package/build/EntityPrivacyPolicy.js.map +1 -1
- package/build/EntityQueryContext.d.ts +2 -1
- package/build/EntityQueryContext.js +11 -6
- package/build/EntityQueryContext.js.map +1 -1
- package/build/EntitySecondaryCacheLoader.js +5 -1
- package/build/EntitySecondaryCacheLoader.js.map +1 -1
- package/build/GenericEntityCacheAdapter.js +1 -0
- package/build/GenericEntityCacheAdapter.js.map +1 -1
- package/build/GenericSecondaryEntityCache.js +2 -0
- package/build/GenericSecondaryEntityCache.js.map +1 -1
- package/build/IEntityCacheAdapterProvider.d.ts +1 -1
- package/build/IEntityDatabaseAdapterProvider.d.ts +1 -1
- package/build/ReadonlyEntity.js +5 -1
- package/build/ReadonlyEntity.js.map +1 -1
- package/build/ViewerContext.js +2 -0
- package/build/ViewerContext.js.map +1 -1
- package/build/ViewerScopedEntityCompanion.js +2 -0
- package/build/ViewerScopedEntityCompanion.js.map +1 -1
- package/build/ViewerScopedEntityCompanionProvider.d.ts +0 -1
- package/build/ViewerScopedEntityCompanionProvider.js +2 -1
- package/build/ViewerScopedEntityCompanionProvider.js.map +1 -1
- package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
- package/build/ViewerScopedEntityLoaderFactory.js +2 -0
- package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
- package/build/ViewerScopedEntityMutatorFactory.js +2 -0
- package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
- package/build/__tests__/ComposedCacheAdapter-test.js +2 -0
- package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
- package/build/__tests__/ComposedSecondaryEntityCache-test.js +1 -0
- package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +1 -1
- package/build/__tests__/EnforcingEntityLoader-test.js +101 -113
- package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
- package/build/__tests__/Entity-test.js +0 -132
- package/build/__tests__/Entity-test.js.map +1 -1
- package/build/__tests__/EntityAssociationLoader-test.js +6 -2
- package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js +24 -22
- package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
- package/build/__tests__/EntityCompanion-test.js +26 -3
- package/build/__tests__/EntityCompanion-test.js.map +1 -1
- package/build/__tests__/EntityConfiguration-test.js +103 -0
- package/build/__tests__/EntityConfiguration-test.js.map +1 -0
- package/build/__tests__/EntityDatabaseAdapter-test.js +6 -0
- package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
- package/build/__tests__/EntityEdges-test.js +61 -20
- package/build/__tests__/EntityEdges-test.js.map +1 -1
- package/build/__tests__/EntityFields-test.js +6 -0
- package/build/__tests__/EntityFields-test.js.map +1 -1
- package/build/__tests__/EntityLoader-constructor-test.js +16 -17
- package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
- package/build/__tests__/EntityLoader-test.js +74 -22
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +12 -15
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
- package/build/__tests__/EntityMutator-test.js +54 -9
- package/build/__tests__/EntityMutator-test.js.map +1 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js +77 -59
- package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
- package/build/__tests__/EntityQueryContext-test.js +9 -0
- package/build/__tests__/EntityQueryContext-test.js.map +1 -1
- package/build/__tests__/EntitySelfReferentialEdges-test.js +42 -25
- package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +20 -18
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +12 -15
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
- package/build/entityUtils.d.ts +1 -1
- package/build/entityUtils.js.map +1 -1
- package/build/errors/EntityCacheAdapterError.js +2 -5
- package/build/errors/EntityCacheAdapterError.js.map +1 -1
- package/build/errors/EntityDatabaseAdapterError.js +14 -35
- package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
- package/build/errors/EntityError.js +1 -0
- package/build/errors/EntityError.js.map +1 -1
- package/build/errors/EntityInvalidFieldValueError.js +2 -2
- package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
- package/build/errors/EntityNotAuthorizedError.js +3 -2
- package/build/errors/EntityNotAuthorizedError.js.map +1 -1
- package/build/errors/EntityNotFoundError.js +2 -2
- package/build/errors/EntityNotFoundError.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/internal/EntityDataManager.d.ts +1 -1
- package/build/internal/EntityDataManager.js +6 -1
- package/build/internal/EntityDataManager.js.map +1 -1
- package/build/internal/EntityFieldTransformationUtils.d.ts +5 -5
- package/build/internal/EntityFieldTransformationUtils.js +5 -8
- package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/internal/EntityTableDataCoordinator.d.ts +1 -1
- package/build/internal/EntityTableDataCoordinator.js +5 -0
- package/build/internal/EntityTableDataCoordinator.js.map +1 -1
- package/build/internal/ReadThroughEntityCache.d.ts +1 -1
- package/build/internal/ReadThroughEntityCache.js +2 -0
- package/build/internal/ReadThroughEntityCache.js.map +1 -1
- package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +6 -2
- package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
- package/build/internal/__tests__/ReadThroughEntityCache-test.js +33 -0
- package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
- package/build/metrics/IEntityMetricsAdapter.d.ts +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
- package/build/rules/PrivacyPolicyRule.d.ts +1 -1
- package/build/rules/PrivacyPolicyRule.js.map +1 -1
- package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
- package/build/testfixtures/DateIDTestEntity.js +12 -15
- package/build/testfixtures/DateIDTestEntity.js.map +1 -1
- package/build/testfixtures/SimpleTestEntity.js +12 -15
- package/build/testfixtures/SimpleTestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity.js +12 -15
- package/build/testfixtures/TestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity2.js +12 -15
- package/build/testfixtures/TestEntity2.js.map +1 -1
- package/build/testfixtures/TestEntityNumberKey.js +12 -15
- package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
- package/build/testfixtures/TestEntityWithMutationTriggers.d.ts +36 -0
- package/build/testfixtures/TestEntityWithMutationTriggers.js +82 -0
- package/build/testfixtures/TestEntityWithMutationTriggers.js.map +1 -0
- package/build/utils/EntityPrivacyUtils.d.ts +34 -0
- package/build/utils/EntityPrivacyUtils.js +160 -0
- package/build/utils/EntityPrivacyUtils.js.map +1 -0
- package/build/utils/__tests__/EntityPrivacyUtils-test.d.ts +1 -0
- package/build/utils/__tests__/EntityPrivacyUtils-test.js +395 -0
- package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -0
- package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.d.ts +1 -0
- package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js +26 -0
- package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js.map +1 -0
- package/build/utils/collections/maps.js.map +1 -1
- package/build/utils/mergeEntityMutationTriggerConfigurations.d.ts +4 -0
- package/build/utils/mergeEntityMutationTriggerConfigurations.js +28 -0
- package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -0
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
- package/build/utils/testing/StubCacheAdapter.d.ts +3 -3
- package/build/utils/testing/StubCacheAdapter.js +3 -3
- package/build/utils/testing/StubCacheAdapter.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapter.d.ts +2 -2
- package/build/utils/testing/StubDatabaseAdapter.js +4 -2
- package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapterProvider.d.ts +1 -1
- package/build/utils/testing/StubDatabaseAdapterProvider.js +1 -3
- package/build/utils/testing/StubDatabaseAdapterProvider.js.map +1 -1
- package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.d.ts +1 -0
- package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js +42 -0
- package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js.map +1 -0
- package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +53 -0
- package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
- package/build/utils/testing/describeFieldTestCase.js.map +1 -1
- package/package.json +4 -3
- package/src/AuthorizationResultBasedEntityLoader.ts +297 -0
- package/src/ComposedEntityCacheAdapter.ts +6 -6
- package/src/ComposedSecondaryEntityCache.ts +8 -8
- package/src/EnforcingEntityLoader.ts +20 -19
- package/src/Entity.ts +11 -126
- package/src/EntityAssociationLoader.ts +40 -41
- package/src/EntityCompanion.ts +8 -4
- package/src/EntityCompanionProvider.ts +24 -16
- package/src/EntityConfiguration.ts +18 -7
- package/src/EntityDatabaseAdapter.ts +41 -41
- package/src/EntityFieldDefinition.ts +28 -18
- package/src/EntityFields.ts +15 -0
- package/src/EntityLoader.ts +63 -357
- package/src/EntityLoaderFactory.ts +10 -4
- package/src/EntityLoaderUtils.ts +149 -0
- package/src/EntityMutationInfo.ts +2 -2
- package/src/EntityMutationTriggerConfiguration.ts +5 -5
- package/src/EntityMutationValidator.ts +2 -2
- package/src/EntityMutator.ts +146 -144
- package/src/EntityMutatorFactory.ts +8 -8
- package/src/EntityPrivacyPolicy.ts +78 -28
- package/src/EntityQueryContext.ts +14 -13
- package/src/EntityQueryContextProvider.ts +5 -5
- package/src/EntitySecondaryCacheLoader.ts +13 -11
- package/src/GenericEntityCacheAdapter.ts +10 -10
- package/src/GenericSecondaryEntityCache.ts +6 -6
- package/src/IEntityCacheAdapter.ts +4 -4
- package/src/IEntityCacheAdapterProvider.ts +2 -2
- package/src/IEntityDatabaseAdapterProvider.ts +2 -2
- package/src/ReadonlyEntity.ts +5 -5
- package/src/ViewerContext.ts +5 -5
- package/src/ViewerScopedEntityCompanion.ts +4 -4
- package/src/ViewerScopedEntityCompanionProvider.ts +4 -5
- package/src/ViewerScopedEntityLoaderFactory.ts +10 -4
- package/src/ViewerScopedEntityMutatorFactory.ts +5 -5
- package/src/__tests__/ComposedCacheAdapter-test.ts +12 -10
- package/src/__tests__/ComposedSecondaryEntityCache-test.ts +8 -8
- package/src/__tests__/EnforcingEntityLoader-test.ts +236 -159
- package/src/__tests__/Entity-test.ts +0 -202
- package/src/__tests__/EntityAssociationLoader-test.ts +29 -25
- package/src/__tests__/EntityCommonUseCases-test.ts +29 -13
- package/src/__tests__/EntityCompanion-test.ts +57 -5
- package/src/__tests__/EntityConfiguration-test.ts +118 -0
- package/src/__tests__/EntityDatabaseAdapter-test.ts +11 -11
- package/src/__tests__/EntityEdges-test.ts +108 -36
- package/src/__tests__/EntityFields-test.ts +14 -2
- package/src/__tests__/EntityLoader-constructor-test.ts +20 -7
- package/src/__tests__/EntityLoader-test.ts +214 -86
- package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +2 -2
- package/src/__tests__/EntityMutator-test.ts +281 -96
- package/src/__tests__/EntityPrivacyPolicy-test.ts +166 -53
- package/src/__tests__/EntityQueryContext-test.ts +30 -12
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +46 -26
- package/src/__tests__/GenericEntityCacheAdapter-test.ts +2 -2
- package/src/__tests__/ViewerContext-test.ts +1 -1
- package/src/__tests__/ViewerScopedEntityCompanion-test.ts +2 -2
- package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +2 -2
- package/src/__tests__/ViewerScopedEntityLoaderFactory-test.ts +2 -1
- package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +19 -19
- package/src/__tests__/entityUtils-test.ts +2 -2
- package/src/entityUtils.ts +4 -4
- package/src/errors/EntityError.ts +4 -1
- package/src/errors/EntityInvalidFieldValueError.ts +2 -2
- package/src/errors/EntityNotAuthorizedError.ts +3 -3
- package/src/errors/EntityNotFoundError.ts +2 -2
- package/src/index.ts +1 -0
- package/src/internal/EntityDataManager.ts +24 -24
- package/src/internal/EntityFieldTransformationUtils.ts +39 -32
- package/src/internal/EntityTableDataCoordinator.ts +3 -3
- package/src/internal/ReadThroughEntityCache.ts +9 -9
- package/src/internal/__tests__/EntityDataManager-test.ts +51 -51
- package/src/internal/__tests__/EntityFieldTransformationUtils-test.ts +14 -10
- package/src/internal/__tests__/ReadThroughEntityCache-test.ts +74 -18
- package/src/metrics/EntityMetricsUtils.ts +4 -4
- package/src/metrics/IEntityMetricsAdapter.ts +1 -1
- package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +9 -3
- package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +9 -3
- package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +9 -3
- package/src/rules/PrivacyPolicyRule.ts +9 -3
- package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -1
- package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -1
- package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -1
- package/src/testfixtures/TestEntity.ts +1 -1
- package/src/testfixtures/TestEntityWithMutationTriggers.ts +156 -0
- package/src/utils/EntityPrivacyUtils.ts +325 -0
- package/src/utils/__tests__/EntityPrivacyUtils-test.ts +570 -0
- package/src/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.ts +29 -0
- package/src/utils/collections/__tests__/maps-test.ts +2 -2
- package/src/utils/collections/maps.ts +11 -11
- package/src/utils/mergeEntityMutationTriggerConfigurations.ts +44 -0
- package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +25 -22
- package/src/utils/testing/StubCacheAdapter.ts +17 -15
- package/src/utils/testing/StubDatabaseAdapter.ts +35 -30
- package/src/utils/testing/StubDatabaseAdapterProvider.ts +2 -2
- package/src/utils/testing/StubQueryContextProvider.ts +2 -2
- package/src/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.ts +42 -0
- package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +111 -29
- package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +2 -2
- package/src/utils/testing/describeFieldTestCase.ts +1 -1
- package/build/__tests__/EntityDataConfiguration-test.js +0 -68
- package/build/__tests__/EntityDataConfiguration-test.js.map +0 -1
- package/src/__tests__/EntityDataConfiguration-test.ts +0 -77
- /package/build/__tests__/{EntityDataConfiguration-test.d.ts → EntityConfiguration-test.d.ts} +0 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { asyncResult } from '@expo/results';
|
|
2
|
+
|
|
3
|
+
import Entity, { IEntityClass } from '../Entity';
|
|
4
|
+
import { EntityEdgeDeletionBehavior } from '../EntityFieldDefinition';
|
|
5
|
+
import { EntityCascadingDeletionInfo } from '../EntityMutationInfo';
|
|
6
|
+
import EntityPrivacyPolicy from '../EntityPrivacyPolicy';
|
|
7
|
+
import { EntityQueryContext } from '../EntityQueryContext';
|
|
8
|
+
import ViewerContext from '../ViewerContext';
|
|
9
|
+
import { failedResults } from '../entityUtils';
|
|
10
|
+
import EntityNotAuthorizedError from '../errors/EntityNotAuthorizedError';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check whether an entity loaded by a viewer can be updated by that same viewer.
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
*
|
|
17
|
+
* This may be useful in situations relying upon the thrown privacy policy thrown authorization error
|
|
18
|
+
* is insufficient for the task at hand. When dealing with purely a sequence of mutations it is easy
|
|
19
|
+
* to roll back all mutations given a single authorization error by wrapping them in a single transaction.
|
|
20
|
+
* When certain portions of a mutation cannot be rolled back transactionally (third pary calls,
|
|
21
|
+
* legacy code, etc), using this method can help decide whether the sequence of mutations will fail before
|
|
22
|
+
* attempting them. Note that if any privacy policy rules use a piece of data being updated in the mutations
|
|
23
|
+
* the result of this method and the update mutation itself may differ.
|
|
24
|
+
*
|
|
25
|
+
* @param entityClass - class of entity
|
|
26
|
+
* @param sourceEntity - entity loaded by viewer
|
|
27
|
+
* @param queryContext - query context in which to perform the check
|
|
28
|
+
*/
|
|
29
|
+
export async function canViewerUpdateAsync<
|
|
30
|
+
TMFields extends object,
|
|
31
|
+
TMID extends NonNullable<TMFields[TMSelectedFields]>,
|
|
32
|
+
TMViewerContext extends ViewerContext,
|
|
33
|
+
TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
|
|
34
|
+
TMPrivacyPolicy extends EntityPrivacyPolicy<
|
|
35
|
+
TMFields,
|
|
36
|
+
TMID,
|
|
37
|
+
TMViewerContext,
|
|
38
|
+
TMEntity,
|
|
39
|
+
TMSelectedFields
|
|
40
|
+
>,
|
|
41
|
+
TMSelectedFields extends keyof TMFields = keyof TMFields,
|
|
42
|
+
>(
|
|
43
|
+
entityClass: IEntityClass<
|
|
44
|
+
TMFields,
|
|
45
|
+
TMID,
|
|
46
|
+
TMViewerContext,
|
|
47
|
+
TMEntity,
|
|
48
|
+
TMPrivacyPolicy,
|
|
49
|
+
TMSelectedFields
|
|
50
|
+
>,
|
|
51
|
+
sourceEntity: TMEntity,
|
|
52
|
+
queryContext: EntityQueryContext = sourceEntity
|
|
53
|
+
.getViewerContext()
|
|
54
|
+
.getViewerScopedEntityCompanionForClass(entityClass)
|
|
55
|
+
.getQueryContextProvider()
|
|
56
|
+
.getQueryContext(),
|
|
57
|
+
): Promise<boolean> {
|
|
58
|
+
return await canViewerUpdateInternalAsync(
|
|
59
|
+
entityClass,
|
|
60
|
+
sourceEntity,
|
|
61
|
+
/* cascadingDeleteCause */ null,
|
|
62
|
+
queryContext,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function canViewerUpdateInternalAsync<
|
|
67
|
+
TMFields extends object,
|
|
68
|
+
TMID extends NonNullable<TMFields[TMSelectedFields]>,
|
|
69
|
+
TMViewerContext extends ViewerContext,
|
|
70
|
+
TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
|
|
71
|
+
TMPrivacyPolicy extends EntityPrivacyPolicy<
|
|
72
|
+
TMFields,
|
|
73
|
+
TMID,
|
|
74
|
+
TMViewerContext,
|
|
75
|
+
TMEntity,
|
|
76
|
+
TMSelectedFields
|
|
77
|
+
>,
|
|
78
|
+
TMSelectedFields extends keyof TMFields = keyof TMFields,
|
|
79
|
+
>(
|
|
80
|
+
entityClass: IEntityClass<
|
|
81
|
+
TMFields,
|
|
82
|
+
TMID,
|
|
83
|
+
TMViewerContext,
|
|
84
|
+
TMEntity,
|
|
85
|
+
TMPrivacyPolicy,
|
|
86
|
+
TMSelectedFields
|
|
87
|
+
>,
|
|
88
|
+
sourceEntity: TMEntity,
|
|
89
|
+
cascadingDeleteCause: EntityCascadingDeletionInfo | null,
|
|
90
|
+
queryContext: EntityQueryContext,
|
|
91
|
+
): Promise<boolean> {
|
|
92
|
+
const companion = sourceEntity
|
|
93
|
+
.getViewerContext()
|
|
94
|
+
.getViewerScopedEntityCompanionForClass(entityClass);
|
|
95
|
+
const privacyPolicy = companion.entityCompanion.privacyPolicy;
|
|
96
|
+
const evaluationResult = await asyncResult(
|
|
97
|
+
privacyPolicy.authorizeUpdateAsync(
|
|
98
|
+
sourceEntity.getViewerContext(),
|
|
99
|
+
queryContext,
|
|
100
|
+
{ previousValue: null, cascadingDeleteCause },
|
|
101
|
+
sourceEntity,
|
|
102
|
+
companion.getMetricsAdapter(),
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
if (!evaluationResult.ok) {
|
|
106
|
+
if (evaluationResult.reason instanceof EntityNotAuthorizedError) {
|
|
107
|
+
return false;
|
|
108
|
+
} else {
|
|
109
|
+
throw evaluationResult.reason;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return evaluationResult.ok;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Check whether a single entity loaded by a viewer can be deleted by that same viewer.
|
|
117
|
+
* This recursively checks edge cascade permissions (EntityEdgeDeletionBehavior) as well.
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* See remarks for canViewerUpdate.
|
|
121
|
+
*
|
|
122
|
+
* @param entityClass - class of entity
|
|
123
|
+
* @param sourceEntity - entity loaded by viewer
|
|
124
|
+
* @param queryContext - query context in which to perform the check
|
|
125
|
+
*/
|
|
126
|
+
export async function canViewerDeleteAsync<
|
|
127
|
+
TFields extends object,
|
|
128
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
129
|
+
TMViewerContext extends ViewerContext,
|
|
130
|
+
TEntity extends Entity<TFields, TID, TMViewerContext, TSelectedFields>,
|
|
131
|
+
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
132
|
+
TFields,
|
|
133
|
+
TID,
|
|
134
|
+
TMViewerContext,
|
|
135
|
+
TEntity,
|
|
136
|
+
TSelectedFields
|
|
137
|
+
>,
|
|
138
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
139
|
+
>(
|
|
140
|
+
entityClass: IEntityClass<
|
|
141
|
+
TFields,
|
|
142
|
+
TID,
|
|
143
|
+
TMViewerContext,
|
|
144
|
+
TEntity,
|
|
145
|
+
TPrivacyPolicy,
|
|
146
|
+
TSelectedFields
|
|
147
|
+
>,
|
|
148
|
+
sourceEntity: TEntity,
|
|
149
|
+
queryContext: EntityQueryContext = sourceEntity
|
|
150
|
+
.getViewerContext()
|
|
151
|
+
.getViewerScopedEntityCompanionForClass(entityClass)
|
|
152
|
+
.getQueryContextProvider()
|
|
153
|
+
.getQueryContext(),
|
|
154
|
+
): Promise<boolean> {
|
|
155
|
+
return await canViewerDeleteInternalAsync(
|
|
156
|
+
entityClass,
|
|
157
|
+
sourceEntity,
|
|
158
|
+
/* cascadingDeleteCause */ null,
|
|
159
|
+
queryContext,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function canViewerDeleteInternalAsync<
|
|
164
|
+
TFields extends object,
|
|
165
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
166
|
+
TMViewerContext extends ViewerContext,
|
|
167
|
+
TEntity extends Entity<TFields, TID, TMViewerContext, TSelectedFields>,
|
|
168
|
+
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
169
|
+
TFields,
|
|
170
|
+
TID,
|
|
171
|
+
TMViewerContext,
|
|
172
|
+
TEntity,
|
|
173
|
+
TSelectedFields
|
|
174
|
+
>,
|
|
175
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
176
|
+
>(
|
|
177
|
+
entityClass: IEntityClass<
|
|
178
|
+
TFields,
|
|
179
|
+
TID,
|
|
180
|
+
TMViewerContext,
|
|
181
|
+
TEntity,
|
|
182
|
+
TPrivacyPolicy,
|
|
183
|
+
TSelectedFields
|
|
184
|
+
>,
|
|
185
|
+
sourceEntity: TEntity,
|
|
186
|
+
cascadingDeleteCause: EntityCascadingDeletionInfo | null,
|
|
187
|
+
queryContext: EntityQueryContext,
|
|
188
|
+
): Promise<boolean> {
|
|
189
|
+
const viewerContext = sourceEntity.getViewerContext();
|
|
190
|
+
const entityCompanionProvider = viewerContext.entityCompanionProvider;
|
|
191
|
+
const viewerScopedCompanion = sourceEntity
|
|
192
|
+
.getViewerContext()
|
|
193
|
+
.getViewerScopedEntityCompanionForClass(entityClass);
|
|
194
|
+
|
|
195
|
+
const privacyPolicy = viewerScopedCompanion.entityCompanion.privacyPolicy;
|
|
196
|
+
const evaluationResult = await asyncResult(
|
|
197
|
+
privacyPolicy.authorizeDeleteAsync(
|
|
198
|
+
sourceEntity.getViewerContext(),
|
|
199
|
+
queryContext,
|
|
200
|
+
{ previousValue: null, cascadingDeleteCause },
|
|
201
|
+
sourceEntity,
|
|
202
|
+
viewerScopedCompanion.getMetricsAdapter(),
|
|
203
|
+
),
|
|
204
|
+
);
|
|
205
|
+
if (!evaluationResult.ok) {
|
|
206
|
+
if (evaluationResult.reason instanceof EntityNotAuthorizedError) {
|
|
207
|
+
return false;
|
|
208
|
+
} else {
|
|
209
|
+
throw evaluationResult.reason;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const newCascadingDeleteCause = {
|
|
214
|
+
entity: sourceEntity,
|
|
215
|
+
cascadingDeleteCause,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Take entity X which is proposed to be deleted, look at inbound edges (entities that reference X).
|
|
219
|
+
// These inbound edges are the entities that will either get deleted or have their references
|
|
220
|
+
// to X nullified based on the EntityEdgeDeletionBehavior when entity X is deleted.
|
|
221
|
+
// For each of these inboundEdge entities Y, look at the field(s) on Y that reference X.
|
|
222
|
+
// For each of the field(s) on Y that reference X,
|
|
223
|
+
// - if EntityEdgeDeletionBehavior is cascade set null, check if user can update Y
|
|
224
|
+
// - if EntityEdgeDeletionBehavior is cascade delete, recursively run canViewerDeleteAsync on Y
|
|
225
|
+
// Return the conjunction (returning eagerly when false) of all checks recursively.
|
|
226
|
+
|
|
227
|
+
const entityConfiguration =
|
|
228
|
+
viewerScopedCompanion.entityCompanion.entityCompanionDefinition.entityConfiguration;
|
|
229
|
+
const inboundEdges = entityConfiguration.inboundEdges;
|
|
230
|
+
|
|
231
|
+
for (const inboundEdge of inboundEdges) {
|
|
232
|
+
const configurationForInboundEdge =
|
|
233
|
+
entityCompanionProvider.getCompanionForEntity(inboundEdge).entityCompanionDefinition
|
|
234
|
+
.entityConfiguration;
|
|
235
|
+
|
|
236
|
+
const loader = viewerContext
|
|
237
|
+
.getViewerScopedEntityCompanionForClass(inboundEdge)
|
|
238
|
+
.getLoaderFactory()
|
|
239
|
+
.forLoad(queryContext, {
|
|
240
|
+
previousValue: null,
|
|
241
|
+
cascadingDeleteCause: newCascadingDeleteCause,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
for (const [fieldName, fieldDefinition] of configurationForInboundEdge.schema) {
|
|
245
|
+
const association = fieldDefinition.association;
|
|
246
|
+
if (!association) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const associatedConfiguration = entityCompanionProvider.getCompanionForEntity(
|
|
251
|
+
association.associatedEntityClass,
|
|
252
|
+
).entityCompanionDefinition.entityConfiguration;
|
|
253
|
+
if (associatedConfiguration !== entityConfiguration) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const entityResultsForInboundEdge = await loader
|
|
258
|
+
.withAuthorizationResults()
|
|
259
|
+
.loadManyByFieldEqualingAsync(
|
|
260
|
+
fieldName,
|
|
261
|
+
association.associatedEntityLookupByField
|
|
262
|
+
? sourceEntity.getField(association.associatedEntityLookupByField as any)
|
|
263
|
+
: sourceEntity.getID(),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const failedEntityLoadResults = failedResults(entityResultsForInboundEdge);
|
|
267
|
+
for (const failedResult of failedEntityLoadResults) {
|
|
268
|
+
if (failedResult.reason instanceof EntityNotAuthorizedError) {
|
|
269
|
+
return false;
|
|
270
|
+
} else {
|
|
271
|
+
throw failedResult.reason;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// all results should be success at this point due to check above
|
|
276
|
+
const entitiesForInboundEdge = entityResultsForInboundEdge.map((r) => r.enforceValue());
|
|
277
|
+
|
|
278
|
+
switch (association.edgeDeletionBehavior) {
|
|
279
|
+
case EntityEdgeDeletionBehavior.CASCADE_DELETE:
|
|
280
|
+
case EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY: {
|
|
281
|
+
const canDeleteAll = (
|
|
282
|
+
await Promise.all(
|
|
283
|
+
entitiesForInboundEdge.map((entity) =>
|
|
284
|
+
canViewerDeleteInternalAsync(
|
|
285
|
+
inboundEdge,
|
|
286
|
+
entity,
|
|
287
|
+
newCascadingDeleteCause,
|
|
288
|
+
queryContext,
|
|
289
|
+
),
|
|
290
|
+
),
|
|
291
|
+
)
|
|
292
|
+
).every((b) => b);
|
|
293
|
+
|
|
294
|
+
if (!canDeleteAll) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
case EntityEdgeDeletionBehavior.SET_NULL:
|
|
301
|
+
case EntityEdgeDeletionBehavior.SET_NULL_INVALIDATE_CACHE_ONLY: {
|
|
302
|
+
const canUpdateAll = (
|
|
303
|
+
await Promise.all(
|
|
304
|
+
entitiesForInboundEdge.map((entity) =>
|
|
305
|
+
canViewerUpdateInternalAsync(
|
|
306
|
+
inboundEdge,
|
|
307
|
+
entity,
|
|
308
|
+
newCascadingDeleteCause,
|
|
309
|
+
queryContext,
|
|
310
|
+
),
|
|
311
|
+
),
|
|
312
|
+
)
|
|
313
|
+
).every((b) => b);
|
|
314
|
+
|
|
315
|
+
if (!canUpdateAll) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return true;
|
|
325
|
+
}
|