Skip to content

Commit 6a6febd

Browse files
Merge branch 'refactor-evaluator-to-support-no-target' into configs-sdk-client
2 parents 767324d + 57300db commit 6a6febd

15 files changed

Lines changed: 86 additions & 128 deletions

File tree

src/evaluator/Engine.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ export function engineParser(log: ILogger, split: ISplit, storage: IStorageSync
2929

3030
return {
3131

32-
getTreatment(key: SplitIO.SplitKey, attributes: SplitIO.Attributes | undefined, splitEvaluator: ISplitEvaluator): MaybeThenable<IEvaluationResult> {
33-
34-
const parsedKey = keyParser(key);
32+
getTreatment(key: SplitIO.SplitKey | undefined, attributes: SplitIO.Attributes | undefined, splitEvaluator: ISplitEvaluator): MaybeThenable<IEvaluationResult> {
3533

3634
function evaluate(prerequisitesMet: boolean) {
3735
if (!prerequisitesMet) {
@@ -42,7 +40,7 @@ export function engineParser(log: ILogger, split: ISplit, storage: IStorageSync
4240
};
4341
}
4442

45-
const evaluation = evaluator(parsedKey, seed, trafficAllocation, trafficAllocationSeed, attributes, splitEvaluator) as MaybeThenable<IEvaluation>;
43+
const evaluation = evaluator(key ? keyParser(key) : undefined, seed, trafficAllocation, trafficAllocationSeed, attributes, splitEvaluator) as MaybeThenable<IEvaluation>;
4644

4745
return thenable(evaluation) ?
4846
evaluation.then(result => evaluationResult(result, defaultTreatment)) :

src/evaluator/combiners/ifelseif.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function ifElseIfCombinerContext(log: ILogger, predicates: IEvaluator[]):
3333
return undefined;
3434
}
3535

36-
function ifElseIfCombiner(key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {
36+
function ifElseIfCombiner(key?: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {
3737
// In Async environments we are going to have async predicates. There is none way to know
3838
// before hand so we need to evaluate all the predicates, verify for thenables, and finally,
3939
// define how to return the treatment (wrap result into a Promise or not).

src/evaluator/condition/engineUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ export function getTreatment(log: ILogger, key: string, seed: number | undefined
1818
/**
1919
* Evaluates the traffic allocation to see if we should apply rollout conditions or not.
2020
*/
21-
export function shouldApplyRollout(trafficAllocation: number, key: string, trafficAllocationSeed: number) {
21+
export function shouldApplyRollout(trafficAllocation: number, bucketingKey: string, trafficAllocationSeed: number) {
2222
// For rollout, if traffic allocation for splits is 100%, we don't need to filter it because everything should evaluate the rollout.
2323
if (trafficAllocation < 100) {
24-
const _bucket = bucket(key, trafficAllocationSeed);
24+
const _bucket = bucket(bucketingKey, trafficAllocationSeed);
2525

2626
if (_bucket > trafficAllocation) {
2727
return false;

src/evaluator/condition/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ function match(log: ILogger, matchingResult: boolean, bucketingKey: string | und
2424
// Condition factory
2525
export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.SplitKeyObject, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) => MaybeThenable<boolean>, treatments?: { getTreatmentFor: (x: number) => string }, label?: string, conditionType?: 'ROLLOUT' | 'WHITELIST'): IEvaluator {
2626

27-
return function conditionEvaluator(key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {
27+
return function conditionEvaluator(key?: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) {
2828

2929
// Whitelisting has more priority than traffic allocation, so we don't apply this filtering to those conditions.
30-
if (conditionType === 'ROLLOUT' && !shouldApplyRollout(trafficAllocation!, key.bucketingKey, trafficAllocationSeed!)) {
30+
if (!key || (conditionType === 'ROLLOUT' && !shouldApplyRollout(trafficAllocation!, key.bucketingKey, trafficAllocationSeed!))) {
3131
return {
3232
treatment: undefined, // treatment value is assigned later
3333
label: NOT_IN_SPLIT

src/evaluator/fallbackTreatmentsCalculator/__tests__/fallback-calculator.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ describe('FallbackTreatmentsCalculator' , () => {
99
'featureA': { treatment: 'TREATMENT_A', config: '{ value: 1 }' },
1010
},
1111
};
12-
const calculator = new FallbackTreatmentsCalculator(config);
13-
const result = calculator.resolve('featureA', 'label by flag');
12+
const calculator = FallbackTreatmentsCalculator(config);
13+
const result = calculator('featureA', 'label by flag');
1414

1515
expect(result).toEqual({
1616
treatment: 'TREATMENT_A',
@@ -24,8 +24,8 @@ describe('FallbackTreatmentsCalculator' , () => {
2424
byFlag: {},
2525
global: { treatment: 'GLOBAL_TREATMENT', config: '{ global: true }' },
2626
};
27-
const calculator = new FallbackTreatmentsCalculator(config);
28-
const result = calculator.resolve('missingFlag', 'label by global');
27+
const calculator = FallbackTreatmentsCalculator(config);
28+
const result = calculator('missingFlag', 'label by global');
2929

3030
expect(result).toEqual({
3131
treatment: 'GLOBAL_TREATMENT',
@@ -38,8 +38,8 @@ describe('FallbackTreatmentsCalculator' , () => {
3838
const config: FallbackTreatmentConfiguration = {
3939
byFlag: {},
4040
};
41-
const calculator = new FallbackTreatmentsCalculator(config);
42-
const result = calculator.resolve('missingFlag', 'label by noFallback');
41+
const calculator = FallbackTreatmentsCalculator(config);
42+
const result = calculator('missingFlag', 'label by noFallback');
4343

4444
expect(result).toEqual({
4545
treatment: CONTROL,
Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,32 @@
1-
import { FallbackTreatmentConfiguration, Treatment, TreatmentWithConfig } from '../../../types/splitio';
1+
import { FallbackTreatmentConfiguration, TreatmentWithConfig } from '../../../types/splitio';
22
import { CONTROL } from '../../utils/constants';
33
import { isString } from '../../utils/lang';
44

5-
export type IFallbackTreatmentsCalculator = {
6-
resolve(flagName: string, label: string): TreatmentWithConfig & { label: string };
7-
}
5+
export type IFallbackTreatmentsCalculator = (flagName: string, label?: string) => TreatmentWithConfig & { label: string };
86

97
export const FALLBACK_PREFIX = 'fallback - ';
108

11-
export class FallbackTreatmentsCalculator implements IFallbackTreatmentsCalculator {
12-
private readonly fallbacks: FallbackTreatmentConfiguration;
13-
14-
constructor(fallbacks: FallbackTreatmentConfiguration = {}) {
15-
this.fallbacks = fallbacks;
16-
}
17-
18-
resolve(flagName: string, label: string): TreatmentWithConfig & { label: string } {
19-
const treatment = this.fallbacks.byFlag?.[flagName];
20-
if (treatment) {
21-
return this.copyWithLabel(treatment, label);
22-
}
23-
24-
if (this.fallbacks.global) {
25-
return this.copyWithLabel(this.fallbacks.global, label);
26-
}
27-
28-
return {
29-
treatment: CONTROL,
30-
config: null,
31-
label,
32-
};
33-
}
34-
35-
private copyWithLabel(fallback: Treatment | TreatmentWithConfig, label: string): TreatmentWithConfig & { label: string } {
36-
if (isString(fallback)) {
37-
return {
38-
treatment: fallback,
9+
export function FallbackTreatmentsCalculator(fallbacks: FallbackTreatmentConfiguration = {}): IFallbackTreatmentsCalculator {
10+
11+
return (flagName: string, label = '') => {
12+
const fallback = fallbacks.byFlag?.[flagName] || fallbacks.global;
13+
14+
return fallback ?
15+
isString(fallback) ?
16+
{
17+
treatment: fallback,
18+
config: null,
19+
label: `${FALLBACK_PREFIX}${label}`,
20+
} :
21+
{
22+
treatment: fallback.treatment,
23+
config: fallback.config,
24+
label: `${FALLBACK_PREFIX}${label}`,
25+
} :
26+
{
27+
treatment: CONTROL,
3928
config: null,
40-
label: `${FALLBACK_PREFIX}${label}`,
29+
label,
4130
};
42-
}
43-
44-
return {
45-
treatment: fallback.treatment,
46-
config: fallback.config,
47-
label: `${FALLBACK_PREFIX}${label}`,
48-
};
49-
}
31+
};
5032
}

src/evaluator/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ function treatmentsException(splitNames: string[]) {
2424
return evaluations;
2525
}
2626

27+
// @TODO: test cases with no key
2728
export function evaluateFeature(
2829
log: ILogger,
29-
key: SplitIO.SplitKey,
30+
key: SplitIO.SplitKey | undefined,
3031
splitName: string,
3132
attributes: SplitIO.Attributes | undefined,
3233
storage: IStorageSync | IStorageAsync,
@@ -139,7 +140,7 @@ export function evaluateFeaturesByFlagSets(
139140

140141
function getEvaluation(
141142
log: ILogger,
142-
key: SplitIO.SplitKey,
143+
key: SplitIO.SplitKey | undefined,
143144
splitJSON: ISplit | null,
144145
attributes: SplitIO.Attributes | undefined,
145146
storage: IStorageSync | IStorageAsync,

src/evaluator/matchers/prerequisites.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { IDependencyMatcherValue, ISplitEvaluator } from '../types';
66

77
export function prerequisitesMatcherContext(prerequisites: ISplit['prerequisites'], storage: IStorageSync | IStorageAsync, log: ILogger) {
88

9-
return function prerequisitesMatcher({ key, attributes }: IDependencyMatcherValue, splitEvaluator: ISplitEvaluator): MaybeThenable<boolean> {
9+
return function prerequisitesMatcher({ key, attributes }: Partial<IDependencyMatcherValue>, splitEvaluator: ISplitEvaluator): MaybeThenable<boolean> {
1010

1111
prerequisites = prerequisites == null ? [] : prerequisites;
1212

src/evaluator/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ export interface IEvaluation {
2727

2828
export type IEvaluationResult = IEvaluation & { treatment: string; impressionsDisabled?: boolean }
2929

30-
export type ISplitEvaluator = (log: ILogger, key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>
30+
export type ISplitEvaluator = (log: ILogger, key: SplitIO.SplitKey | undefined, splitName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>
3131

32-
export type IEvaluator = (key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) => MaybeThenable<IEvaluation | boolean | undefined>
32+
export type IEvaluator = (key?: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) => MaybeThenable<IEvaluation | boolean | undefined>
3333

3434
export type IMatcher = (value: string | number | boolean | string[] | IDependencyMatcherValue, splitEvaluator?: ISplitEvaluator) => MaybeThenable<boolean>

src/sdkClient/__tests__/clientInputValidation.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const settings: any = {
1414
const EVALUATION_RESULT = 'on';
1515
const client: any = createClientMock(EVALUATION_RESULT);
1616

17-
const fallbackTreatmentsCalculator: IFallbackTreatmentsCalculator = new FallbackTreatmentsCalculator(settings);
17+
const fallbackTreatmentsCalculator: IFallbackTreatmentsCalculator = FallbackTreatmentsCalculator();
1818

1919
const readinessManager: any = {
2020
isReadyFromCache: () => true,

0 commit comments

Comments
 (0)