mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-21 13:47:39 +02:00
refactor: playground uses segment read model (#6424)
This commit is contained in:
parent
62dc77db16
commit
095b6eca84
@ -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<AdvancedPlaygroundFeatureEvaluationResult[]> {
|
||||
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<PlaygroundFeatureEvaluationResult[]> {
|
||||
const [{ features, featureProject }, segments] = await Promise.all([
|
||||
this.resolveFeatures(projects, environment),
|
||||
this.segmentService.getActive(),
|
||||
this.segmentReadModel.getActive(),
|
||||
]);
|
||||
|
||||
const result = await this.evaluate({
|
||||
|
@ -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<IFeatureStrategySegment[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getActive(): Promise<ISegment[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getActiveForClient(): Promise<IClientSegment[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { IFeatureStrategySegment, ISegment } from '../../types';
|
||||
import { IClientSegment, IFeatureStrategySegment, ISegment } from '../../types';
|
||||
|
||||
export interface ISegmentReadModel {
|
||||
getAll(): Promise<ISegment[]>;
|
||||
getAllFeatureStrategySegments(): Promise<IFeatureStrategySegment[]>;
|
||||
getActive(): Promise<ISegment[]>;
|
||||
getActiveForClient(): Promise<IClientSegment[]>;
|
||||
}
|
||||
|
@ -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<ISegment[]> {
|
||||
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<IClientSegment[]> {
|
||||
const fullSegments = await this.getActive();
|
||||
|
||||
return fullSegments.map((segments) => ({
|
||||
id: segments.id,
|
||||
name: segments.name,
|
||||
constraints: segments.constraints,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ export interface ISegmentService {
|
||||
|
||||
validateName(name: string): Promise<void>;
|
||||
|
||||
getActive(): Promise<ISegment[]>;
|
||||
|
||||
getActiveForClient(): Promise<IClientSegment[]>;
|
||||
|
||||
getAll(): Promise<ISegment[]>;
|
||||
|
@ -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,
|
||||
|
@ -79,10 +79,6 @@ export class SegmentService implements ISegmentService {
|
||||
return this.segmentStore.getAll(this.config.isEnterprise);
|
||||
}
|
||||
|
||||
async getActive(): Promise<ISegment[]> {
|
||||
return this.segmentStore.getActive();
|
||||
}
|
||||
|
||||
async getActiveForClient(): Promise<IClientSegment[]> {
|
||||
return this.segmentStore.getActiveForClient();
|
||||
}
|
||||
|
@ -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]);
|
||||
|
@ -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 () => {
|
||||
|
Loading…
Reference in New Issue
Block a user