@expo/entity 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/AuthorizationResultBasedEntityLoader.d.ts +128 -0
- package/build/AuthorizationResultBasedEntityLoader.js +196 -0
- package/build/AuthorizationResultBasedEntityLoader.js.map +1 -0
- package/build/ComposedEntityCacheAdapter.js +1 -0
- package/build/ComposedEntityCacheAdapter.js.map +1 -1
- package/build/ComposedSecondaryEntityCache.js +1 -0
- package/build/ComposedSecondaryEntityCache.js.map +1 -1
- package/build/EnforcingEntityLoader.d.ts +5 -4
- package/build/EnforcingEntityLoader.js +4 -2
- package/build/EnforcingEntityLoader.js.map +1 -1
- package/build/Entity.d.ts +0 -27
- package/build/Entity.js +0 -50
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.d.ts +1 -1
- package/build/EntityAssociationLoader.js +17 -8
- package/build/EntityAssociationLoader.js.map +1 -1
- package/build/EntityCompanion.js +9 -1
- package/build/EntityCompanion.js.map +1 -1
- package/build/EntityCompanionProvider.d.ts +3 -1
- package/build/EntityCompanionProvider.js +10 -4
- package/build/EntityCompanionProvider.js.map +1 -1
- package/build/EntityConfiguration.d.ts +2 -1
- package/build/EntityConfiguration.js +19 -1
- package/build/EntityConfiguration.js.map +1 -1
- package/build/EntityDatabaseAdapter.d.ts +2 -2
- package/build/EntityDatabaseAdapter.js +5 -3
- package/build/EntityDatabaseAdapter.js.map +1 -1
- package/build/EntityFieldDefinition.d.ts +21 -10
- package/build/EntityFieldDefinition.js +8 -9
- package/build/EntityFieldDefinition.js.map +1 -1
- package/build/EntityFields.d.ts +10 -0
- package/build/EntityFields.js +15 -1
- package/build/EntityFields.js.map +1 -1
- package/build/EntityLoader.d.ts +12 -125
- package/build/EntityLoader.js +24 -239
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityLoaderFactory.d.ts +1 -1
- package/build/EntityLoaderFactory.js +3 -0
- package/build/EntityLoaderFactory.js.map +1 -1
- package/build/EntityLoaderUtils.d.ts +58 -0
- package/build/EntityLoaderUtils.js +109 -0
- package/build/EntityLoaderUtils.js.map +1 -0
- package/build/EntityMutator.d.ts +1 -0
- package/build/EntityMutator.js +71 -56
- package/build/EntityMutator.js.map +1 -1
- package/build/EntityMutatorFactory.js +9 -0
- package/build/EntityMutatorFactory.js.map +1 -1
- package/build/EntityPrivacyPolicy.d.ts +11 -5
- package/build/EntityPrivacyPolicy.js +5 -7
- package/build/EntityPrivacyPolicy.js.map +1 -1
- package/build/EntityQueryContext.d.ts +2 -1
- package/build/EntityQueryContext.js +11 -6
- package/build/EntityQueryContext.js.map +1 -1
- package/build/EntitySecondaryCacheLoader.js +5 -1
- package/build/EntitySecondaryCacheLoader.js.map +1 -1
- package/build/GenericEntityCacheAdapter.js +1 -0
- package/build/GenericEntityCacheAdapter.js.map +1 -1
- package/build/GenericSecondaryEntityCache.js +2 -0
- package/build/GenericSecondaryEntityCache.js.map +1 -1
- package/build/IEntityCacheAdapterProvider.d.ts +1 -1
- package/build/IEntityDatabaseAdapterProvider.d.ts +1 -1
- package/build/ReadonlyEntity.js +5 -1
- package/build/ReadonlyEntity.js.map +1 -1
- package/build/ViewerContext.js +2 -0
- package/build/ViewerContext.js.map +1 -1
- package/build/ViewerScopedEntityCompanion.js +2 -0
- package/build/ViewerScopedEntityCompanion.js.map +1 -1
- package/build/ViewerScopedEntityCompanionProvider.d.ts +0 -1
- package/build/ViewerScopedEntityCompanionProvider.js +2 -1
- package/build/ViewerScopedEntityCompanionProvider.js.map +1 -1
- package/build/ViewerScopedEntityLoaderFactory.d.ts +1 -1
- package/build/ViewerScopedEntityLoaderFactory.js +2 -0
- package/build/ViewerScopedEntityLoaderFactory.js.map +1 -1
- package/build/ViewerScopedEntityMutatorFactory.js +2 -0
- package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
- package/build/__tests__/ComposedCacheAdapter-test.js +2 -0
- package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
- package/build/__tests__/ComposedSecondaryEntityCache-test.js +1 -0
- package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +1 -1
- package/build/__tests__/EnforcingEntityLoader-test.js +101 -113
- package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
- package/build/__tests__/Entity-test.js +0 -132
- package/build/__tests__/Entity-test.js.map +1 -1
- package/build/__tests__/EntityAssociationLoader-test.js +6 -2
- package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js +24 -22
- package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
- package/build/__tests__/EntityCompanion-test.js +26 -3
- package/build/__tests__/EntityCompanion-test.js.map +1 -1
- package/build/__tests__/EntityConfiguration-test.js +103 -0
- package/build/__tests__/EntityConfiguration-test.js.map +1 -0
- package/build/__tests__/EntityDatabaseAdapter-test.js +6 -0
- package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
- package/build/__tests__/EntityEdges-test.js +61 -20
- package/build/__tests__/EntityEdges-test.js.map +1 -1
- package/build/__tests__/EntityFields-test.js +6 -0
- package/build/__tests__/EntityFields-test.js.map +1 -1
- package/build/__tests__/EntityLoader-constructor-test.js +16 -17
- package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
- package/build/__tests__/EntityLoader-test.js +74 -22
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +12 -15
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -1
- package/build/__tests__/EntityMutator-test.js +54 -9
- package/build/__tests__/EntityMutator-test.js.map +1 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js +77 -59
- package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
- package/build/__tests__/EntityQueryContext-test.js +9 -0
- package/build/__tests__/EntityQueryContext-test.js.map +1 -1
- package/build/__tests__/EntitySelfReferentialEdges-test.js +42 -25
- package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +20 -18
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +12 -15
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
- package/build/entityUtils.d.ts +1 -1
- package/build/entityUtils.js.map +1 -1
- package/build/errors/EntityCacheAdapterError.js +2 -5
- package/build/errors/EntityCacheAdapterError.js.map +1 -1
- package/build/errors/EntityDatabaseAdapterError.js +14 -35
- package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
- package/build/errors/EntityError.js +1 -0
- package/build/errors/EntityError.js.map +1 -1
- package/build/errors/EntityInvalidFieldValueError.js +2 -2
- package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
- package/build/errors/EntityNotAuthorizedError.js +3 -2
- package/build/errors/EntityNotAuthorizedError.js.map +1 -1
- package/build/errors/EntityNotFoundError.js +2 -2
- package/build/errors/EntityNotFoundError.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/internal/EntityDataManager.d.ts +1 -1
- package/build/internal/EntityDataManager.js +6 -1
- package/build/internal/EntityDataManager.js.map +1 -1
- package/build/internal/EntityFieldTransformationUtils.d.ts +5 -5
- package/build/internal/EntityFieldTransformationUtils.js +5 -8
- package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/internal/EntityTableDataCoordinator.d.ts +1 -1
- package/build/internal/EntityTableDataCoordinator.js +5 -0
- package/build/internal/EntityTableDataCoordinator.js.map +1 -1
- package/build/internal/ReadThroughEntityCache.d.ts +1 -1
- package/build/internal/ReadThroughEntityCache.js +2 -0
- package/build/internal/ReadThroughEntityCache.js.map +1 -1
- package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +6 -2
- package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
- package/build/internal/__tests__/ReadThroughEntityCache-test.js +33 -0
- package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
- package/build/metrics/IEntityMetricsAdapter.d.ts +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
- package/build/rules/PrivacyPolicyRule.d.ts +1 -1
- package/build/rules/PrivacyPolicyRule.js.map +1 -1
- package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
- package/build/testfixtures/DateIDTestEntity.js +12 -15
- package/build/testfixtures/DateIDTestEntity.js.map +1 -1
- package/build/testfixtures/SimpleTestEntity.js +12 -15
- package/build/testfixtures/SimpleTestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity.js +12 -15
- package/build/testfixtures/TestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity2.js +12 -15
- package/build/testfixtures/TestEntity2.js.map +1 -1
- package/build/testfixtures/TestEntityNumberKey.js +12 -15
- package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
- package/build/testfixtures/TestEntityWithMutationTriggers.d.ts +36 -0
- package/build/testfixtures/TestEntityWithMutationTriggers.js +82 -0
- package/build/testfixtures/TestEntityWithMutationTriggers.js.map +1 -0
- package/build/utils/EntityPrivacyUtils.d.ts +34 -0
- package/build/utils/EntityPrivacyUtils.js +160 -0
- package/build/utils/EntityPrivacyUtils.js.map +1 -0
- package/build/utils/__tests__/EntityPrivacyUtils-test.d.ts +1 -0
- package/build/utils/__tests__/EntityPrivacyUtils-test.js +395 -0
- package/build/utils/__tests__/EntityPrivacyUtils-test.js.map +1 -0
- package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.d.ts +1 -0
- package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js +26 -0
- package/build/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.js.map +1 -0
- package/build/utils/collections/maps.js.map +1 -1
- package/build/utils/mergeEntityMutationTriggerConfigurations.d.ts +4 -0
- package/build/utils/mergeEntityMutationTriggerConfigurations.js +28 -0
- package/build/utils/mergeEntityMutationTriggerConfigurations.js.map +1 -0
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
- package/build/utils/testing/StubCacheAdapter.d.ts +3 -3
- package/build/utils/testing/StubCacheAdapter.js +3 -3
- package/build/utils/testing/StubCacheAdapter.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapter.d.ts +2 -2
- package/build/utils/testing/StubDatabaseAdapter.js +4 -2
- package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapterProvider.d.ts +1 -1
- package/build/utils/testing/StubDatabaseAdapterProvider.js +1 -3
- package/build/utils/testing/StubDatabaseAdapterProvider.js.map +1 -1
- package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.d.ts +1 -0
- package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js +42 -0
- package/build/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.js.map +1 -0
- package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +53 -0
- package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
- package/build/utils/testing/describeFieldTestCase.js.map +1 -1
- package/package.json +4 -3
- package/src/AuthorizationResultBasedEntityLoader.ts +297 -0
- package/src/ComposedEntityCacheAdapter.ts +6 -6
- package/src/ComposedSecondaryEntityCache.ts +8 -8
- package/src/EnforcingEntityLoader.ts +20 -19
- package/src/Entity.ts +11 -126
- package/src/EntityAssociationLoader.ts +40 -41
- package/src/EntityCompanion.ts +8 -4
- package/src/EntityCompanionProvider.ts +24 -16
- package/src/EntityConfiguration.ts +18 -7
- package/src/EntityDatabaseAdapter.ts +41 -41
- package/src/EntityFieldDefinition.ts +28 -18
- package/src/EntityFields.ts +15 -0
- package/src/EntityLoader.ts +63 -357
- package/src/EntityLoaderFactory.ts +10 -4
- package/src/EntityLoaderUtils.ts +149 -0
- package/src/EntityMutationInfo.ts +2 -2
- package/src/EntityMutationTriggerConfiguration.ts +5 -5
- package/src/EntityMutationValidator.ts +2 -2
- package/src/EntityMutator.ts +146 -144
- package/src/EntityMutatorFactory.ts +8 -8
- package/src/EntityPrivacyPolicy.ts +78 -28
- package/src/EntityQueryContext.ts +14 -13
- package/src/EntityQueryContextProvider.ts +5 -5
- package/src/EntitySecondaryCacheLoader.ts +13 -11
- package/src/GenericEntityCacheAdapter.ts +10 -10
- package/src/GenericSecondaryEntityCache.ts +6 -6
- package/src/IEntityCacheAdapter.ts +4 -4
- package/src/IEntityCacheAdapterProvider.ts +2 -2
- package/src/IEntityDatabaseAdapterProvider.ts +2 -2
- package/src/ReadonlyEntity.ts +5 -5
- package/src/ViewerContext.ts +5 -5
- package/src/ViewerScopedEntityCompanion.ts +4 -4
- package/src/ViewerScopedEntityCompanionProvider.ts +4 -5
- package/src/ViewerScopedEntityLoaderFactory.ts +10 -4
- package/src/ViewerScopedEntityMutatorFactory.ts +5 -5
- package/src/__tests__/ComposedCacheAdapter-test.ts +12 -10
- package/src/__tests__/ComposedSecondaryEntityCache-test.ts +8 -8
- package/src/__tests__/EnforcingEntityLoader-test.ts +236 -159
- package/src/__tests__/Entity-test.ts +0 -202
- package/src/__tests__/EntityAssociationLoader-test.ts +29 -25
- package/src/__tests__/EntityCommonUseCases-test.ts +29 -13
- package/src/__tests__/EntityCompanion-test.ts +57 -5
- package/src/__tests__/EntityConfiguration-test.ts +118 -0
- package/src/__tests__/EntityDatabaseAdapter-test.ts +11 -11
- package/src/__tests__/EntityEdges-test.ts +108 -36
- package/src/__tests__/EntityFields-test.ts +14 -2
- package/src/__tests__/EntityLoader-constructor-test.ts +20 -7
- package/src/__tests__/EntityLoader-test.ts +214 -86
- package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +2 -2
- package/src/__tests__/EntityMutator-test.ts +281 -96
- package/src/__tests__/EntityPrivacyPolicy-test.ts +166 -53
- package/src/__tests__/EntityQueryContext-test.ts +30 -12
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -7
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +46 -26
- package/src/__tests__/GenericEntityCacheAdapter-test.ts +2 -2
- package/src/__tests__/ViewerContext-test.ts +1 -1
- package/src/__tests__/ViewerScopedEntityCompanion-test.ts +2 -2
- package/src/__tests__/ViewerScopedEntityCompanionProvider-test.ts +2 -2
- package/src/__tests__/ViewerScopedEntityLoaderFactory-test.ts +2 -1
- package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +19 -19
- package/src/__tests__/entityUtils-test.ts +2 -2
- package/src/entityUtils.ts +4 -4
- package/src/errors/EntityError.ts +4 -1
- package/src/errors/EntityInvalidFieldValueError.ts +2 -2
- package/src/errors/EntityNotAuthorizedError.ts +3 -3
- package/src/errors/EntityNotFoundError.ts +2 -2
- package/src/index.ts +1 -0
- package/src/internal/EntityDataManager.ts +24 -24
- package/src/internal/EntityFieldTransformationUtils.ts +39 -32
- package/src/internal/EntityTableDataCoordinator.ts +3 -3
- package/src/internal/ReadThroughEntityCache.ts +9 -9
- package/src/internal/__tests__/EntityDataManager-test.ts +51 -51
- package/src/internal/__tests__/EntityFieldTransformationUtils-test.ts +14 -10
- package/src/internal/__tests__/ReadThroughEntityCache-test.ts +74 -18
- package/src/metrics/EntityMetricsUtils.ts +4 -4
- package/src/metrics/IEntityMetricsAdapter.ts +1 -1
- package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +9 -3
- package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +9 -3
- package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +9 -3
- package/src/rules/PrivacyPolicyRule.ts +9 -3
- package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -1
- package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -1
- package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -1
- package/src/testfixtures/TestEntity.ts +1 -1
- package/src/testfixtures/TestEntityWithMutationTriggers.ts +156 -0
- package/src/utils/EntityPrivacyUtils.ts +325 -0
- package/src/utils/__tests__/EntityPrivacyUtils-test.ts +570 -0
- package/src/utils/__tests__/mergeEntityMutationTriggerConfigurations-test.ts +29 -0
- package/src/utils/collections/__tests__/maps-test.ts +2 -2
- package/src/utils/collections/maps.ts +11 -11
- package/src/utils/mergeEntityMutationTriggerConfigurations.ts +44 -0
- package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +25 -22
- package/src/utils/testing/StubCacheAdapter.ts +17 -15
- package/src/utils/testing/StubDatabaseAdapter.ts +35 -30
- package/src/utils/testing/StubDatabaseAdapterProvider.ts +2 -2
- package/src/utils/testing/StubQueryContextProvider.ts +2 -2
- package/src/utils/testing/__tests__/PrivacyPolicyRuleTestUtils-test.ts +42 -0
- package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +111 -29
- package/src/utils/testing/createUnitTestEntityCompanionProvider.ts +2 -2
- package/src/utils/testing/describeFieldTestCase.ts +1 -1
- package/build/__tests__/EntityDataConfiguration-test.js +0 -68
- package/build/__tests__/EntityDataConfiguration-test.js.map +0 -1
- package/src/__tests__/EntityDataConfiguration-test.ts +0 -77
- /package/build/__tests__/{EntityDataConfiguration-test.d.ts → EntityConfiguration-test.d.ts} +0 -0
|
@@ -96,25 +96,33 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE', () => {
|
|
|
96
96
|
.enforceCreateAsync();
|
|
97
97
|
|
|
98
98
|
await expect(
|
|
99
|
-
CategoryEntity.loader(viewerContext)
|
|
99
|
+
CategoryEntity.loader(viewerContext)
|
|
100
|
+
.enforcing()
|
|
101
|
+
.loadByIDNullableAsync(parentCategory.getID()),
|
|
100
102
|
).resolves.not.toBeNull();
|
|
101
103
|
await expect(
|
|
102
|
-
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID())
|
|
104
|
+
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID()),
|
|
103
105
|
).resolves.not.toBeNull();
|
|
104
106
|
await expect(
|
|
105
|
-
CategoryEntity.loader(viewerContext)
|
|
107
|
+
CategoryEntity.loader(viewerContext)
|
|
108
|
+
.enforcing()
|
|
109
|
+
.loadByIDNullableAsync(subSubCategory.getID()),
|
|
106
110
|
).resolves.not.toBeNull();
|
|
107
111
|
|
|
108
112
|
await CategoryEntity.enforceDeleteAsync(parentCategory);
|
|
109
113
|
|
|
110
114
|
await expect(
|
|
111
|
-
CategoryEntity.loader(viewerContext)
|
|
115
|
+
CategoryEntity.loader(viewerContext)
|
|
116
|
+
.enforcing()
|
|
117
|
+
.loadByIDNullableAsync(parentCategory.getID()),
|
|
112
118
|
).resolves.toBeNull();
|
|
113
119
|
await expect(
|
|
114
|
-
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID())
|
|
120
|
+
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID()),
|
|
115
121
|
).resolves.toBeNull();
|
|
116
122
|
await expect(
|
|
117
|
-
CategoryEntity.loader(viewerContext)
|
|
123
|
+
CategoryEntity.loader(viewerContext)
|
|
124
|
+
.enforcing()
|
|
125
|
+
.loadByIDNullableAsync(subSubCategory.getID()),
|
|
118
126
|
).resolves.toBeNull();
|
|
119
127
|
});
|
|
120
128
|
|
|
@@ -135,10 +143,10 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE', () => {
|
|
|
135
143
|
await CategoryEntity.enforceDeleteAsync(categoryA);
|
|
136
144
|
|
|
137
145
|
await expect(
|
|
138
|
-
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(categoryA.getID())
|
|
146
|
+
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(categoryA.getID()),
|
|
139
147
|
).resolves.toBeNull();
|
|
140
148
|
await expect(
|
|
141
|
-
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(categoryB.getID())
|
|
149
|
+
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(categoryB.getID()),
|
|
142
150
|
).resolves.toBeNull();
|
|
143
151
|
});
|
|
144
152
|
});
|
|
@@ -159,19 +167,25 @@ describe('EntityEdgeDeletionBehavior.SET_NULL', () => {
|
|
|
159
167
|
.enforceCreateAsync();
|
|
160
168
|
|
|
161
169
|
await expect(
|
|
162
|
-
CategoryEntity.loader(viewerContext)
|
|
170
|
+
CategoryEntity.loader(viewerContext)
|
|
171
|
+
.enforcing()
|
|
172
|
+
.loadByIDNullableAsync(parentCategory.getID()),
|
|
163
173
|
).resolves.not.toBeNull();
|
|
164
174
|
await expect(
|
|
165
|
-
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID())
|
|
175
|
+
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID()),
|
|
166
176
|
).resolves.not.toBeNull();
|
|
167
177
|
await expect(
|
|
168
|
-
CategoryEntity.loader(viewerContext)
|
|
178
|
+
CategoryEntity.loader(viewerContext)
|
|
179
|
+
.enforcing()
|
|
180
|
+
.loadByIDNullableAsync(subSubCategory.getID()),
|
|
169
181
|
).resolves.not.toBeNull();
|
|
170
182
|
|
|
171
183
|
await CategoryEntity.enforceDeleteAsync(parentCategory);
|
|
172
184
|
|
|
173
185
|
await expect(
|
|
174
|
-
CategoryEntity.loader(viewerContext)
|
|
186
|
+
CategoryEntity.loader(viewerContext)
|
|
187
|
+
.enforcing()
|
|
188
|
+
.loadByIDNullableAsync(parentCategory.getID()),
|
|
175
189
|
).resolves.toBeNull();
|
|
176
190
|
|
|
177
191
|
const loadedSubCategory = await CategoryEntity.loader(viewerContext)
|
|
@@ -211,7 +225,7 @@ describe('EntityEdgeDeletionBehavior.SET_NULL', () => {
|
|
|
211
225
|
describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
212
226
|
it('invalidates the cache', async () => {
|
|
213
227
|
const { CategoryEntity } = makeEntityClass(
|
|
214
|
-
EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY
|
|
228
|
+
EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY,
|
|
215
229
|
);
|
|
216
230
|
|
|
217
231
|
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
@@ -226,21 +240,23 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
226
240
|
.enforceCreateAsync();
|
|
227
241
|
|
|
228
242
|
await expect(
|
|
229
|
-
CategoryEntity.loader(viewerContext)
|
|
243
|
+
CategoryEntity.loader(viewerContext)
|
|
244
|
+
.enforcing()
|
|
245
|
+
.loadByIDNullableAsync(parentCategory.getID()),
|
|
230
246
|
).resolves.not.toBeNull();
|
|
231
247
|
await expect(
|
|
232
248
|
CategoryEntity.loader(viewerContext)
|
|
233
249
|
.enforcing()
|
|
234
|
-
.loadByFieldEqualingAsync('parent_category_id', parentCategory.getID())
|
|
250
|
+
.loadByFieldEqualingAsync('parent_category_id', parentCategory.getID()),
|
|
235
251
|
).resolves.not.toBeNull();
|
|
236
252
|
await expect(
|
|
237
253
|
CategoryEntity.loader(viewerContext)
|
|
238
254
|
.enforcing()
|
|
239
|
-
.loadByFieldEqualingAsync('parent_category_id', subCategory.getID())
|
|
255
|
+
.loadByFieldEqualingAsync('parent_category_id', subCategory.getID()),
|
|
240
256
|
).resolves.not.toBeNull();
|
|
241
257
|
|
|
242
258
|
const categoryCacheAdapter = viewerContext.getViewerScopedEntityCompanionForClass(
|
|
243
|
-
CategoryEntity
|
|
259
|
+
CategoryEntity,
|
|
244
260
|
)['entityCompanion']['tableDataCoordinator'][
|
|
245
261
|
'cacheAdapter'
|
|
246
262
|
] as InMemoryFullCacheStubCacheAdapter<CategoryFields>;
|
|
@@ -251,7 +267,7 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
251
267
|
|
|
252
268
|
const subSubCategoryCachedBefore = await categoryCacheAdapter.loadManyAsync(
|
|
253
269
|
'parent_category_id',
|
|
254
|
-
[subCategory.getID()]
|
|
270
|
+
[subCategory.getID()],
|
|
255
271
|
);
|
|
256
272
|
expect(subSubCategoryCachedBefore.get(subCategory.getID())?.status).toEqual(CacheStatus.HIT);
|
|
257
273
|
|
|
@@ -264,24 +280,28 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
264
280
|
|
|
265
281
|
const subSubCategoryCachedAfter = await categoryCacheAdapter.loadManyAsync(
|
|
266
282
|
'parent_category_id',
|
|
267
|
-
[subCategory.getID()]
|
|
283
|
+
[subCategory.getID()],
|
|
268
284
|
);
|
|
269
285
|
expect(subSubCategoryCachedAfter.get(subCategory.getID())?.status).toEqual(CacheStatus.MISS);
|
|
270
286
|
|
|
271
287
|
await expect(
|
|
272
|
-
CategoryEntity.loader(viewerContext)
|
|
288
|
+
CategoryEntity.loader(viewerContext)
|
|
289
|
+
.enforcing()
|
|
290
|
+
.loadByIDNullableAsync(parentCategory.getID()),
|
|
273
291
|
).resolves.toBeNull();
|
|
274
292
|
await expect(
|
|
275
|
-
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID())
|
|
293
|
+
CategoryEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(subCategory.getID()),
|
|
276
294
|
).resolves.not.toBeNull();
|
|
277
295
|
await expect(
|
|
278
|
-
CategoryEntity.loader(viewerContext)
|
|
296
|
+
CategoryEntity.loader(viewerContext)
|
|
297
|
+
.enforcing()
|
|
298
|
+
.loadByIDNullableAsync(subSubCategory.getID()),
|
|
279
299
|
).resolves.not.toBeNull();
|
|
280
300
|
});
|
|
281
301
|
|
|
282
302
|
it('handles cycles', async () => {
|
|
283
303
|
const { CategoryEntity } = makeEntityClass(
|
|
284
|
-
EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY
|
|
304
|
+
EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY,
|
|
285
305
|
);
|
|
286
306
|
|
|
287
307
|
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
@@ -298,16 +318,16 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
298
318
|
await expect(
|
|
299
319
|
CategoryEntity.loader(viewerContext)
|
|
300
320
|
.enforcing()
|
|
301
|
-
.loadByFieldEqualingAsync('parent_category_id', categoryA.getID())
|
|
321
|
+
.loadByFieldEqualingAsync('parent_category_id', categoryA.getID()),
|
|
302
322
|
).resolves.not.toBeNull();
|
|
303
323
|
await expect(
|
|
304
324
|
CategoryEntity.loader(viewerContext)
|
|
305
325
|
.enforcing()
|
|
306
|
-
.loadByFieldEqualingAsync('parent_category_id', categoryB.getID())
|
|
326
|
+
.loadByFieldEqualingAsync('parent_category_id', categoryB.getID()),
|
|
307
327
|
).resolves.not.toBeNull();
|
|
308
328
|
|
|
309
329
|
const categoryCacheAdapter = viewerContext.getViewerScopedEntityCompanionForClass(
|
|
310
|
-
CategoryEntity
|
|
330
|
+
CategoryEntity,
|
|
311
331
|
)['entityCompanion']['tableDataCoordinator'][
|
|
312
332
|
'cacheAdapter'
|
|
313
333
|
] as InMemoryFullCacheStubCacheAdapter<CategoryFields>;
|
|
@@ -20,7 +20,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
20
20
|
['id.wat', { status: CacheStatus.HIT, item: { id: 'wat' } }],
|
|
21
21
|
['id.who', { status: CacheStatus.NEGATIVE }],
|
|
22
22
|
['id.why', { status: CacheStatus.MISS }],
|
|
23
|
-
])
|
|
23
|
+
]),
|
|
24
24
|
);
|
|
25
25
|
|
|
26
26
|
const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
|
|
@@ -55,7 +55,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
55
55
|
await cacheAdapter.cacheManyAsync('id', new Map([['wat', { id: 'wat' }]]));
|
|
56
56
|
|
|
57
57
|
verify(
|
|
58
|
-
mockGenericCacher.cacheManyAsync(deepEqual(new Map([['id.wat', { id: 'wat' }]])))
|
|
58
|
+
mockGenericCacher.cacheManyAsync(deepEqual(new Map([['id.wat', { id: 'wat' }]]))),
|
|
59
59
|
).once();
|
|
60
60
|
});
|
|
61
61
|
});
|
|
@@ -23,10 +23,10 @@ describe(ViewerScopedEntityCompanion, () => {
|
|
|
23
23
|
>();
|
|
24
24
|
const viewerScopedEntityCompanion = new ViewerScopedEntityCompanion(entityCompanion, vc);
|
|
25
25
|
expect(viewerScopedEntityCompanion.getLoaderFactory()).toBeInstanceOf(
|
|
26
|
-
ViewerScopedEntityLoaderFactory
|
|
26
|
+
ViewerScopedEntityLoaderFactory,
|
|
27
27
|
);
|
|
28
28
|
expect(viewerScopedEntityCompanion.getMutatorFactory()).toBeInstanceOf(
|
|
29
|
-
ViewerScopedEntityMutatorFactory
|
|
29
|
+
ViewerScopedEntityMutatorFactory,
|
|
30
30
|
);
|
|
31
31
|
});
|
|
32
32
|
});
|
|
@@ -12,10 +12,10 @@ describe(ViewerScopedEntityCompanionProvider, () => {
|
|
|
12
12
|
const entityCompanionProvider = instance(mock(EntityCompanionProvider));
|
|
13
13
|
const viewerScopedEntityCompanionProvider = new ViewerScopedEntityCompanionProvider(
|
|
14
14
|
entityCompanionProvider,
|
|
15
|
-
vc
|
|
15
|
+
vc,
|
|
16
16
|
);
|
|
17
17
|
expect(
|
|
18
|
-
viewerScopedEntityCompanionProvider.getViewerScopedCompanionForEntity(TestEntity)
|
|
18
|
+
viewerScopedEntityCompanionProvider.getViewerScopedCompanionForEntity(TestEntity),
|
|
19
19
|
).toBeInstanceOf(ViewerScopedEntityCompanion);
|
|
20
20
|
});
|
|
21
21
|
});
|
|
@@ -9,7 +9,8 @@ import ViewerScopedEntityLoaderFactory from '../ViewerScopedEntityLoaderFactory'
|
|
|
9
9
|
describe(ViewerScopedEntityLoaderFactory, () => {
|
|
10
10
|
it('correctly scopes viewer to entity loads', async () => {
|
|
11
11
|
const viewerContext = instance(mock(ViewerContext));
|
|
12
|
-
const privacyPolicyEvaluationContext =
|
|
12
|
+
const privacyPolicyEvaluationContext =
|
|
13
|
+
instance(mock<EntityPrivacyPolicyEvaluationContext<any, any, any, any, any>>());
|
|
13
14
|
const queryContext = instance(mock(EntityQueryContext));
|
|
14
15
|
const baseLoader = mock<EntityLoaderFactory<any, any, any, any, any, any>>(EntityLoaderFactory);
|
|
15
16
|
const baseLoaderInstance = instance(baseLoader);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Entity from '../../Entity';
|
|
2
2
|
import { EntityCompanionDefinition } from '../../EntityCompanionProvider';
|
|
3
3
|
import EntityConfiguration from '../../EntityConfiguration';
|
|
4
|
-
import { UUIDField,
|
|
4
|
+
import { UUIDField, StringField, StrictEnumField } from '../../EntityFields';
|
|
5
5
|
import EntityPrivacyPolicy from '../../EntityPrivacyPolicy';
|
|
6
6
|
import ViewerContext from '../../ViewerContext';
|
|
7
7
|
import { successfulResults, failedResults } from '../../entityUtils';
|
|
@@ -28,17 +28,16 @@ describe('Two entities backed by the same table', () => {
|
|
|
28
28
|
expect(two).toBeInstanceOf(TwoTestEntity);
|
|
29
29
|
|
|
30
30
|
await expect(
|
|
31
|
-
TwoTestEntity.loader(viewerContext).enforcing().loadByIDAsync(one.getID())
|
|
31
|
+
TwoTestEntity.loader(viewerContext).enforcing().loadByIDAsync(one.getID()),
|
|
32
32
|
).rejects.toThrowError('TwoTestEntity must be instantiated with two data');
|
|
33
33
|
|
|
34
34
|
await expect(
|
|
35
|
-
OneTestEntity.loader(viewerContext).enforcing().loadByIDAsync(two.getID())
|
|
35
|
+
OneTestEntity.loader(viewerContext).enforcing().loadByIDAsync(two.getID()),
|
|
36
36
|
).rejects.toThrowError('OneTestEntity must be instantiated with one data');
|
|
37
37
|
|
|
38
|
-
const manyResults = await OneTestEntity.loader(viewerContext)
|
|
39
|
-
|
|
40
|
-
'wat'
|
|
41
|
-
);
|
|
38
|
+
const manyResults = await OneTestEntity.loader(viewerContext)
|
|
39
|
+
.withAuthorizationResults()
|
|
40
|
+
.loadManyByFieldEqualingAsync('common_other_field', 'wat');
|
|
42
41
|
const successfulManyResults = successfulResults(manyResults);
|
|
43
42
|
const failedManyResults = failedResults(manyResults);
|
|
44
43
|
|
|
@@ -47,22 +46,22 @@ describe('Two entities backed by the same table', () => {
|
|
|
47
46
|
|
|
48
47
|
expect(successfulManyResults[0]!.enforceValue().getID()).toEqual(one.getID());
|
|
49
48
|
expect(failedManyResults[0]!.enforceError().message).toEqual(
|
|
50
|
-
'OneTestEntity must be instantiated with one data'
|
|
49
|
+
'OneTestEntity must be instantiated with one data',
|
|
51
50
|
);
|
|
52
51
|
|
|
53
|
-
const fieldEqualityConjunctionResults = await OneTestEntity.loader(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
const fieldEqualityConjunctionResults = await OneTestEntity.loader(viewerContext)
|
|
53
|
+
.withAuthorizationResults()
|
|
54
|
+
.loadManyByFieldEqualityConjunctionAsync([
|
|
55
|
+
{
|
|
56
|
+
fieldName: 'common_other_field',
|
|
57
|
+
fieldValue: 'wat',
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
61
60
|
const successfulfieldEqualityConjunctionResultsResults = successfulResults(
|
|
62
|
-
fieldEqualityConjunctionResults
|
|
61
|
+
fieldEqualityConjunctionResults,
|
|
63
62
|
);
|
|
64
63
|
const failedfieldEqualityConjunctionResultsResults = failedResults(
|
|
65
|
-
fieldEqualityConjunctionResults
|
|
64
|
+
fieldEqualityConjunctionResults,
|
|
66
65
|
);
|
|
67
66
|
expect(successfulfieldEqualityConjunctionResultsResults).toHaveLength(1);
|
|
68
67
|
expect(failedfieldEqualityConjunctionResultsResults).toHaveLength(1);
|
|
@@ -98,8 +97,9 @@ const testEntityConfiguration = new EntityConfiguration<TestFields>({
|
|
|
98
97
|
common_other_field: new StringField({
|
|
99
98
|
columnName: 'common_other_field',
|
|
100
99
|
}),
|
|
101
|
-
entity_type: new
|
|
100
|
+
entity_type: new StrictEnumField({
|
|
102
101
|
columnName: 'entity_type',
|
|
102
|
+
enum: EntityType,
|
|
103
103
|
}),
|
|
104
104
|
},
|
|
105
105
|
databaseAdapterFlavor: 'postgres',
|
|
@@ -52,7 +52,7 @@ describe(successfulResultsFilterMap, () => {
|
|
|
52
52
|
a: result1,
|
|
53
53
|
b: result2,
|
|
54
54
|
c: result3,
|
|
55
|
-
})
|
|
55
|
+
}),
|
|
56
56
|
);
|
|
57
57
|
|
|
58
58
|
const resultingMap = successfulResultsFilterMap(allResults);
|
|
@@ -73,7 +73,7 @@ describe(failedResultsFilterMap, () => {
|
|
|
73
73
|
a: result1,
|
|
74
74
|
b: result2,
|
|
75
75
|
c: result3,
|
|
76
|
-
})
|
|
76
|
+
}),
|
|
77
77
|
);
|
|
78
78
|
|
|
79
79
|
const resultingMap = failedResultsFilterMap(allResults);
|
package/src/entityUtils.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Result, Success, Failure } from '@expo/results';
|
|
|
5
5
|
* @param resultsPromise - promise returning an array of results to enforce
|
|
6
6
|
*/
|
|
7
7
|
export const enforceResultsAsync = async <T>(
|
|
8
|
-
resultsPromise: Promise<readonly Result<T>[]
|
|
8
|
+
resultsPromise: Promise<readonly Result<T>[]>,
|
|
9
9
|
): Promise<readonly T[]> => {
|
|
10
10
|
const results = await resultsPromise;
|
|
11
11
|
return results.map((result) => result.enforceValue());
|
|
@@ -44,7 +44,7 @@ export const failedResults = <T>(results: readonly Result<T>[]): readonly Failur
|
|
|
44
44
|
* @param results - map of results to filter.
|
|
45
45
|
*/
|
|
46
46
|
export const successfulResultsFilterMap = <K, T>(
|
|
47
|
-
results: ReadonlyMap<K, Result<T
|
|
47
|
+
results: ReadonlyMap<K, Result<T>>,
|
|
48
48
|
): ReadonlyMap<K, Success<T>> => {
|
|
49
49
|
const ret: Map<K, Success<T>> = new Map();
|
|
50
50
|
for (const [k, result] of results) {
|
|
@@ -60,7 +60,7 @@ export const successfulResultsFilterMap = <K, T>(
|
|
|
60
60
|
* @param results - map of results to filter.
|
|
61
61
|
*/
|
|
62
62
|
export const failedResultsFilterMap = <K, T>(
|
|
63
|
-
results: ReadonlyMap<K, Result<T
|
|
63
|
+
results: ReadonlyMap<K, Result<T>>,
|
|
64
64
|
): ReadonlyMap<K, Failure<T>> => {
|
|
65
65
|
const ret: Map<K, Failure<T>> = new Map();
|
|
66
66
|
for (const [k, result] of results) {
|
|
@@ -97,6 +97,6 @@ const isError = <T>(value: T | Error): value is Error => {
|
|
|
97
97
|
export const pick = <T extends object, U extends keyof T>(object: T, props: U[]): Pick<T, U> => {
|
|
98
98
|
const propsSet = new Set(props);
|
|
99
99
|
return Object.fromEntries(
|
|
100
|
-
Object.entries(object).filter((entry) => propsSet.has(entry[0] as any))
|
|
100
|
+
Object.entries(object).filter((entry) => propsSet.has(entry[0] as any)),
|
|
101
101
|
) as any;
|
|
102
102
|
};
|
|
@@ -24,7 +24,10 @@ export default abstract class EntityError extends ES6Error {
|
|
|
24
24
|
public abstract readonly state: EntityErrorState;
|
|
25
25
|
public abstract readonly code: EntityErrorCode;
|
|
26
26
|
|
|
27
|
-
constructor(
|
|
27
|
+
constructor(
|
|
28
|
+
message: string,
|
|
29
|
+
public override readonly cause?: Error,
|
|
30
|
+
) {
|
|
28
31
|
super(message);
|
|
29
32
|
}
|
|
30
33
|
}
|
|
@@ -17,7 +17,7 @@ export default class EntityInvalidFieldValueError<
|
|
|
17
17
|
TSelectedFields
|
|
18
18
|
>,
|
|
19
19
|
N extends keyof TFields,
|
|
20
|
-
TSelectedFields extends keyof TFields = keyof TFields
|
|
20
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
21
21
|
> extends EntityError {
|
|
22
22
|
public readonly state = EntityErrorState.PERMANENT;
|
|
23
23
|
public readonly code = EntityErrorCode.ERR_ENTITY_INVALID_FIELD_VALUE;
|
|
@@ -32,7 +32,7 @@ export default class EntityInvalidFieldValueError<
|
|
|
32
32
|
TSelectedFields
|
|
33
33
|
>,
|
|
34
34
|
fieldName: N,
|
|
35
|
-
fieldValue?: TFields[N]
|
|
35
|
+
fieldValue?: TFields[N],
|
|
36
36
|
) {
|
|
37
37
|
super(`Entity field not valid: ${entityClass.name} (${String(fieldName)} = ${fieldValue})`);
|
|
38
38
|
}
|
|
@@ -8,7 +8,7 @@ export default class EntityNotAuthorizedError<
|
|
|
8
8
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
9
9
|
TViewerContext extends ViewerContext,
|
|
10
10
|
TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
11
|
-
TSelectedFields extends keyof TFields = keyof TFields
|
|
11
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
12
12
|
> extends EntityError {
|
|
13
13
|
public readonly state = EntityErrorState.PERMANENT;
|
|
14
14
|
public readonly code = EntityErrorCode.ERR_ENTITY_NOT_AUTHORIZED;
|
|
@@ -19,10 +19,10 @@ export default class EntityNotAuthorizedError<
|
|
|
19
19
|
entity: TEntity,
|
|
20
20
|
viewerContext: TViewerContext,
|
|
21
21
|
action: EntityAuthorizationAction,
|
|
22
|
-
ruleIndex: number
|
|
22
|
+
ruleIndex: number,
|
|
23
23
|
) {
|
|
24
24
|
super(
|
|
25
|
-
`Entity not authorized: ${entity} (viewer = ${viewerContext}, action = ${EntityAuthorizationAction[action]}, ruleIndex = ${ruleIndex})
|
|
25
|
+
`Entity not authorized: ${entity} (viewer = ${viewerContext}, action = ${EntityAuthorizationAction[action]}, ruleIndex = ${ruleIndex})`,
|
|
26
26
|
);
|
|
27
27
|
this.entityClassName = entity.constructor.name;
|
|
28
28
|
}
|
|
@@ -17,7 +17,7 @@ export default class EntityNotFoundError<
|
|
|
17
17
|
TSelectedFields
|
|
18
18
|
>,
|
|
19
19
|
N extends keyof TFields,
|
|
20
|
-
TSelectedFields extends keyof TFields = keyof TFields
|
|
20
|
+
TSelectedFields extends keyof TFields = keyof TFields,
|
|
21
21
|
> extends EntityError {
|
|
22
22
|
public readonly state = EntityErrorState.PERMANENT;
|
|
23
23
|
public readonly code = EntityErrorCode.ERR_ENTITY_NOT_FOUND;
|
|
@@ -32,7 +32,7 @@ export default class EntityNotFoundError<
|
|
|
32
32
|
TSelectedFields
|
|
33
33
|
>,
|
|
34
34
|
fieldName: N,
|
|
35
|
-
fieldValue: TFields[N]
|
|
35
|
+
fieldValue: TFields[N],
|
|
36
36
|
) {
|
|
37
37
|
super(`Entity not found: ${entityClass.name} (${String(fieldName)} = ${fieldValue})`);
|
|
38
38
|
}
|
package/src/index.ts
CHANGED
|
@@ -76,3 +76,4 @@ export { default as StubDatabaseAdapterProvider } from './utils/testing/StubData
|
|
|
76
76
|
export { default as StubQueryContextProvider } from './utils/testing/StubQueryContextProvider';
|
|
77
77
|
export * from './utils/testing/createUnitTestEntityCompanionProvider';
|
|
78
78
|
export * from './utils/collections/maps';
|
|
79
|
+
export * from './utils/EntityPrivacyUtils';
|
|
@@ -25,7 +25,7 @@ import { computeIfAbsent, zipToMap } from '../utils/collections/maps';
|
|
|
25
25
|
*
|
|
26
26
|
* It is also responsible for invalidating all sources of data when mutated using EntityMutator.
|
|
27
27
|
*/
|
|
28
|
-
export default class EntityDataManager<TFields
|
|
28
|
+
export default class EntityDataManager<TFields extends Record<string, any>> {
|
|
29
29
|
private readonly fieldDataLoaders: Map<
|
|
30
30
|
keyof TFields,
|
|
31
31
|
DataLoader<NonNullable<TFields[keyof TFields]>, readonly Readonly<TFields>[]>
|
|
@@ -36,30 +36,30 @@ export default class EntityDataManager<TFields> {
|
|
|
36
36
|
private readonly entityCache: ReadThroughEntityCache<TFields>,
|
|
37
37
|
private readonly queryContextProvider: EntityQueryContextProvider,
|
|
38
38
|
private readonly metricsAdapter: IEntityMetricsAdapter,
|
|
39
|
-
private readonly entityClassName: string
|
|
39
|
+
private readonly entityClassName: string,
|
|
40
40
|
) {}
|
|
41
41
|
|
|
42
42
|
private getFieldDataLoaderForFieldName<N extends keyof TFields>(
|
|
43
|
-
fieldName: N
|
|
43
|
+
fieldName: N,
|
|
44
44
|
): DataLoader<NonNullable<TFields[N]>, readonly Readonly<TFields>[]> {
|
|
45
45
|
return computeIfAbsent(this.fieldDataLoaders, fieldName, () => {
|
|
46
46
|
return new DataLoader(
|
|
47
47
|
async (
|
|
48
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
48
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
49
49
|
): Promise<readonly (readonly TFields[])[]> => {
|
|
50
50
|
const objectMap = await this.loadManyForDataLoaderByFieldEqualingAsync(
|
|
51
51
|
fieldName,
|
|
52
|
-
fieldValues
|
|
52
|
+
fieldValues,
|
|
53
53
|
);
|
|
54
54
|
return fieldValues.map((fv) => objectMap.get(fv) ?? []);
|
|
55
|
-
}
|
|
55
|
+
},
|
|
56
56
|
);
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
private async loadManyForDataLoaderByFieldEqualingAsync<N extends keyof TFields>(
|
|
61
61
|
fieldName: N,
|
|
62
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
62
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
63
63
|
): Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Readonly<TFields>[]>> {
|
|
64
64
|
this.metricsAdapter.incrementDataManagerLoadCount({
|
|
65
65
|
type: IncrementLoadCountEventType.CACHE,
|
|
@@ -78,9 +78,9 @@ export default class EntityDataManager<TFields> {
|
|
|
78
78
|
return await this.databaseAdapter.fetchManyWhereAsync(
|
|
79
79
|
this.queryContextProvider.getQueryContext(),
|
|
80
80
|
fieldName,
|
|
81
|
-
fetcherValues
|
|
81
|
+
fetcherValues,
|
|
82
82
|
);
|
|
83
|
-
}
|
|
83
|
+
},
|
|
84
84
|
);
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -95,28 +95,28 @@ export default class EntityDataManager<TFields> {
|
|
|
95
95
|
async loadManyByFieldEqualingAsync<N extends keyof TFields>(
|
|
96
96
|
queryContext: EntityQueryContext,
|
|
97
97
|
fieldName: N,
|
|
98
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
98
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
99
99
|
): Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Readonly<TFields>[]>> {
|
|
100
100
|
return await timeAndLogLoadMapEventAsync(
|
|
101
101
|
this.metricsAdapter,
|
|
102
102
|
EntityMetricsLoadType.LOAD_MANY,
|
|
103
|
-
this.entityClassName
|
|
103
|
+
this.entityClassName,
|
|
104
104
|
)(this.loadManyByFieldEqualingInternalAsync(queryContext, fieldName, fieldValues));
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
private async loadManyByFieldEqualingInternalAsync<N extends keyof TFields>(
|
|
108
108
|
queryContext: EntityQueryContext,
|
|
109
109
|
fieldName: N,
|
|
110
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
110
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
111
111
|
): Promise<ReadonlyMap<NonNullable<TFields[N]>, readonly Readonly<TFields>[]>> {
|
|
112
112
|
const nullOrUndefinedValueIndex = fieldValues.findIndex(
|
|
113
|
-
(value) => value === null || value === undefined
|
|
113
|
+
(value) => value === null || value === undefined,
|
|
114
114
|
);
|
|
115
115
|
if (nullOrUndefinedValueIndex >= 0) {
|
|
116
116
|
throw new Error(
|
|
117
117
|
`Invalid load: ${this.entityClassName} (${String(fieldName)} = ${
|
|
118
118
|
fieldValues[nullOrUndefinedValueIndex]
|
|
119
|
-
})
|
|
119
|
+
})`,
|
|
120
120
|
);
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -153,18 +153,18 @@ export default class EntityDataManager<TFields> {
|
|
|
153
153
|
async loadManyByFieldEqualityConjunctionAsync<N extends keyof TFields>(
|
|
154
154
|
queryContext: EntityQueryContext,
|
|
155
155
|
fieldEqualityOperands: FieldEqualityCondition<TFields, N>[],
|
|
156
|
-
querySelectionModifiers: QuerySelectionModifiers<TFields
|
|
156
|
+
querySelectionModifiers: QuerySelectionModifiers<TFields>,
|
|
157
157
|
): Promise<readonly Readonly<TFields>[]> {
|
|
158
158
|
return await timeAndLogLoadEventAsync(
|
|
159
159
|
this.metricsAdapter,
|
|
160
160
|
EntityMetricsLoadType.LOAD_MANY_EQUALITY_CONJUNCTION,
|
|
161
|
-
this.entityClassName
|
|
161
|
+
this.entityClassName,
|
|
162
162
|
)(
|
|
163
163
|
this.databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
|
|
164
164
|
queryContext,
|
|
165
165
|
fieldEqualityOperands,
|
|
166
|
-
querySelectionModifiers
|
|
167
|
-
)
|
|
166
|
+
querySelectionModifiers,
|
|
167
|
+
),
|
|
168
168
|
);
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -181,25 +181,25 @@ export default class EntityDataManager<TFields> {
|
|
|
181
181
|
queryContext: EntityQueryContext,
|
|
182
182
|
rawWhereClause: string,
|
|
183
183
|
bindings: any[] | object,
|
|
184
|
-
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields
|
|
184
|
+
querySelectionModifiers: QuerySelectionModifiersWithOrderByRaw<TFields>,
|
|
185
185
|
): Promise<readonly Readonly<TFields>[]> {
|
|
186
186
|
return await timeAndLogLoadEventAsync(
|
|
187
187
|
this.metricsAdapter,
|
|
188
188
|
EntityMetricsLoadType.LOAD_MANY_RAW,
|
|
189
|
-
this.entityClassName
|
|
189
|
+
this.entityClassName,
|
|
190
190
|
)(
|
|
191
191
|
this.databaseAdapter.fetchManyByRawWhereClauseAsync(
|
|
192
192
|
queryContext,
|
|
193
193
|
rawWhereClause,
|
|
194
194
|
bindings,
|
|
195
|
-
querySelectionModifiers
|
|
196
|
-
)
|
|
195
|
+
querySelectionModifiers,
|
|
196
|
+
),
|
|
197
197
|
);
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
private async invalidateManyByFieldEqualingAsync<N extends keyof TFields>(
|
|
201
201
|
fieldName: N,
|
|
202
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
202
|
+
fieldValues: readonly NonNullable<TFields[N]>[],
|
|
203
203
|
): Promise<void> {
|
|
204
204
|
await this.entityCache.invalidateManyAsync(fieldName, fieldValues);
|
|
205
205
|
const dataLoader = this.getFieldDataLoaderForFieldName(fieldName);
|
|
@@ -222,7 +222,7 @@ export default class EntityDataManager<TFields> {
|
|
|
222
222
|
value as NonNullable<TFields[keyof TFields]>,
|
|
223
223
|
]);
|
|
224
224
|
}
|
|
225
|
-
})
|
|
225
|
+
}),
|
|
226
226
|
);
|
|
227
227
|
}
|
|
228
228
|
}
|