From 8605eff0ab63ab11d99e886bb2a87ecbc550afbc Mon Sep 17 00:00:00 2001 From: edsonloor Date: Thu, 6 Oct 2022 12:46:39 -0500 Subject: [PATCH 01/14] is set, is not set first test --- flagsmith-engine/segments/constants.ts | 6 ++- flagsmith-engine/segments/models.ts | 16 ++++--- package-lock.json | 4 +- sdk/models.ts | 1 - .../unit/segments/segments_model.test.ts | 42 ++++++++++--------- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/flagsmith-engine/segments/constants.ts b/flagsmith-engine/segments/constants.ts index ba6fafc..3c41421 100644 --- a/flagsmith-engine/segments/constants.ts +++ b/flagsmith-engine/segments/constants.ts @@ -16,6 +16,8 @@ export const NOT_CONTAINS = 'NOT_CONTAINS'; export const NOT_EQUAL = 'NOT_EQUAL'; export const REGEX = 'REGEX'; export const PERCENTAGE_SPLIT = 'PERCENTAGE_SPLIT'; +export const IS_SET = 'IS_SET'; +export const IS_NOT_SET = 'IS_NOT_SET'; export const CONDITION_OPERATORS = { EQUAL, @@ -27,5 +29,7 @@ export const CONDITION_OPERATORS = { NOT_CONTAINS, NOT_EQUAL, REGEX, - PERCENTAGE_SPLIT + PERCENTAGE_SPLIT, + IS_SET, + IS_NOT_SET }; diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index fabd9a5..a5b99d0 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -30,16 +30,20 @@ export const matchingFunctions = { export const semverMatchingFunction = { ...matchingFunctions, - [CONDITION_OPERATORS.EQUAL]: (thisValue: any, otherValue: any) => semver.eq(thisValue, otherValue), - [CONDITION_OPERATORS.GREATER_THAN]: (thisValue: any, otherValue: any) => semver.gt(otherValue, thisValue), + [CONDITION_OPERATORS.EQUAL]: (thisValue: any, otherValue: any) => + semver.eq(thisValue, otherValue), + [CONDITION_OPERATORS.GREATER_THAN]: (thisValue: any, otherValue: any) => + semver.gt(otherValue, thisValue), [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE]: (thisValue: any, otherValue: any) => semver.gte(otherValue, thisValue), - [CONDITION_OPERATORS.LESS_THAN]: (thisValue: any, otherValue: any) => semver.gt(thisValue, otherValue), + [CONDITION_OPERATORS.LESS_THAN]: (thisValue: any, otherValue: any) => + semver.gt(thisValue, otherValue), [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE]: (thisValue: any, otherValue: any) => - semver.gte(thisValue, otherValue), -} + semver.gte(thisValue, otherValue) +}; -export const getMatchingFunctions = (semver: boolean) => (semver ? semverMatchingFunction : matchingFunctions); +export const getMatchingFunctions = (semver: boolean) => + semver ? semverMatchingFunction : matchingFunctions; export class SegmentConditionModel { EXCEPTION_OPERATOR_METHODS: { [key: string]: string } = { diff --git a/package-lock.json b/package-lock.json index fac583e..41db697 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "flagsmith-nodejs", - "version": "2.2.2", + "version": "2.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "flagsmith-nodejs", - "version": "2.2.2", + "version": "2.3.0", "license": "MIT", "dependencies": { "big-integer": "^1.6.51", diff --git a/sdk/models.ts b/sdk/models.ts index 27e1cb7..b6bf10b 100644 --- a/sdk/models.ts +++ b/sdk/models.ts @@ -125,7 +125,6 @@ export class Flags { } return { enabled: false, isDefault: true, value: undefined }; - } if (this.analyticsProcessor && flag.featureId) { diff --git a/tests/engine/unit/segments/segments_model.test.ts b/tests/engine/unit/segments/segments_model.test.ts index 09f9f8b..fb545da 100644 --- a/tests/engine/unit/segments/segments_model.test.ts +++ b/tests/engine/unit/segments/segments_model.test.ts @@ -12,6 +12,7 @@ import { } from '../../../../flagsmith-engine/segments/models'; const conditionMatchCases: [string, string | number | boolean, string, boolean][] = [ + [CONDITION_OPERATORS.IS_SET, 'bar', 'bar', false], [CONDITION_OPERATORS.EQUAL, 'bar', 'bar', true], [CONDITION_OPERATORS.EQUAL, 'bar', 'baz', false], [CONDITION_OPERATORS.EQUAL, 1, '1', true], @@ -62,26 +63,27 @@ const conditionMatchCases: [string, string | number | boolean, string, boolean][ [CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'baz', true], [CONDITION_OPERATORS.REGEX, 'foo', '[a-z]+', true], [CONDITION_OPERATORS.REGEX, 'FOO', '[a-z]+', false], - [CONDITION_OPERATORS.EQUAL, "1.0.0", "1.0.0:semver", true], - [CONDITION_OPERATORS.EQUAL, "1.0.0", "1.0.0:semver", true], - [CONDITION_OPERATORS.EQUAL, "1.0.0", "1.0.1:semver", false], - [CONDITION_OPERATORS.NOT_EQUAL, "1.0.0", "1.0.0:semver", false], - [CONDITION_OPERATORS.NOT_EQUAL, "1.0.0", "1.0.1:semver", true], - [CONDITION_OPERATORS.GREATER_THAN, "1.0.1", "1.0.0:semver", true], - [CONDITION_OPERATORS.GREATER_THAN, "1.0.0", "1.0.0-beta:semver", true], - [CONDITION_OPERATORS.GREATER_THAN, "1.0.1", "1.2.0:semver", false], - [CONDITION_OPERATORS.GREATER_THAN, "1.0.1", "1.0.1:semver", false], - [CONDITION_OPERATORS.GREATER_THAN, "1.2.4", "1.2.3-pre.2+build.4:semver", true], - [CONDITION_OPERATORS.LESS_THAN, "1.0.0", "1.0.1:semver", true], - [CONDITION_OPERATORS.LESS_THAN, "1.0.0", "1.0.0:semver", false], - [CONDITION_OPERATORS.LESS_THAN, "1.0.1", "1.0.0:semver", false], - [CONDITION_OPERATORS.LESS_THAN, "1.0.0-rc.2", "1.0.0-rc.3:semver", true], - [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, "1.0.1", "1.0.0:semver", true], - [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, "1.0.1", "1.2.0:semver", false], - [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, "1.0.1", "1.0.1:semver", true], - [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, "1.0.0", "1.0.1:semver", true], - [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, "1.0.0", "1.0.0:semver", true], - [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, "1.0.1", "1.0.0:semver", false], + [CONDITION_OPERATORS.EQUAL, '1.0.0', '1.0.0:semver', true], + [CONDITION_OPERATORS.EQUAL, '1.0.0', '1.0.0:semver', true], + [CONDITION_OPERATORS.EQUAL, '1.0.0', '1.0.1:semver', false], + [CONDITION_OPERATORS.NOT_EQUAL, '1.0.0', '1.0.0:semver', false], + [CONDITION_OPERATORS.NOT_EQUAL, '1.0.0', '1.0.1:semver', true], + [CONDITION_OPERATORS.GREATER_THAN, '1.0.1', '1.0.0:semver', true], + [CONDITION_OPERATORS.GREATER_THAN, '1.0.0', '1.0.0-beta:semver', true], + [CONDITION_OPERATORS.GREATER_THAN, '1.0.1', '1.2.0:semver', false], + [CONDITION_OPERATORS.GREATER_THAN, '1.0.1', '1.0.1:semver', false], + [CONDITION_OPERATORS.GREATER_THAN, '1.2.4', '1.2.3-pre.2+build.4:semver', true], + [CONDITION_OPERATORS.LESS_THAN, '1.0.0', '1.0.1:semver', true], + [CONDITION_OPERATORS.LESS_THAN, '1.0.0', '1.0.0:semver', false], + [CONDITION_OPERATORS.LESS_THAN, '1.0.1', '1.0.0:semver', false], + [CONDITION_OPERATORS.LESS_THAN, '1.0.0-rc.2', '1.0.0-rc.3:semver', true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, '1.0.1', '1.0.0:semver', true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, '1.0.1', '1.2.0:semver', false], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, '1.0.1', '1.0.1:semver', true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.0', '1.0.1:semver', true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.0', '1.0.0:semver', true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.1', '1.0.0:semver', false], + [CONDITION_OPERATORS.IS_SET, 'bar', 'bar', false], ['BAD_OP', 'a', 'a', false] ]; From a7b6e3c9741006f35c87297f1c05da4f6c3fbeef Mon Sep 17 00:00:00 2001 From: edsonloor Date: Fri, 7 Oct 2022 00:42:23 -0500 Subject: [PATCH 02/14] is set, is not set new conditions --- .../unit/segments/segment_operator.test.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/engine/unit/segments/segment_operator.test.ts diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts new file mode 100644 index 0000000..f760234 --- /dev/null +++ b/tests/engine/unit/segments/segment_operator.test.ts @@ -0,0 +1,28 @@ +import { + CONDITION_OPERATORS, +} from '../../../../flagsmith-engine/segments/constants'; +import { + segmentConditionProperty, + segmentConditionStringValue +} from "../utils"; +import { + SegmentConditionModel, +} from '../../../../flagsmith-engine/segments/models'; +import {TraitModel} from "../../../../flagsmith-engine"; + +const conditionMatchCases: [string, string | number | boolean, string, object ,boolean][] = [ + [CONDITION_OPERATORS.IS_SET, 'foo','', {}, false], + [CONDITION_OPERATORS.IS_SET, 'foo', '', {'foo':'bar'}, true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', '',{'foo':'bar'}, false], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', '', {}, true] +]; + +test('test_segment_condition_matches_Trait', () => { + const trait_key = new TraitModel (segmentConditionProperty, segmentConditionStringValue); + const trait_models = Object.values(trait_key) + for (const testCase of conditionMatchCases) { + expect( + trait_models[0]==testCase[1] + ).toBe(testCase[4]); + } +}); \ No newline at end of file From ad27e13613649240085dd692ed7207f6752a8674 Mon Sep 17 00:00:00 2001 From: edsonloor Date: Mon, 10 Oct 2022 01:06:06 -0500 Subject: [PATCH 03/14] is set, is not set traits test --- flagsmith-engine/segments/models.ts | 5 +++-- .../unit/segments/segment_operator.test.ts | 21 ++++++++++--------- .../unit/segments/segments_model.test.ts | 2 -- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index a5b99d0..f15ae9b 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -52,10 +52,10 @@ export class SegmentConditionModel { }; operator: string; - value: string; + value: string | null | undefined; property_: string | undefined; - constructor(operator: string, value: string, property?: string) { + constructor(operator: string, value?: string | null, property?: string) { this.operator = operator; this.value = value; this.property_ = property; @@ -67,6 +67,7 @@ export class SegmentConditionModel { return !traitValue.includes(this.value); }, evaluateRegex: (traitValue: any) => { + // @ts-ignore return !!traitValue.match(new RegExp(this.value)); } }; diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts index f760234..6aaf09c 100644 --- a/tests/engine/unit/segments/segment_operator.test.ts +++ b/tests/engine/unit/segments/segment_operator.test.ts @@ -10,19 +10,20 @@ import { } from '../../../../flagsmith-engine/segments/models'; import {TraitModel} from "../../../../flagsmith-engine"; -const conditionMatchCases: [string, string | number | boolean, string, object ,boolean][] = [ - [CONDITION_OPERATORS.IS_SET, 'foo','', {}, false], - [CONDITION_OPERATORS.IS_SET, 'foo', '', {'foo':'bar'}, true], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', '',{'foo':'bar'}, false], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', '', {}, true] +const conditionMatchCases: [string, string | undefined, string | null, Array ,boolean][] = [ + [CONDITION_OPERATORS.IS_SET, 'foo',null, [{null:null}], false], + [CONDITION_OPERATORS.IS_SET, 'foo', '', [{'foo':'bar'}], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', '', [{null:null}], true] ]; test('test_segment_condition_matches_Trait', () => { - const trait_key = new TraitModel (segmentConditionProperty, segmentConditionStringValue); - const trait_models = Object.values(trait_key) - for (const testCase of conditionMatchCases) { + for (const conditionModel of conditionMatchCases) { + const traitModel: TraitModel = new TraitModel (segmentConditionProperty, segmentConditionStringValue); expect( - trait_models[0]==testCase[1] - ).toBe(testCase[4]); + new SegmentConditionModel(conditionModel[0], conditionModel[2], traitModel.traitKey).matchesTraitValue( + Object.keys(conditionModel[3]) + ) + ).toBe(conditionModel[4]); } }); \ No newline at end of file diff --git a/tests/engine/unit/segments/segments_model.test.ts b/tests/engine/unit/segments/segments_model.test.ts index fb545da..e2e009e 100644 --- a/tests/engine/unit/segments/segments_model.test.ts +++ b/tests/engine/unit/segments/segments_model.test.ts @@ -12,7 +12,6 @@ import { } from '../../../../flagsmith-engine/segments/models'; const conditionMatchCases: [string, string | number | boolean, string, boolean][] = [ - [CONDITION_OPERATORS.IS_SET, 'bar', 'bar', false], [CONDITION_OPERATORS.EQUAL, 'bar', 'bar', true], [CONDITION_OPERATORS.EQUAL, 'bar', 'baz', false], [CONDITION_OPERATORS.EQUAL, 1, '1', true], @@ -83,7 +82,6 @@ const conditionMatchCases: [string, string | number | boolean, string, boolean][ [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.0', '1.0.1:semver', true], [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.0', '1.0.0:semver', true], [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.1', '1.0.0:semver', false], - [CONDITION_OPERATORS.IS_SET, 'bar', 'bar', false], ['BAD_OP', 'a', 'a', false] ]; From 2d6e6fdf145f488ccda3fb799088634c85a75461 Mon Sep 17 00:00:00 2001 From: edsonloor Date: Mon, 10 Oct 2022 20:11:03 -0500 Subject: [PATCH 04/14] is set, is not set key trait test --- flagsmith-engine/segments/evaluators.ts | 2 +- flagsmith-engine/segments/models.ts | 2 ++ .../unit/segments/segment_operator.test.ts | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index e8bb6cc..22f7bb2 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -62,7 +62,7 @@ function traitsMatchSegmentCondition( identityId: number | string ): boolean { if (condition.operator == PERCENTAGE_SPLIT) { - return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); + return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); } const traits = identityTraits.filter(t => t.traitKey === condition.property_); diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index f15ae9b..93184e2 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -26,6 +26,8 @@ export const matchingFunctions = { [CONDITION_OPERATORS.NOT_EQUAL]: (thisValue: any, otherValue: any) => thisValue != otherValue, [CONDITION_OPERATORS.CONTAINS]: (thisValue: any, otherValue: any) => otherValue.includes(thisValue), + [CONDITION_OPERATORS.IS_SET]: (thisValue: any, otherValue: any) => thisValue == otherValue, + [CONDITION_OPERATORS.IS_NOT_SET]: (thisValue: any, otherValue: any) => thisValue != otherValue, }; export const semverMatchingFunction = { diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts index 6aaf09c..fe548c2 100644 --- a/tests/engine/unit/segments/segment_operator.test.ts +++ b/tests/engine/unit/segments/segment_operator.test.ts @@ -10,19 +10,21 @@ import { } from '../../../../flagsmith-engine/segments/models'; import {TraitModel} from "../../../../flagsmith-engine"; -const conditionMatchCases: [string, string | undefined, string | null, Array ,boolean][] = [ - [CONDITION_OPERATORS.IS_SET, 'foo',null, [{null:null}], false], - [CONDITION_OPERATORS.IS_SET, 'foo', '', [{'foo':'bar'}], true], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', '', [{null:null}], true] +const conditionMatchCases: [string, string | undefined, string | null | undefined, Array ,boolean][] = [ + [CONDITION_OPERATORS.IS_SET, 'foo',null, [{}], false], + //[CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{'foo':'bar'}], true], + //[CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{}], true] ]; test('test_segment_condition_matches_Trait', () => { for (const conditionModel of conditionMatchCases) { - const traitModel: TraitModel = new TraitModel (segmentConditionProperty, segmentConditionStringValue); + let traitsKey = Object.keys ((conditionModel[3])[0]) + let traitsValue = Object.values ((conditionModel[3])[0]) + const traitModel: TraitModel = new TraitModel (traitsKey[0], traitsValue[0]); expect( - new SegmentConditionModel(conditionModel[0], conditionModel[2], traitModel.traitKey).matchesTraitValue( - Object.keys(conditionModel[3]) + new SegmentConditionModel(conditionModel[0], conditionModel[2], (traitModel.traitKey)).matchesTraitValue( + traitModel.traitValue ) ).toBe(conditionModel[4]); } From ffddbdfbfeff509dc20f0f2763c2787b57b27d87 Mon Sep 17 00:00:00 2001 From: edsonloor Date: Tue, 11 Oct 2022 21:35:26 -0500 Subject: [PATCH 05/14] is set, is not set all test passed!! --- flagsmith-engine/segments/evaluators.ts | 26 ++++++++++++++----- .../unit/segments/segment_operator.test.ts | 13 ++++------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index 22f7bb2..73bed8a 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -2,8 +2,9 @@ import { EnvironmentModel } from '../environments/models'; import { IdentityModel } from '../identities/models'; import { TraitModel } from '../identities/traits/models'; import { getHashedPercentateForObjIds } from '../utils/hashing'; -import { PERCENTAGE_SPLIT } from './constants'; +import { PERCENTAGE_SPLIT, IS_SET, IS_NOT_SET } from './constants'; import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models'; +import constants_1 from "../../build/flagsmith-engine/segments/constants"; export function getIdentitySegments( environment: EnvironmentModel, @@ -55,7 +56,7 @@ function traitsMatchSegmentRule( ); } -function traitsMatchSegmentCondition( +export function traitsMatchSegmentCondition( identityTraits: TraitModel[], condition: SegmentConditionModel, segmentId: number | string, @@ -63,10 +64,21 @@ function traitsMatchSegmentCondition( ): boolean { if (condition.operator == PERCENTAGE_SPLIT) { return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); - } - - const traits = identityTraits.filter(t => t.traitKey === condition.property_); - const trait = traits.length > 0 ? traits[0] : undefined; + } else if (condition.operator === IS_SET || condition.operator === IS_NOT_SET) { + // @ts-ignore + return handleTraitExistenceConditions (condition, identityTraits); + } else { + const traits = identityTraits.filter(t => t.traitKey === condition.property_); + const trait = traits.length > 0 ? traits[0] : undefined; - return trait ? condition.matchesTraitValue(trait.traitValue) : false; + return trait ? condition.matchesTraitValue(trait.traitValue) : false; + } } +function handleTraitExistenceConditions (condition: SegmentConditionModel, identityTraits: TraitModel[] ) { + let traitIdentityKey=Object.keys(identityTraits[0]) + if (condition.operator === IS_SET ) { + return traitIdentityKey[0] === condition.property_ + } + return !(traitIdentityKey[0] === condition.property_) +} + diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts index fe548c2..e415f05 100644 --- a/tests/engine/unit/segments/segment_operator.test.ts +++ b/tests/engine/unit/segments/segment_operator.test.ts @@ -9,23 +9,20 @@ import { SegmentConditionModel, } from '../../../../flagsmith-engine/segments/models'; import {TraitModel} from "../../../../flagsmith-engine"; +import {traitsMatchSegmentCondition} from "../../../../flagsmith-engine/segments/evaluators"; const conditionMatchCases: [string, string | undefined, string | null | undefined, Array ,boolean][] = [ [CONDITION_OPERATORS.IS_SET, 'foo',null, [{}], false], - //[CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{'foo':'bar'}], true], - //[CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], + [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{foo:'bar'}], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{}], true] ]; test('test_segment_condition_matches_Trait', () => { for (const conditionModel of conditionMatchCases) { - let traitsKey = Object.keys ((conditionModel[3])[0]) - let traitsValue = Object.values ((conditionModel[3])[0]) - const traitModel: TraitModel = new TraitModel (traitsKey[0], traitsValue[0]); + let segmentModel = new SegmentConditionModel(conditionModel[0], conditionModel[2], conditionModel[1]) expect( - new SegmentConditionModel(conditionModel[0], conditionModel[2], (traitModel.traitKey)).matchesTraitValue( - traitModel.traitValue - ) + traitsMatchSegmentCondition (conditionModel[3], segmentModel, 'any','any') ).toBe(conditionModel[4]); } }); \ No newline at end of file From 169ce2d51329ddfa442fcfedf989dd05de9dfb2f Mon Sep 17 00:00:00 2001 From: edsonloor Date: Wed, 12 Oct 2022 16:08:12 -0500 Subject: [PATCH 06/14] models file fixed --- sdk/models.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/models.ts b/sdk/models.ts index b6bf10b..5ca0701 100644 --- a/sdk/models.ts +++ b/sdk/models.ts @@ -125,6 +125,7 @@ export class Flags { } return { enabled: false, isDefault: true, value: undefined }; + } if (this.analyticsProcessor && flag.featureId) { @@ -141,4 +142,4 @@ export class Flags { isFeatureEnabled(featureName: string): boolean { return this.getFlag(featureName).enabled; } -} +} \ No newline at end of file From bf9c15de353ffd5b438688e2eb364ea2060a5743 Mon Sep 17 00:00:00 2001 From: edsonloor Date: Wed, 12 Oct 2022 20:28:03 -0500 Subject: [PATCH 07/14] handleTraitExistenceConditions function to modify --- flagsmith-engine/segments/evaluators.ts | 8 +++----- flagsmith-engine/segments/models.ts | 7 ++++--- .../unit/segments/segment_operator.test.ts | 17 +++++++++-------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index 73bed8a..df27530 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -65,17 +65,15 @@ export function traitsMatchSegmentCondition( if (condition.operator == PERCENTAGE_SPLIT) { return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); } else if (condition.operator === IS_SET || condition.operator === IS_NOT_SET) { - // @ts-ignore return handleTraitExistenceConditions (condition, identityTraits); } else { - const traits = identityTraits.filter(t => t.traitKey === condition.property_); - const trait = traits.length > 0 ? traits[0] : undefined; - + const traits = identityTraits.filter(t => t.traitKey === condition.property_);const trait = traits.length > 0 ? traits[0] : undefined; return trait ? condition.matchesTraitValue(trait.traitValue) : false; } } function handleTraitExistenceConditions (condition: SegmentConditionModel, identityTraits: TraitModel[] ) { - let traitIdentityKey=Object.keys(identityTraits[0]) + + let traitIdentityKey=Object.keys(identityTraits) if (condition.operator === IS_SET ) { return traitIdentityKey[0] === condition.property_ } diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index 93184e2..dc98ce2 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -66,11 +66,12 @@ export class SegmentConditionModel { matchesTraitValue(traitValue: any) { const evaluators: { [key: string]: CallableFunction } = { evaluateNotContains: (traitValue: any) => { - return !traitValue.includes(this.value); + return !traitValue.includes(this.value) }, evaluateRegex: (traitValue: any) => { - // @ts-ignore - return !!traitValue.match(new RegExp(this.value)); + if (this.value != null || this.value != undefined){ + return !!traitValue.match(new RegExp(this.value)) + } } }; diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts index e415f05..315d628 100644 --- a/tests/engine/unit/segments/segment_operator.test.ts +++ b/tests/engine/unit/segments/segment_operator.test.ts @@ -12,17 +12,18 @@ import {TraitModel} from "../../../../flagsmith-engine"; import {traitsMatchSegmentCondition} from "../../../../flagsmith-engine/segments/evaluators"; const conditionMatchCases: [string, string | undefined, string | null | undefined, Array ,boolean][] = [ - [CONDITION_OPERATORS.IS_SET, 'foo',null, [{}], false], - [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{foo:'bar'}], true], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{}], true] + // [CONDITION_OPERATORS.IS_SET, 'foo',null, [{}], false], + // [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{foo:'bar'}], true], + // [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], + // [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{}], true], + [CONDITION_OPERATORS.IS_SET, 'foo', null, [{johnny: 'bravo'}, {foo: 'bar'}], true] ]; test('test_segment_condition_matches_Trait', () => { - for (const conditionModel of conditionMatchCases) { - let segmentModel = new SegmentConditionModel(conditionModel[0], conditionModel[2], conditionModel[1]) + for (const conditionTraits of conditionMatchCases) { + let segmentModel = new SegmentConditionModel(conditionTraits[0], conditionTraits[2], conditionTraits[1]) expect( - traitsMatchSegmentCondition (conditionModel[3], segmentModel, 'any','any') - ).toBe(conditionModel[4]); + traitsMatchSegmentCondition (conditionTraits[3], segmentModel, 'any','any') + ).toBe(conditionTraits[4]); } }); \ No newline at end of file From 6916985cf38cecddb404d9ae174826bc88ac8797 Mon Sep 17 00:00:00 2001 From: edsonloor Date: Fri, 14 Oct 2022 00:18:25 -0500 Subject: [PATCH 08/14] handleTraitExistenceConditions with one ts-ignore --- flagsmith-engine/segments/evaluators.ts | 20 ++++++++++++------- flagsmith-engine/segments/models.ts | 4 ++-- .../unit/segments/segment_operator.test.ts | 15 +++++--------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index df27530..a0f2e47 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -72,11 +72,17 @@ export function traitsMatchSegmentCondition( } } function handleTraitExistenceConditions (condition: SegmentConditionModel, identityTraits: TraitModel[] ) { - - let traitIdentityKey=Object.keys(identityTraits) - if (condition.operator === IS_SET ) { - return traitIdentityKey[0] === condition.property_ + let traitKeysArray: string[]=[] + identityTraits.map(function (e){ + let objectKey = Object.keys (e); + traitKeysArray.push(objectKey[0]) + }) + if (condition.operator === IS_SET && condition.property_ != undefined) { + return traitKeysArray.includes(condition.property_) } - return !(traitIdentityKey[0] === condition.property_) -} - + else + { + // @ts-ignore + return !(traitKeysArray.includes(condition.property_)) + } +} \ No newline at end of file diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index dc98ce2..1315e80 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -55,9 +55,9 @@ export class SegmentConditionModel { operator: string; value: string | null | undefined; - property_: string | undefined; + property_: string | null | undefined; - constructor(operator: string, value?: string | null, property?: string) { + constructor(operator: string, value?: string | null | undefined, property?: string | null | undefined) { this.operator = operator; this.value = value; this.property_ = property; diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts index 315d628..e673a58 100644 --- a/tests/engine/unit/segments/segment_operator.test.ts +++ b/tests/engine/unit/segments/segment_operator.test.ts @@ -1,21 +1,16 @@ import { CONDITION_OPERATORS, } from '../../../../flagsmith-engine/segments/constants'; -import { - segmentConditionProperty, - segmentConditionStringValue -} from "../utils"; import { SegmentConditionModel, } from '../../../../flagsmith-engine/segments/models'; -import {TraitModel} from "../../../../flagsmith-engine"; import {traitsMatchSegmentCondition} from "../../../../flagsmith-engine/segments/evaluators"; -const conditionMatchCases: [string, string | undefined, string | null | undefined, Array ,boolean][] = [ - // [CONDITION_OPERATORS.IS_SET, 'foo',null, [{}], false], - // [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{foo:'bar'}], true], - // [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{'foo':'bar'}], false], - // [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{}], true], +const conditionMatchCases: [string, string | null | undefined, string | null | undefined, Array ,boolean][] = [ + [CONDITION_OPERATORS.IS_SET,'foo',null, [{}], false], + [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{foo:'bar'}], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{johnny: 'bravo'}, {'foo':'bar'}], false], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{}], true], [CONDITION_OPERATORS.IS_SET, 'foo', null, [{johnny: 'bravo'}, {foo: 'bar'}], true] ]; From f04c88715da3a034c29a87e696f42b89352b3c0f Mon Sep 17 00:00:00 2001 From: edsonloor Date: Fri, 14 Oct 2022 00:20:05 -0500 Subject: [PATCH 09/14] segments_model modified --- .../unit/segments/segments_model.test.ts | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/engine/unit/segments/segments_model.test.ts b/tests/engine/unit/segments/segments_model.test.ts index e2e009e..09f9f8b 100644 --- a/tests/engine/unit/segments/segments_model.test.ts +++ b/tests/engine/unit/segments/segments_model.test.ts @@ -62,26 +62,26 @@ const conditionMatchCases: [string, string | number | boolean, string, boolean][ [CONDITION_OPERATORS.NOT_CONTAINS, 'bar', 'baz', true], [CONDITION_OPERATORS.REGEX, 'foo', '[a-z]+', true], [CONDITION_OPERATORS.REGEX, 'FOO', '[a-z]+', false], - [CONDITION_OPERATORS.EQUAL, '1.0.0', '1.0.0:semver', true], - [CONDITION_OPERATORS.EQUAL, '1.0.0', '1.0.0:semver', true], - [CONDITION_OPERATORS.EQUAL, '1.0.0', '1.0.1:semver', false], - [CONDITION_OPERATORS.NOT_EQUAL, '1.0.0', '1.0.0:semver', false], - [CONDITION_OPERATORS.NOT_EQUAL, '1.0.0', '1.0.1:semver', true], - [CONDITION_OPERATORS.GREATER_THAN, '1.0.1', '1.0.0:semver', true], - [CONDITION_OPERATORS.GREATER_THAN, '1.0.0', '1.0.0-beta:semver', true], - [CONDITION_OPERATORS.GREATER_THAN, '1.0.1', '1.2.0:semver', false], - [CONDITION_OPERATORS.GREATER_THAN, '1.0.1', '1.0.1:semver', false], - [CONDITION_OPERATORS.GREATER_THAN, '1.2.4', '1.2.3-pre.2+build.4:semver', true], - [CONDITION_OPERATORS.LESS_THAN, '1.0.0', '1.0.1:semver', true], - [CONDITION_OPERATORS.LESS_THAN, '1.0.0', '1.0.0:semver', false], - [CONDITION_OPERATORS.LESS_THAN, '1.0.1', '1.0.0:semver', false], - [CONDITION_OPERATORS.LESS_THAN, '1.0.0-rc.2', '1.0.0-rc.3:semver', true], - [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, '1.0.1', '1.0.0:semver', true], - [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, '1.0.1', '1.2.0:semver', false], - [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, '1.0.1', '1.0.1:semver', true], - [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.0', '1.0.1:semver', true], - [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.0', '1.0.0:semver', true], - [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, '1.0.1', '1.0.0:semver', false], + [CONDITION_OPERATORS.EQUAL, "1.0.0", "1.0.0:semver", true], + [CONDITION_OPERATORS.EQUAL, "1.0.0", "1.0.0:semver", true], + [CONDITION_OPERATORS.EQUAL, "1.0.0", "1.0.1:semver", false], + [CONDITION_OPERATORS.NOT_EQUAL, "1.0.0", "1.0.0:semver", false], + [CONDITION_OPERATORS.NOT_EQUAL, "1.0.0", "1.0.1:semver", true], + [CONDITION_OPERATORS.GREATER_THAN, "1.0.1", "1.0.0:semver", true], + [CONDITION_OPERATORS.GREATER_THAN, "1.0.0", "1.0.0-beta:semver", true], + [CONDITION_OPERATORS.GREATER_THAN, "1.0.1", "1.2.0:semver", false], + [CONDITION_OPERATORS.GREATER_THAN, "1.0.1", "1.0.1:semver", false], + [CONDITION_OPERATORS.GREATER_THAN, "1.2.4", "1.2.3-pre.2+build.4:semver", true], + [CONDITION_OPERATORS.LESS_THAN, "1.0.0", "1.0.1:semver", true], + [CONDITION_OPERATORS.LESS_THAN, "1.0.0", "1.0.0:semver", false], + [CONDITION_OPERATORS.LESS_THAN, "1.0.1", "1.0.0:semver", false], + [CONDITION_OPERATORS.LESS_THAN, "1.0.0-rc.2", "1.0.0-rc.3:semver", true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, "1.0.1", "1.0.0:semver", true], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, "1.0.1", "1.2.0:semver", false], + [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE, "1.0.1", "1.0.1:semver", true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, "1.0.0", "1.0.1:semver", true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, "1.0.0", "1.0.0:semver", true], + [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE, "1.0.1", "1.0.0:semver", false], ['BAD_OP', 'a', 'a', false] ]; From 9995fa2f15aaae49eb6f3cd4106fa49ff661c414 Mon Sep 17 00:00:00 2001 From: edsonloor Date: Sun, 16 Oct 2022 11:41:15 -0500 Subject: [PATCH 10/14] function traitsMatchSegmentCondition modified --- flagsmith-engine/segments/evaluators.ts | 25 +++++-------------- .../unit/segments/segment_operator.test.ts | 21 ++++++++-------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index a0f2e47..ed12b80 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -4,7 +4,6 @@ import { TraitModel } from '../identities/traits/models'; import { getHashedPercentateForObjIds } from '../utils/hashing'; import { PERCENTAGE_SPLIT, IS_SET, IS_NOT_SET } from './constants'; import { SegmentConditionModel, SegmentModel, SegmentRuleModel } from './models'; -import constants_1 from "../../build/flagsmith-engine/segments/constants"; export function getIdentitySegments( environment: EnvironmentModel, @@ -62,27 +61,15 @@ export function traitsMatchSegmentCondition( segmentId: number | string, identityId: number | string ): boolean { + const traits = identityTraits.filter(t => t.traitKey === condition.property_); + const trait = traits.length > 0 ? traits[0] : undefined; if (condition.operator == PERCENTAGE_SPLIT) { return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); - } else if (condition.operator === IS_SET || condition.operator === IS_NOT_SET) { - return handleTraitExistenceConditions (condition, identityTraits); + } else if (condition.operator === IS_SET ) { + return traits.length > 0 + } else if (condition.operator === IS_NOT_SET){ + return !(traits.length > 0) } else { - const traits = identityTraits.filter(t => t.traitKey === condition.property_);const trait = traits.length > 0 ? traits[0] : undefined; return trait ? condition.matchesTraitValue(trait.traitValue) : false; } -} -function handleTraitExistenceConditions (condition: SegmentConditionModel, identityTraits: TraitModel[] ) { - let traitKeysArray: string[]=[] - identityTraits.map(function (e){ - let objectKey = Object.keys (e); - traitKeysArray.push(objectKey[0]) - }) - if (condition.operator === IS_SET && condition.property_ != undefined) { - return traitKeysArray.includes(condition.property_) - } - else - { - // @ts-ignore - return !(traitKeysArray.includes(condition.property_)) - } } \ No newline at end of file diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts index e673a58..08e1a1a 100644 --- a/tests/engine/unit/segments/segment_operator.test.ts +++ b/tests/engine/unit/segments/segment_operator.test.ts @@ -5,20 +5,21 @@ import { SegmentConditionModel, } from '../../../../flagsmith-engine/segments/models'; import {traitsMatchSegmentCondition} from "../../../../flagsmith-engine/segments/evaluators"; +import {TraitModel} from "../../../../build"; -const conditionMatchCases: [string, string | null | undefined, string | null | undefined, Array ,boolean][] = [ - [CONDITION_OPERATORS.IS_SET,'foo',null, [{}], false], - [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{foo:'bar'}], true], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{johnny: 'bravo'}, {'foo':'bar'}], false], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{}], true], - [CONDITION_OPERATORS.IS_SET, 'foo', null, [{johnny: 'bravo'}, {foo: 'bar'}], true] +const conditionMatchesTraitkey: [string, string | null | undefined, string | null | undefined, Array ,boolean][] = [ + [CONDITION_OPERATORS.IS_SET,'foo',null, [{traitKey:'',traitValue:''}], false], + [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{traitKey:'foo',traitValue:'bar'}], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{traitKey:'foo',traitValue:'bar'}], false], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{traitKey:'',traitValue:''}], true], + [CONDITION_OPERATORS.IS_SET, 'foo', null, [{traitKey:'foo',traitValue:'bar'}], true] ]; test('test_segment_condition_matches_Trait', () => { - for (const conditionTraits of conditionMatchCases) { - let segmentModel = new SegmentConditionModel(conditionTraits[0], conditionTraits[2], conditionTraits[1]) + for (const conditionTraitProperty of conditionMatchesTraitkey) { + let segmentModel = new SegmentConditionModel(conditionTraitProperty[0], conditionTraitProperty[2], conditionTraitProperty[1]) expect( - traitsMatchSegmentCondition (conditionTraits[3], segmentModel, 'any','any') - ).toBe(conditionTraits[4]); + traitsMatchSegmentCondition (conditionTraitProperty[3], segmentModel, 'any','any') + ).toBe(conditionTraitProperty[4]); } }); \ No newline at end of file From 922d853128f9959e8c5734e2ce19fa9985cb2579 Mon Sep 17 00:00:00 2001 From: edsonloor Date: Sun, 16 Oct 2022 11:46:59 -0500 Subject: [PATCH 11/14] models.ts modified --- sdk/models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/models.ts b/sdk/models.ts index 5ca0701..27e1cb7 100644 --- a/sdk/models.ts +++ b/sdk/models.ts @@ -142,4 +142,4 @@ export class Flags { isFeatureEnabled(featureName: string): boolean { return this.getFlag(featureName).enabled; } -} \ No newline at end of file +} From 5ebd0603d0c29c8c09f33ae30ab79d4c5e6fa45a Mon Sep 17 00:00:00 2001 From: edsonloor Date: Mon, 17 Oct 2022 17:16:52 -0500 Subject: [PATCH 12/14] segment_operator.test.ts modified to segment_evaluators.test.ts --- flagsmith-engine/identities/models.ts | 14 ++++++---- flagsmith-engine/identities/traits/models.ts | 4 +-- flagsmith-engine/segments/evaluators.ts | 15 ++++++----- flagsmith-engine/segments/models.ts | 22 ++++++--------- .../unit/segments/segment_evaluators.test.ts | 27 +++++++++++++++++++ .../unit/segments/segment_operator.test.ts | 25 ----------------- 6 files changed, 54 insertions(+), 53 deletions(-) create mode 100644 tests/engine/unit/segments/segment_evaluators.test.ts delete mode 100644 tests/engine/unit/segments/segment_operator.test.ts diff --git a/flagsmith-engine/identities/models.ts b/flagsmith-engine/identities/models.ts index f841c12..aaabb66 100644 --- a/flagsmith-engine/identities/models.ts +++ b/flagsmith-engine/identities/models.ts @@ -40,14 +40,18 @@ export class IdentityModel { updateTraits(traits: TraitModel[]) { const existingTraits: Map = new Map(); for (const trait of this.identityTraits) { - existingTraits.set(trait.traitKey, trait); + if (trait.traitKey!= null){ + existingTraits.set(trait.traitKey, trait); + } } for (const trait of traits) { - if (!!trait.traitValue) { - existingTraits.set(trait.traitKey, trait); - } else { - existingTraits.delete(trait.traitKey); + if (trait.traitKey!= null) { + if (!!trait.traitValue) { + existingTraits.set(trait.traitKey, trait); + } else { + existingTraits.delete(trait.traitKey); + } } } diff --git a/flagsmith-engine/identities/traits/models.ts b/flagsmith-engine/identities/traits/models.ts index 99f42f3..239668b 100644 --- a/flagsmith-engine/identities/traits/models.ts +++ b/flagsmith-engine/identities/traits/models.ts @@ -1,8 +1,8 @@ export class TraitModel { - traitKey: string; + traitKey: string | null; traitValue: any; - constructor(key: string, value: any) { + constructor(key: string | null, value: any) { this.traitKey = key; this.traitValue = value; } diff --git a/flagsmith-engine/segments/evaluators.ts b/flagsmith-engine/segments/evaluators.ts index ed12b80..78a151e 100644 --- a/flagsmith-engine/segments/evaluators.ts +++ b/flagsmith-engine/segments/evaluators.ts @@ -61,15 +61,16 @@ export function traitsMatchSegmentCondition( segmentId: number | string, identityId: number | string ): boolean { + if (condition.operator == PERCENTAGE_SPLIT) { + return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(String(condition.value)); + } const traits = identityTraits.filter(t => t.traitKey === condition.property_); const trait = traits.length > 0 ? traits[0] : undefined; - if (condition.operator == PERCENTAGE_SPLIT) { - return getHashedPercentateForObjIds([segmentId, identityId]) <= parseFloat(condition.value); - } else if (condition.operator === IS_SET ) { - return traits.length > 0 + if (condition.operator === IS_SET ) { + return !!trait; } else if (condition.operator === IS_NOT_SET){ - return !(traits.length > 0) - } else { - return trait ? condition.matchesTraitValue(trait.traitValue) : false; + return trait == undefined; } + return trait ? condition.matchesTraitValue(trait.traitValue) : false; + } \ No newline at end of file diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index 1315e80..da64ae0 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -26,26 +26,20 @@ export const matchingFunctions = { [CONDITION_OPERATORS.NOT_EQUAL]: (thisValue: any, otherValue: any) => thisValue != otherValue, [CONDITION_OPERATORS.CONTAINS]: (thisValue: any, otherValue: any) => otherValue.includes(thisValue), - [CONDITION_OPERATORS.IS_SET]: (thisValue: any, otherValue: any) => thisValue == otherValue, - [CONDITION_OPERATORS.IS_NOT_SET]: (thisValue: any, otherValue: any) => thisValue != otherValue, }; export const semverMatchingFunction = { ...matchingFunctions, - [CONDITION_OPERATORS.EQUAL]: (thisValue: any, otherValue: any) => - semver.eq(thisValue, otherValue), - [CONDITION_OPERATORS.GREATER_THAN]: (thisValue: any, otherValue: any) => - semver.gt(otherValue, thisValue), + [CONDITION_OPERATORS.EQUAL]: (thisValue: any, otherValue: any) => semver.eq(thisValue, otherValue), + [CONDITION_OPERATORS.GREATER_THAN]: (thisValue: any, otherValue: any) => semver.gt(otherValue, thisValue), [CONDITION_OPERATORS.GREATER_THAN_INCLUSIVE]: (thisValue: any, otherValue: any) => semver.gte(otherValue, thisValue), - [CONDITION_OPERATORS.LESS_THAN]: (thisValue: any, otherValue: any) => - semver.gt(thisValue, otherValue), + [CONDITION_OPERATORS.LESS_THAN]: (thisValue: any, otherValue: any) => semver.gt(thisValue, otherValue), [CONDITION_OPERATORS.LESS_THAN_INCLUSIVE]: (thisValue: any, otherValue: any) => - semver.gte(thisValue, otherValue) -}; + semver.gte(thisValue, otherValue), +} -export const getMatchingFunctions = (semver: boolean) => - semver ? semverMatchingFunction : matchingFunctions; +export const getMatchingFunctions = (semver: boolean) => (semver ? semverMatchingFunction : matchingFunctions); export class SegmentConditionModel { EXCEPTION_OPERATOR_METHODS: { [key: string]: string } = { @@ -66,10 +60,10 @@ export class SegmentConditionModel { matchesTraitValue(traitValue: any) { const evaluators: { [key: string]: CallableFunction } = { evaluateNotContains: (traitValue: any) => { - return !traitValue.includes(this.value) + return !traitValue.includes(this.value); }, evaluateRegex: (traitValue: any) => { - if (this.value != null || this.value != undefined){ + if (this.value != null){ return !!traitValue.match(new RegExp(this.value)) } } diff --git a/tests/engine/unit/segments/segment_evaluators.test.ts b/tests/engine/unit/segments/segment_evaluators.test.ts new file mode 100644 index 0000000..bed0181 --- /dev/null +++ b/tests/engine/unit/segments/segment_evaluators.test.ts @@ -0,0 +1,27 @@ +import { + CONDITION_OPERATORS, +} from '../../../../flagsmith-engine/segments/constants'; +import { + SegmentConditionModel, +} from '../../../../flagsmith-engine/segments/models'; +import {traitsMatchSegmentCondition} from "../../../../flagsmith-engine/segments/evaluators"; +import {TraitModel} from "../../../../flagsmith-engine"; + +let traitExistenceTestCases: [string, string | null | undefined, string | null | undefined, TraitModel [],boolean][] = [ + [CONDITION_OPERATORS.IS_SET,'foo',null,[{traitKey: null, traitValue: undefined}] , false], + [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{traitKey: 'foo', traitValue: 'bar'}], true], + [CONDITION_OPERATORS.IS_SET, 'foo', null, [{traitKey: 'foo', traitValue: 'bar'},{traitKey: 'fooBaz', traitValue: 'baz'}], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [{traitKey: 'foo', traitValue: 'bar'}], false], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{traitKey: null, traitValue: undefined}], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [{traitKey: 'foo', traitValue: 'bar'},{traitKey: 'fooBaz', traitValue: 'baz'}], false] +]; + +test('test_traits_match_segment_condition_for_trait_existence_operators', () => { + for (const testCase of traitExistenceTestCases) { + const [operator, conditionProperty, conditionValue, traits, expectedResult] = testCase + let segmentModel = new SegmentConditionModel(operator, conditionValue, conditionProperty) + expect( + traitsMatchSegmentCondition (traits, segmentModel, 'any','any') + ).toBe(expectedResult); + } +}); \ No newline at end of file diff --git a/tests/engine/unit/segments/segment_operator.test.ts b/tests/engine/unit/segments/segment_operator.test.ts deleted file mode 100644 index 08e1a1a..0000000 --- a/tests/engine/unit/segments/segment_operator.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - CONDITION_OPERATORS, -} from '../../../../flagsmith-engine/segments/constants'; -import { - SegmentConditionModel, -} from '../../../../flagsmith-engine/segments/models'; -import {traitsMatchSegmentCondition} from "../../../../flagsmith-engine/segments/evaluators"; -import {TraitModel} from "../../../../build"; - -const conditionMatchesTraitkey: [string, string | null | undefined, string | null | undefined, Array ,boolean][] = [ - [CONDITION_OPERATORS.IS_SET,'foo',null, [{traitKey:'',traitValue:''}], false], - [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{traitKey:'foo',traitValue:'bar'}], true], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null,[{traitKey:'foo',traitValue:'bar'}], false], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{traitKey:'',traitValue:''}], true], - [CONDITION_OPERATORS.IS_SET, 'foo', null, [{traitKey:'foo',traitValue:'bar'}], true] -]; - -test('test_segment_condition_matches_Trait', () => { - for (const conditionTraitProperty of conditionMatchesTraitkey) { - let segmentModel = new SegmentConditionModel(conditionTraitProperty[0], conditionTraitProperty[2], conditionTraitProperty[1]) - expect( - traitsMatchSegmentCondition (conditionTraitProperty[3], segmentModel, 'any','any') - ).toBe(conditionTraitProperty[4]); - } -}); \ No newline at end of file From b5385a6cf53fd34c9d65ac9965897df9587f7aae Mon Sep 17 00:00:00 2001 From: edsonloor Date: Tue, 18 Oct 2022 11:07:07 -0500 Subject: [PATCH 13/14] segment_operator.test.ts and models.ts modified --- flagsmith-engine/identities/models.ts | 14 +++++--------- flagsmith-engine/identities/traits/models.ts | 4 ++-- flagsmith-engine/segments/models.ts | 4 +--- .../unit/segments/segment_evaluators.test.ts | 12 ++++++------ 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/flagsmith-engine/identities/models.ts b/flagsmith-engine/identities/models.ts index aaabb66..f841c12 100644 --- a/flagsmith-engine/identities/models.ts +++ b/flagsmith-engine/identities/models.ts @@ -40,18 +40,14 @@ export class IdentityModel { updateTraits(traits: TraitModel[]) { const existingTraits: Map = new Map(); for (const trait of this.identityTraits) { - if (trait.traitKey!= null){ - existingTraits.set(trait.traitKey, trait); - } + existingTraits.set(trait.traitKey, trait); } for (const trait of traits) { - if (trait.traitKey!= null) { - if (!!trait.traitValue) { - existingTraits.set(trait.traitKey, trait); - } else { - existingTraits.delete(trait.traitKey); - } + if (!!trait.traitValue) { + existingTraits.set(trait.traitKey, trait); + } else { + existingTraits.delete(trait.traitKey); } } diff --git a/flagsmith-engine/identities/traits/models.ts b/flagsmith-engine/identities/traits/models.ts index 239668b..99f42f3 100644 --- a/flagsmith-engine/identities/traits/models.ts +++ b/flagsmith-engine/identities/traits/models.ts @@ -1,8 +1,8 @@ export class TraitModel { - traitKey: string | null; + traitKey: string; traitValue: any; - constructor(key: string | null, value: any) { + constructor(key: string, value: any) { this.traitKey = key; this.traitValue = value; } diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index da64ae0..481b50b 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -63,9 +63,7 @@ export class SegmentConditionModel { return !traitValue.includes(this.value); }, evaluateRegex: (traitValue: any) => { - if (this.value != null){ - return !!traitValue.match(new RegExp(this.value)) - } + return !!this.value && !!traitValue.match(new RegExp(this.value)) } }; diff --git a/tests/engine/unit/segments/segment_evaluators.test.ts b/tests/engine/unit/segments/segment_evaluators.test.ts index bed0181..e0969de 100644 --- a/tests/engine/unit/segments/segment_evaluators.test.ts +++ b/tests/engine/unit/segments/segment_evaluators.test.ts @@ -8,12 +8,12 @@ import {traitsMatchSegmentCondition} from "../../../../flagsmith-engine/segments import {TraitModel} from "../../../../flagsmith-engine"; let traitExistenceTestCases: [string, string | null | undefined, string | null | undefined, TraitModel [],boolean][] = [ - [CONDITION_OPERATORS.IS_SET,'foo',null,[{traitKey: null, traitValue: undefined}] , false], - [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [{traitKey: 'foo', traitValue: 'bar'}], true], - [CONDITION_OPERATORS.IS_SET, 'foo', null, [{traitKey: 'foo', traitValue: 'bar'},{traitKey: 'fooBaz', traitValue: 'baz'}], true], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [{traitKey: 'foo', traitValue: 'bar'}], false], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [{traitKey: null, traitValue: undefined}], true], - [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [{traitKey: 'foo', traitValue: 'bar'},{traitKey: 'fooBaz', traitValue: 'baz'}], false] + [CONDITION_OPERATORS.IS_SET,'foo', null,[] , false], + [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [new TraitModel('foo','bar')], true], + [CONDITION_OPERATORS.IS_SET, 'foo',undefined , [new TraitModel('foo','bar'), new TraitModel('fooBaz','baz')], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', undefined, [], true], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [new TraitModel('foo','bar')], false], + [CONDITION_OPERATORS.IS_NOT_SET, 'foo', null, [new TraitModel('foo','bar'), new TraitModel('fooBaz','baz')], false] ]; test('test_traits_match_segment_condition_for_trait_existence_operators', () => { From 716bae2d3926e467d886d66ead71cce8fd341bf4 Mon Sep 17 00:00:00 2001 From: Matthew Elwell Date: Fri, 21 Oct 2022 17:52:03 +0100 Subject: [PATCH 14/14] Post merge fix --- flagsmith-engine/segments/models.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flagsmith-engine/segments/models.ts b/flagsmith-engine/segments/models.ts index 30c2f8b..41fe096 100644 --- a/flagsmith-engine/segments/models.ts +++ b/flagsmith-engine/segments/models.ts @@ -68,11 +68,11 @@ export class SegmentConditionModel { return !!this.value && !!traitValue.match(new RegExp(this.value)); }, evaluateModulo: (traitValue: any) => { - if (isNaN(parseFloat(traitValue))) { + if (isNaN(parseFloat(traitValue)) || !this.value) { return false } - const myArray = (this.value).split("|"); - let [divisor, reminder] = [parseFloat(myArray[0]), parseFloat(myArray[1])]; + const parts = (this.value).split("|"); + const [divisor, reminder] = [parseFloat(parts[0]), parseFloat(parts[1])]; return traitValue % divisor === reminder } };