1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-04 01:18:20 +02:00

refactor: segment-store getAll refactor, move mappers out of main method. (#6423)

For `getAll` method, kept only sql queries and moved mappers into
separate functions.
No change in logic, just refactoring.
This commit is contained in:
Jaanus Sellin 2024-03-04 16:54:55 +02:00 committed by GitHub
parent f3df7269cb
commit ce8e15347c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 152 additions and 123 deletions

View File

@ -18,13 +18,11 @@ import { DashboardHeader } from './components/DashboardHeader/DashboardHeader';
import { UserStats } from './componentsStat/UserStats/UserStats'; import { UserStats } from './componentsStat/UserStats/UserStats';
import { FlagStats } from './componentsStat/FlagStats/FlagStats'; import { FlagStats } from './componentsStat/FlagStats/FlagStats';
import { HealthStats } from './componentsStat/HealthStats/HealthStats'; import { HealthStats } from './componentsStat/HealthStats/HealthStats';
import { TimeToProduction } from './componentsStat/TimeToProduction/TimeToProduction';
import { UsersChart } from './componentsChart/UsersChart/UsersChart'; import { UsersChart } from './componentsChart/UsersChart/UsersChart';
import { FlagsChart } from './componentsChart/FlagsChart/FlagsChart'; import { FlagsChart } from './componentsChart/FlagsChart/FlagsChart';
import { FlagsProjectChart } from './componentsChart/FlagsProjectChart/FlagsProjectChart'; import { FlagsProjectChart } from './componentsChart/FlagsProjectChart/FlagsProjectChart';
import { ProjectHealthChart } from './componentsChart/ProjectHealthChart/ProjectHealthChart'; import { ProjectHealthChart } from './componentsChart/ProjectHealthChart/ProjectHealthChart';
import { TimeToProductionChart } from './componentsChart/TimeToProductionChart/TimeToProductionChart';
import { MetricsSummaryChart } from './componentsChart/MetricsSummaryChart/MetricsSummaryChart'; import { MetricsSummaryChart } from './componentsChart/MetricsSummaryChart/MetricsSummaryChart';
import { UsersPerProjectChart } from './componentsChart/UsersPerProjectChart/UsersPerProjectChart'; import { UsersPerProjectChart } from './componentsChart/UsersPerProjectChart/UsersPerProjectChart';

View File

@ -116,141 +116,172 @@ export default class SegmentStore implements ISegmentStore {
includeChangeRequestUsageData: boolean = false, includeChangeRequestUsageData: boolean = false,
): Promise<ISegment[]> { ): Promise<ISegment[]> {
if (includeChangeRequestUsageData) { if (includeChangeRequestUsageData) {
const pendingCRs = await this.db return this.getAllWithChangeRequestUsageData();
.select('id', 'project') } else {
.from('change_requests') return this.getAllWithoutChangeRequestUsageData();
.whereNotIn('state', ['Applied', 'Rejected', 'Cancelled']); }
}
const pendingChangeRequestIds = pendingCRs.map((cr) => cr.id); private async getAllWithoutChangeRequestUsageData(): Promise<ISegment[]> {
const rows: ISegmentRow[] = await this.db
.select(
this.prefixColumns(),
'used_in_projects',
'used_in_features',
)
.countDistinct(
`${T.featureStrategies}.project_name AS used_in_projects`,
)
.countDistinct(
`${T.featureStrategies}.feature_name AS used_in_features`,
)
.from(T.segments)
.leftJoin(
T.featureStrategySegment,
`${T.segments}.id`,
`${T.featureStrategySegment}.segment_id`,
)
.leftJoin(
T.featureStrategies,
`${T.featureStrategies}.id`,
`${T.featureStrategySegment}.feature_strategy_id`,
)
.groupBy(this.prefixColumns())
.orderBy('name', 'asc');
const crFeatures = await this.db return rows.map(this.mapRow);
.select( }
'payload',
'feature',
'change_request_id as changeRequestId',
)
.from('change_request_events')
.whereIn('change_request_id', pendingChangeRequestIds)
.whereIn('action', ['addStrategy', 'updateStrategy'])
.andWhereRaw("jsonb_array_length(payload -> 'segments') > 0");
const changeRequestToProjectMap = pendingCRs.reduce( private async getAllWithChangeRequestUsageData(): Promise<ISegment[]> {
(acc, { id, project }) => { const pendingCRs = await this.db
acc[id] = project; .select('id', 'project')
return acc; .from('change_requests')
}, .whereNotIn('state', ['Applied', 'Rejected', 'Cancelled']);
{},
const pendingChangeRequestIds = pendingCRs.map((cr) => cr.id);
const crFeatures = await this.db
.select(
'payload',
'feature',
'change_request_id as changeRequestId',
)
.from('change_request_events')
.whereIn('change_request_id', pendingChangeRequestIds)
.whereIn('action', ['addStrategy', 'updateStrategy'])
.andWhereRaw("jsonb_array_length(payload -> 'segments') > 0");
const combinedUsageData = this.combineUsageData(pendingCRs, crFeatures);
const currentSegmentUsage = await this.db
.select(
`${T.featureStrategies}.feature_name as featureName`,
`${T.featureStrategies}.project_name as projectName`,
'segment_id as segmentId',
)
.from(T.featureStrategySegment)
.leftJoin(
T.featureStrategies,
`${T.featureStrategies}.id`,
`${T.featureStrategySegment}.feature_strategy_id`,
); );
const combinedUsageData = crFeatures.reduce((acc, segmentEvent) => { this.mergeCurrentUsageWithCombinedData(
const { payload, changeRequestId, feature } = segmentEvent; combinedUsageData,
const project = changeRequestToProjectMap[changeRequestId]; currentSegmentUsage,
);
for (const segmentId of payload.segments) { const rows: ISegmentRow[] = await this.db
const existingData = acc[segmentId]; .select(this.prefixColumns())
if (existingData) { .from(T.segments)
acc[segmentId] = { .leftJoin(
features: existingData.features.add(feature), T.featureStrategySegment,
projects: existingData.projects.add(project), `${T.segments}.id`,
}; `${T.featureStrategySegment}.segment_id`,
} else { )
acc[segmentId] = { .groupBy(this.prefixColumns())
features: new Set([feature]), .orderBy('name', 'asc');
projects: new Set([project]),
}; const rowsWithUsageData = this.mapRowsWithUsageData(
} rows,
} combinedUsageData,
);
return rowsWithUsageData.map(this.mapRow);
}
private mapRowsWithUsageData(
rows: ISegmentRow[],
combinedUsageData: any,
): ISegmentRow[] {
return rows.map((row) => {
const usageData = combinedUsageData[row.id];
if (usageData) {
return {
...row,
used_in_features: usageData.features.size,
used_in_projects: usageData.projects.size,
};
} else {
return {
...row,
used_in_features: 0,
used_in_projects: 0,
};
}
});
}
private combineUsageData = (pendingCRs, crFeatures) => {
const changeRequestToProjectMap = pendingCRs.reduce(
(acc, { id, project }) => {
acc[id] = project;
return acc; return acc;
}, {}); },
{},
);
const currentSegmentUsage = await this.db const combinedUsageData = crFeatures.reduce((acc, segmentEvent) => {
.select( const { payload, changeRequestId, feature } = segmentEvent;
`${T.featureStrategies}.feature_name as featureName`, const project = changeRequestToProjectMap[changeRequestId];
`${T.featureStrategies}.project_name as projectName`,
'segment_id as segmentId',
)
.from(T.featureStrategySegment)
.leftJoin(
T.featureStrategies,
`${T.featureStrategies}.id`,
`${T.featureStrategySegment}.feature_strategy_id`,
);
currentSegmentUsage.forEach( for (const segmentId of payload.segments) {
({ segmentId, featureName, projectName }) => { const existingData = acc[segmentId];
const usage = combinedUsageData[segmentId]; if (existingData) {
if (usage) { acc[segmentId] = {
combinedUsageData[segmentId] = { features: existingData.features.add(feature),
features: usage.features.add(featureName), projects: existingData.projects.add(project),
projects: usage.projects.add(projectName),
};
} else {
combinedUsageData[segmentId] = {
features: new Set([featureName]),
projects: new Set([projectName]),
};
}
},
);
const rows: ISegmentRow[] = await this.db
.select(this.prefixColumns())
.from(T.segments)
.leftJoin(
T.featureStrategySegment,
`${T.segments}.id`,
`${T.featureStrategySegment}.segment_id`,
)
.groupBy(this.prefixColumns())
.orderBy('name', 'asc');
const rowsWithUsageData: ISegmentRow[] = rows.map((row) => {
const usageData = combinedUsageData[row.id];
if (usageData) {
return {
...row,
used_in_features: usageData.features.size,
used_in_projects: usageData.projects.size,
}; };
} else { } else {
return { acc[segmentId] = {
...row, features: new Set([feature]),
used_in_features: 0, projects: new Set([project]),
used_in_projects: 0,
}; };
} }
}); }
return acc;
}, {});
return combinedUsageData;
};
return rowsWithUsageData.map(this.mapRow); private mergeCurrentUsageWithCombinedData(
} else { combinedUsageData: any,
const rows: ISegmentRow[] = await this.db currentSegmentUsage: any[],
.select( ) {
this.prefixColumns(), currentSegmentUsage.forEach(
'used_in_projects', ({ segmentId, featureName, projectName }) => {
'used_in_features', const usage = combinedUsageData[segmentId];
) if (usage) {
.countDistinct( usage.features.add(featureName);
`${T.featureStrategies}.project_name AS used_in_projects`, usage.projects.add(projectName);
) } else {
.countDistinct( combinedUsageData[segmentId] = {
`${T.featureStrategies}.feature_name AS used_in_features`, features: new Set([featureName]),
) projects: new Set([projectName]),
.from(T.segments) };
.leftJoin( }
T.featureStrategySegment, },
`${T.segments}.id`, );
`${T.featureStrategySegment}.segment_id`,
)
.leftJoin(
T.featureStrategies,
`${T.featureStrategies}.id`,
`${T.featureStrategySegment}.feature_strategy_id`,
)
.groupBy(this.prefixColumns())
.orderBy('name', 'asc');
return rows.map(this.mapRow);
}
} }
async getActive(): Promise<ISegment[]> { async getActive(): Promise<ISegment[]> {