Skip to content

Commit f3b575c

Browse files
authored
feat: add EvaluateIfEntityFieldPredicatePrivacyPolicyRule (#400)
# Why One other rule we've found useful in the Expo application is a simple predicate rule based on an entity field. This PR upstreams this rule. # How Add rule and test. # Test Plan Run test.
1 parent 56ed357 commit f3b575c

3 files changed

Lines changed: 94 additions & 0 deletions

File tree

packages/entity/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export * from './rules/AllowIfInParentCascadeDeletionPrivacyPolicyRule';
7070
export * from './rules/AlwaysAllowPrivacyPolicyRule';
7171
export * from './rules/AlwaysDenyPrivacyPolicyRule';
7272
export * from './rules/AlwaysSkipPrivacyPolicyRule';
73+
export * from './rules/EvaluateIfEntityFieldPredicatePrivacyPolicyRule';
7374
export * from './rules/PrivacyPolicyRule';
7475
export * from './utils/EntityCreationUtils';
7576
export * from './utils/EntityPrivacyUtils';
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { EntityPrivacyPolicyEvaluationContext } from '../EntityPrivacyPolicy';
2+
import { EntityQueryContext } from '../EntityQueryContext';
3+
import { ReadonlyEntity } from '../ReadonlyEntity';
4+
import { ViewerContext } from '../ViewerContext';
5+
import { PrivacyPolicyRule, RuleEvaluationResult } from './PrivacyPolicyRule';
6+
7+
export class EvaluateIfEntityFieldPredicatePrivacyPolicyRule<
8+
TFields extends object,
9+
TIDField extends keyof NonNullable<Pick<TFields, TSelectedFields>>,
10+
TViewerContext extends ViewerContext,
11+
TEntity extends ReadonlyEntity<TFields, TIDField, TViewerContext, TSelectedFields>,
12+
N extends TSelectedFields,
13+
TSelectedFields extends keyof TFields = keyof TFields,
14+
> extends PrivacyPolicyRule<TFields, TIDField, TViewerContext, TEntity, TSelectedFields> {
15+
constructor(
16+
private readonly fieldName: N,
17+
private readonly shouldEvaluatePredicate: (fieldValue: TFields[N]) => boolean,
18+
private readonly rule: PrivacyPolicyRule<
19+
TFields,
20+
TIDField,
21+
TViewerContext,
22+
TEntity,
23+
TSelectedFields
24+
>,
25+
) {
26+
super();
27+
}
28+
29+
async evaluateAsync(
30+
viewerContext: TViewerContext,
31+
queryContext: EntityQueryContext,
32+
evaluationContext: EntityPrivacyPolicyEvaluationContext<
33+
TFields,
34+
TIDField,
35+
TViewerContext,
36+
TEntity,
37+
TSelectedFields
38+
>,
39+
entity: TEntity,
40+
): Promise<RuleEvaluationResult> {
41+
const fieldValue = entity.getField(this.fieldName);
42+
return this.shouldEvaluatePredicate(fieldValue)
43+
? await this.rule.evaluateAsync(viewerContext, queryContext, evaluationContext, entity)
44+
: RuleEvaluationResult.SKIP;
45+
}
46+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { mock, instance, when } from 'ts-mockito';
2+
3+
import { EntityPrivacyPolicyEvaluationContext } from '../../EntityPrivacyPolicy';
4+
import { EntityQueryContext } from '../../EntityQueryContext';
5+
import { ViewerContext } from '../../ViewerContext';
6+
import { describePrivacyPolicyRule } from '../../utils/__testfixtures__/PrivacyPolicyRuleTestUtils';
7+
import { TestEntity, TestFields } from '../../utils/__testfixtures__/TestEntity';
8+
import { AlwaysAllowPrivacyPolicyRule } from '../AlwaysAllowPrivacyPolicyRule';
9+
import { EvaluateIfEntityFieldPredicatePrivacyPolicyRule } from '../EvaluateIfEntityFieldPredicatePrivacyPolicyRule';
10+
11+
const entityBlahMock = mock(TestEntity);
12+
when(entityBlahMock.getField('testIndexedField')).thenReturn('1');
13+
const entityBlah = instance(entityBlahMock);
14+
15+
const entityFooMock = mock(TestEntity);
16+
when(entityFooMock.getField('testIndexedField')).thenReturn('2');
17+
const entityFoo = instance(entityFooMock);
18+
19+
describePrivacyPolicyRule<TestFields, 'customIdField', ViewerContext, TestEntity>(
20+
new EvaluateIfEntityFieldPredicatePrivacyPolicyRule<
21+
TestFields,
22+
'customIdField',
23+
ViewerContext,
24+
TestEntity,
25+
'testIndexedField'
26+
>('testIndexedField', (val) => val === '1', new AlwaysAllowPrivacyPolicyRule()),
27+
{
28+
allowCases: [
29+
{
30+
viewerContext: instance(mock(ViewerContext)),
31+
queryContext: instance(mock(EntityQueryContext)),
32+
evaluationContext:
33+
instance(mock<EntityPrivacyPolicyEvaluationContext<any, any, any, any, any>>()),
34+
entity: entityBlah,
35+
},
36+
],
37+
skipCases: [
38+
{
39+
viewerContext: instance(mock(ViewerContext)),
40+
queryContext: instance(mock(EntityQueryContext)),
41+
evaluationContext:
42+
instance(mock<EntityPrivacyPolicyEvaluationContext<any, any, any, any, any>>()),
43+
entity: entityFoo,
44+
},
45+
],
46+
},
47+
);

0 commit comments

Comments
 (0)