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:
parent
f3df7269cb
commit
ce8e15347c
@ -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';
|
||||||
|
|
||||||
|
@ -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[]> {
|
||||||
|
Loading…
Reference in New Issue
Block a user