@expo/entity 0.35.0 → 0.37.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 +26 -20
- package/build/index.js +38 -28
- 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 +5 -4
- 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 +26 -20
- 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
package/src/Entity.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Result
|
|
1
|
+
import { Result } from '@expo/results';
|
|
2
2
|
|
|
3
3
|
import { EntityCompanionDefinition } from './EntityCompanionProvider';
|
|
4
4
|
import { CreateMutator, UpdateMutator } from './EntityMutator';
|
|
@@ -29,7 +29,7 @@ export default abstract class Entity<
|
|
|
29
29
|
TFields extends object,
|
|
30
30
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
31
31
|
TViewerContext extends ViewerContext,
|
|
32
|
-
TSelectedFields extends keyof TFields = keyof TFields
|
|
32
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
33
33
|
> extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields> {
|
|
34
34
|
/**
|
|
35
35
|
* Vend mutator for creating a new entity in given query context.
|
|
@@ -50,7 +50,7 @@ export default abstract class Entity<
|
|
|
50
50
|
TMEntity,
|
|
51
51
|
TMSelectedFields
|
|
52
52
|
>,
|
|
53
|
-
TMSelectedFields extends keyof TMFields = keyof TMFields
|
|
53
|
+
TMSelectedFields extends keyof TMFields = keyof TMFields,
|
|
54
54
|
>(
|
|
55
55
|
this: IEntityClass<
|
|
56
56
|
TMFields,
|
|
@@ -64,7 +64,7 @@ export default abstract class Entity<
|
|
|
64
64
|
queryContext: EntityQueryContext = viewerContext
|
|
65
65
|
.getViewerScopedEntityCompanionForClass(this)
|
|
66
66
|
.getQueryContextProvider()
|
|
67
|
-
.getQueryContext()
|
|
67
|
+
.getQueryContext(),
|
|
68
68
|
): CreateMutator<TMFields, TMID, TMViewerContext, TMEntity, TMPrivacyPolicy, TMSelectedFields> {
|
|
69
69
|
return viewerContext
|
|
70
70
|
.getViewerScopedEntityCompanionForClass(this)
|
|
@@ -90,7 +90,7 @@ export default abstract class Entity<
|
|
|
90
90
|
TMEntity,
|
|
91
91
|
TMSelectedFields
|
|
92
92
|
>,
|
|
93
|
-
TMSelectedFields extends keyof TMFields = keyof TMFields
|
|
93
|
+
TMSelectedFields extends keyof TMFields = keyof TMFields,
|
|
94
94
|
>(
|
|
95
95
|
this: IEntityClass<
|
|
96
96
|
TMFields,
|
|
@@ -105,7 +105,7 @@ export default abstract class Entity<
|
|
|
105
105
|
.getViewerContext()
|
|
106
106
|
.getViewerScopedEntityCompanionForClass(this)
|
|
107
107
|
.getQueryContextProvider()
|
|
108
|
-
.getQueryContext()
|
|
108
|
+
.getQueryContext(),
|
|
109
109
|
): UpdateMutator<TMFields, TMID, TMViewerContext, TMEntity, TMPrivacyPolicy, TMSelectedFields> {
|
|
110
110
|
return existingEntity
|
|
111
111
|
.getViewerContext()
|
|
@@ -131,7 +131,7 @@ export default abstract class Entity<
|
|
|
131
131
|
TMEntity,
|
|
132
132
|
TMSelectedFields
|
|
133
133
|
>,
|
|
134
|
-
TMSelectedFields extends keyof TMFields = keyof TMFields
|
|
134
|
+
TMSelectedFields extends keyof TMFields = keyof TMFields,
|
|
135
135
|
>(
|
|
136
136
|
this: IEntityClass<
|
|
137
137
|
TMFields,
|
|
@@ -146,7 +146,7 @@ export default abstract class Entity<
|
|
|
146
146
|
.getViewerContext()
|
|
147
147
|
.getViewerScopedEntityCompanionForClass(this)
|
|
148
148
|
.getQueryContextProvider()
|
|
149
|
-
.getQueryContext()
|
|
149
|
+
.getQueryContext(),
|
|
150
150
|
): Promise<Result<void>> {
|
|
151
151
|
return existingEntity
|
|
152
152
|
.getViewerContext()
|
|
@@ -173,7 +173,7 @@ export default abstract class Entity<
|
|
|
173
173
|
TMEntity,
|
|
174
174
|
TMSelectedFields
|
|
175
175
|
>,
|
|
176
|
-
TMSelectedFields extends keyof TMFields = keyof TMFields
|
|
176
|
+
TMSelectedFields extends keyof TMFields = keyof TMFields,
|
|
177
177
|
>(
|
|
178
178
|
this: IEntityClass<
|
|
179
179
|
TMFields,
|
|
@@ -188,7 +188,7 @@ export default abstract class Entity<
|
|
|
188
188
|
.getViewerContext()
|
|
189
189
|
.getViewerScopedEntityCompanionForClass(this)
|
|
190
190
|
.getQueryContextProvider()
|
|
191
|
-
.getQueryContext()
|
|
191
|
+
.getQueryContext(),
|
|
192
192
|
): Promise<void> {
|
|
193
193
|
return existingEntity
|
|
194
194
|
.getViewerContext()
|
|
@@ -197,121 +197,6 @@ export default abstract class Entity<
|
|
|
197
197
|
.forDelete(existingEntity, queryContext)
|
|
198
198
|
.enforceDeleteAsync();
|
|
199
199
|
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Check whether an entity loaded by a viewer can be updated by that same viewer.
|
|
203
|
-
*
|
|
204
|
-
* @remarks
|
|
205
|
-
*
|
|
206
|
-
* This may be useful in situations relying upon the thrown privacy policy thrown authorization error
|
|
207
|
-
* is insufficient for the task at hand. When dealing with purely a sequence of mutations it is easy
|
|
208
|
-
* to roll back all mutations given a single authorization error by wrapping them in a single transaction.
|
|
209
|
-
* When certain portions of a mutation cannot be rolled back transactionally (third pary calls,
|
|
210
|
-
* legacy code, etc), using this method can help decide whether the sequence of mutations will fail before
|
|
211
|
-
* attempting them. Note that if any privacy policy rules use a piece of data being updated in the mutations
|
|
212
|
-
* the result of this method and the update mutation itself may differ.
|
|
213
|
-
*
|
|
214
|
-
* @param existingEntity - entity loaded by viewer
|
|
215
|
-
* @param queryContext - query context in which to perform the check
|
|
216
|
-
*/
|
|
217
|
-
static async canViewerUpdateAsync<
|
|
218
|
-
TMFields extends object,
|
|
219
|
-
TMID extends NonNullable<TMFields[TMSelectedFields]>,
|
|
220
|
-
TMViewerContext extends ViewerContext,
|
|
221
|
-
TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
|
|
222
|
-
TMPrivacyPolicy extends EntityPrivacyPolicy<
|
|
223
|
-
TMFields,
|
|
224
|
-
TMID,
|
|
225
|
-
TMViewerContext,
|
|
226
|
-
TMEntity,
|
|
227
|
-
TMSelectedFields
|
|
228
|
-
>,
|
|
229
|
-
TMSelectedFields extends keyof TMFields = keyof TMFields
|
|
230
|
-
>(
|
|
231
|
-
this: IEntityClass<
|
|
232
|
-
TMFields,
|
|
233
|
-
TMID,
|
|
234
|
-
TMViewerContext,
|
|
235
|
-
TMEntity,
|
|
236
|
-
TMPrivacyPolicy,
|
|
237
|
-
TMSelectedFields
|
|
238
|
-
>,
|
|
239
|
-
existingEntity: TMEntity,
|
|
240
|
-
queryContext: EntityQueryContext = existingEntity
|
|
241
|
-
.getViewerContext()
|
|
242
|
-
.getViewerScopedEntityCompanionForClass(this)
|
|
243
|
-
.getQueryContextProvider()
|
|
244
|
-
.getQueryContext()
|
|
245
|
-
): Promise<boolean> {
|
|
246
|
-
const companion = existingEntity
|
|
247
|
-
.getViewerContext()
|
|
248
|
-
.getViewerScopedEntityCompanionForClass(this);
|
|
249
|
-
const privacyPolicy = companion.entityCompanion.privacyPolicy;
|
|
250
|
-
const evaluationResult = await asyncResult(
|
|
251
|
-
privacyPolicy.authorizeUpdateAsync(
|
|
252
|
-
existingEntity.getViewerContext(),
|
|
253
|
-
queryContext,
|
|
254
|
-
{ cascadingDeleteCause: null },
|
|
255
|
-
existingEntity,
|
|
256
|
-
companion.getMetricsAdapter()
|
|
257
|
-
)
|
|
258
|
-
);
|
|
259
|
-
return evaluationResult.ok;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Check whether an entity loaded by a viewer can be deleted by that same viewer.
|
|
264
|
-
*
|
|
265
|
-
* @remarks
|
|
266
|
-
* See remarks for canViewerUpdate.
|
|
267
|
-
*
|
|
268
|
-
* @param existingEntity - entity loaded by viewer
|
|
269
|
-
* @param queryContext - query context in which to perform the check
|
|
270
|
-
*/
|
|
271
|
-
static async canViewerDeleteAsync<
|
|
272
|
-
TMFields extends object,
|
|
273
|
-
TMID extends NonNullable<TMFields[TMSelectedFields]>,
|
|
274
|
-
TMViewerContext extends ViewerContext,
|
|
275
|
-
TMEntity extends Entity<TMFields, TMID, TMViewerContext, TMSelectedFields>,
|
|
276
|
-
TMPrivacyPolicy extends EntityPrivacyPolicy<
|
|
277
|
-
TMFields,
|
|
278
|
-
TMID,
|
|
279
|
-
TMViewerContext,
|
|
280
|
-
TMEntity,
|
|
281
|
-
TMSelectedFields
|
|
282
|
-
>,
|
|
283
|
-
TMSelectedFields extends keyof TMFields = keyof TMFields
|
|
284
|
-
>(
|
|
285
|
-
this: IEntityClass<
|
|
286
|
-
TMFields,
|
|
287
|
-
TMID,
|
|
288
|
-
TMViewerContext,
|
|
289
|
-
TMEntity,
|
|
290
|
-
TMPrivacyPolicy,
|
|
291
|
-
TMSelectedFields
|
|
292
|
-
>,
|
|
293
|
-
existingEntity: TMEntity,
|
|
294
|
-
queryContext: EntityQueryContext = existingEntity
|
|
295
|
-
.getViewerContext()
|
|
296
|
-
.getViewerScopedEntityCompanionForClass(this)
|
|
297
|
-
.getQueryContextProvider()
|
|
298
|
-
.getQueryContext()
|
|
299
|
-
): Promise<boolean> {
|
|
300
|
-
const companion = existingEntity
|
|
301
|
-
.getViewerContext()
|
|
302
|
-
.getViewerScopedEntityCompanionForClass(this);
|
|
303
|
-
const privacyPolicy = companion.entityCompanion.privacyPolicy;
|
|
304
|
-
const evaluationResult = await asyncResult(
|
|
305
|
-
privacyPolicy.authorizeDeleteAsync(
|
|
306
|
-
existingEntity.getViewerContext(),
|
|
307
|
-
queryContext,
|
|
308
|
-
{ cascadingDeleteCause: null },
|
|
309
|
-
existingEntity,
|
|
310
|
-
companion.getMetricsAdapter()
|
|
311
|
-
)
|
|
312
|
-
);
|
|
313
|
-
return evaluationResult.ok;
|
|
314
|
-
}
|
|
315
200
|
}
|
|
316
201
|
|
|
317
202
|
/**
|
|
@@ -329,7 +214,7 @@ export interface IEntityClass<
|
|
|
329
214
|
TEntity,
|
|
330
215
|
TSelectedFields
|
|
331
216
|
>,
|
|
332
|
-
TSelectedFields extends keyof TFields = keyof TFields
|
|
217
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
333
218
|
> {
|
|
334
219
|
new (constructorParam: {
|
|
335
220
|
viewerContext: TViewerContext;
|
|
@@ -16,7 +16,7 @@ export default class EntityAssociationLoader<
|
|
|
16
16
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
17
17
|
TViewerContext extends ViewerContext,
|
|
18
18
|
TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
19
|
-
TSelectedFields extends keyof TFields
|
|
19
|
+
TSelectedFields extends keyof TFields,
|
|
20
20
|
> {
|
|
21
21
|
constructor(private readonly entity: TEntity) {}
|
|
22
22
|
|
|
@@ -44,7 +44,7 @@ export default class EntityAssociationLoader<
|
|
|
44
44
|
TAssociatedEntity,
|
|
45
45
|
TAssociatedSelectedFields
|
|
46
46
|
>,
|
|
47
|
-
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
|
|
47
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
48
48
|
>(
|
|
49
49
|
fieldIdentifyingAssociatedEntity: TIdentifyingField,
|
|
50
50
|
associatedEntityClass: IEntityClass<
|
|
@@ -59,7 +59,7 @@ export default class EntityAssociationLoader<
|
|
|
59
59
|
.getViewerContext()
|
|
60
60
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
61
61
|
.getQueryContextProvider()
|
|
62
|
-
.getQueryContext()
|
|
62
|
+
.getQueryContext(),
|
|
63
63
|
): Promise<
|
|
64
64
|
Result<null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity>
|
|
65
65
|
> {
|
|
@@ -74,9 +74,11 @@ export default class EntityAssociationLoader<
|
|
|
74
74
|
.getViewerContext()
|
|
75
75
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
76
76
|
.getLoaderFactory()
|
|
77
|
-
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
77
|
+
.forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
|
|
78
78
|
|
|
79
|
-
return (await loader
|
|
79
|
+
return (await loader
|
|
80
|
+
.withAuthorizationResults()
|
|
81
|
+
.loadByIDAsync(associatedEntityID as unknown as TAssociatedID)) as Result<
|
|
80
82
|
null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
|
|
81
83
|
>;
|
|
82
84
|
}
|
|
@@ -106,7 +108,7 @@ export default class EntityAssociationLoader<
|
|
|
106
108
|
TAssociatedEntity,
|
|
107
109
|
TAssociatedSelectedFields
|
|
108
110
|
>,
|
|
109
|
-
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
|
|
111
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
110
112
|
>(
|
|
111
113
|
associatedEntityClass: IEntityClass<
|
|
112
114
|
TAssociatedFields,
|
|
@@ -121,18 +123,17 @@ export default class EntityAssociationLoader<
|
|
|
121
123
|
.getViewerContext()
|
|
122
124
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
123
125
|
.getQueryContextProvider()
|
|
124
|
-
.getQueryContext()
|
|
126
|
+
.getQueryContext(),
|
|
125
127
|
): Promise<readonly Result<TAssociatedEntity>[]> {
|
|
126
128
|
const thisID = this.entity.getID();
|
|
127
129
|
const loader = this.entity
|
|
128
130
|
.getViewerContext()
|
|
129
131
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
130
132
|
.getLoaderFactory()
|
|
131
|
-
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
132
|
-
return await loader
|
|
133
|
-
|
|
134
|
-
thisID as any
|
|
135
|
-
);
|
|
133
|
+
.forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
|
|
134
|
+
return await loader
|
|
135
|
+
.withAuthorizationResults()
|
|
136
|
+
.loadManyByFieldEqualingAsync(associatedEntityFieldContainingThisID, thisID as any);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
/**
|
|
@@ -159,7 +160,7 @@ export default class EntityAssociationLoader<
|
|
|
159
160
|
TAssociatedEntity,
|
|
160
161
|
TAssociatedSelectedFields
|
|
161
162
|
>,
|
|
162
|
-
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
|
|
163
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
163
164
|
>(
|
|
164
165
|
fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
|
|
165
166
|
associatedEntityClass: IEntityClass<
|
|
@@ -175,7 +176,7 @@ export default class EntityAssociationLoader<
|
|
|
175
176
|
.getViewerContext()
|
|
176
177
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
177
178
|
.getQueryContextProvider()
|
|
178
|
-
.getQueryContext()
|
|
179
|
+
.getQueryContext(),
|
|
179
180
|
): Promise<Result<TAssociatedEntity> | null> {
|
|
180
181
|
const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
|
|
181
182
|
if (!associatedFieldValue) {
|
|
@@ -185,11 +186,10 @@ export default class EntityAssociationLoader<
|
|
|
185
186
|
.getViewerContext()
|
|
186
187
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
187
188
|
.getLoaderFactory()
|
|
188
|
-
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
189
|
-
return await loader
|
|
190
|
-
|
|
191
|
-
associatedFieldValue as any
|
|
192
|
-
);
|
|
189
|
+
.forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
|
|
190
|
+
return await loader
|
|
191
|
+
.withAuthorizationResults()
|
|
192
|
+
.loadByFieldEqualingAsync(associatedEntityLookupByField, associatedFieldValue as any);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
@@ -216,7 +216,7 @@ export default class EntityAssociationLoader<
|
|
|
216
216
|
TAssociatedEntity,
|
|
217
217
|
TAssociatedSelectedFields
|
|
218
218
|
>,
|
|
219
|
-
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
|
|
219
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
220
220
|
>(
|
|
221
221
|
fieldIdentifyingAssociatedEntity: keyof Pick<TFields, TSelectedFields>,
|
|
222
222
|
associatedEntityClass: IEntityClass<
|
|
@@ -232,7 +232,7 @@ export default class EntityAssociationLoader<
|
|
|
232
232
|
.getViewerContext()
|
|
233
233
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
234
234
|
.getQueryContextProvider()
|
|
235
|
-
.getQueryContext()
|
|
235
|
+
.getQueryContext(),
|
|
236
236
|
): Promise<readonly Result<TAssociatedEntity>[]> {
|
|
237
237
|
const associatedFieldValue = this.entity.getField(fieldIdentifyingAssociatedEntity);
|
|
238
238
|
if (!associatedFieldValue) {
|
|
@@ -243,11 +243,10 @@ export default class EntityAssociationLoader<
|
|
|
243
243
|
.getViewerContext()
|
|
244
244
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
245
245
|
.getLoaderFactory()
|
|
246
|
-
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
247
|
-
return await loader
|
|
248
|
-
|
|
249
|
-
associatedFieldValue as any
|
|
250
|
-
);
|
|
246
|
+
.forLoad(queryContext, { previousValue: null, cascadingDeleteCause: null });
|
|
247
|
+
return await loader
|
|
248
|
+
.withAuthorizationResults()
|
|
249
|
+
.loadManyByFieldEqualingAsync(associatedEntityLookupByField, associatedFieldValue as any);
|
|
251
250
|
}
|
|
252
251
|
|
|
253
252
|
/**
|
|
@@ -267,7 +266,7 @@ export default class EntityAssociationLoader<
|
|
|
267
266
|
TEntity2,
|
|
268
267
|
TSelectedFields2
|
|
269
268
|
>,
|
|
270
|
-
TSelectedFields2 extends keyof TFields2 = keyof TFields2
|
|
269
|
+
TSelectedFields2 extends keyof TFields2 = keyof TFields2,
|
|
271
270
|
>(
|
|
272
271
|
loadDirectives: [
|
|
273
272
|
EntityLoadThroughDirective<
|
|
@@ -279,9 +278,9 @@ export default class EntityAssociationLoader<
|
|
|
279
278
|
TPrivacyPolicy2,
|
|
280
279
|
TSelectedFields,
|
|
281
280
|
TSelectedFields2
|
|
282
|
-
|
|
281
|
+
>,
|
|
283
282
|
],
|
|
284
|
-
queryContext?: EntityQueryContext
|
|
283
|
+
queryContext?: EntityQueryContext,
|
|
285
284
|
): Promise<Result<TEntity2> | null>;
|
|
286
285
|
|
|
287
286
|
/**
|
|
@@ -312,7 +311,7 @@ export default class EntityAssociationLoader<
|
|
|
312
311
|
TSelectedFields3
|
|
313
312
|
>,
|
|
314
313
|
TSelectedFields2 extends keyof TFields2 = keyof TFields2,
|
|
315
|
-
TSelectedFields3 extends keyof TFields3 = keyof TFields3
|
|
314
|
+
TSelectedFields3 extends keyof TFields3 = keyof TFields3,
|
|
316
315
|
>(
|
|
317
316
|
loadDirectives: [
|
|
318
317
|
EntityLoadThroughDirective<
|
|
@@ -334,9 +333,9 @@ export default class EntityAssociationLoader<
|
|
|
334
333
|
TPrivacyPolicy3,
|
|
335
334
|
TSelectedFields2,
|
|
336
335
|
TSelectedFields3
|
|
337
|
-
|
|
336
|
+
>,
|
|
338
337
|
],
|
|
339
|
-
queryContext?: EntityQueryContext
|
|
338
|
+
queryContext?: EntityQueryContext,
|
|
340
339
|
): Promise<Result<TEntity3> | null>;
|
|
341
340
|
|
|
342
341
|
/**
|
|
@@ -378,9 +377,9 @@ export default class EntityAssociationLoader<
|
|
|
378
377
|
>,
|
|
379
378
|
TSelectedFields2 extends keyof TFields2 = keyof TFields2,
|
|
380
379
|
TSelectedFields3 extends keyof TFields3 = keyof TFields3,
|
|
381
|
-
TSelectedFields4 extends keyof TFields4 = keyof TFields4
|
|
380
|
+
TSelectedFields4 extends keyof TFields4 = keyof TFields4,
|
|
382
381
|
>(
|
|
383
|
-
|
|
382
|
+
loadDirectives: [
|
|
384
383
|
EntityLoadThroughDirective<
|
|
385
384
|
TViewerContext,
|
|
386
385
|
TFields,
|
|
@@ -410,9 +409,9 @@ export default class EntityAssociationLoader<
|
|
|
410
409
|
TPrivacyPolicy4,
|
|
411
410
|
TSelectedFields3,
|
|
412
411
|
TSelectedFields4
|
|
413
|
-
|
|
412
|
+
>,
|
|
414
413
|
],
|
|
415
|
-
queryContext?: EntityQueryContext
|
|
414
|
+
queryContext?: EntityQueryContext,
|
|
416
415
|
): Promise<Result<TEntity4> | null>;
|
|
417
416
|
|
|
418
417
|
/**
|
|
@@ -423,12 +422,12 @@ export default class EntityAssociationLoader<
|
|
|
423
422
|
*/
|
|
424
423
|
async loadAssociatedEntityThroughAsync(
|
|
425
424
|
loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
|
|
426
|
-
queryContext?: EntityQueryContext
|
|
425
|
+
queryContext?: EntityQueryContext,
|
|
427
426
|
): Promise<Result<ReadonlyEntity<any, any, any, any>> | null>;
|
|
428
427
|
|
|
429
428
|
async loadAssociatedEntityThroughAsync(
|
|
430
429
|
loadDirectives: EntityLoadThroughDirective<TViewerContext, any, any, any, any, any, any, any>[],
|
|
431
|
-
queryContext?: EntityQueryContext
|
|
430
|
+
queryContext?: EntityQueryContext,
|
|
432
431
|
): Promise<Result<ReadonlyEntity<any, any, any, any>> | null> {
|
|
433
432
|
let currentEntity: ReadonlyEntity<any, any, any, any> = this.entity;
|
|
434
433
|
for (const loadDirective of loadDirectives) {
|
|
@@ -445,7 +444,7 @@ export default class EntityAssociationLoader<
|
|
|
445
444
|
fieldIdentifyingAssociatedEntity,
|
|
446
445
|
associatedEntityClass,
|
|
447
446
|
associatedEntityLookupByField,
|
|
448
|
-
queryContext
|
|
447
|
+
queryContext,
|
|
449
448
|
);
|
|
450
449
|
} else {
|
|
451
450
|
const associatedEntityResultLocal = await currentEntity
|
|
@@ -453,7 +452,7 @@ export default class EntityAssociationLoader<
|
|
|
453
452
|
.loadAssociatedEntityAsync(
|
|
454
453
|
fieldIdentifyingAssociatedEntity,
|
|
455
454
|
associatedEntityClass,
|
|
456
|
-
queryContext
|
|
455
|
+
queryContext,
|
|
457
456
|
);
|
|
458
457
|
|
|
459
458
|
if (associatedEntityResultLocal.ok && associatedEntityResultLocal.value === null) {
|
|
@@ -498,7 +497,7 @@ export interface EntityLoadThroughDirective<
|
|
|
498
497
|
TAssociatedSelectedFields
|
|
499
498
|
>,
|
|
500
499
|
TSelectedFields extends keyof TFields = keyof TFields,
|
|
501
|
-
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields
|
|
500
|
+
TAssociatedSelectedFields extends keyof TAssociatedFields = keyof TAssociatedFields,
|
|
502
501
|
> {
|
|
503
502
|
/**
|
|
504
503
|
* Class of entity to load at this step.
|
package/src/EntityCompanion.ts
CHANGED
|
@@ -7,6 +7,7 @@ import ReadonlyEntity from './ReadonlyEntity';
|
|
|
7
7
|
import ViewerContext from './ViewerContext';
|
|
8
8
|
import EntityTableDataCoordinator from './internal/EntityTableDataCoordinator';
|
|
9
9
|
import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
|
|
10
|
+
import { mergeEntityMutationTriggerConfigurations } from './utils/mergeEntityMutationTriggerConfigurations';
|
|
10
11
|
|
|
11
12
|
export interface IPrivacyPolicyClass<TPrivacyPolicy> {
|
|
12
13
|
new (): TPrivacyPolicy;
|
|
@@ -27,7 +28,7 @@ export default class EntityCompanion<
|
|
|
27
28
|
TEntity,
|
|
28
29
|
TSelectedFields
|
|
29
30
|
>,
|
|
30
|
-
TSelectedFields extends keyof TFields
|
|
31
|
+
TSelectedFields extends keyof TFields,
|
|
31
32
|
> {
|
|
32
33
|
public readonly privacyPolicy: TPrivacyPolicy;
|
|
33
34
|
|
|
@@ -59,7 +60,7 @@ export default class EntityCompanion<
|
|
|
59
60
|
TSelectedFields
|
|
60
61
|
>,
|
|
61
62
|
private readonly tableDataCoordinator: EntityTableDataCoordinator<TFields>,
|
|
62
|
-
private readonly metricsAdapter: IEntityMetricsAdapter
|
|
63
|
+
private readonly metricsAdapter: IEntityMetricsAdapter,
|
|
63
64
|
) {
|
|
64
65
|
this.privacyPolicy = new entityCompanionDefinition.privacyPolicyClass();
|
|
65
66
|
this.entityLoaderFactory = new EntityLoaderFactory<
|
|
@@ -76,10 +77,13 @@ export default class EntityCompanion<
|
|
|
76
77
|
entityCompanionDefinition.entityClass,
|
|
77
78
|
this.privacyPolicy,
|
|
78
79
|
entityCompanionDefinition.mutationValidators ?? [],
|
|
79
|
-
|
|
80
|
+
mergeEntityMutationTriggerConfigurations(
|
|
81
|
+
entityCompanionDefinition.mutationTriggers ?? {},
|
|
82
|
+
entityCompanionProvider.globalMutationTriggers ?? {},
|
|
83
|
+
),
|
|
80
84
|
this.entityLoaderFactory,
|
|
81
85
|
tableDataCoordinator.databaseAdapter,
|
|
82
|
-
metricsAdapter
|
|
86
|
+
metricsAdapter,
|
|
83
87
|
);
|
|
84
88
|
}
|
|
85
89
|
|
|
@@ -61,7 +61,7 @@ export interface EntityCompanionDefinition<
|
|
|
61
61
|
TEntity,
|
|
62
62
|
TSelectedFields
|
|
63
63
|
>,
|
|
64
|
-
TSelectedFields extends keyof TFields = keyof TFields
|
|
64
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
65
65
|
> {
|
|
66
66
|
/**
|
|
67
67
|
* The concrete Entity class for which this is the definition.
|
|
@@ -139,6 +139,7 @@ export default class EntityCompanionProvider {
|
|
|
139
139
|
* @param metricsAdapter - An IEntityMetricsAdapter for collecting metrics on this instance
|
|
140
140
|
* @param databaseAdapterFlavors - Database adapter configurations for this instance
|
|
141
141
|
* @param cacheAdapterFlavors - Cache adapter configurations for this instance
|
|
142
|
+
* @param globalMutationTriggers - Optional set of EntityMutationTrigger to run for all entity mutations systemwide.
|
|
142
143
|
*/
|
|
143
144
|
constructor(
|
|
144
145
|
public readonly metricsAdapter: IEntityMetricsAdapter,
|
|
@@ -146,7 +147,14 @@ export default class EntityCompanionProvider {
|
|
|
146
147
|
DatabaseAdapterFlavor,
|
|
147
148
|
DatabaseAdapterFlavorDefinition
|
|
148
149
|
>,
|
|
149
|
-
private cacheAdapterFlavors: ReadonlyMap<CacheAdapterFlavor, CacheAdapterFlavorDefinition
|
|
150
|
+
private cacheAdapterFlavors: ReadonlyMap<CacheAdapterFlavor, CacheAdapterFlavorDefinition>,
|
|
151
|
+
readonly globalMutationTriggers: EntityMutationTriggerConfiguration<
|
|
152
|
+
any,
|
|
153
|
+
any,
|
|
154
|
+
any,
|
|
155
|
+
any,
|
|
156
|
+
any
|
|
157
|
+
> = {},
|
|
150
158
|
) {}
|
|
151
159
|
|
|
152
160
|
/**
|
|
@@ -167,7 +175,7 @@ export default class EntityCompanionProvider {
|
|
|
167
175
|
TEntity,
|
|
168
176
|
TSelectedFields
|
|
169
177
|
>,
|
|
170
|
-
TSelectedFields extends keyof TFields
|
|
178
|
+
TSelectedFields extends keyof TFields,
|
|
171
179
|
>(
|
|
172
180
|
entityClass: IEntityClass<
|
|
173
181
|
TFields,
|
|
@@ -176,58 +184,58 @@ export default class EntityCompanionProvider {
|
|
|
176
184
|
TEntity,
|
|
177
185
|
TPrivacyPolicy,
|
|
178
186
|
TSelectedFields
|
|
179
|
-
|
|
187
|
+
>,
|
|
180
188
|
): EntityCompanion<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
|
|
181
189
|
const entityCompanionDefinition = computeIfAbsent(
|
|
182
190
|
this.companionDefinitionMap,
|
|
183
191
|
entityClass.name,
|
|
184
|
-
() => entityClass.defineCompanionDefinition()
|
|
192
|
+
() => entityClass.defineCompanionDefinition(),
|
|
185
193
|
);
|
|
186
194
|
const tableDataCoordinator = this.getTableDataCoordinatorForEntity(
|
|
187
195
|
entityCompanionDefinition.entityConfiguration,
|
|
188
|
-
entityClass.name
|
|
196
|
+
entityClass.name,
|
|
189
197
|
);
|
|
190
198
|
return computeIfAbsent(this.companionMap, entityClass.name, () => {
|
|
191
199
|
return new EntityCompanion(
|
|
192
200
|
this,
|
|
193
201
|
entityCompanionDefinition,
|
|
194
202
|
tableDataCoordinator,
|
|
195
|
-
this.metricsAdapter
|
|
203
|
+
this.metricsAdapter,
|
|
196
204
|
);
|
|
197
205
|
});
|
|
198
206
|
}
|
|
199
207
|
|
|
200
208
|
getQueryContextProviderForDatabaseAdaptorFlavor(
|
|
201
|
-
databaseAdapterFlavor: DatabaseAdapterFlavor
|
|
209
|
+
databaseAdapterFlavor: DatabaseAdapterFlavor,
|
|
202
210
|
): EntityQueryContextProvider {
|
|
203
211
|
const entityDatabaseAdapterFlavor = this.databaseAdapterFlavors.get(databaseAdapterFlavor);
|
|
204
212
|
invariant(
|
|
205
213
|
entityDatabaseAdapterFlavor,
|
|
206
|
-
`No database adaptor configuration found for flavor: ${databaseAdapterFlavor}
|
|
214
|
+
`No database adaptor configuration found for flavor: ${databaseAdapterFlavor}`,
|
|
207
215
|
);
|
|
208
216
|
|
|
209
217
|
return entityDatabaseAdapterFlavor.queryContextProvider;
|
|
210
218
|
}
|
|
211
219
|
|
|
212
|
-
private getTableDataCoordinatorForEntity<TFields
|
|
220
|
+
private getTableDataCoordinatorForEntity<TFields extends Record<string, any>>(
|
|
213
221
|
entityConfiguration: EntityConfiguration<TFields>,
|
|
214
|
-
entityClassName: string
|
|
222
|
+
entityClassName: string,
|
|
215
223
|
): EntityTableDataCoordinator<TFields> {
|
|
216
224
|
return computeIfAbsent(this.tableDataCoordinatorMap, entityConfiguration.tableName, () => {
|
|
217
225
|
const entityDatabaseAdapterFlavor = this.databaseAdapterFlavors.get(
|
|
218
|
-
entityConfiguration.databaseAdapterFlavor
|
|
226
|
+
entityConfiguration.databaseAdapterFlavor,
|
|
219
227
|
);
|
|
220
228
|
invariant(
|
|
221
229
|
entityDatabaseAdapterFlavor,
|
|
222
|
-
`No database adaptor configuration found for flavor: ${entityConfiguration.databaseAdapterFlavor}
|
|
230
|
+
`No database adaptor configuration found for flavor: ${entityConfiguration.databaseAdapterFlavor}`,
|
|
223
231
|
);
|
|
224
232
|
|
|
225
233
|
const entityCacheAdapterFlavor = this.cacheAdapterFlavors.get(
|
|
226
|
-
entityConfiguration.cacheAdapterFlavor
|
|
234
|
+
entityConfiguration.cacheAdapterFlavor,
|
|
227
235
|
);
|
|
228
236
|
invariant(
|
|
229
237
|
entityCacheAdapterFlavor,
|
|
230
|
-
`No cache adaptor configuration found for flavor: ${entityConfiguration.cacheAdapterFlavor}
|
|
238
|
+
`No cache adaptor configuration found for flavor: ${entityConfiguration.cacheAdapterFlavor}`,
|
|
231
239
|
);
|
|
232
240
|
|
|
233
241
|
return new EntityTableDataCoordinator(
|
|
@@ -236,7 +244,7 @@ export default class EntityCompanionProvider {
|
|
|
236
244
|
entityCacheAdapterFlavor.cacheAdapterProvider,
|
|
237
245
|
entityDatabaseAdapterFlavor.queryContextProvider,
|
|
238
246
|
this.metricsAdapter,
|
|
239
|
-
entityClassName
|
|
247
|
+
entityClassName,
|
|
240
248
|
);
|
|
241
249
|
});
|
|
242
250
|
}
|
|
@@ -7,7 +7,7 @@ import { mapMap, invertMap, reduceMap } from './utils/collections/maps';
|
|
|
7
7
|
* The data storage configuration for a type of Entity. Contains information relating to IDs,
|
|
8
8
|
* cachable fields, field mappings, and types of cache and database adapter.
|
|
9
9
|
*/
|
|
10
|
-
export default class EntityConfiguration<TFields
|
|
10
|
+
export default class EntityConfiguration<TFields extends Record<string, any>> {
|
|
11
11
|
readonly idField: keyof TFields;
|
|
12
12
|
readonly tableName: string;
|
|
13
13
|
readonly cacheableKeys: ReadonlySet<keyof TFields>;
|
|
@@ -75,18 +75,29 @@ export default class EntityConfiguration<TFields> {
|
|
|
75
75
|
|
|
76
76
|
// external schema is a Record to typecheck that all fields have FieldDefinitions,
|
|
77
77
|
// but internally the most useful representation is a map for lookups
|
|
78
|
-
|
|
79
|
-
this.schema = new Map(Object.entries(schema)
|
|
78
|
+
EntityConfiguration.validateSchema(schema);
|
|
79
|
+
this.schema = new Map(Object.entries(schema));
|
|
80
80
|
|
|
81
81
|
this.cacheableKeys = EntityConfiguration.computeCacheableKeys(this.schema);
|
|
82
82
|
this.entityToDBFieldsKeyMapping = EntityConfiguration.computeEntityToDBFieldsKeyMapping(
|
|
83
|
-
this.schema
|
|
83
|
+
this.schema,
|
|
84
84
|
);
|
|
85
85
|
this.dbToEntityFieldsKeyMapping = invertMap(this.entityToDBFieldsKeyMapping);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
private static validateSchema<TFields extends Record<string, any>>(schema: TFields): void {
|
|
89
|
+
const disallowedFieldsKeys = Object.getOwnPropertyNames(Object.prototype);
|
|
90
|
+
for (const disallowedFieldsKey of disallowedFieldsKeys) {
|
|
91
|
+
if (Object.hasOwn(schema, disallowedFieldsKey)) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Entity field name not allowed to prevent conflicts with standard Object prototype fields: ${disallowedFieldsKey}`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
88
99
|
private static computeCacheableKeys<TFields>(
|
|
89
|
-
schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any
|
|
100
|
+
schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any>>,
|
|
90
101
|
): ReadonlySet<keyof TFields> {
|
|
91
102
|
return reduceMap(
|
|
92
103
|
schema,
|
|
@@ -96,12 +107,12 @@ export default class EntityConfiguration<TFields> {
|
|
|
96
107
|
}
|
|
97
108
|
return acc;
|
|
98
109
|
},
|
|
99
|
-
new Set<keyof TFields>()
|
|
110
|
+
new Set<keyof TFields>(),
|
|
100
111
|
);
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
private static computeEntityToDBFieldsKeyMapping<TFields>(
|
|
104
|
-
schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any
|
|
115
|
+
schema: ReadonlyMap<keyof TFields, EntityFieldDefinition<any>>,
|
|
105
116
|
): ReadonlyMap<keyof TFields, string> {
|
|
106
117
|
return mapMap(schema, (v) => v.columnName);
|
|
107
118
|
}
|