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

fix: refactor getProjectOverview store method (#4972)

This PR cleans up and refactors the feature-strategy-store method
getFeatureOverview to join on the new table and attempts to make the
function more readable by extracting some of the logic into separate
functions. Keeping the LastSeenMapper for now in case there is a reason
to use it for the other endpoints.
This commit is contained in:
Fredrik Strand Oseberg 2023-10-10 07:34:21 +02:00 committed by GitHub
parent ab739eb6c3
commit 30d8444c80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 64 deletions

View File

@ -39,13 +39,6 @@ const COLUMNS = [
'created_at',
'disabled',
];
/*
const mapperToColumnNames = {
createdAt: 'created_at',
featureName: 'feature_name',
strategyName: 'strategy_name',
};
*/
const T = {
features: 'features',
@ -111,6 +104,32 @@ function mapInput(input: IFeatureStrategy): IFeatureStrategiesTable {
};
}
const getUniqueRows = (rows: any[]) => {
const seen = {};
return rows.filter((row) => {
const key = `${row.environment}-${row.feature_name}`;
if (seen[key]) {
return false;
}
seen[key] = true;
return true;
});
};
const sortEnvironments = (overview: IFeatureOverview) => {
return Object.values(overview).map((data: IFeatureOverview) => ({
...data,
environments: data.environments
.filter((f) => f.name)
.sort((a, b) => {
if (a.sortOrder === b.sortOrder) {
return a.name.localeCompare(b.name);
}
return a.sortOrder - b.sortOrder;
}),
}));
};
interface StrategyUpdate {
strategy_name: string;
parameters: object;
@ -514,6 +533,14 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
)
.leftJoin('feature_tag as ft', 'ft.feature_name', 'features.name');
if (this.flagResolver.isEnabled('useLastSeenRefactor')) {
query.leftJoin(
'last_seen_at_metrics',
'last_seen_at_metrics.environment',
'environments.name',
);
}
let selectColumns = [
'features.name as feature_name',
'features.description as description',
@ -525,13 +552,22 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
'feature_environments.enabled as enabled',
'feature_environments.environment as environment',
'feature_environments.variants as variants',
'feature_environments.last_seen_at as env_last_seen_at',
'environments.type as environment_type',
'environments.sort_order as environment_sort_order',
'ft.tag_value as tag_value',
'ft.tag_type as tag_type',
] as (string | Raw<any>)[];
if (this.flagResolver.isEnabled('useLastSeenRefactor')) {
selectColumns.push(
'last_seen_at_metrics.last_seen_at as env_last_seen_at',
);
} else {
selectColumns.push(
'feature_environments.last_seen_at as env_last_seen_at',
);
}
if (userId) {
query = query.leftJoin(`favorite_features`, function () {
this.on('favorite_features.feature', 'features.name').andOnVal(
@ -552,7 +588,15 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
const rows = await query;
if (rows.length > 0) {
const overview = rows.reduce((acc, row) => {
const overview = this.getFeatureOverviewData(getUniqueRows(rows));
return sortEnvironments(overview);
}
return [];
}
getFeatureOverviewData(rows): IFeatureOverview {
return rows.reduce((acc, row) => {
if (acc[row.feature_name] !== undefined) {
acc[row.feature_name].environments.push(
FeatureStrategiesStore.getEnvironment(row),
@ -570,9 +614,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
lastSeenAt: row.last_seen_at,
stale: row.stale,
impressionData: row.impression_data,
environments: [
FeatureStrategiesStore.getEnvironment(row),
],
environments: [FeatureStrategiesStore.getEnvironment(row)],
};
if (this.isNewTag(acc[row.feature_name], row)) {
this.addTag(acc[row.feature_name], row);
@ -580,20 +622,6 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
}
return acc;
}, {});
return Object.values(overview).map((o: IFeatureOverview) => ({
...o,
environments: o.environments
.filter((f) => f.name)
.sort((a, b) => {
if (a.sortOrder === b.sortOrder) {
return a.name.localeCompare(b.name);
}
return a.sortOrder - b.sortOrder;
}),
}));
}
return [];
}
async getStrategyById(id: string): Promise<IFeatureStrategy> {

View File

@ -1077,22 +1077,6 @@ export default class ProjectService {
this.projectStatsStore.getProjectStats(projectId),
]);
let decoratedFeatures = features;
if (this.flagResolver.isEnabled('useLastSeenRefactor')) {
const mapper = new LastSeenMapper();
const featureNames = features.map((feature) => feature.name);
const lastSeenAtPerEnvironment =
await this.lastSeenReadModel.getForFeature(featureNames);
decoratedFeatures = mapper.mapToFeatures(
decoratedFeatures,
lastSeenAtPerEnvironment,
this.logger,
);
}
return {
stats: projectStats,
name: project.name,
@ -1106,7 +1090,7 @@ export default class ProjectService {
updatedAt: project.updatedAt,
createdAt: project.createdAt,
environments,
features: decoratedFeatures,
features: features,
members,
version: 1,
};