@expo/entity 0.34.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 +4 -31
- package/build/Entity.js +19 -46
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.d.ts +9 -9
- package/build/EntityAssociationLoader.js +37 -12
- 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/EntityQueryContextProvider.d.ts +1 -1
- package/build/EntityQueryContextProvider.js +1 -1
- package/build/EntityQueryContextProvider.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.d.ts +1 -1
- package/build/ReadonlyEntity.js +9 -2
- package/build/ReadonlyEntity.js.map +1 -1
- package/build/ViewerContext.d.ts +2 -2
- package/build/ViewerContext.js +5 -3
- 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 +5 -137
- package/build/__tests__/Entity-test.js.map +1 -1
- package/build/__tests__/EntityAssociationLoader-test.js +37 -65
- package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js +31 -37
- 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 +89 -80
- 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 +17 -18
- package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
- package/build/__tests__/EntityLoader-test.js +93 -41
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +18 -21
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
- package/build/__tests__/EntityMutator-test.js +74 -29
- 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__/EntitySecondaryCacheLoader-test.js +10 -10
- package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
- package/build/__tests__/EntitySelfReferentialEdges-test.js +59 -74
- package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
- package/build/__tests__/ReadonlyEntity-test.js +13 -13
- package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
- package/build/__tests__/ViewerContext-test.js +2 -2
- package/build/__tests__/ViewerContext-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +26 -28
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +25 -30
- 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 +7 -2
- 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__/EntityDataManager-test.js +11 -11
- package/build/internal/__tests__/EntityDataManager-test.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.d.ts +8 -8
- package/build/testfixtures/SimpleTestEntity.js +12 -15
- package/build/testfixtures/SimpleTestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity.d.ts +12 -12
- package/build/testfixtures/TestEntity.js +12 -15
- package/build/testfixtures/TestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity2.d.ts +8 -8
- 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/testfixtures/TestViewerContext.d.ts +0 -3
- package/build/testfixtures/TestViewerContext.js +0 -6
- package/build/testfixtures/TestViewerContext.js.map +1 -1
- 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 +26 -118
- package/src/EntityAssociationLoader.ts +56 -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 +6 -6
- 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 +8 -5
- package/src/ViewerContext.ts +10 -10
- 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 +5 -223
- package/src/__tests__/EntityAssociationLoader-test.ts +91 -169
- package/src/__tests__/EntityCommonUseCases-test.ts +36 -38
- 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 +128 -118
- package/src/__tests__/EntityFields-test.ts +14 -2
- package/src/__tests__/EntityLoader-constructor-test.ts +21 -8
- package/src/__tests__/EntityLoader-test.ts +233 -105
- package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +17 -20
- package/src/__tests__/EntityMutator-test.ts +342 -163
- package/src/__tests__/EntityPrivacyPolicy-test.ts +166 -53
- package/src/__tests__/EntityQueryContext-test.ts +30 -12
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +17 -26
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +67 -115
- package/src/__tests__/GenericEntityCacheAdapter-test.ts +2 -2
- package/src/__tests__/ReadonlyEntity-test.ts +13 -15
- package/src/__tests__/ViewerContext-test.ts +3 -4
- 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 +34 -45
- package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +22 -30
- 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 +25 -25
- 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 +62 -62
- 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/SimpleTestEntity.ts +8 -8
- package/src/testfixtures/TestEntity.ts +13 -16
- package/src/testfixtures/TestEntity2.ts +8 -8
- package/src/testfixtures/TestEntityWithMutationTriggers.ts +156 -0
- package/src/testfixtures/TestViewerContext.ts +1 -12
- 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,297 @@
|
|
|
1
|
+
import { Result, result } from '@expo/results';
|
|
2
|
+
import invariant from 'invariant';
|
|
3
|
+
import nullthrows from 'nullthrows';
|
|
4
|
+
|
|
5
|
+
import { IEntityClass } from './Entity';
|
|
6
|
+
import EntityConfiguration from './EntityConfiguration';
|
|
7
|
+
import {
|
|
8
|
+
FieldEqualityCondition,
|
|
9
|
+
QuerySelectionModifiers,
|
|
10
|
+
isSingleValueFieldEqualityCondition,
|
|
11
|
+
QuerySelectionModifiersWithOrderByRaw,
|
|
12
|
+
} from './EntityDatabaseAdapter';
|
|
13
|
+
import EntityLoaderUtils from './EntityLoaderUtils';
|
|
14
|
+
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
15
|
+
import { EntityQueryContext } from './EntityQueryContext';
|
|
16
|
+
import ReadonlyEntity from './ReadonlyEntity';
|
|
17
|
+
import ViewerContext from './ViewerContext';
|
|
18
|
+
import EntityInvalidFieldValueError from './errors/EntityInvalidFieldValueError';
|
|
19
|
+
import EntityNotFoundError from './errors/EntityNotFoundError';
|
|
20
|
+
import EntityDataManager from './internal/EntityDataManager';
|
|
21
|
+
import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
|
|
22
|
+
import { mapMap } from './utils/collections/maps';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Authorization-result-based entity loader. All normal loads are batched,
|
|
26
|
+
* cached, and authorized against the entity's EntityPrivacyPolicy. All loads through this
|
|
27
|
+
* loader are are results (or null for some loader methods), where an unsuccessful result
|
|
28
|
+
* means an authorization error or entity construction error occurred. Other errors are thrown.
|
|
29
|
+
*/
|
|
30
|
+
export default class AuthorizationResultBasedEntityLoader<
|
|
31
|
+
TFields extends object,
|
|
32
|
+
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
33
|
+
TViewerContext extends ViewerContext,
|
|
34
|
+
TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
35
|
+
TPrivacyPolicy extends EntityPrivacyPolicy<
|
|
36
|
+
TFields,
|
|
37
|
+
TID,
|
|
38
|
+
TViewerContext,
|
|
39
|
+
TEntity,
|
|
40
|
+
TSelectedFields
|
|
41
|
+
>,
|
|
42
|
+
TSelectedFields extends keyof TFields,
|
|
43
|
+
> {
|
|
44
|
+
constructor(
|
|
45
|
+
private readonly queryContext: EntityQueryContext,
|
|
46
|
+
private readonly entityConfiguration: EntityConfiguration<TFields>,
|
|
47
|
+
private readonly entityClass: IEntityClass<
|
|
48
|
+
TFields,
|
|
49
|
+
TID,
|
|
50
|
+
TViewerContext,
|
|
51
|
+
TEntity,
|
|
52
|
+
TPrivacyPolicy,
|
|
53
|
+
TSelectedFields
|
|
54
|
+
>,
|
|
55
|
+
private readonly dataManager: EntityDataManager<TFields>,
|
|
56
|
+
protected readonly metricsAdapter: IEntityMetricsAdapter,
|
|
57
|
+
private readonly utils: EntityLoaderUtils<
|
|
58
|
+
TFields,
|
|
59
|
+
TID,
|
|
60
|
+
TViewerContext,
|
|
61
|
+
TEntity,
|
|
62
|
+
TPrivacyPolicy,
|
|
63
|
+
TSelectedFields
|
|
64
|
+
>,
|
|
65
|
+
) {}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Load many entities where fieldName is one of fieldValues.
|
|
69
|
+
* @param fieldName - entity field being queried
|
|
70
|
+
* @param fieldValues - fieldName field values being queried
|
|
71
|
+
* @returns map from fieldValue to entity results that match the query for that fieldValue,
|
|
72
|
+
* where result errors can be UnauthorizedError
|
|
73
|
+
*/
|
|
74
|
+
async loadManyByFieldEqualingManyAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
75
|
+
fieldName: N,
|
|
76
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
77
|
+
): Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Result<TEntity>[]>> {
|
|
78
|
+
this.validateFieldValues(fieldName, fieldValues);
|
|
79
|
+
|
|
80
|
+
const fieldValuesToFieldObjects = await this.dataManager.loadManyByFieldEqualingAsync(
|
|
81
|
+
this.queryContext,
|
|
82
|
+
fieldName,
|
|
83
|
+
fieldValues,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return await this.utils.constructAndAuthorizeEntitiesAsync(fieldValuesToFieldObjects);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Load many entities where fieldName equals fieldValue.
|
|
91
|
+
* @param fieldName - entity field being queried
|
|
92
|
+
* @param fieldValue - fieldName field value being queried
|
|
93
|
+
* @returns array of entity results that match the query for fieldValue, where result error can be UnauthorizedError
|
|
94
|
+
*/
|
|
95
|
+
async loadManyByFieldEqualingAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
96
|
+
fieldName: N,
|
|
97
|
+
fieldValue: NonNullable<TFields[N]>,
|
|
98
|
+
): Promise<readonly Result<TEntity>[]> {
|
|
99
|
+
const entityResults = await this.loadManyByFieldEqualingManyAsync(fieldName, [fieldValue]);
|
|
100
|
+
const entityResultsForFieldValue = entityResults.get(fieldValue);
|
|
101
|
+
invariant(
|
|
102
|
+
entityResultsForFieldValue !== undefined,
|
|
103
|
+
`${fieldValue} should be guaranteed to be present in returned map of entities`,
|
|
104
|
+
);
|
|
105
|
+
return entityResultsForFieldValue!;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Load an entity where fieldName equals fieldValue, or null if no entity exists.
|
|
110
|
+
* @param uniqueFieldName - entity field being queried
|
|
111
|
+
* @param fieldValue - uniqueFieldName field value being queried
|
|
112
|
+
* @returns entity result where uniqueFieldName equals fieldValue, or null if no entity matches the condition.
|
|
113
|
+
* @throws when multiple entities match the condition
|
|
114
|
+
*/
|
|
115
|
+
async loadByFieldEqualingAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
116
|
+
uniqueFieldName: N,
|
|
117
|
+
fieldValue: NonNullable<TFields[N]>,
|
|
118
|
+
): Promise<Result<TEntity> | null> {
|
|
119
|
+
const entityResults = await this.loadManyByFieldEqualingAsync(uniqueFieldName, fieldValue);
|
|
120
|
+
invariant(
|
|
121
|
+
entityResults.length <= 1,
|
|
122
|
+
`loadByFieldEqualing: Multiple entities of type ${this.entityClass.name} found for ${String(
|
|
123
|
+
uniqueFieldName,
|
|
124
|
+
)}=${fieldValue}`,
|
|
125
|
+
);
|
|
126
|
+
return entityResults[0] ?? null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Loads an entity by a specified ID.
|
|
131
|
+
* @param id - ID of the entity
|
|
132
|
+
* @returns entity result for matching ID, where result error can be UnauthorizedError or EntityNotFoundError.
|
|
133
|
+
*/
|
|
134
|
+
async loadByIDAsync(id: TID): Promise<Result<TEntity>> {
|
|
135
|
+
const entityResults = await this.loadManyByIDsAsync([id]);
|
|
136
|
+
// loadManyByIDsAsync is always populated for each id supplied
|
|
137
|
+
return nullthrows(entityResults.get(id));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Load an entity by a specified ID, or return null if non-existent.
|
|
142
|
+
* @param id - ID of the entity
|
|
143
|
+
* @returns entity result for matching ID, or null if no entity exists for ID.
|
|
144
|
+
*/
|
|
145
|
+
async loadByIDNullableAsync(id: TID): Promise<Result<TEntity> | null> {
|
|
146
|
+
return await this.loadByFieldEqualingAsync(
|
|
147
|
+
this.entityConfiguration.idField as TSelectedFields,
|
|
148
|
+
id,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Loads many entities for a list of IDs.
|
|
154
|
+
* @param ids - IDs of the entities to load
|
|
155
|
+
* @returns map from ID to corresponding entity result, where result error can be UnauthorizedError or EntityNotFoundError.
|
|
156
|
+
*/
|
|
157
|
+
async loadManyByIDsAsync(ids: readonly TID[]): Promise<ReadonlyMap<TID, Result<TEntity>>> {
|
|
158
|
+
const entityResults = (await this.loadManyByFieldEqualingManyAsync(
|
|
159
|
+
this.entityConfiguration.idField as TSelectedFields,
|
|
160
|
+
ids,
|
|
161
|
+
)) as ReadonlyMap<TID, readonly Result<TEntity>[]>;
|
|
162
|
+
return mapMap(entityResults, (entityResultsForId, id) => {
|
|
163
|
+
const entityResult = entityResultsForId[0];
|
|
164
|
+
return (
|
|
165
|
+
entityResult ??
|
|
166
|
+
result(new EntityNotFoundError(this.entityClass, this.entityConfiguration.idField, id))
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Loads many entities for a list of IDs, returning null for any IDs that are non-existent.
|
|
173
|
+
* @param ids - IDs of the entities to load
|
|
174
|
+
* @returns map from ID to nullable corresponding entity result, where result error can be UnauthorizedError or EntityNotFoundError.
|
|
175
|
+
*/
|
|
176
|
+
async loadManyByIDsNullableAsync(
|
|
177
|
+
ids: readonly TID[],
|
|
178
|
+
): Promise<ReadonlyMap<TID, Result<TEntity> | null>> {
|
|
179
|
+
const entityResults = (await this.loadManyByFieldEqualingManyAsync(
|
|
180
|
+
this.entityConfiguration.idField as TSelectedFields,
|
|
181
|
+
ids,
|
|
182
|
+
)) as ReadonlyMap<TID, readonly Result<TEntity>[]>;
|
|
183
|
+
return mapMap(entityResults, (entityResultsForId) => {
|
|
184
|
+
return entityResultsForId[0] ?? null;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Loads the first entity matching the selection constructed from the conjunction of specified
|
|
190
|
+
* operands, or null if no matching entity exists. Entities loaded using this method are not
|
|
191
|
+
* batched or cached.
|
|
192
|
+
*
|
|
193
|
+
* This is a convenience method for {@link loadManyByFieldEqualityConjunctionAsync}. However, the
|
|
194
|
+
* `orderBy` option must be specified to define what "first" means. If ordering doesn't matter,
|
|
195
|
+
* explicitly pass in an empty array.
|
|
196
|
+
*
|
|
197
|
+
* @param fieldEqualityOperands - list of field equality selection operand specifications
|
|
198
|
+
* @param querySelectionModifiers - orderBy and optional offset for the query
|
|
199
|
+
* @returns the first entity results that matches the query, where result error can be
|
|
200
|
+
* UnauthorizedError
|
|
201
|
+
*/
|
|
202
|
+
async loadFirstByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
203
|
+
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
|
|
204
|
+
querySelectionModifiers: Omit<QuerySelectionModifiers<TFields>, 'limit'> &
|
|
205
|
+
Required<Pick<QuerySelectionModifiers<TFields>, 'orderBy'>>,
|
|
206
|
+
): Promise<Result<TEntity> | null> {
|
|
207
|
+
const results = await this.loadManyByFieldEqualityConjunctionAsync(fieldEqualityOperands, {
|
|
208
|
+
...querySelectionModifiers,
|
|
209
|
+
limit: 1,
|
|
210
|
+
});
|
|
211
|
+
return results[0] ?? null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Loads many entities matching the selection constructed from the conjunction of specified operands.
|
|
216
|
+
* Entities loaded using this method are not batched or cached.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* fieldEqualityOperands:
|
|
220
|
+
* `[{fieldName: 'hello', fieldValue: 1}, {fieldName: 'world', fieldValues: [2, 3]}]`
|
|
221
|
+
* Entities returned with a SQL EntityDatabaseAdapter:
|
|
222
|
+
* `WHERE hello = 1 AND world = ANY({2, 3})`
|
|
223
|
+
*
|
|
224
|
+
* @param fieldEqualityOperands - list of field equality selection operand specifications
|
|
225
|
+
* @param querySelectionModifiers - limit, offset, and orderBy for the query
|
|
226
|
+
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
227
|
+
*/
|
|
228
|
+
async loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
229
|
+
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
|
|
230
|
+
querySelectionModifiers: QuerySelectionModifiers<TFields> = {},
|
|
231
|
+
): Promise<readonly Result<TEntity>[]> {
|
|
232
|
+
for (const fieldEqualityOperand of fieldEqualityOperands) {
|
|
233
|
+
const fieldValues = isSingleValueFieldEqualityCondition(fieldEqualityOperand)
|
|
234
|
+
? [fieldEqualityOperand.fieldValue]
|
|
235
|
+
: fieldEqualityOperand.fieldValues;
|
|
236
|
+
this.validateFieldValues(fieldEqualityOperand.fieldName, fieldValues);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const fieldObjects = await this.dataManager.loadManyByFieldEqualityConjunctionAsync(
|
|
240
|
+
this.queryContext,
|
|
241
|
+
fieldEqualityOperands,
|
|
242
|
+
querySelectionModifiers,
|
|
243
|
+
);
|
|
244
|
+
return await this.utils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Loads many entities matching the raw WHERE clause. Corresponds to the knex `whereRaw` argument format.
|
|
249
|
+
*
|
|
250
|
+
* @remarks
|
|
251
|
+
* Important notes:
|
|
252
|
+
* - Fields in clause are database column names instead of transformed entity field names.
|
|
253
|
+
* - Entities loaded using this method are not batched or cached.
|
|
254
|
+
* - Not all database adapters implement the ability to execute this method of fetching entities.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* rawWhereClause: `id = ?`
|
|
258
|
+
* bindings: `[1]`
|
|
259
|
+
* Entites returned `WHERE id = 1`
|
|
260
|
+
*
|
|
261
|
+
* http://knexjs.org/#Builder-whereRaw
|
|
262
|
+
* http://knexjs.org/#Raw-Bindings
|
|
263
|
+
*
|
|
264
|
+
* @param rawWhereClause - parameterized SQL WHERE clause with positional binding placeholders or named binding placeholders
|
|
265
|
+
* @param bindings - array of positional bindings or object of named bindings
|
|
266
|
+
* @param querySelectionModifiers - limit, offset, orderBy, and orderByRaw for the query
|
|
267
|
+
* @returns array of entity results that match the query, where result error can be UnauthorizedError
|
|
268
|
+
* @throws Error when rawWhereClause or bindings are invalid
|
|
269
|
+
*/
|
|
270
|
+
async loadManyByRawWhereClauseAsync(
|
|
271
|
+
rawWhereClause: string,
|
|
272
|
+
bindings: any[] | object,
|
|
273
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {},
|
|
274
|
+
): Promise<readonly Result<TEntity>[]> {
|
|
275
|
+
const fieldObjects = await this.dataManager.loadManyByRawWhereClauseAsync(
|
|
276
|
+
this.queryContext,
|
|
277
|
+
rawWhereClause,
|
|
278
|
+
bindings,
|
|
279
|
+
querySelectionModifiers,
|
|
280
|
+
);
|
|
281
|
+
return await this.utils.constructAndAuthorizeEntitiesArrayAsync(fieldObjects);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private validateFieldValues<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
285
|
+
fieldName: N,
|
|
286
|
+
fieldValues: readonly TFields[N][],
|
|
287
|
+
): void {
|
|
288
|
+
const fieldDefinition = this.entityConfiguration.schema.get(fieldName);
|
|
289
|
+
invariant(fieldDefinition, `must have field definition for field = ${String(fieldName)}`);
|
|
290
|
+
for (const fieldValue of fieldValues) {
|
|
291
|
+
const isInputValid = fieldDefinition.validateInputValue(fieldValue);
|
|
292
|
+
if (!isInputValid) {
|
|
293
|
+
throw new EntityInvalidFieldValueError(this.entityClass, fieldName, fieldValue);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
@@ -17,12 +17,12 @@ export default class ComposedEntityCacheAdapter<TFields> implements IEntityCache
|
|
|
17
17
|
|
|
18
18
|
public async loadManyAsync<N extends keyof TFields>(
|
|
19
19
|
fieldName: N,
|
|
20
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
20
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
21
21
|
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>> {
|
|
22
22
|
const retMap = new Map<NonNullable<TFields[N]>, CacheLoadResult<TFields>>();
|
|
23
23
|
const fulfilledFieldValuesByCacheIndex: NonNullable<TFields[N]>[][] = Array.from(
|
|
24
24
|
{ length: this.cacheAdapters.length },
|
|
25
|
-
() => []
|
|
25
|
+
() => [],
|
|
26
26
|
);
|
|
27
27
|
|
|
28
28
|
let unfulfilledFieldValues = fieldValues;
|
|
@@ -30,7 +30,7 @@ export default class ComposedEntityCacheAdapter<TFields> implements IEntityCache
|
|
|
30
30
|
const cacheAdapter = nullthrows(this.cacheAdapters[i]);
|
|
31
31
|
const cacheResultsFromAdapter = await cacheAdapter.loadManyAsync(
|
|
32
32
|
fieldName,
|
|
33
|
-
unfulfilledFieldValues
|
|
33
|
+
unfulfilledFieldValues,
|
|
34
34
|
);
|
|
35
35
|
|
|
36
36
|
const newUnfulfilledFieldValues = [];
|
|
@@ -87,7 +87,7 @@ export default class ComposedEntityCacheAdapter<TFields> implements IEntityCache
|
|
|
87
87
|
|
|
88
88
|
public async cacheManyAsync<N extends keyof TFields>(
|
|
89
89
|
fieldName: N,
|
|
90
|
-
objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields
|
|
90
|
+
objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>,
|
|
91
91
|
): Promise<void> {
|
|
92
92
|
// write to lower layers first
|
|
93
93
|
for (let i = this.cacheAdapters.length - 1; i >= 0; i--) {
|
|
@@ -98,7 +98,7 @@ export default class ComposedEntityCacheAdapter<TFields> implements IEntityCache
|
|
|
98
98
|
|
|
99
99
|
public async cacheDBMissesAsync<N extends keyof TFields>(
|
|
100
100
|
fieldName: N,
|
|
101
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
101
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
102
102
|
): Promise<void> {
|
|
103
103
|
// write to lower layers first
|
|
104
104
|
for (let i = this.cacheAdapters.length - 1; i >= 0; i--) {
|
|
@@ -109,7 +109,7 @@ export default class ComposedEntityCacheAdapter<TFields> implements IEntityCache
|
|
|
109
109
|
|
|
110
110
|
public async invalidateManyAsync<N extends keyof TFields>(
|
|
111
111
|
fieldName: N,
|
|
112
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
112
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
113
113
|
): Promise<void> {
|
|
114
114
|
// delete from lower layers first
|
|
115
115
|
for (let i = this.cacheAdapters.length - 1; i >= 0; i--) {
|
|
@@ -14,19 +14,19 @@ export default class ComposedSecondaryEntityCache<TLoadParams, TFields>
|
|
|
14
14
|
* Typically, caches closer to the application should be ordered before caches closer to the database.
|
|
15
15
|
*/
|
|
16
16
|
constructor(
|
|
17
|
-
private readonly secondaryEntityCaches: ISecondaryEntityCache<TFields, TLoadParams>[]
|
|
17
|
+
private readonly secondaryEntityCaches: ISecondaryEntityCache<TFields, TLoadParams>[],
|
|
18
18
|
) {}
|
|
19
19
|
|
|
20
20
|
async loadManyThroughAsync(
|
|
21
21
|
loadParamsArray: readonly Readonly<TLoadParams>[],
|
|
22
22
|
fetcher: (
|
|
23
|
-
fetcherLoadParamsArray: readonly Readonly<TLoadParams>[]
|
|
24
|
-
) => Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null
|
|
23
|
+
fetcherLoadParamsArray: readonly Readonly<TLoadParams>[],
|
|
24
|
+
) => Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>>,
|
|
25
25
|
): Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>> {
|
|
26
26
|
return await ComposedSecondaryEntityCache.loadManyThroughRecursivelyAsync(
|
|
27
27
|
this.secondaryEntityCaches,
|
|
28
28
|
loadParamsArray,
|
|
29
|
-
fetcher
|
|
29
|
+
fetcher,
|
|
30
30
|
);
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -34,8 +34,8 @@ export default class ComposedSecondaryEntityCache<TLoadParams, TFields>
|
|
|
34
34
|
secondaryEntityCaches: ISecondaryEntityCache<TFields, TLoadParams>[],
|
|
35
35
|
loadParamsArray: readonly Readonly<TLoadParams>[],
|
|
36
36
|
fetcher: (
|
|
37
|
-
fetcherLoadParamsArray: readonly Readonly<TLoadParams>[]
|
|
38
|
-
) => Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null
|
|
37
|
+
fetcherLoadParamsArray: readonly Readonly<TLoadParams>[],
|
|
38
|
+
) => Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>>,
|
|
39
39
|
): Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>> {
|
|
40
40
|
if (secondaryEntityCaches.length === 0) {
|
|
41
41
|
return await fetcher(loadParamsArray);
|
|
@@ -49,8 +49,8 @@ export default class ComposedSecondaryEntityCache<TLoadParams, TFields>
|
|
|
49
49
|
ComposedSecondaryEntityCache.loadManyThroughRecursivelyAsync(
|
|
50
50
|
restCaches,
|
|
51
51
|
fetcherLoadParamsArray,
|
|
52
|
-
fetcher
|
|
53
|
-
)
|
|
52
|
+
fetcher,
|
|
53
|
+
),
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import AuthorizationResultBasedEntityLoader from './AuthorizationResultBasedEntityLoader';
|
|
1
2
|
import {
|
|
2
3
|
FieldEqualityCondition,
|
|
3
4
|
QuerySelectionModifiers,
|
|
4
5
|
QuerySelectionModifiersWithOrderByRaw,
|
|
5
6
|
} from './EntityDatabaseAdapter';
|
|
6
|
-
import EntityLoader from './EntityLoader';
|
|
7
7
|
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
8
8
|
import ReadonlyEntity from './ReadonlyEntity';
|
|
9
9
|
import ViewerContext from './ViewerContext';
|
|
10
10
|
import { mapMap } from './utils/collections/maps';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Enforcing
|
|
14
|
-
*
|
|
13
|
+
* Enforcing entity loader. All normal loads are batched,
|
|
14
|
+
* cached, and authorized against the entity's EntityPrivacyPolicy. All loads
|
|
15
|
+
* through this loader will throw if the load is not successful.
|
|
15
16
|
*/
|
|
16
17
|
export default class EnforcingEntityLoader<
|
|
17
18
|
TFields extends object,
|
|
@@ -25,17 +26,17 @@ export default class EnforcingEntityLoader<
|
|
|
25
26
|
TEntity,
|
|
26
27
|
TSelectedFields
|
|
27
28
|
>,
|
|
28
|
-
TSelectedFields extends keyof TFields
|
|
29
|
+
TSelectedFields extends keyof TFields,
|
|
29
30
|
> {
|
|
30
31
|
constructor(
|
|
31
|
-
private readonly entityLoader:
|
|
32
|
+
private readonly entityLoader: AuthorizationResultBasedEntityLoader<
|
|
32
33
|
TFields,
|
|
33
34
|
TID,
|
|
34
35
|
TViewerContext,
|
|
35
36
|
TEntity,
|
|
36
37
|
TPrivacyPolicy,
|
|
37
38
|
TSelectedFields
|
|
38
|
-
|
|
39
|
+
>,
|
|
39
40
|
) {}
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -44,14 +45,14 @@ export default class EnforcingEntityLoader<
|
|
|
44
45
|
*/
|
|
45
46
|
async loadManyByFieldEqualingManyAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
46
47
|
fieldName: N,
|
|
47
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
48
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
48
49
|
): Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly TEntity[]>> {
|
|
49
50
|
const fieldValuesToResults = await this.entityLoader.loadManyByFieldEqualingManyAsync(
|
|
50
51
|
fieldName,
|
|
51
|
-
fieldValues
|
|
52
|
+
fieldValues,
|
|
52
53
|
);
|
|
53
54
|
return mapMap(fieldValuesToResults, (results) =>
|
|
54
|
-
results.map((result) => result.enforceValue())
|
|
55
|
+
results.map((result) => result.enforceValue()),
|
|
55
56
|
);
|
|
56
57
|
}
|
|
57
58
|
|
|
@@ -61,11 +62,11 @@ export default class EnforcingEntityLoader<
|
|
|
61
62
|
*/
|
|
62
63
|
async loadManyByFieldEqualingAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
63
64
|
fieldName: N,
|
|
64
|
-
fieldValue: NonNullable<TFields[N]
|
|
65
|
+
fieldValue: NonNullable<TFields[N]>,
|
|
65
66
|
): Promise<readonly TEntity[]> {
|
|
66
67
|
const entityResults = await this.entityLoader.loadManyByFieldEqualingAsync(
|
|
67
68
|
fieldName,
|
|
68
|
-
fieldValue
|
|
69
|
+
fieldValue,
|
|
69
70
|
);
|
|
70
71
|
return entityResults.map((result) => result.enforceValue());
|
|
71
72
|
}
|
|
@@ -77,11 +78,11 @@ export default class EnforcingEntityLoader<
|
|
|
77
78
|
*/
|
|
78
79
|
async loadByFieldEqualingAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
79
80
|
uniqueFieldName: N,
|
|
80
|
-
fieldValue: NonNullable<TFields[N]
|
|
81
|
+
fieldValue: NonNullable<TFields[N]>,
|
|
81
82
|
): Promise<TEntity | null> {
|
|
82
83
|
const entityResult = await this.entityLoader.loadByFieldEqualingAsync(
|
|
83
84
|
uniqueFieldName,
|
|
84
|
-
fieldValue
|
|
85
|
+
fieldValue,
|
|
85
86
|
);
|
|
86
87
|
return entityResult ? entityResult.enforceValue() : null;
|
|
87
88
|
}
|
|
@@ -130,11 +131,11 @@ export default class EnforcingEntityLoader<
|
|
|
130
131
|
async loadFirstByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
131
132
|
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
|
|
132
133
|
querySelectionModifiers: Omit<QuerySelectionModifiers<TFields>, 'limit'> &
|
|
133
|
-
Required<Pick<QuerySelectionModifiers<TFields>, 'orderBy'
|
|
134
|
+
Required<Pick<QuerySelectionModifiers<TFields>, 'orderBy'>>,
|
|
134
135
|
): Promise<TEntity | null> {
|
|
135
136
|
const entityResult = await this.entityLoader.loadFirstByFieldEqualityConjunctionAsync(
|
|
136
137
|
fieldEqualityOperands,
|
|
137
|
-
querySelectionModifiers
|
|
138
|
+
querySelectionModifiers,
|
|
138
139
|
);
|
|
139
140
|
return entityResult ? entityResult.enforceValue() : null;
|
|
140
141
|
}
|
|
@@ -145,11 +146,11 @@ export default class EnforcingEntityLoader<
|
|
|
145
146
|
*/
|
|
146
147
|
async loadManyByFieldEqualityConjunctionAsync<N extends keyof Pick<TFields, TSelectedFields>>(
|
|
147
148
|
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
|
|
148
|
-
querySelectionModifiers: QuerySelectionModifiers<TFields> = {}
|
|
149
|
+
querySelectionModifiers: QuerySelectionModifiers<TFields> = {},
|
|
149
150
|
): Promise<readonly TEntity[]> {
|
|
150
151
|
const entityResults = await this.entityLoader.loadManyByFieldEqualityConjunctionAsync(
|
|
151
152
|
fieldEqualityOperands,
|
|
152
|
-
querySelectionModifiers
|
|
153
|
+
querySelectionModifiers,
|
|
153
154
|
);
|
|
154
155
|
return entityResults.map((result) => result.enforceValue());
|
|
155
156
|
}
|
|
@@ -161,12 +162,12 @@ export default class EnforcingEntityLoader<
|
|
|
161
162
|
async loadManyByRawWhereClauseAsync(
|
|
162
163
|
rawWhereClause: string,
|
|
163
164
|
bindings: any[] | object,
|
|
164
|
-
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {}
|
|
165
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields> = {},
|
|
165
166
|
): Promise<readonly TEntity[]> {
|
|
166
167
|
const entityResults = await this.entityLoader.loadManyByRawWhereClauseAsync(
|
|
167
168
|
rawWhereClause,
|
|
168
169
|
bindings,
|
|
169
|
-
querySelectionModifiers
|
|
170
|
+
querySelectionModifiers,
|
|
170
171
|
);
|
|
171
172
|
return entityResults.map((result) => result.enforceValue());
|
|
172
173
|
}
|