diff --git a/src/lib/features/playground/playground-service.ts b/src/lib/features/playground/playground-service.ts index caefb5f0b8aa..3da945dd9433 100644 --- a/src/lib/features/playground/playground-service.ts +++ b/src/lib/features/playground/playground-service.ts @@ -4,22 +4,28 @@ import { IUnleashServices } from '../../types/services'; import { ALL } from '../../types/models/api-token'; import { PlaygroundFeatureSchema } from '../../openapi/spec/playground-feature-schema'; import { Logger } from '../../logger'; -import { IFlagResolver, ISegment, IUnleashConfig } from '../../types'; +import { + IFlagResolver, + ISegment, + ISegmentReadModel, + IUnleashConfig, +} from '../../types'; import { offlineUnleashClient } from './offline-unleash-client'; import { FeatureInterface } from '../../features/playground/feature-evaluator/feature'; import { EvaluatedPlaygroundStrategy, FeatureStrategiesEvaluationResult, } from '../../features/playground/feature-evaluator/client'; -import { ISegmentService } from '../../segments/segment-service-interface'; import { FeatureConfigurationClient } from '../feature-toggle/types/feature-toggle-strategies-store-type'; import { generateObjectCombinations } from './generateObjectCombinations'; import groupBy from 'lodash.groupby'; import { omitKeys } from '../../util'; -import { AdvancedPlaygroundFeatureSchema } from '../../openapi'; +import { + AdvancedPlaygroundFeatureSchema, + playgroundStrategyEvaluation, +} from '../../openapi'; import { AdvancedPlaygroundEnvironmentFeatureSchema } from '../../openapi/spec/advanced-playground-environment-feature-schema'; import { validateQueryComplexity } from './validateQueryComplexity'; -import { playgroundStrategyEvaluation } from '../../openapi'; import { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType'; import { getDefaultVariant } from './feature-evaluator/variant'; @@ -66,30 +72,28 @@ export class PlaygroundService { private readonly featureToggleService: FeatureToggleService; - private readonly segmentService: ISegmentService; + private readonly flagResolver: IFlagResolver; - private flagResolver: IFlagResolver; + private readonly privateProjectChecker: IPrivateProjectChecker; - private privateProjectChecker: IPrivateProjectChecker; + private readonly segmentReadModel: ISegmentReadModel; constructor( config: IUnleashConfig, { featureToggleServiceV2, - segmentService, privateProjectChecker, }: Pick< IUnleashServices, - | 'featureToggleServiceV2' - | 'segmentService' - | 'privateProjectChecker' + 'featureToggleServiceV2' | 'privateProjectChecker' >, + segmentReadModel: ISegmentReadModel, ) { this.logger = config.getLogger('services/playground-service.ts'); this.flagResolver = config.flagResolver; this.featureToggleService = featureToggleServiceV2; - this.segmentService = segmentService; this.privateProjectChecker = privateProjectChecker; + this.segmentReadModel = segmentReadModel; } async evaluateAdvancedQuery( @@ -99,7 +103,7 @@ export class PlaygroundService { limit: number, userId: number, ): Promise { - const segments = await this.segmentService.getActive(); + const segments = await this.segmentReadModel.getActive(); let filteredProjects: typeof projects = projects; @@ -266,7 +270,7 @@ export class PlaygroundService { ): Promise { const [{ features, featureProject }, segments] = await Promise.all([ this.resolveFeatures(projects, environment), - this.segmentService.getActive(), + this.segmentReadModel.getActive(), ]); const result = await this.evaluate({ diff --git a/src/lib/features/segment/fake-segment-read-model.ts b/src/lib/features/segment/fake-segment-read-model.ts index 44963a071b23..a5ac2451178f 100644 --- a/src/lib/features/segment/fake-segment-read-model.ts +++ b/src/lib/features/segment/fake-segment-read-model.ts @@ -1,4 +1,4 @@ -import { IFeatureStrategySegment, ISegment } from '../../types'; +import { IClientSegment, IFeatureStrategySegment, ISegment } from '../../types'; import { ISegmentReadModel } from './segment-read-model-type'; export class FakeSegmentReadModel implements ISegmentReadModel { @@ -9,4 +9,12 @@ export class FakeSegmentReadModel implements ISegmentReadModel { async getAllFeatureStrategySegments(): Promise { return []; } + + async getActive(): Promise { + return []; + } + + async getActiveForClient(): Promise { + return []; + } } diff --git a/src/lib/features/segment/segment-read-model-type.ts b/src/lib/features/segment/segment-read-model-type.ts index 0a46fc22ef8f..74a4da2bd240 100644 --- a/src/lib/features/segment/segment-read-model-type.ts +++ b/src/lib/features/segment/segment-read-model-type.ts @@ -1,6 +1,8 @@ -import { IFeatureStrategySegment, ISegment } from '../../types'; +import { IClientSegment, IFeatureStrategySegment, ISegment } from '../../types'; export interface ISegmentReadModel { getAll(): Promise; getAllFeatureStrategySegments(): Promise; + getActive(): Promise; + getActiveForClient(): Promise; } diff --git a/src/lib/features/segment/segment-read-model.ts b/src/lib/features/segment/segment-read-model.ts index 642288576511..6b5b10707a9d 100644 --- a/src/lib/features/segment/segment-read-model.ts +++ b/src/lib/features/segment/segment-read-model.ts @@ -1,4 +1,9 @@ -import { IConstraint, IFeatureStrategySegment, ISegment } from '../../types'; +import { + IClientSegment, + IConstraint, + IFeatureStrategySegment, + ISegment, +} from '../../types'; import { ISegmentReadModel } from './segment-read-model-type'; import NotFoundError from '../../error/notfound-error'; import { Db } from '../../db/db'; @@ -75,4 +80,28 @@ export class SegmentReadModel implements ISegmentReadModel { segmentId: row.segment_id, })); } + + async getActive(): Promise { + const rows: ISegmentRow[] = await this.db + .distinct(this.prefixColumns()) + .from('segments') + .orderBy('name', 'asc') + .join( + 'feature_strategy_segment', + 'feature_strategy_segment.segment_id', + 'segments.id', + ); + + return rows.map(this.mapRow); + } + + async getActiveForClient(): Promise { + const fullSegments = await this.getActive(); + + return fullSegments.map((segments) => ({ + id: segments.id, + name: segments.name, + constraints: segments.constraints, + })); + } } diff --git a/src/lib/segments/segment-service-interface.ts b/src/lib/segments/segment-service-interface.ts index 0300f52408c8..4e6b278dc601 100644 --- a/src/lib/segments/segment-service-interface.ts +++ b/src/lib/segments/segment-service-interface.ts @@ -33,8 +33,6 @@ export interface ISegmentService { validateName(name: string): Promise; - getActive(): Promise; - getActiveForClient(): Promise; getAll(): Promise; diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts index c33988783752..80fb65bb0c60 100644 --- a/src/lib/services/index.ts +++ b/src/lib/services/index.ts @@ -109,6 +109,8 @@ import { createInstanceStatsService, } from '../features/instance-stats/createInstanceStatsService'; import { InactiveUsersService } from '../users/inactive/inactive-users-service'; +import { SegmentReadModel } from '../features/segment/segment-read-model'; +import { FakeSegmentReadModel } from '../features/segment/fake-segment-read-model'; export const createServices = ( stores: IUnleashStores, @@ -138,6 +140,9 @@ export const createServices = ( const dependentFeaturesReadModel = db ? new DependentFeaturesReadModel(db) : new FakeDependentFeaturesReadModel(); + const segmentReadModel = db + ? new SegmentReadModel(db) + : new FakeSegmentReadModel(); const contextService = new ContextService( stores, @@ -270,11 +275,14 @@ export const createServices = ( const userSplashService = new UserSplashService(stores, config); const openApiService = new OpenApiService(config); const clientSpecService = new ClientSpecService(config); - const playgroundService = new PlaygroundService(config, { - featureToggleServiceV2, - segmentService, - privateProjectChecker, - }); + const playgroundService = new PlaygroundService( + config, + { + featureToggleServiceV2, + privateProjectChecker, + }, + segmentReadModel, + ); const configurationRevisionService = new ConfigurationRevisionService( stores, diff --git a/src/lib/services/segment-service.ts b/src/lib/services/segment-service.ts index 3003905f40a5..796f7098c49a 100644 --- a/src/lib/services/segment-service.ts +++ b/src/lib/services/segment-service.ts @@ -79,10 +79,6 @@ export class SegmentService implements ISegmentService { return this.segmentStore.getAll(this.config.isEnterprise); } - async getActive(): Promise { - return this.segmentStore.getActive(); - } - async getActiveForClient(): Promise { return this.segmentStore.getActiveForClient(); } diff --git a/src/test/e2e/api/admin/state.e2e.test.ts b/src/test/e2e/api/admin/state.e2e.test.ts index fbf9b406165b..fc118c5ed7fc 100644 --- a/src/test/e2e/api/admin/state.e2e.test.ts +++ b/src/test/e2e/api/admin/state.e2e.test.ts @@ -377,7 +377,7 @@ test(`should import segments and connect them to feature strategies`, async () = .expect(202); const allSegments = await app.services.segmentService.getAll(); - const activeSegments = await app.services.segmentService.getActive(); + const activeSegments = await db.stores.segmentReadModel.getActive(); expect(allSegments.length).toEqual(2); expect(collectIds(allSegments)).toEqual([1, 2]); diff --git a/src/test/e2e/services/playground-service.test.ts b/src/test/e2e/services/playground-service.test.ts index 0decadfb62f2..0937774592ff 100644 --- a/src/test/e2e/services/playground-service.test.ts +++ b/src/test/e2e/services/playground-service.test.ts @@ -20,18 +20,14 @@ import { SdkContextSchema } from '../../../lib/openapi/spec/sdk-context-schema'; import { SegmentSchema } from '../../../lib/openapi/spec/segment-schema'; import { playgroundStrategyEvaluation } from '../../../lib/openapi/spec/playground-strategy-schema'; import { PlaygroundSegmentSchema } from '../../../lib/openapi/spec/playground-segment-schema'; -import { ISegmentService } from '../../../lib/segments/segment-service-interface'; import { createPrivateProjectChecker } from '../../../lib/features/private-project/createPrivateProjectChecker'; -import { - createFeatureToggleService, - createSegmentService, -} from '../../../lib/features'; +import { createFeatureToggleService } from '../../../lib/features'; +import { SegmentReadModel } from '../../../lib/features/segment/segment-read-model'; let stores: IUnleashStores; let db: ITestDb; let service: PlaygroundService; let featureToggleService: FeatureToggleService; -let segmentService: ISegmentService; beforeAll(async () => { const config = createTestConfig(); @@ -41,14 +37,17 @@ beforeAll(async () => { db.rawDatabase, config, ); - segmentService = createSegmentService(db.rawDatabase, config); + const segmentReadModel = new SegmentReadModel(db.rawDatabase); featureToggleService = createFeatureToggleService(db.rawDatabase, config); - service = new PlaygroundService(config, { - featureToggleServiceV2: featureToggleService, - segmentService, - privateProjectChecker, - }); + service = new PlaygroundService( + config, + { + featureToggleServiceV2: featureToggleService, + privateProjectChecker, + }, + segmentReadModel, + ); }); afterAll(async () => {