Skip to content

Commit

Permalink
refactor: playground uses segment read model (#6424)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Mar 5, 2024
1 parent 62dc77d commit 095b6ec
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 41 deletions.
32 changes: 18 additions & 14 deletions src/lib/features/playground/playground-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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(
Expand All @@ -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;

Expand Down Expand Up @@ -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({
Expand Down
10 changes: 9 additions & 1 deletion src/lib/features/segment/fake-segment-read-model.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -9,4 +9,12 @@ export class FakeSegmentReadModel implements ISegmentReadModel {
async getAllFeatureStrategySegments(): Promise<IFeatureStrategySegment[]> {
return [];
}

async getActive(): Promise<ISegment[]> {
return [];
}

async getActiveForClient(): Promise<IClientSegment[]> {
return [];
}
}
4 changes: 3 additions & 1 deletion src/lib/features/segment/segment-read-model-type.ts
Original file line number Diff line number Diff line change
@@ -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[]>;
}
31 changes: 30 additions & 1 deletion src/lib/features/segment/segment-read-model.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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,
}));
}
}
2 changes: 0 additions & 2 deletions src/lib/segments/segment-service-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ export interface ISegmentService {

validateName(name: string): Promise<void>;

getActive(): Promise<ISegment[]>;

getActiveForClient(): Promise<IClientSegment[]>;

getAll(): Promise<ISegment[]>;
Expand Down
18 changes: 13 additions & 5 deletions src/lib/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 0 additions & 4 deletions src/lib/services/segment-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/e2e/api/admin/state.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
23 changes: 11 additions & 12 deletions src/test/e2e/services/playground-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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 () => {
Expand Down

0 comments on commit 095b6ec

Please sign in to comment.