1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-26 01:17:00 +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 { FlagStats } from './componentsStat/FlagStats/FlagStats';
import { HealthStats } from './componentsStat/HealthStats/HealthStats';
import { TimeToProduction } from './componentsStat/TimeToProduction/TimeToProduction';
import { UsersChart } from './componentsChart/UsersChart/UsersChart';
import { FlagsChart } from './componentsChart/FlagsChart/FlagsChart';
import { FlagsProjectChart } from './componentsChart/FlagsProjectChart/FlagsProjectChart';
import { ProjectHealthChart } from './componentsChart/ProjectHealthChart/ProjectHealthChart';
import { TimeToProductionChart } from './componentsChart/TimeToProductionChart/TimeToProductionChart';
import { MetricsSummaryChart } from './componentsChart/MetricsSummaryChart/MetricsSummaryChart';
import { UsersPerProjectChart } from './componentsChart/UsersPerProjectChart/UsersPerProjectChart';

View File

@ -116,141 +116,172 @@ export default class SegmentStore implements ISegmentStore {
includeChangeRequestUsageData: boolean = false,
): Promise<ISegment[]> {
if (includeChangeRequestUsageData) {
const pendingCRs = await this.db
.select('id', 'project')
.from('change_requests')
.whereNotIn('state', ['Applied', 'Rejected', 'Cancelled']);
return this.getAllWithChangeRequestUsageData();
} else {
return this.getAllWithoutChangeRequestUsageData();
}
}
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
.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");
return rows.map(this.mapRow);
}
const changeRequestToProjectMap = pendingCRs.reduce(
(acc, { id, project }) => {
acc[id] = project;
return acc;
},
{},
private async getAllWithChangeRequestUsageData(): Promise<ISegment[]> {
const pendingCRs = await this.db
.select('id', 'project')
.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) => {
const { payload, changeRequestId, feature } = segmentEvent;
const project = changeRequestToProjectMap[changeRequestId];
this.mergeCurrentUsageWithCombinedData(
combinedUsageData,
currentSegmentUsage,
);
for (const segmentId of payload.segments) {
const existingData = acc[segmentId];
if (existingData) {
acc[segmentId] = {
features: existingData.features.add(feature),
projects: existingData.projects.add(project),
};
} else {
acc[segmentId] = {
features: new Set([feature]),
projects: new Set([project]),
};
}
}
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 = 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;
}, {});
},
{},
);
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) => {
const { payload, changeRequestId, feature } = segmentEvent;
const project = changeRequestToProjectMap[changeRequestId];
currentSegmentUsage.forEach(
({ segmentId, featureName, projectName }) => {
const usage = combinedUsageData[segmentId];
if (usage) {
combinedUsageData[segmentId] = {
features: usage.features.add(featureName),
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,
for (const segmentId of payload.segments) {
const existingData = acc[segmentId];
if (existingData) {
acc[segmentId] = {
features: existingData.features.add(feature),
projects: existingData.projects.add(project),
};
} else {
return {
...row,
used_in_features: 0,
used_in_projects: 0,
acc[segmentId] = {
features: new Set([feature]),
projects: new Set([project]),
};
}
});
}
return acc;
}, {});
return combinedUsageData;
};
return rowsWithUsageData.map(this.mapRow);
} else {
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');
return rows.map(this.mapRow);
}
private mergeCurrentUsageWithCombinedData(
combinedUsageData: any,
currentSegmentUsage: any[],
) {
currentSegmentUsage.forEach(
({ segmentId, featureName, projectName }) => {
const usage = combinedUsageData[segmentId];
if (usage) {
usage.features.add(featureName);
usage.projects.add(projectName);
} else {
combinedUsageData[segmentId] = {
features: new Set([featureName]),
projects: new Set([projectName]),
};
}
},
);
}
async getActive(): Promise<ISegment[]> {