mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-19 01:17:18 +02:00
refactor: segment read model used in export-import (#6418)
This commit is contained in:
parent
19fbd7a0c4
commit
14796aedc1
@ -25,12 +25,10 @@ import {
|
|||||||
createFakeFeatureToggleService,
|
createFakeFeatureToggleService,
|
||||||
createFeatureToggleService,
|
createFeatureToggleService,
|
||||||
} from '../feature-toggle/createFeatureToggleService';
|
} from '../feature-toggle/createFeatureToggleService';
|
||||||
import SegmentStore from '../../db/segment-store';
|
|
||||||
import { FeatureEnvironmentStore } from '../../db/feature-environment-store';
|
import { FeatureEnvironmentStore } from '../../db/feature-environment-store';
|
||||||
import FakeFeatureToggleStore from '../feature-toggle/fakes/fake-feature-toggle-store';
|
import FakeFeatureToggleStore from '../feature-toggle/fakes/fake-feature-toggle-store';
|
||||||
import FakeTagStore from '../../../test/fixtures/fake-tag-store';
|
import FakeTagStore from '../../../test/fixtures/fake-tag-store';
|
||||||
import FakeTagTypeStore from '../tag-type/fake-tag-type-store';
|
import FakeTagTypeStore from '../tag-type/fake-tag-type-store';
|
||||||
import FakeSegmentStore from '../../../test/fixtures/fake-segment-store';
|
|
||||||
import FakeProjectStore from '../../../test/fixtures/fake-project-store';
|
import FakeProjectStore from '../../../test/fixtures/fake-project-store';
|
||||||
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
import FakeFeatureTagStore from '../../../test/fixtures/fake-feature-tag-store';
|
||||||
import FakeContextFieldStore from '../../../test/fixtures/fake-context-field-store';
|
import FakeContextFieldStore from '../../../test/fixtures/fake-context-field-store';
|
||||||
@ -46,15 +44,13 @@ import {
|
|||||||
import { DeferredServiceFactory } from '../../db/transaction';
|
import { DeferredServiceFactory } from '../../db/transaction';
|
||||||
import { DependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model';
|
import { DependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model';
|
||||||
import { FakeDependentFeaturesReadModel } from '../dependent-features/fake-dependent-features-read-model';
|
import { FakeDependentFeaturesReadModel } from '../dependent-features/fake-dependent-features-read-model';
|
||||||
import {
|
|
||||||
createFakeSegmentService,
|
|
||||||
createSegmentService,
|
|
||||||
} from '../segment/createSegmentService';
|
|
||||||
import {
|
import {
|
||||||
createDependentFeaturesService,
|
createDependentFeaturesService,
|
||||||
createFakeDependentFeaturesService,
|
createFakeDependentFeaturesService,
|
||||||
} from '../dependent-features/createDependentFeaturesService';
|
} from '../dependent-features/createDependentFeaturesService';
|
||||||
import { createEventsService } from '../events/createEventsService';
|
import { createEventsService } from '../events/createEventsService';
|
||||||
|
import { SegmentReadModel } from '../segment/segment-read-model';
|
||||||
|
import { FakeSegmentReadModel } from '../segment/fake-segment-read-model';
|
||||||
|
|
||||||
export const createFakeExportImportTogglesService = (
|
export const createFakeExportImportTogglesService = (
|
||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
@ -64,7 +60,6 @@ export const createFakeExportImportTogglesService = (
|
|||||||
const featureToggleStore = new FakeFeatureToggleStore();
|
const featureToggleStore = new FakeFeatureToggleStore();
|
||||||
const tagStore = new FakeTagStore();
|
const tagStore = new FakeTagStore();
|
||||||
const tagTypeStore = new FakeTagTypeStore();
|
const tagTypeStore = new FakeTagTypeStore();
|
||||||
const segmentStore = new FakeSegmentStore();
|
|
||||||
const projectStore = new FakeProjectStore();
|
const projectStore = new FakeProjectStore();
|
||||||
const featureTagStore = new FakeFeatureTagStore();
|
const featureTagStore = new FakeFeatureTagStore();
|
||||||
const strategyStore = new FakeStrategiesStore();
|
const strategyStore = new FakeStrategiesStore();
|
||||||
@ -115,7 +110,7 @@ export const createFakeExportImportTogglesService = (
|
|||||||
);
|
);
|
||||||
const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();
|
const dependentFeaturesReadModel = new FakeDependentFeaturesReadModel();
|
||||||
|
|
||||||
const segmentService = createFakeSegmentService(config);
|
const segmentReadModel = new FakeSegmentReadModel();
|
||||||
|
|
||||||
const dependentFeaturesService = createFakeDependentFeaturesService(config);
|
const dependentFeaturesService = createFakeDependentFeaturesService(config);
|
||||||
|
|
||||||
@ -126,7 +121,6 @@ export const createFakeExportImportTogglesService = (
|
|||||||
contextFieldStore,
|
contextFieldStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
featureTagStore,
|
featureTagStore,
|
||||||
segmentStore,
|
|
||||||
tagTypeStore,
|
tagTypeStore,
|
||||||
featureEnvironmentStore,
|
featureEnvironmentStore,
|
||||||
},
|
},
|
||||||
@ -139,10 +133,10 @@ export const createFakeExportImportTogglesService = (
|
|||||||
contextService,
|
contextService,
|
||||||
strategyService,
|
strategyService,
|
||||||
tagTypeService,
|
tagTypeService,
|
||||||
segmentService,
|
|
||||||
dependentFeaturesService,
|
dependentFeaturesService,
|
||||||
},
|
},
|
||||||
dependentFeaturesReadModel,
|
dependentFeaturesReadModel,
|
||||||
|
segmentReadModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
return exportImportService;
|
return exportImportService;
|
||||||
@ -162,12 +156,6 @@ export const deferredExportImportTogglesService = (
|
|||||||
);
|
);
|
||||||
const tagStore = new TagStore(db, eventBus, getLogger);
|
const tagStore = new TagStore(db, eventBus, getLogger);
|
||||||
const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
|
const tagTypeStore = new TagTypeStore(db, eventBus, getLogger);
|
||||||
const segmentStore = new SegmentStore(
|
|
||||||
db,
|
|
||||||
eventBus,
|
|
||||||
getLogger,
|
|
||||||
flagResolver,
|
|
||||||
);
|
|
||||||
const projectStore = new ProjectStore(
|
const projectStore = new ProjectStore(
|
||||||
db,
|
db,
|
||||||
eventBus,
|
eventBus,
|
||||||
@ -230,7 +218,7 @@ export const deferredExportImportTogglesService = (
|
|||||||
);
|
);
|
||||||
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
const dependentFeaturesReadModel = new DependentFeaturesReadModel(db);
|
||||||
|
|
||||||
const segmentService = createSegmentService(db, config);
|
const segmentReadModel = new SegmentReadModel(db);
|
||||||
|
|
||||||
const dependentFeaturesService =
|
const dependentFeaturesService =
|
||||||
createDependentFeaturesService(config)(db);
|
createDependentFeaturesService(config)(db);
|
||||||
@ -242,7 +230,6 @@ export const deferredExportImportTogglesService = (
|
|||||||
contextFieldStore,
|
contextFieldStore,
|
||||||
featureToggleStore,
|
featureToggleStore,
|
||||||
featureTagStore,
|
featureTagStore,
|
||||||
segmentStore,
|
|
||||||
tagTypeStore,
|
tagTypeStore,
|
||||||
featureEnvironmentStore,
|
featureEnvironmentStore,
|
||||||
},
|
},
|
||||||
@ -255,10 +242,10 @@ export const deferredExportImportTogglesService = (
|
|||||||
contextService,
|
contextService,
|
||||||
strategyService,
|
strategyService,
|
||||||
tagTypeService,
|
tagTypeService,
|
||||||
segmentService,
|
|
||||||
dependentFeaturesService,
|
dependentFeaturesService,
|
||||||
},
|
},
|
||||||
dependentFeaturesReadModel,
|
dependentFeaturesReadModel,
|
||||||
|
segmentReadModel,
|
||||||
);
|
);
|
||||||
|
|
||||||
return exportImportService;
|
return exportImportService;
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
IFeatureStrategySegment,
|
IFeatureStrategySegment,
|
||||||
IFeatureTagStore,
|
IFeatureTagStore,
|
||||||
IFlagResolver,
|
IFlagResolver,
|
||||||
ISegmentStore,
|
|
||||||
ITagTypeStore,
|
ITagTypeStore,
|
||||||
IUnleashConfig,
|
IUnleashConfig,
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
@ -51,8 +50,8 @@ import { findDuplicates } from '../../util/findDuplicates';
|
|||||||
import { FeatureNameCheckResultWithFeaturePattern } from '../feature-toggle/feature-toggle-service';
|
import { FeatureNameCheckResultWithFeaturePattern } from '../feature-toggle/feature-toggle-service';
|
||||||
import { IDependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model-type';
|
import { IDependentFeaturesReadModel } from '../dependent-features/dependent-features-read-model-type';
|
||||||
import groupBy from 'lodash.groupby';
|
import groupBy from 'lodash.groupby';
|
||||||
import { ISegmentService } from '../../segments/segment-service-interface';
|
|
||||||
import { allSettledWithRejection } from '../../util/allSettledWithRejection';
|
import { allSettledWithRejection } from '../../util/allSettledWithRejection';
|
||||||
|
import { ISegmentReadModel } from '../segment/segment-read-model-type';
|
||||||
|
|
||||||
export type IImportService = {
|
export type IImportService = {
|
||||||
validate(
|
validate(
|
||||||
@ -88,8 +87,6 @@ export default class ExportImportService
|
|||||||
|
|
||||||
private featureTagStore: IFeatureTagStore;
|
private featureTagStore: IFeatureTagStore;
|
||||||
|
|
||||||
private segmentStore: ISegmentStore;
|
|
||||||
|
|
||||||
private flagResolver: IFlagResolver;
|
private flagResolver: IFlagResolver;
|
||||||
|
|
||||||
private featureToggleService: FeatureToggleService;
|
private featureToggleService: FeatureToggleService;
|
||||||
@ -106,7 +103,7 @@ export default class ExportImportService
|
|||||||
|
|
||||||
private tagTypeService: TagTypeService;
|
private tagTypeService: TagTypeService;
|
||||||
|
|
||||||
private segmentService: ISegmentService;
|
private segmentReadModel: ISegmentReadModel;
|
||||||
|
|
||||||
private featureTagService: FeatureTagService;
|
private featureTagService: FeatureTagService;
|
||||||
|
|
||||||
@ -125,7 +122,6 @@ export default class ExportImportService
|
|||||||
| 'featureEnvironmentStore'
|
| 'featureEnvironmentStore'
|
||||||
| 'tagTypeStore'
|
| 'tagTypeStore'
|
||||||
| 'featureTagStore'
|
| 'featureTagStore'
|
||||||
| 'segmentStore'
|
|
||||||
| 'contextFieldStore'
|
| 'contextFieldStore'
|
||||||
>,
|
>,
|
||||||
{
|
{
|
||||||
@ -140,7 +136,6 @@ export default class ExportImportService
|
|||||||
eventService,
|
eventService,
|
||||||
tagTypeService,
|
tagTypeService,
|
||||||
featureTagService,
|
featureTagService,
|
||||||
segmentService,
|
|
||||||
dependentFeaturesService,
|
dependentFeaturesService,
|
||||||
}: Pick<
|
}: Pick<
|
||||||
IUnleashServices,
|
IUnleashServices,
|
||||||
@ -151,10 +146,10 @@ export default class ExportImportService
|
|||||||
| 'eventService'
|
| 'eventService'
|
||||||
| 'tagTypeService'
|
| 'tagTypeService'
|
||||||
| 'featureTagService'
|
| 'featureTagService'
|
||||||
| 'segmentService'
|
|
||||||
| 'dependentFeaturesService'
|
| 'dependentFeaturesService'
|
||||||
>,
|
>,
|
||||||
dependentFeaturesReadModel: IDependentFeaturesReadModel,
|
dependentFeaturesReadModel: IDependentFeaturesReadModel,
|
||||||
|
segmentReadModel: ISegmentReadModel,
|
||||||
) {
|
) {
|
||||||
this.toggleStore = stores.featureToggleStore;
|
this.toggleStore = stores.featureToggleStore;
|
||||||
this.importTogglesStore = stores.importTogglesStore;
|
this.importTogglesStore = stores.importTogglesStore;
|
||||||
@ -162,14 +157,12 @@ export default class ExportImportService
|
|||||||
this.featureEnvironmentStore = stores.featureEnvironmentStore;
|
this.featureEnvironmentStore = stores.featureEnvironmentStore;
|
||||||
this.tagTypeStore = stores.tagTypeStore;
|
this.tagTypeStore = stores.tagTypeStore;
|
||||||
this.featureTagStore = stores.featureTagStore;
|
this.featureTagStore = stores.featureTagStore;
|
||||||
this.segmentStore = stores.segmentStore;
|
|
||||||
this.flagResolver = flagResolver;
|
this.flagResolver = flagResolver;
|
||||||
this.featureToggleService = featureToggleService;
|
this.featureToggleService = featureToggleService;
|
||||||
this.contextFieldStore = stores.contextFieldStore;
|
this.contextFieldStore = stores.contextFieldStore;
|
||||||
this.strategyService = strategyService;
|
this.strategyService = strategyService;
|
||||||
this.contextService = contextService;
|
this.contextService = contextService;
|
||||||
this.accessService = accessService;
|
this.accessService = accessService;
|
||||||
this.segmentService = segmentService;
|
|
||||||
this.eventService = eventService;
|
this.eventService = eventService;
|
||||||
this.tagTypeService = tagTypeService;
|
this.tagTypeService = tagTypeService;
|
||||||
this.featureTagService = featureTagService;
|
this.featureTagService = featureTagService;
|
||||||
@ -181,6 +174,7 @@ export default class ExportImportService
|
|||||||
this.contextService,
|
this.contextService,
|
||||||
);
|
);
|
||||||
this.dependentFeaturesReadModel = dependentFeaturesReadModel;
|
this.dependentFeaturesReadModel = dependentFeaturesReadModel;
|
||||||
|
this.segmentReadModel = segmentReadModel;
|
||||||
this.logger = getLogger('services/state-service.js');
|
this.logger = getLogger('services/state-service.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +473,7 @@ export default class ExportImportService
|
|||||||
private async getUnsupportedSegments(
|
private async getUnsupportedSegments(
|
||||||
dto: ImportTogglesSchema,
|
dto: ImportTogglesSchema,
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
const supportedSegments = await this.segmentService.getAll();
|
const supportedSegments = await this.segmentReadModel.getAll();
|
||||||
const targetProject = dto.project;
|
const targetProject = dto.project;
|
||||||
return dto.data.segments
|
return dto.data.segments
|
||||||
? dto.data.segments
|
? dto.data.segments
|
||||||
@ -583,7 +577,7 @@ export default class ExportImportService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async remapSegments(dto: ImportTogglesSchema) {
|
private async remapSegments(dto: ImportTogglesSchema) {
|
||||||
const existingSegments = await this.segmentService.getAll();
|
const existingSegments = await this.segmentReadModel.getAll();
|
||||||
|
|
||||||
const segmentMapping = new Map(
|
const segmentMapping = new Map(
|
||||||
dto.data.segments?.map((segment) => [
|
dto.data.segments?.map((segment) => [
|
||||||
@ -820,10 +814,10 @@ export default class ExportImportService
|
|||||||
featureNames,
|
featureNames,
|
||||||
query.environment,
|
query.environment,
|
||||||
),
|
),
|
||||||
this.segmentStore.getAllFeatureStrategySegments(),
|
this.segmentReadModel.getAllFeatureStrategySegments(),
|
||||||
this.contextFieldStore.getAll(),
|
this.contextFieldStore.getAll(),
|
||||||
this.featureTagStore.getAllByFeatures(featureNames),
|
this.featureTagStore.getAllByFeatures(featureNames),
|
||||||
this.segmentStore.getAll(),
|
this.segmentReadModel.getAll(),
|
||||||
this.tagTypeStore.getAll(),
|
this.tagTypeStore.getAll(),
|
||||||
this.dependentFeaturesReadModel.getDependencies(featureNames),
|
this.dependentFeaturesReadModel.getDependencies(featureNames),
|
||||||
]);
|
]);
|
||||||
|
12
src/lib/features/segment/fake-segment-read-model.ts
Normal file
12
src/lib/features/segment/fake-segment-read-model.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { IFeatureStrategySegment, ISegment } from '../../types';
|
||||||
|
import { ISegmentReadModel } from './segment-read-model-type';
|
||||||
|
|
||||||
|
export class FakeSegmentReadModel implements ISegmentReadModel {
|
||||||
|
async getAll(): Promise<ISegment[]> {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllFeatureStrategySegments(): Promise<IFeatureStrategySegment[]> {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
6
src/lib/features/segment/segment-read-model-type.ts
Normal file
6
src/lib/features/segment/segment-read-model-type.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { IFeatureStrategySegment, ISegment } from '../../types';
|
||||||
|
|
||||||
|
export interface ISegmentReadModel {
|
||||||
|
getAll(): Promise<ISegment[]>;
|
||||||
|
getAllFeatureStrategySegments(): Promise<IFeatureStrategySegment[]>;
|
||||||
|
}
|
78
src/lib/features/segment/segment-read-model.ts
Normal file
78
src/lib/features/segment/segment-read-model.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { IConstraint, IFeatureStrategySegment, ISegment } from '../../types';
|
||||||
|
import { ISegmentReadModel } from './segment-read-model-type';
|
||||||
|
import NotFoundError from '../../error/notfound-error';
|
||||||
|
import { Db } from '../../db/db';
|
||||||
|
|
||||||
|
interface ISegmentRow {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
segment_project_id?: string;
|
||||||
|
created_by?: string;
|
||||||
|
created_at: Date;
|
||||||
|
constraints: IConstraint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const COLUMNS = [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'segment_project_id',
|
||||||
|
'created_by',
|
||||||
|
'created_at',
|
||||||
|
'constraints',
|
||||||
|
];
|
||||||
|
|
||||||
|
interface IFeatureStrategySegmentRow {
|
||||||
|
feature_strategy_id: string;
|
||||||
|
segment_id: number;
|
||||||
|
created_at?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SegmentReadModel implements ISegmentReadModel {
|
||||||
|
private db: Db;
|
||||||
|
|
||||||
|
constructor(db: Db) {
|
||||||
|
this.db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixColumns(): string[] {
|
||||||
|
return COLUMNS.map((c) => `segments.${c}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapRow(row?: ISegmentRow): ISegment {
|
||||||
|
if (!row) {
|
||||||
|
throw new NotFoundError('No row');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
description: row.description,
|
||||||
|
project: row.segment_project_id || undefined,
|
||||||
|
constraints: row.constraints,
|
||||||
|
createdBy: row.created_by,
|
||||||
|
createdAt: row.created_at,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAll(): Promise<ISegment[]> {
|
||||||
|
const rows: ISegmentRow[] = await this.db
|
||||||
|
.select(this.prefixColumns())
|
||||||
|
.from('segments')
|
||||||
|
.orderBy('segments.name', 'asc');
|
||||||
|
|
||||||
|
return rows.map(this.mapRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllFeatureStrategySegments(): Promise<IFeatureStrategySegment[]> {
|
||||||
|
const rows: IFeatureStrategySegmentRow[] = await this.db
|
||||||
|
.select(['segment_id', 'feature_strategy_id'])
|
||||||
|
.from('feature_strategy_segment');
|
||||||
|
|
||||||
|
return rows.map((row) => ({
|
||||||
|
featureStrategyId: row.feature_strategy_id,
|
||||||
|
segmentId: row.segment_id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user