Skip to content

Commit 014f38b

Browse files
authored
feat: removed-feature-key-and-segment-key-from-schema (#210)
* feat: removed-feature-key-and-segment-key-from-schema * feat: re-organized-models * chore: camel-cased-flagsmith-id * chore: throw-error-if-metadata-missing * feat: boolean-trait-returns-false-in-operator * feat: implemented-implicit-identity-key (#211) * fix: environment evaluation skip segments (#213) * feat: implemented-implicit-identity-key * fix: skip-segment-if-environment-flag-and-moved-flagsmith-id-to-id * fix: rename-custom-to-sdk-metadata
1 parent 7004897 commit 014f38b

File tree

14 files changed

+208
-139
lines changed

14 files changed

+208
-139
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "tests/engine/engine-tests/engine-test-data"]
22
path = tests/engine/engine-tests/engine-test-data
33
url = [email protected]:Flagsmith/engine-test-data.git
4-
branch = v2.5.0
4+
branch = v3.1.0

flagsmith-engine/evaluation/evaluationContext/evaluationContext.types.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@
66
*/
77

88
/**
9-
* An environment's unique identifier.
9+
* Unique environment key. May be used for selecting a value for a multivariate feature, or for % split segmentation.
1010
*/
1111
export type Key = string;
1212
/**
1313
* An environment's human-readable name.
1414
*/
1515
export type Name = string;
1616
/**
17-
* A unique identifier for an identity, used for segment and multivariate feature flag targeting, and displayed in the Flagsmith UI.
17+
* A unique identifier for an identity as displayed in the Flagsmith UI.
1818
*/
1919
export type Identifier = string;
2020
/**
2121
* Key used when selecting a value for a multivariate feature, or for % split segmentation. Set to an internal identifier or a composite value based on the environment key and identifier, depending on Flagsmith implementation.
2222
*/
2323
export type Key1 = string;
2424
/**
25-
* Key used for % split segmentation.
25+
* Unique segment key used for % split segmentation.
2626
*/
2727
export type Key2 = string;
2828
/**
@@ -85,13 +85,9 @@ export type SubRules = SegmentRule[];
8585
*/
8686
export type Rules = SegmentRule[];
8787
/**
88-
* Key used when selecting a value for a multivariate feature. Set to an internal identifier or a UUID, depending on Flagsmith implementation.
88+
* Unique feature key used when selecting a variant if the feature is multivariate. Set to an internal identifier or a UUID, depending on Flagsmith implementation.
8989
*/
9090
export type Key3 = string;
91-
/**
92-
* Unique feature identifier.
93-
*/
94-
export type FeatureKey = string;
9591
/**
9692
* Feature name.
9793
*/
@@ -155,7 +151,7 @@ export interface EnvironmentContext {
155151
*/
156152
export interface IdentityContext {
157153
identifier: Identifier;
158-
key: Key1;
154+
key?: Key1;
159155
traits?: Traits;
160156
[k: string]: unknown;
161157
}
@@ -214,7 +210,6 @@ export interface InSegmentCondition {
214210
*/
215211
export interface FeatureContext {
216212
key: Key3;
217-
feature_key: FeatureKey;
218213
name: Name2;
219214
enabled: Enabled;
220215
value: Value2;

flagsmith-engine/evaluation/evaluationContext/mappers.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import {
22
FeaturesWithMetadata,
3-
Segments,
43
Traits,
54
GenericEvaluationContext,
65
EnvironmentContext,
76
IdentityContext,
8-
SegmentSource
7+
SegmentSource,
8+
SDKFeatureMetadata,
9+
SegmentsWithMetadata,
10+
SDKSegmentMetadata
911
} from '../models.js';
1012
import { EnvironmentModel } from '../../environments/models.js';
1113
import { IdentityModel } from '../../identities/models.js';
@@ -17,9 +19,13 @@ import { uuidToBigInt } from '../../features/util.js';
1719
export function getEvaluationContext(
1820
environment: EnvironmentModel,
1921
identity?: IdentityModel,
20-
overrideTraits?: TraitModel[]
22+
overrideTraits?: TraitModel[],
23+
isEnvironmentEvaluation: boolean = false
2124
): GenericEvaluationContext {
2225
const environmentContext = mapEnvironmentModelToEvaluationContext(environment);
26+
if (isEnvironmentEvaluation) {
27+
return environmentContext;
28+
}
2329
const identityContext = identity
2430
? mapIdentityModelToIdentityContext(identity, overrideTraits)
2531
: undefined;
@@ -40,7 +46,7 @@ function mapEnvironmentModelToEvaluationContext(
4046
name: environment.project.name
4147
};
4248

43-
const features: FeaturesWithMetadata = {};
49+
const features: FeaturesWithMetadata<SDKFeatureMetadata> = {};
4450
for (const fs of environment.featureStates) {
4551
const variants =
4652
fs.multivariateFeatureStateValues?.length > 0
@@ -53,19 +59,18 @@ function mapEnvironmentModelToEvaluationContext(
5359

5460
features[fs.feature.name] = {
5561
key: fs.djangoID?.toString() || fs.featurestateUUID,
56-
feature_key: fs.feature.id.toString(),
5762
name: fs.feature.name,
5863
enabled: fs.enabled,
5964
value: fs.getValue(),
6065
variants,
6166
priority: fs.featureSegment?.priority,
6267
metadata: {
63-
flagsmithId: fs.feature.id
68+
id: fs.feature.id
6469
}
6570
};
6671
}
6772

68-
const segmentOverrides: Segments = {};
73+
const segmentOverrides: SegmentsWithMetadata<SDKSegmentMetadata> = {};
6974
for (const segment of environment.project.segments) {
7075
segmentOverrides[segment.id.toString()] = {
7176
key: segment.id.toString(),
@@ -75,21 +80,23 @@ function mapEnvironmentModelToEvaluationContext(
7580
segment.featureStates.length > 0
7681
? segment.featureStates.map(fs => ({
7782
key: fs.djangoID?.toString() || fs.featurestateUUID,
78-
feature_key: fs.feature.id.toString(),
7983
name: fs.feature.name,
8084
enabled: fs.enabled,
8185
value: fs.getValue(),
82-
priority: fs.featureSegment?.priority
86+
priority: fs.featureSegment?.priority,
87+
metadata: {
88+
id: fs.feature.id
89+
}
8390
}))
8491
: [],
8592
metadata: {
8693
source: SegmentSource.API,
87-
flagsmith_id: segment.id
94+
id: segment.id
8895
}
8996
};
9097
}
9198

92-
let identityOverrideSegments: Segments = {};
99+
let identityOverrideSegments: SegmentsWithMetadata<SDKSegmentMetadata> = {};
93100
if (environment.identityOverrides && environment.identityOverrides.length > 0) {
94101
identityOverrideSegments = mapIdentityOverridesToSegments(environment.identityOverrides);
95102
}
@@ -115,11 +122,16 @@ function mapIdentityModelToIdentityContext(
115122
traitsContext[trait.traitKey] = trait.traitValue;
116123
}
117124

118-
return {
125+
const identityContext: IdentityContext = {
119126
identifier: identity.identifier,
120-
key: identity.djangoID?.toString() || identity.compositeKey,
121127
traits: traitsContext
122128
};
129+
130+
if (identity.djangoID !== undefined) {
131+
identityContext.key = identity.djangoID.toString();
132+
}
133+
134+
return identityContext;
123135
}
124136

125137
function mapSegmentRuleModelToRule(rule: any): any {
@@ -134,8 +146,10 @@ function mapSegmentRuleModelToRule(rule: any): any {
134146
};
135147
}
136148

137-
function mapIdentityOverridesToSegments(identityOverrides: IdentityModel[]): Segments {
138-
const segments: Segments = {};
149+
function mapIdentityOverridesToSegments(
150+
identityOverrides: IdentityModel[]
151+
): SegmentsWithMetadata<SDKSegmentMetadata> {
152+
const segments: SegmentsWithMetadata<SDKSegmentMetadata> = {};
139153
const featuresToIdentifiers = new Map<string, { identifiers: string[]; overrides: any[] }>();
140154

141155
for (const identity of identityOverrides) {
@@ -147,13 +161,12 @@ function mapIdentityOverridesToSegments(identityOverrides: IdentityModel[]): Seg
147161
a.feature.name.localeCompare(b.feature.name)
148162
);
149163
const overridesKey = sortedFeatures.map(fs => ({
150-
feature_key: fs.feature.id.toString(),
151164
name: fs.feature.name,
152165
enabled: fs.enabled,
153166
value: fs.getValue(),
154167
priority: -Infinity,
155168
metadata: {
156-
flagsmithId: fs.feature.id
169+
id: fs.feature.id
157170
}
158171
}));
159172

flagsmith-engine/evaluation/evaluationResult/evaluationResult.types.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
* and run json-schema-to-typescript to regenerate this file.
66
*/
77

8-
/**
9-
* Unique feature identifier.
10-
*/
11-
export type FeatureKey = string;
128
/**
139
* Feature name.
1410
*/
@@ -25,10 +21,6 @@ export type Value = string | number | boolean | null;
2521
* Reason for the feature flag evaluation.
2622
*/
2723
export type Reason = string;
28-
/**
29-
* Unique segment identifier.
30-
*/
31-
export type Key = string;
3224
/**
3325
* Segment name.
3426
*/
@@ -53,7 +45,6 @@ export interface Flags {
5345
[k: string]: FlagResult;
5446
}
5547
export interface FlagResult {
56-
feature_key: FeatureKey;
5748
name: Name;
5849
enabled: Enabled;
5950
value: Value;
@@ -68,7 +59,6 @@ export interface FeatureMetadata {
6859
[k: string]: unknown;
6960
}
7061
export interface SegmentResult {
71-
key: Key;
7262
name: Name1;
7363
metadata?: SegmentMetadata;
7464
[k: string]: unknown;

flagsmith-engine/evaluation/models.ts

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,27 @@
55
import type {
66
EvaluationResult as EvaluationContextResult,
77
FlagResult,
8-
FeatureMetadata
8+
FeatureMetadata,
9+
SegmentMetadata
910
} from './evaluationResult/evaluationResult.types.js';
1011

1112
import type {
1213
FeatureContext,
1314
EnvironmentContext,
1415
IdentityContext,
15-
Segments
16+
SegmentContext
1617
} from './evaluationContext/evaluationContext.types.js';
1718

18-
export interface CustomFeatureMetadata extends FeatureMetadata {
19-
flagsmithId?: number;
19+
export * from './evaluationContext/evaluationContext.types.js';
20+
21+
export enum SegmentSource {
22+
API = 'api',
23+
IDENTITY_OVERRIDE = 'identity_override'
24+
}
25+
26+
// Feature types
27+
export interface SDKFeatureMetadata extends FeatureMetadata {
28+
id: number;
2029
}
2130

2231
export interface FeatureContextWithMetadata<T extends FeatureMetadata = FeatureMetadata>
@@ -29,14 +38,6 @@ export type FeaturesWithMetadata<T extends FeatureMetadata = FeatureMetadata> =
2938
[k: string]: FeatureContextWithMetadata<T>;
3039
};
3140

32-
export interface GenericEvaluationContext<T extends FeatureMetadata = FeatureMetadata> {
33-
environment: EnvironmentContext;
34-
identity?: IdentityContext | null;
35-
segments?: Segments;
36-
features?: FeaturesWithMetadata<T>;
37-
[k: string]: unknown;
38-
}
39-
4041
export type FlagResultWithMetadata<T extends FeatureMetadata = FeatureMetadata> = FlagResult & {
4142
metadata: T;
4243
};
@@ -46,19 +47,50 @@ export type EvaluationResultFlags<T extends FeatureMetadata = FeatureMetadata> =
4647
FlagResultWithMetadata<T>
4748
>;
4849

49-
export type EvaluationResultSegments = EvaluationContextResult['segments'];
50+
// Segment types
51+
export interface SDKSegmentMetadata extends SegmentMetadata {
52+
id?: number;
53+
source?: SegmentSource;
54+
}
5055

51-
export type EvaluationResult<T extends FeatureMetadata = FeatureMetadata> = {
52-
flags: EvaluationResultFlags<T>;
53-
segments: EvaluationResultSegments;
56+
export interface SegmentContextWithMetadata<T extends SegmentMetadata = SegmentMetadata>
57+
extends SegmentContext {
58+
metadata: T;
59+
overrides?: FeatureContextWithMetadata<FeatureMetadata>[];
60+
}
61+
62+
export type SegmentsWithMetadata<T extends SegmentMetadata = SegmentMetadata> = {
63+
[k: string]: SegmentContextWithMetadata<T>;
5464
};
5565

56-
export type EvaluationResultWithMetadata = EvaluationResult<CustomFeatureMetadata>;
57-
export type EvaluationContextWithMetadata = GenericEvaluationContext<CustomFeatureMetadata>;
66+
export interface SegmentResultWithMetadata {
67+
name: string;
68+
metadata: SDKSegmentMetadata;
69+
}
5870

59-
export enum SegmentSource {
60-
API = 'api',
61-
IDENTITY_OVERRIDE = 'identity_override'
71+
export type EvaluationResultSegments = SegmentResultWithMetadata[];
72+
73+
// Evaluation context types
74+
export interface GenericEvaluationContext<
75+
T extends FeatureMetadata = FeatureMetadata,
76+
S extends SegmentMetadata = SegmentMetadata
77+
> {
78+
environment: EnvironmentContext;
79+
identity?: IdentityContext | null;
80+
segments?: SegmentsWithMetadata<S>;
81+
features?: FeaturesWithMetadata<T>;
82+
[k: string]: unknown;
6283
}
6384

64-
export * from './evaluationContext/evaluationContext.types.js';
85+
export type EvaluationContextWithMetadata = GenericEvaluationContext<
86+
SDKFeatureMetadata,
87+
SDKSegmentMetadata
88+
>;
89+
90+
// Evaluation result types
91+
export type EvaluationResult<T extends FeatureMetadata = FeatureMetadata> = {
92+
flags: EvaluationResultFlags<T>;
93+
segments: EvaluationResultSegments;
94+
};
95+
96+
export type EvaluationResultWithMetadata = EvaluationResult<SDKFeatureMetadata>;

0 commit comments

Comments
 (0)