From 7d69750f3b34cf61722b0d6eb5ae647642893542 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Tue, 13 Jun 2023 11:26:10 +0200 Subject: [PATCH] refactor: Extract playground steps (#3966) --- .../generateObjectCombinations.test.ts | 0 .../playground}/generateObjectCombinations.ts | 4 +- .../playground/offline-unleash-client.ts | 2 +- .../features/playground/playground-service.ts | 92 +++++++++++++++---- 4 files changed, 75 insertions(+), 23 deletions(-) rename src/lib/{util => features/playground}/generateObjectCombinations.test.ts (100%) rename src/lib/{util => features/playground}/generateObjectCombinations.ts (89%) diff --git a/src/lib/util/generateObjectCombinations.test.ts b/src/lib/features/playground/generateObjectCombinations.test.ts similarity index 100% rename from src/lib/util/generateObjectCombinations.test.ts rename to src/lib/features/playground/generateObjectCombinations.test.ts diff --git a/src/lib/util/generateObjectCombinations.ts b/src/lib/features/playground/generateObjectCombinations.ts similarity index 89% rename from src/lib/util/generateObjectCombinations.ts rename to src/lib/features/playground/generateObjectCombinations.ts index 19fba40a54..fe0a3aebc0 100644 --- a/src/lib/util/generateObjectCombinations.ts +++ b/src/lib/features/playground/generateObjectCombinations.ts @@ -7,7 +7,7 @@ export const splitByComma = >( Object.entries(obj).map(([key, value]) => [key, value.split(',')]), ) as Dict; -export const generateCombinations = >( +export const generateCombinations = >( obj: Dict, ): T[] => { const keys = Object.keys(obj) as (keyof T)[]; @@ -21,7 +21,7 @@ export const generateCombinations = >( ) as T[]; }; -export const generateObjectCombinations = >( +export const generateObjectCombinations = >( obj: T, ): T[] => { const splitObj = splitByComma(obj); diff --git a/src/lib/features/playground/offline-unleash-client.ts b/src/lib/features/playground/offline-unleash-client.ts index d8051bcab6..4bf4327211 100644 --- a/src/lib/features/playground/offline-unleash-client.ts +++ b/src/lib/features/playground/offline-unleash-client.ts @@ -64,7 +64,7 @@ export const offlineUnleashClient = async ({ }, }); - client.start(); + await client.start(); return client; }; diff --git a/src/lib/features/playground/playground-service.ts b/src/lib/features/playground/playground-service.ts index 376456c2d3..17762c44da 100644 --- a/src/lib/features/playground/playground-service.ts +++ b/src/lib/features/playground/playground-service.ts @@ -4,11 +4,20 @@ import { IUnleashServices } from 'lib/types/services'; import { ALL } from '../../types/models/api-token'; import { PlaygroundFeatureSchema } from 'lib/openapi/spec/playground-feature-schema'; import { Logger } from '../../logger'; -import { IUnleashConfig } from 'lib/types'; +import { ISegment, IUnleashConfig } from 'lib/types'; import { offlineUnleashClient } from './offline-unleash-client'; import { FeatureInterface } from 'lib/features/playground/feature-evaluator/feature'; import { FeatureStrategiesEvaluationResult } from 'lib/features/playground/feature-evaluator/client'; import { ISegmentService } from 'lib/segments/segment-service-interface'; +import { FeatureConfigurationClient } from '../../types/stores/feature-strategies-store'; +import { generateObjectCombinations } from './generateObjectCombinations'; + +type EvaluationInput = { + features: FeatureConfigurationClient[]; + segments: ISegment[]; + featureProject: Record; + context: SdkContextSchema; +}; export class PlaygroundService { private readonly logger: Logger; @@ -29,30 +38,38 @@ export class PlaygroundService { this.segmentService = segmentService; } - async evaluateQuery( + async evaluateAdvancedQuery( projects: typeof ALL | string[], - environment: string, + environments: string[], context: SdkContextSchema, ): Promise { - const [features, segments] = await Promise.all([ - this.featureToggleService.getClientFeatures( - { - project: projects === ALL ? undefined : projects, - environment, - }, - true, - false, - ), - this.segmentService.getActive(), - ]); - const featureProject: Record = features.reduce( - (obj, feature) => { - obj[feature.name] = feature.project; - return obj; - }, - {}, + const segments = await this.segmentService.getActive(); + const environmentFeatures = await Promise.all( + environments.map((env) => this.resolveFeatures(projects, env)), ); + const contexts = generateObjectCombinations(context); + const results = await Promise.all( + environmentFeatures.flatMap(({ features, featureProject }) => + contexts.map((singleContext) => + this.evaluate({ + features, + featureProject, + context: singleContext, + segments, + }), + ), + ), + ); + return results.flat(); + } + + private async evaluate({ + featureProject, + features, + segments, + context, + }: EvaluationInput): Promise { const [head, ...rest] = features; if (!head) { return []; @@ -102,4 +119,39 @@ export class PlaygroundService { return output; } } + + private async resolveFeatures( + projects: typeof ALL | string[], + environment: string, + ): Promise> { + const features = await this.featureToggleService.getClientFeatures( + { + project: projects === ALL ? undefined : projects, + environment, + }, + true, + false, + ); + const featureProject: Record = features.reduce( + (obj, feature) => { + obj[feature.name] = feature.project; + return obj; + }, + {}, + ); + return { features, featureProject }; + } + + async evaluateQuery( + projects: typeof ALL | string[], + environment: string, + context: SdkContextSchema, + ): Promise { + const [{ features, featureProject }, segments] = await Promise.all([ + this.resolveFeatures(projects, environment), + this.segmentService.getActive(), + ]); + + return this.evaluate({ features, featureProject, segments, context }); + } }