@expo/entity 0.55.0 → 0.57.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/src/AuthorizationResultBasedEntityAssociationLoader.d.ts +1 -1
- package/build/src/AuthorizationResultBasedEntityAssociationLoader.js.map +1 -1
- package/build/src/AuthorizationResultBasedEntityLoader.d.ts +18 -24
- package/build/src/AuthorizationResultBasedEntityLoader.js +37 -56
- package/build/src/AuthorizationResultBasedEntityLoader.js.map +1 -1
- package/build/src/AuthorizationResultBasedEntityMutator.js +26 -19
- package/build/src/AuthorizationResultBasedEntityMutator.js.map +1 -1
- package/build/src/EnforcingEntityCreator.d.ts +1 -1
- package/build/src/EnforcingEntityCreator.js +1 -1
- package/build/src/EnforcingEntityLoader.d.ts +1 -58
- package/build/src/EnforcingEntityLoader.js +0 -65
- package/build/src/EnforcingEntityLoader.js.map +1 -1
- package/build/src/Entity.d.ts +6 -0
- package/build/src/Entity.js +6 -0
- package/build/src/Entity.js.map +1 -1
- package/build/src/EntityCompanion.d.ts +2 -2
- package/build/src/EntityCompanion.js.map +1 -1
- package/build/src/EntityCompanionProvider.d.ts +1 -1
- package/build/src/EntityCompanionProvider.js +4 -4
- package/build/src/EntityConfiguration.d.ts +1 -1
- package/build/src/EntityConfiguration.js +1 -2
- package/build/src/EntityConfiguration.js.map +1 -1
- package/build/src/{EntityLoaderUtils.d.ts → EntityConstructionUtils.d.ts} +15 -29
- package/build/src/EntityConstructionUtils.js +118 -0
- package/build/src/EntityConstructionUtils.js.map +1 -0
- package/build/src/EntityDatabaseAdapter.d.ts +10 -108
- package/build/src/EntityDatabaseAdapter.js +14 -76
- package/build/src/EntityDatabaseAdapter.js.map +1 -1
- package/build/src/EntityFieldDefinition.d.ts +1 -1
- package/build/src/EntityInvalidationUtils.d.ts +41 -0
- package/build/src/EntityInvalidationUtils.js +71 -0
- package/build/src/EntityInvalidationUtils.js.map +1 -0
- package/build/src/EntityLoader.d.ts +0 -6
- package/build/src/EntityLoader.js +0 -7
- package/build/src/EntityLoader.js.map +1 -1
- package/build/src/EntityLoaderFactory.d.ts +4 -0
- package/build/src/EntityLoaderFactory.js +10 -3
- package/build/src/EntityLoaderFactory.js.map +1 -1
- package/build/src/EntityPrivacyPolicy.d.ts +27 -0
- package/build/src/EntityPrivacyPolicy.js +22 -1
- package/build/src/EntityPrivacyPolicy.js.map +1 -1
- package/build/src/EntitySecondaryCacheLoader.d.ts +14 -3
- package/build/src/EntitySecondaryCacheLoader.js +21 -4
- package/build/src/EntitySecondaryCacheLoader.js.map +1 -1
- package/build/src/ReadonlyEntity.d.ts +4 -5
- package/build/src/ReadonlyEntity.js +7 -8
- package/build/src/ReadonlyEntity.js.map +1 -1
- package/build/src/ViewerContext.d.ts +6 -6
- package/build/src/ViewerContext.js +8 -8
- package/build/src/ViewerScopedEntityCompanion.d.ts +1 -1
- package/build/src/ViewerScopedEntityCompanion.js.map +1 -1
- package/build/src/ViewerScopedEntityLoaderFactory.d.ts +4 -0
- package/build/src/ViewerScopedEntityLoaderFactory.js +6 -0
- package/build/src/ViewerScopedEntityLoaderFactory.js.map +1 -1
- package/build/src/errors/EntityDatabaseAdapterError.d.ts +4 -0
- package/build/src/errors/EntityDatabaseAdapterError.js +13 -1
- package/build/src/errors/EntityDatabaseAdapterError.js.map +1 -1
- package/build/src/errors/EntityError.d.ts +2 -1
- package/build/src/errors/EntityError.js +1 -0
- package/build/src/errors/EntityError.js.map +1 -1
- package/build/src/index.d.ts +2 -1
- package/build/src/index.js +2 -1
- package/build/src/index.js.map +1 -1
- package/build/src/internal/EntityDataManager.d.ts +8 -16
- package/build/src/internal/EntityDataManager.js +8 -18
- package/build/src/internal/EntityDataManager.js.map +1 -1
- package/build/src/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/src/internal/EntityLoadInterfaces.d.ts +2 -0
- package/build/src/internal/EntityLoadInterfaces.js +2 -0
- package/build/src/internal/EntityLoadInterfaces.js.map +1 -1
- package/build/src/internal/EntityTableDataCoordinator.d.ts +2 -0
- package/build/src/internal/EntityTableDataCoordinator.js +4 -0
- package/build/src/internal/EntityTableDataCoordinator.js.map +1 -1
- package/build/src/metrics/EntityMetricsUtils.d.ts +1 -0
- package/build/src/metrics/EntityMetricsUtils.js +15 -1
- package/build/src/metrics/EntityMetricsUtils.js.map +1 -1
- package/build/src/metrics/IEntityMetricsAdapter.d.ts +4 -1
- package/build/src/metrics/IEntityMetricsAdapter.js +3 -0
- package/build/src/metrics/IEntityMetricsAdapter.js.map +1 -1
- package/build/src/rules/AllowIfAllSubRulesAllowPrivacyPolicyRule.d.ts +2 -2
- package/build/src/rules/AllowIfAnySubRuleAllowsPrivacyPolicyRule.d.ts +2 -2
- package/build/src/rules/EvaluateIfEntityFieldPredicatePrivacyPolicyRule.d.ts +2 -2
- package/build/src/rules/PrivacyPolicyRule.d.ts +2 -2
- package/build/src/utils/EntityPrivacyUtils.js +11 -20
- package/build/src/utils/EntityPrivacyUtils.js.map +1 -1
- package/build/src/utils/collections/maps.d.ts +2 -2
- package/build/src/utils/collections/maps.js +2 -2
- package/package.json +4 -4
- package/src/AuthorizationResultBasedEntityAssociationLoader.ts +4 -7
- package/src/AuthorizationResultBasedEntityLoader.ts +58 -88
- package/src/AuthorizationResultBasedEntityMutator.ts +35 -20
- package/src/EnforcingEntityCreator.ts +1 -1
- package/src/EnforcingEntityLoader.ts +1 -95
- package/src/Entity.ts +6 -0
- package/src/EntityCompanion.ts +2 -2
- package/src/EntityCompanionProvider.ts +4 -4
- package/src/EntityConfiguration.ts +8 -5
- package/src/EntityConstructionUtils.ts +168 -0
- package/src/EntityDatabaseAdapter.ts +32 -222
- package/src/EntityFieldDefinition.ts +1 -1
- package/src/{EntityLoaderUtils.ts → EntityInvalidationUtils.ts} +5 -96
- package/src/EntityLoader.ts +0 -16
- package/src/EntityLoaderFactory.ts +50 -10
- package/src/EntityPrivacyPolicy.ts +44 -1
- package/src/EntitySecondaryCacheLoader.ts +54 -3
- package/src/ReadonlyEntity.ts +9 -11
- package/src/ViewerContext.ts +10 -10
- package/src/ViewerScopedEntityCompanion.ts +1 -1
- package/src/ViewerScopedEntityLoaderFactory.ts +37 -0
- package/src/__tests__/AuthorizationResultBasedEntityLoader-constructor-test.ts +3 -5
- package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +34 -419
- package/src/__tests__/ComposedCacheAdapter-test.ts +3 -3
- package/src/__tests__/EnforcingEntityLoader-test.ts +2 -134
- package/src/__tests__/EntityCompanion-test.ts +18 -0
- package/src/__tests__/EntityConfiguration-test.ts +4 -4
- package/src/__tests__/EntityDatabaseAdapter-test.ts +33 -68
- package/src/__tests__/EntityEdges-test.ts +10 -10
- package/src/__tests__/EntityLoader-test.ts +6 -4
- package/src/__tests__/EntityMutator-test.ts +27 -15
- package/src/__tests__/EntityPrivacyPolicy-test.ts +102 -0
- package/src/__tests__/EntityQueryContext-test.ts +11 -11
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +10 -5
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +6 -6
- package/src/__tests__/GenericEntityCacheAdapter-test.ts +18 -15
- package/src/__tests__/GenericSecondaryEntityCache-test.ts +27 -5
- package/src/__tests__/ReadonlyEntity-test.ts +6 -4
- package/src/__tests__/ViewerContext-test.ts +4 -4
- package/src/__tests__/ViewerScopedEntityCompanion-test.ts +1 -0
- package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +0 -17
- package/src/errors/EntityDatabaseAdapterError.ts +14 -0
- package/src/errors/EntityError.ts +1 -0
- package/src/errors/__tests__/EntityDatabaseAdapterError-test.ts +9 -0
- package/src/errors/__tests__/EntityError-test.ts +13 -5
- package/src/index.ts +2 -1
- package/src/internal/EntityDataManager.ts +19 -54
- package/src/internal/EntityFieldTransformationUtils.ts +5 -5
- package/src/internal/EntityLoadInterfaces.ts +2 -0
- package/src/internal/EntityTableDataCoordinator.ts +2 -2
- package/src/internal/__tests__/CompositeFieldHolder-test.ts +8 -2
- package/src/internal/__tests__/EntityDataManager-test.ts +71 -202
- package/src/internal/__tests__/ReadThroughEntityCache-test.ts +39 -24
- package/src/metrics/EntityMetricsUtils.ts +23 -0
- package/src/metrics/IEntityMetricsAdapter.ts +3 -0
- package/src/metrics/__tests__/EntityMetricsUtils-test.ts +120 -0
- package/src/rules/AllowIfAllSubRulesAllowPrivacyPolicyRule.ts +2 -2
- package/src/rules/AllowIfAnySubRuleAllowsPrivacyPolicyRule.ts +2 -2
- package/src/rules/EvaluateIfEntityFieldPredicatePrivacyPolicyRule.ts +2 -2
- package/src/rules/PrivacyPolicyRule.ts +2 -2
- package/src/rules/__tests__/AllowIfAllSubRulesAllowPrivacyPolicyRule-test.ts +4 -4
- package/src/rules/__tests__/AllowIfAnySubRuleAllowsPrivacyPolicyRule-test.ts +4 -4
- package/src/rules/__tests__/AllowIfInParentCascadeDeletionPrivacyPolicyRule-test.ts +11 -1
- package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -2
- package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -2
- package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -2
- package/src/rules/__tests__/EvaluateIfEntityFieldPredicatePrivacyPolicyRule-test.ts +3 -3
- package/src/utils/EntityPrivacyUtils.ts +18 -29
- package/src/utils/__testfixtures__/PrivacyPolicyRuleTestUtils.ts +2 -2
- package/src/utils/__testfixtures__/StubDatabaseAdapter.ts +13 -101
- package/src/utils/__tests__/EntityCreationUtils-test.ts +6 -6
- package/src/utils/__tests__/EntityPrivacyUtils-test.ts +2 -2
- package/src/utils/collections/maps.ts +2 -2
- package/build/src/EntityLoaderUtils.js +0 -147
- package/build/src/EntityLoaderUtils.js.map +0 -1
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
EntityPrivacyPolicyEvaluationContext,
|
|
12
12
|
EntityPrivacyPolicyEvaluationMode,
|
|
13
13
|
EntityPrivacyPolicyEvaluator,
|
|
14
|
+
EntityPrivacyPolicyRuleEvaluationContext,
|
|
14
15
|
} from '../EntityPrivacyPolicy';
|
|
15
16
|
import { EntityQueryContext } from '../EntityQueryContext';
|
|
16
17
|
import { ViewerContext } from '../ViewerContext';
|
|
@@ -273,6 +274,47 @@ class EmptyPolicy extends EntityPrivacyPolicy<BlahFields, 'id', ViewerContext, B
|
|
|
273
274
|
protected override readonly deleteRules = [];
|
|
274
275
|
}
|
|
275
276
|
|
|
277
|
+
class ContextCapturingRule extends PrivacyPolicyRule<BlahFields, 'id', ViewerContext, BlahEntity> {
|
|
278
|
+
public capturedContext: EntityPrivacyPolicyRuleEvaluationContext<
|
|
279
|
+
BlahFields,
|
|
280
|
+
'id',
|
|
281
|
+
ViewerContext,
|
|
282
|
+
BlahEntity
|
|
283
|
+
> | null = null;
|
|
284
|
+
|
|
285
|
+
async evaluateAsync(
|
|
286
|
+
_viewerContext: ViewerContext,
|
|
287
|
+
_queryContext: EntityQueryContext,
|
|
288
|
+
evaluationContext: EntityPrivacyPolicyRuleEvaluationContext<
|
|
289
|
+
BlahFields,
|
|
290
|
+
'id',
|
|
291
|
+
ViewerContext,
|
|
292
|
+
BlahEntity
|
|
293
|
+
>,
|
|
294
|
+
_entity: BlahEntity,
|
|
295
|
+
): Promise<RuleEvaluationResult> {
|
|
296
|
+
this.capturedContext = evaluationContext;
|
|
297
|
+
return RuleEvaluationResult.ALLOW;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
class ContextCapturingPolicy extends EntityPrivacyPolicy<
|
|
302
|
+
BlahFields,
|
|
303
|
+
'id',
|
|
304
|
+
ViewerContext,
|
|
305
|
+
BlahEntity
|
|
306
|
+
> {
|
|
307
|
+
public readonly createRule = new ContextCapturingRule();
|
|
308
|
+
public readonly readRule = new ContextCapturingRule();
|
|
309
|
+
public readonly updateRule = new ContextCapturingRule();
|
|
310
|
+
public readonly deleteRule = new ContextCapturingRule();
|
|
311
|
+
|
|
312
|
+
protected override readonly createRules = [this.createRule];
|
|
313
|
+
protected override readonly readRules = [this.readRule];
|
|
314
|
+
protected override readonly updateRules = [this.updateRule];
|
|
315
|
+
protected override readonly deleteRules = [this.deleteRule];
|
|
316
|
+
}
|
|
317
|
+
|
|
276
318
|
describe(EntityPrivacyPolicy, () => {
|
|
277
319
|
describe(EntityPrivacyPolicyEvaluationMode.ENFORCE.toString(), () => {
|
|
278
320
|
it('throws EntityNotAuthorizedError when deny', async () => {
|
|
@@ -718,4 +760,64 @@ describe(EntityPrivacyPolicy, () => {
|
|
|
718
760
|
verify(metricsAdapterMock.logAuthorizationEvent(anything())).never();
|
|
719
761
|
});
|
|
720
762
|
});
|
|
763
|
+
|
|
764
|
+
describe('EntityPrivacyPolicyRuleEvaluationContext', () => {
|
|
765
|
+
it('passes correct authorization action to rules for each CRUD operation', async () => {
|
|
766
|
+
const viewerContext = instance(mock(ViewerContext));
|
|
767
|
+
const queryContext = instance(mock(EntityQueryContext));
|
|
768
|
+
const privacyPolicyEvaluationContext: EntityPrivacyPolicyEvaluationContext<
|
|
769
|
+
BlahFields,
|
|
770
|
+
'id',
|
|
771
|
+
ViewerContext,
|
|
772
|
+
BlahEntity
|
|
773
|
+
> = {
|
|
774
|
+
previousValue: null,
|
|
775
|
+
cascadingDeleteCause: null,
|
|
776
|
+
};
|
|
777
|
+
const metricsAdapter = instance(mock<IEntityMetricsAdapter>());
|
|
778
|
+
const entity = new BlahEntity({
|
|
779
|
+
viewerContext,
|
|
780
|
+
id: '1',
|
|
781
|
+
databaseFields: { id: '1' },
|
|
782
|
+
selectedFields: { id: '1' },
|
|
783
|
+
});
|
|
784
|
+
const policy = new ContextCapturingPolicy();
|
|
785
|
+
|
|
786
|
+
await policy.authorizeCreateAsync(
|
|
787
|
+
viewerContext,
|
|
788
|
+
queryContext,
|
|
789
|
+
privacyPolicyEvaluationContext,
|
|
790
|
+
entity,
|
|
791
|
+
metricsAdapter,
|
|
792
|
+
);
|
|
793
|
+
expect(policy.createRule.capturedContext?.action).toBe(EntityAuthorizationAction.CREATE);
|
|
794
|
+
|
|
795
|
+
await policy.authorizeReadAsync(
|
|
796
|
+
viewerContext,
|
|
797
|
+
queryContext,
|
|
798
|
+
privacyPolicyEvaluationContext,
|
|
799
|
+
entity,
|
|
800
|
+
metricsAdapter,
|
|
801
|
+
);
|
|
802
|
+
expect(policy.readRule.capturedContext?.action).toBe(EntityAuthorizationAction.READ);
|
|
803
|
+
|
|
804
|
+
await policy.authorizeUpdateAsync(
|
|
805
|
+
viewerContext,
|
|
806
|
+
queryContext,
|
|
807
|
+
privacyPolicyEvaluationContext,
|
|
808
|
+
entity,
|
|
809
|
+
metricsAdapter,
|
|
810
|
+
);
|
|
811
|
+
expect(policy.updateRule.capturedContext?.action).toBe(EntityAuthorizationAction.UPDATE);
|
|
812
|
+
|
|
813
|
+
await policy.authorizeDeleteAsync(
|
|
814
|
+
viewerContext,
|
|
815
|
+
queryContext,
|
|
816
|
+
privacyPolicyEvaluationContext,
|
|
817
|
+
entity,
|
|
818
|
+
metricsAdapter,
|
|
819
|
+
);
|
|
820
|
+
expect(policy.deleteRule.capturedContext?.action).toBe(EntityAuthorizationAction.DELETE);
|
|
821
|
+
});
|
|
822
|
+
});
|
|
721
823
|
});
|
|
@@ -49,7 +49,7 @@ describe(EntityQueryContext, () => {
|
|
|
49
49
|
);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
await viewerContext.
|
|
52
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
53
53
|
'postgres',
|
|
54
54
|
async (queryContext) => {
|
|
55
55
|
queryContext.appendPostCommitCallback(postCommitCallback);
|
|
@@ -76,7 +76,7 @@ describe(EntityQueryContext, () => {
|
|
|
76
76
|
const postCommitCallback = jest.fn(async (): Promise<void> => {});
|
|
77
77
|
|
|
78
78
|
await expect(
|
|
79
|
-
viewerContext.
|
|
79
|
+
viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
80
80
|
'postgres',
|
|
81
81
|
async (queryContext) => {
|
|
82
82
|
queryContext.appendPostCommitCallback(postCommitCallback);
|
|
@@ -105,7 +105,7 @@ describe(EntityQueryContext, () => {
|
|
|
105
105
|
const postCommitCallback = jest.fn(async (): Promise<void> => {});
|
|
106
106
|
const postCommitNestedCallback = jest.fn(async (): Promise<void> => {});
|
|
107
107
|
|
|
108
|
-
await viewerContext.
|
|
108
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
109
109
|
'postgres',
|
|
110
110
|
async (queryContext) => {
|
|
111
111
|
queryContext.appendPostCommitCallback(postCommitCallback);
|
|
@@ -152,13 +152,13 @@ describe(EntityQueryContext, () => {
|
|
|
152
152
|
const viewerContext = new ViewerContext(companionProvider);
|
|
153
153
|
|
|
154
154
|
const queryContextProvider =
|
|
155
|
-
companionProvider.
|
|
155
|
+
companionProvider.getQueryContextProviderForDatabaseAdapterFlavor('postgres');
|
|
156
156
|
const queryContextProviderSpy = jest.spyOn(queryContextProvider, 'runInTransactionAsync');
|
|
157
157
|
|
|
158
158
|
const transactionScopeFn = async (): Promise<any> => {};
|
|
159
159
|
const transactionConfig = { isolationLevel: TransactionIsolationLevel.SERIALIZABLE };
|
|
160
160
|
|
|
161
|
-
await viewerContext.
|
|
161
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
162
162
|
'postgres',
|
|
163
163
|
transactionScopeFn,
|
|
164
164
|
transactionConfig,
|
|
@@ -171,7 +171,7 @@ describe(EntityQueryContext, () => {
|
|
|
171
171
|
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
172
172
|
const viewerContext = new ViewerContext(companionProvider);
|
|
173
173
|
|
|
174
|
-
await viewerContext.
|
|
174
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
175
175
|
'postgres',
|
|
176
176
|
async (queryContext) => {
|
|
177
177
|
assert(queryContext.isInTransaction());
|
|
@@ -182,7 +182,7 @@ describe(EntityQueryContext, () => {
|
|
|
182
182
|
{ transactionalDataLoaderMode: TransactionalDataLoaderMode.DISABLED },
|
|
183
183
|
);
|
|
184
184
|
|
|
185
|
-
await viewerContext.
|
|
185
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
186
186
|
'postgres',
|
|
187
187
|
async (queryContext) => {
|
|
188
188
|
assert(queryContext.isInTransaction());
|
|
@@ -193,7 +193,7 @@ describe(EntityQueryContext, () => {
|
|
|
193
193
|
{ transactionalDataLoaderMode: TransactionalDataLoaderMode.ENABLED_BATCH_ONLY },
|
|
194
194
|
);
|
|
195
195
|
|
|
196
|
-
await viewerContext.
|
|
196
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
197
197
|
'postgres',
|
|
198
198
|
async (queryContext) => {
|
|
199
199
|
assert(queryContext.isInTransaction());
|
|
@@ -252,7 +252,7 @@ describe(EntityQueryContext, () => {
|
|
|
252
252
|
);
|
|
253
253
|
const viewerContext = new ViewerContext(companionProvider);
|
|
254
254
|
|
|
255
|
-
await viewerContext.
|
|
255
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
256
256
|
'postgres',
|
|
257
257
|
async (queryContext) => {
|
|
258
258
|
assert(queryContext.isInTransaction());
|
|
@@ -263,7 +263,7 @@ describe(EntityQueryContext, () => {
|
|
|
263
263
|
{ transactionalDataLoaderMode: TransactionalDataLoaderMode.DISABLED },
|
|
264
264
|
);
|
|
265
265
|
|
|
266
|
-
await viewerContext.
|
|
266
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
267
267
|
'postgres',
|
|
268
268
|
async (queryContext) => {
|
|
269
269
|
assert(queryContext.isInTransaction());
|
|
@@ -274,7 +274,7 @@ describe(EntityQueryContext, () => {
|
|
|
274
274
|
{ transactionalDataLoaderMode: TransactionalDataLoaderMode.ENABLED_BATCH_ONLY },
|
|
275
275
|
);
|
|
276
276
|
|
|
277
|
-
await viewerContext.
|
|
277
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
278
278
|
'postgres',
|
|
279
279
|
async (queryContext) => {
|
|
280
280
|
assert(queryContext.isInTransaction());
|
|
@@ -46,7 +46,7 @@ describe(EntitySecondaryCacheLoader, () => {
|
|
|
46
46
|
|
|
47
47
|
const secondaryCacheLoader = new TestSecondaryRedisCacheLoader(
|
|
48
48
|
secondaryEntityCache,
|
|
49
|
-
|
|
49
|
+
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(SimpleTestEntity, vc1),
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
await secondaryCacheLoader.loadManyAsync([loadParams]);
|
|
@@ -70,8 +70,11 @@ describe(EntitySecondaryCacheLoader, () => {
|
|
|
70
70
|
const secondaryEntityCache = instance(secondaryEntityCacheMock);
|
|
71
71
|
|
|
72
72
|
const loader = SimpleTestEntity.loaderWithAuthorizationResults(vc1);
|
|
73
|
-
const spiedPrivacyPolicy = spy(loader
|
|
74
|
-
const secondaryCacheLoader = new TestSecondaryRedisCacheLoader(
|
|
73
|
+
const spiedPrivacyPolicy = spy(loader['constructionUtils']['privacyPolicy']);
|
|
74
|
+
const secondaryCacheLoader = new TestSecondaryRedisCacheLoader(
|
|
75
|
+
secondaryEntityCache,
|
|
76
|
+
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(SimpleTestEntity, vc1),
|
|
77
|
+
);
|
|
75
78
|
|
|
76
79
|
const result = await secondaryCacheLoader.loadManyAsync([loadParams]);
|
|
77
80
|
expect(result.get(loadParams)?.enforceValue().getID()).toEqual(createdEntity.getID());
|
|
@@ -98,8 +101,10 @@ describe(EntitySecondaryCacheLoader, () => {
|
|
|
98
101
|
const secondaryEntityCacheMock =
|
|
99
102
|
mock<ISecondaryEntityCache<SimpleTestFields, TestLoadParams>>();
|
|
100
103
|
const secondaryEntityCache = instance(secondaryEntityCacheMock);
|
|
101
|
-
const
|
|
102
|
-
|
|
104
|
+
const secondaryCacheLoader = new TestSecondaryRedisCacheLoader(
|
|
105
|
+
secondaryEntityCache,
|
|
106
|
+
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(SimpleTestEntity, vc1),
|
|
107
|
+
);
|
|
103
108
|
await secondaryCacheLoader.invalidateManyAsync([loadParams]);
|
|
104
109
|
|
|
105
110
|
verify(secondaryEntityCacheMock.invalidateManyAsync(deepEqual([loadParams]))).once();
|
|
@@ -250,7 +250,7 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
250
250
|
'cacheAdapter'
|
|
251
251
|
] as InMemoryFullCacheStubCacheAdapter<CategoryFields, 'id'>;
|
|
252
252
|
const subCategoryCachedBefore = await categoryCacheAdapter.loadManyAsync(
|
|
253
|
-
new SingleFieldHolder('parent_category_id'),
|
|
253
|
+
new SingleFieldHolder<CategoryFields, 'id', 'parent_category_id'>('parent_category_id'),
|
|
254
254
|
[new SingleFieldValueHolder(parentCategory.getID())],
|
|
255
255
|
);
|
|
256
256
|
expect(
|
|
@@ -258,7 +258,7 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
258
258
|
).toEqual(CacheStatus.HIT);
|
|
259
259
|
|
|
260
260
|
const subSubCategoryCachedBefore = await categoryCacheAdapter.loadManyAsync(
|
|
261
|
-
new SingleFieldHolder('parent_category_id'),
|
|
261
|
+
new SingleFieldHolder<CategoryFields, 'id', 'parent_category_id'>('parent_category_id'),
|
|
262
262
|
[new SingleFieldValueHolder(subCategory.getID())],
|
|
263
263
|
);
|
|
264
264
|
expect(
|
|
@@ -268,7 +268,7 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
268
268
|
await CategoryEntity.deleter(parentCategory).deleteAsync();
|
|
269
269
|
|
|
270
270
|
const subCategoryCachedAfter = await categoryCacheAdapter.loadManyAsync(
|
|
271
|
-
new SingleFieldHolder('parent_category_id'),
|
|
271
|
+
new SingleFieldHolder<CategoryFields, 'id', 'parent_category_id'>('parent_category_id'),
|
|
272
272
|
[new SingleFieldValueHolder(parentCategory.getID())],
|
|
273
273
|
);
|
|
274
274
|
expect(
|
|
@@ -276,7 +276,7 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
276
276
|
).toEqual(CacheStatus.MISS);
|
|
277
277
|
|
|
278
278
|
const subSubCategoryCachedAfter = await categoryCacheAdapter.loadManyAsync(
|
|
279
|
-
new SingleFieldHolder('parent_category_id'),
|
|
279
|
+
new SingleFieldHolder<CategoryFields, 'id', 'parent_category_id'>('parent_category_id'),
|
|
280
280
|
[new SingleFieldValueHolder(subCategory.getID())],
|
|
281
281
|
);
|
|
282
282
|
expect(
|
|
@@ -329,7 +329,7 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
329
329
|
'cacheAdapter'
|
|
330
330
|
] as InMemoryFullCacheStubCacheAdapter<CategoryFields, 'id'>;
|
|
331
331
|
const categoriesCachedBefore = await categoryCacheAdapter.loadManyAsync(
|
|
332
|
-
new SingleFieldHolder('parent_category_id'),
|
|
332
|
+
new SingleFieldHolder<CategoryFields, 'id', 'parent_category_id'>('parent_category_id'),
|
|
333
333
|
[
|
|
334
334
|
new SingleFieldValueHolder(categoryA.getID()),
|
|
335
335
|
new SingleFieldValueHolder(categoryB.getID()),
|
|
@@ -345,7 +345,7 @@ describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE', () => {
|
|
|
345
345
|
await CategoryEntity.deleter(categoryA).deleteAsync();
|
|
346
346
|
|
|
347
347
|
const categoriesCachedAfter = await categoryCacheAdapter.loadManyAsync(
|
|
348
|
-
new SingleFieldHolder('parent_category_id'),
|
|
348
|
+
new SingleFieldHolder<CategoryFields, 'id', 'parent_category_id'>('parent_category_id'),
|
|
349
349
|
[
|
|
350
350
|
new SingleFieldValueHolder(categoryA.getID()),
|
|
351
351
|
new SingleFieldValueHolder(categoryB.getID()),
|
|
@@ -22,7 +22,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
22
22
|
const mockGenericCacher = mock<IEntityGenericCacher<BlahFields, 'id'>>();
|
|
23
23
|
when(
|
|
24
24
|
mockGenericCacher.makeCacheKeyForStorage(
|
|
25
|
-
deepEqualEntityAware(new SingleFieldHolder('id')),
|
|
25
|
+
deepEqualEntityAware(new SingleFieldHolder<BlahFields, 'id', 'id'>('id')),
|
|
26
26
|
anything(),
|
|
27
27
|
),
|
|
28
28
|
).thenCall((fieldHolder, fieldValueHolder) => {
|
|
@@ -38,11 +38,14 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
38
38
|
|
|
39
39
|
const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
|
|
40
40
|
|
|
41
|
-
const results = await cacheAdapter.loadManyAsync(
|
|
42
|
-
new
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
const results = await cacheAdapter.loadManyAsync(
|
|
42
|
+
new SingleFieldHolder<BlahFields, 'id', 'id'>('id'),
|
|
43
|
+
[
|
|
44
|
+
new SingleFieldValueHolder('wat'),
|
|
45
|
+
new SingleFieldValueHolder('who'),
|
|
46
|
+
new SingleFieldValueHolder('why'),
|
|
47
|
+
],
|
|
48
|
+
);
|
|
46
49
|
expect(results.get(new SingleFieldValueHolder('wat'))).toMatchObject({
|
|
47
50
|
status: CacheStatus.HIT,
|
|
48
51
|
item: { id: 'wat' },
|
|
@@ -74,7 +77,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
74
77
|
const mockGenericCacher = mock<IEntityGenericCacher<BlahFields, 'id'>>();
|
|
75
78
|
when(
|
|
76
79
|
mockGenericCacher.makeCacheKeyForStorage(
|
|
77
|
-
deepEqualEntityAware(new SingleFieldHolder('id')),
|
|
80
|
+
deepEqualEntityAware(new SingleFieldHolder<BlahFields, 'id', 'id'>('id')),
|
|
78
81
|
anything(),
|
|
79
82
|
),
|
|
80
83
|
).thenCall((fieldHolder, fieldValueHolder) => {
|
|
@@ -85,7 +88,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
85
88
|
|
|
86
89
|
const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
|
|
87
90
|
await expect(
|
|
88
|
-
cacheAdapter.loadManyAsync(new SingleFieldHolder('id'), [
|
|
91
|
+
cacheAdapter.loadManyAsync(new SingleFieldHolder<BlahFields, 'id', 'id'>('id'), [
|
|
89
92
|
new SingleFieldValueHolder('wat'),
|
|
90
93
|
]),
|
|
91
94
|
).rejects.toThrow(expectedError);
|
|
@@ -99,7 +102,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
99
102
|
const mockGenericCacher = mock<IEntityGenericCacher<BlahFields, 'id'>>();
|
|
100
103
|
when(
|
|
101
104
|
mockGenericCacher.makeCacheKeyForStorage(
|
|
102
|
-
deepEqualEntityAware(new SingleFieldHolder('id')),
|
|
105
|
+
deepEqualEntityAware(new SingleFieldHolder<BlahFields, 'id', 'id'>('id')),
|
|
103
106
|
anything(),
|
|
104
107
|
),
|
|
105
108
|
).thenCall((fieldHolder, fieldValueHolder) => {
|
|
@@ -108,7 +111,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
108
111
|
|
|
109
112
|
const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
|
|
110
113
|
await cacheAdapter.cacheManyAsync(
|
|
111
|
-
new SingleFieldHolder('id'),
|
|
114
|
+
new SingleFieldHolder<BlahFields, 'id', 'id'>('id'),
|
|
112
115
|
new Map([[new SingleFieldValueHolder('wat'), { id: 'wat' }]]),
|
|
113
116
|
);
|
|
114
117
|
|
|
@@ -123,7 +126,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
123
126
|
const mockGenericCacher = mock<IEntityGenericCacher<BlahFields, 'id'>>();
|
|
124
127
|
when(
|
|
125
128
|
mockGenericCacher.makeCacheKeyForStorage(
|
|
126
|
-
deepEqualEntityAware(new SingleFieldHolder('id')),
|
|
129
|
+
deepEqualEntityAware(new SingleFieldHolder<BlahFields, 'id', 'id'>('id')),
|
|
127
130
|
anything(),
|
|
128
131
|
),
|
|
129
132
|
).thenCall((fieldHolder, fieldValueHolder) => {
|
|
@@ -131,7 +134,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
131
134
|
});
|
|
132
135
|
|
|
133
136
|
const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
|
|
134
|
-
await cacheAdapter.cacheDBMissesAsync(new SingleFieldHolder('id'), [
|
|
137
|
+
await cacheAdapter.cacheDBMissesAsync(new SingleFieldHolder<BlahFields, 'id', 'id'>('id'), [
|
|
135
138
|
new SingleFieldValueHolder('wat'),
|
|
136
139
|
]);
|
|
137
140
|
|
|
@@ -144,7 +147,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
144
147
|
const mockGenericCacher = mock<IEntityGenericCacher<BlahFields, 'id'>>();
|
|
145
148
|
when(
|
|
146
149
|
mockGenericCacher.makeCacheKeysForInvalidation(
|
|
147
|
-
deepEqualEntityAware(new SingleFieldHolder('id')),
|
|
150
|
+
deepEqualEntityAware(new SingleFieldHolder<BlahFields, 'id', 'id'>('id')),
|
|
148
151
|
anything(),
|
|
149
152
|
),
|
|
150
153
|
).thenCall((fieldHolder, fieldValueHolder) => {
|
|
@@ -152,7 +155,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
152
155
|
});
|
|
153
156
|
|
|
154
157
|
const cacheAdapter = new GenericEntityCacheAdapter(instance(mockGenericCacher));
|
|
155
|
-
await cacheAdapter.invalidateManyAsync(new SingleFieldHolder('id'), [
|
|
158
|
+
await cacheAdapter.invalidateManyAsync(new SingleFieldHolder<BlahFields, 'id', 'id'>('id'), [
|
|
156
159
|
new SingleFieldValueHolder('wat'),
|
|
157
160
|
]);
|
|
158
161
|
|
|
@@ -163,7 +166,7 @@ describe(GenericEntityCacheAdapter, () => {
|
|
|
163
166
|
const mockGenericCacher = mock<IEntityGenericCacher<BlahFields, 'id'>>();
|
|
164
167
|
when(
|
|
165
168
|
mockGenericCacher.makeCacheKeysForInvalidation(
|
|
166
|
-
deepEqualEntityAware(new SingleFieldHolder('id')),
|
|
169
|
+
deepEqualEntityAware(new SingleFieldHolder<BlahFields, 'id', 'id'>('id')),
|
|
167
170
|
anything(),
|
|
168
171
|
),
|
|
169
172
|
).thenCall((fieldHolder, fieldValueHolder) => {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { describe, it, expect } from '@jest/globals';
|
|
2
2
|
import nullthrows from 'nullthrows';
|
|
3
3
|
|
|
4
|
+
import { AuthorizationResultBasedEntityLoader } from '../AuthorizationResultBasedEntityLoader';
|
|
5
|
+
import { EntityConstructionUtils } from '../EntityConstructionUtils';
|
|
4
6
|
import { EntitySecondaryCacheLoader } from '../EntitySecondaryCacheLoader';
|
|
5
7
|
import { GenericSecondaryEntityCache } from '../GenericSecondaryEntityCache';
|
|
6
8
|
import { IEntityGenericCacher } from '../IEntityGenericCacher';
|
|
@@ -100,6 +102,28 @@ class TestSecondaryCacheLoader extends EntitySecondaryCacheLoader<
|
|
|
100
102
|
> {
|
|
101
103
|
public databaseLoadCount = 0;
|
|
102
104
|
|
|
105
|
+
constructor(
|
|
106
|
+
secondaryEntityCache: TestSecondaryEntityCache<TestFields, 'customIdField', TestLoadParams>,
|
|
107
|
+
constructionUtils: EntityConstructionUtils<
|
|
108
|
+
TestFields,
|
|
109
|
+
'customIdField',
|
|
110
|
+
ViewerContext,
|
|
111
|
+
TestEntity,
|
|
112
|
+
TestEntityPrivacyPolicy,
|
|
113
|
+
keyof TestFields
|
|
114
|
+
>,
|
|
115
|
+
private readonly entityLoader: AuthorizationResultBasedEntityLoader<
|
|
116
|
+
TestFields,
|
|
117
|
+
'customIdField',
|
|
118
|
+
ViewerContext,
|
|
119
|
+
TestEntity,
|
|
120
|
+
TestEntityPrivacyPolicy,
|
|
121
|
+
keyof TestFields
|
|
122
|
+
>,
|
|
123
|
+
) {
|
|
124
|
+
super(secondaryEntityCache, constructionUtils);
|
|
125
|
+
}
|
|
126
|
+
|
|
103
127
|
protected override async fetchObjectsFromDatabaseAsync(
|
|
104
128
|
loadParamsArray: readonly Readonly<TestLoadParams>[],
|
|
105
129
|
): Promise<ReadonlyMap<Readonly<Readonly<TestLoadParams>>, Readonly<TestFields> | null>> {
|
|
@@ -108,11 +132,7 @@ class TestSecondaryCacheLoader extends EntitySecondaryCacheLoader<
|
|
|
108
132
|
const emptyMap = new Map(loadParamsArray.map((p) => [p, null]));
|
|
109
133
|
return await mapMapAsync(emptyMap, async (_value, loadParams) => {
|
|
110
134
|
return (
|
|
111
|
-
(
|
|
112
|
-
await this.entityLoader.loadManyByFieldEqualityConjunctionAsync([
|
|
113
|
-
{ fieldName: 'intField', fieldValue: loadParams.intValue },
|
|
114
|
-
])
|
|
115
|
-
)[0]
|
|
135
|
+
(await this.entityLoader.loadManyByFieldEqualingAsync('intField', loadParams.intValue))[0]
|
|
116
136
|
?.enforceValue()
|
|
117
137
|
?.getAllFields() ?? null
|
|
118
138
|
);
|
|
@@ -133,6 +153,7 @@ describe(GenericSecondaryEntityCache, () => {
|
|
|
133
153
|
new TestGenericCacher(),
|
|
134
154
|
(params) => `intValue.${params.intValue}`,
|
|
135
155
|
),
|
|
156
|
+
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(TestEntity, viewerContext),
|
|
136
157
|
TestEntity.loaderWithAuthorizationResults(viewerContext),
|
|
137
158
|
);
|
|
138
159
|
|
|
@@ -169,6 +190,7 @@ describe(GenericSecondaryEntityCache, () => {
|
|
|
169
190
|
new TestGenericCacher(),
|
|
170
191
|
(params) => `intValue.${params.intValue}`,
|
|
171
192
|
),
|
|
193
|
+
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(TestEntity, viewerContext),
|
|
172
194
|
TestEntity.loaderWithAuthorizationResults(viewerContext),
|
|
173
195
|
);
|
|
174
196
|
|
|
@@ -5,7 +5,7 @@ import { AuthorizationResultBasedEntityAssociationLoader } from '../Authorizatio
|
|
|
5
5
|
import { AuthorizationResultBasedEntityLoader } from '../AuthorizationResultBasedEntityLoader';
|
|
6
6
|
import { EnforcingEntityAssociationLoader } from '../EnforcingEntityAssociationLoader';
|
|
7
7
|
import { EnforcingEntityLoader } from '../EnforcingEntityLoader';
|
|
8
|
-
import {
|
|
8
|
+
import { EntityInvalidationUtils } from '../EntityInvalidationUtils';
|
|
9
9
|
import { ReadonlyEntity } from '../ReadonlyEntity';
|
|
10
10
|
import { ViewerContext } from '../ViewerContext';
|
|
11
11
|
import { SimpleTestEntity } from '../utils/__testfixtures__/SimpleTestEntity';
|
|
@@ -214,11 +214,13 @@ describe(ReadonlyEntity, () => {
|
|
|
214
214
|
});
|
|
215
215
|
});
|
|
216
216
|
|
|
217
|
-
describe('
|
|
218
|
-
it('creates a new
|
|
217
|
+
describe('invalidationUtils', () => {
|
|
218
|
+
it('creates a new EntityInvalidationUtils', async () => {
|
|
219
219
|
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
220
220
|
const viewerContext = new ViewerContext(companionProvider);
|
|
221
|
-
expect(SimpleTestEntity.
|
|
221
|
+
expect(SimpleTestEntity.invalidationUtils(viewerContext)).toBeInstanceOf(
|
|
222
|
+
EntityInvalidationUtils,
|
|
223
|
+
);
|
|
222
224
|
});
|
|
223
225
|
});
|
|
224
226
|
});
|
|
@@ -5,22 +5,22 @@ import { ViewerContext } from '../ViewerContext';
|
|
|
5
5
|
import { createUnitTestEntityCompanionProvider } from '../utils/__testfixtures__/createUnitTestEntityCompanionProvider';
|
|
6
6
|
|
|
7
7
|
describe(ViewerContext, () => {
|
|
8
|
-
describe('
|
|
8
|
+
describe('getQueryContextForDatabaseAdapterFlavor', () => {
|
|
9
9
|
it('creates a new regular query context', () => {
|
|
10
10
|
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
11
11
|
const viewerContext = new ViewerContext(companionProvider);
|
|
12
|
-
const queryContext = viewerContext.
|
|
12
|
+
const queryContext = viewerContext.getQueryContextForDatabaseAdapterFlavor('postgres');
|
|
13
13
|
expect(queryContext).toBeInstanceOf(EntityQueryContext);
|
|
14
14
|
expect(queryContext.isInTransaction()).toBe(false);
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
describe('
|
|
18
|
+
describe('runInTransactionForDatabaseAdapterFlavorAsync', () => {
|
|
19
19
|
it('creates a new transactional query context', async () => {
|
|
20
20
|
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
21
21
|
const viewerContext = new ViewerContext(companionProvider);
|
|
22
22
|
const didCreateTransaction =
|
|
23
|
-
await viewerContext.
|
|
23
|
+
await viewerContext.runInTransactionForDatabaseAdapterFlavorAsync(
|
|
24
24
|
'postgres',
|
|
25
25
|
async (queryContext) => {
|
|
26
26
|
return queryContext.isInTransaction();
|
|
@@ -50,23 +50,6 @@ describe('Two entities backed by the same table', () => {
|
|
|
50
50
|
expect(failedManyResults[0]!.enforceError().message).toEqual(
|
|
51
51
|
'OneTestEntity must be instantiated with one data',
|
|
52
52
|
);
|
|
53
|
-
|
|
54
|
-
const fieldEqualityConjunctionResults = await OneTestEntity.loaderWithAuthorizationResults(
|
|
55
|
-
viewerContext,
|
|
56
|
-
).loadManyByFieldEqualityConjunctionAsync([
|
|
57
|
-
{
|
|
58
|
-
fieldName: 'common_other_field',
|
|
59
|
-
fieldValue: 'wat',
|
|
60
|
-
},
|
|
61
|
-
]);
|
|
62
|
-
const successfulfieldEqualityConjunctionResultsResults = successfulResults(
|
|
63
|
-
fieldEqualityConjunctionResults,
|
|
64
|
-
);
|
|
65
|
-
const failedfieldEqualityConjunctionResultsResults = failedResults(
|
|
66
|
-
fieldEqualityConjunctionResults,
|
|
67
|
-
);
|
|
68
|
-
expect(successfulfieldEqualityConjunctionResultsResults).toHaveLength(1);
|
|
69
|
-
expect(failedfieldEqualityConjunctionResultsResults).toHaveLength(1);
|
|
70
53
|
});
|
|
71
54
|
});
|
|
72
55
|
|
|
@@ -231,3 +231,17 @@ export class EntityDatabaseAdapterExcessiveDeleteResultError extends EntityDatab
|
|
|
231
231
|
return EntityErrorCode.ERR_ENTITY_DATABASE_ADAPTER_EXCESSIVE_DELETE_RESULT;
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
|
+
|
|
235
|
+
export class EntityDatabaseAdapterPaginationCursorInvalidError extends EntityDatabaseAdapterError {
|
|
236
|
+
static {
|
|
237
|
+
this.prototype.name = 'EntityDatabaseAdapterPaginationCursorError';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
get state(): EntityErrorState.PERMANENT {
|
|
241
|
+
return EntityErrorState.PERMANENT;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
get code(): EntityErrorCode.ERR_ENTITY_DATABASE_ADAPTER_PAGINATION_CURSOR_INVALID {
|
|
245
|
+
return EntityErrorCode.ERR_ENTITY_DATABASE_ADAPTER_PAGINATION_CURSOR_INVALID;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -27,6 +27,7 @@ export enum EntityErrorCode {
|
|
|
27
27
|
ERR_ENTITY_DATABASE_ADAPTER_EMPTY_UPDATE_RESULT = 'ERR_ENTITY_DATABASE_ADAPTER_EMPTY_UPDATE_RESULT',
|
|
28
28
|
ERR_ENTITY_DATABASE_ADAPTER_EXCESSIVE_DELETE_RESULT = 'ERR_ENTITY_DATABASE_ADAPTER_EXCESSIVE_DELETE_RESULT',
|
|
29
29
|
ERR_ENTITY_CACHE_ADAPTER_TRANSIENT = 'ERR_ENTITY_CACHE_ADAPTER_TRANSIENT',
|
|
30
|
+
ERR_ENTITY_DATABASE_ADAPTER_PAGINATION_CURSOR_INVALID = 'ERR_ENTITY_DATABASE_ADAPTER_PAGINATION_CURSOR_INVALID',
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
EntityDatabaseAdapterExclusionConstraintError,
|
|
12
12
|
EntityDatabaseAdapterForeignKeyConstraintError,
|
|
13
13
|
EntityDatabaseAdapterNotNullConstraintError,
|
|
14
|
+
EntityDatabaseAdapterPaginationCursorInvalidError,
|
|
14
15
|
EntityDatabaseAdapterTransientError,
|
|
15
16
|
EntityDatabaseAdapterUniqueConstraintError,
|
|
16
17
|
EntityDatabaseAdapterUnknownError,
|
|
@@ -82,5 +83,13 @@ describe(EntityDatabaseAdapterError, () => {
|
|
|
82
83
|
expect(excessiveDeleteError.code).toBe(
|
|
83
84
|
EntityErrorCode.ERR_ENTITY_DATABASE_ADAPTER_EXCESSIVE_DELETE_RESULT,
|
|
84
85
|
);
|
|
86
|
+
|
|
87
|
+
const paginationCursorInvalidError = new EntityDatabaseAdapterPaginationCursorInvalidError(
|
|
88
|
+
'test',
|
|
89
|
+
);
|
|
90
|
+
expect(paginationCursorInvalidError.state).toBe(EntityErrorState.PERMANENT);
|
|
91
|
+
expect(paginationCursorInvalidError.code).toBe(
|
|
92
|
+
EntityErrorCode.ERR_ENTITY_DATABASE_ADAPTER_PAGINATION_CURSOR_INVALID,
|
|
93
|
+
);
|
|
85
94
|
});
|
|
86
95
|
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { instance, mock } from 'ts-mockito';
|
|
2
3
|
|
|
4
|
+
import { ViewerContext } from '../../ViewerContext';
|
|
5
|
+
import { SimpleTestEntity } from '../../utils/__testfixtures__/SimpleTestEntity';
|
|
3
6
|
import { EntityCacheAdapterTransientError } from '../EntityCacheAdapterError';
|
|
4
7
|
import { EntityErrorCode, EntityErrorState } from '../EntityError';
|
|
5
8
|
import { EntityInvalidFieldValueError } from '../EntityInvalidFieldValueError';
|
|
@@ -14,16 +17,21 @@ describe('EntityError subclasses', () => {
|
|
|
14
17
|
});
|
|
15
18
|
|
|
16
19
|
it('EntityNotAuthorizedError has correct state and code', () => {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
+
const viewerContext = instance(mock(ViewerContext));
|
|
21
|
+
const data = { id: '1' };
|
|
22
|
+
const testEntity = new SimpleTestEntity({
|
|
23
|
+
viewerContext,
|
|
24
|
+
id: 'what',
|
|
25
|
+
databaseFields: data,
|
|
26
|
+
selectedFields: data,
|
|
27
|
+
});
|
|
28
|
+
const error = new EntityNotAuthorizedError(testEntity, viewerContext, 0, 0);
|
|
20
29
|
expect(error.state).toBe(EntityErrorState.PERMANENT);
|
|
21
30
|
expect(error.code).toBe(EntityErrorCode.ERR_ENTITY_NOT_AUTHORIZED);
|
|
22
31
|
});
|
|
23
32
|
|
|
24
33
|
it('EntityInvalidFieldValueError has correct state and code', () => {
|
|
25
|
-
const
|
|
26
|
-
const error = new EntityInvalidFieldValueError(mockEntityClass, 'testField', 'badValue');
|
|
34
|
+
const error = new EntityInvalidFieldValueError(SimpleTestEntity, 'id', 'badValue');
|
|
27
35
|
expect(error.state).toBe(EntityErrorState.PERMANENT);
|
|
28
36
|
expect(error.code).toBe(EntityErrorCode.ERR_ENTITY_INVALID_FIELD_VALUE);
|
|
29
37
|
});
|