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:
parent
ab739eb6c3
commit
30d8444c80
@ -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,50 +588,42 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
|
||||
const rows = await query;
|
||||
|
||||
if (rows.length > 0) {
|
||||
const overview = rows.reduce((acc, row) => {
|
||||
if (acc[row.feature_name] !== undefined) {
|
||||
acc[row.feature_name].environments.push(
|
||||
FeatureStrategiesStore.getEnvironment(row),
|
||||
);
|
||||
if (this.isNewTag(acc[row.feature_name], row)) {
|
||||
this.addTag(acc[row.feature_name], row);
|
||||
}
|
||||
} else {
|
||||
acc[row.feature_name] = {
|
||||
type: row.type,
|
||||
description: row.description,
|
||||
favorite: row.favorite,
|
||||
name: row.feature_name,
|
||||
createdAt: row.created_at,
|
||||
lastSeenAt: row.last_seen_at,
|
||||
stale: row.stale,
|
||||
impressionData: row.impression_data,
|
||||
environments: [
|
||||
FeatureStrategiesStore.getEnvironment(row),
|
||||
],
|
||||
};
|
||||
if (this.isNewTag(acc[row.feature_name], row)) {
|
||||
this.addTag(acc[row.feature_name], row);
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
const overview = this.getFeatureOverviewData(getUniqueRows(rows));
|
||||
|
||||
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 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),
|
||||
);
|
||||
if (this.isNewTag(acc[row.feature_name], row)) {
|
||||
this.addTag(acc[row.feature_name], row);
|
||||
}
|
||||
} else {
|
||||
acc[row.feature_name] = {
|
||||
type: row.type,
|
||||
description: row.description,
|
||||
favorite: row.favorite,
|
||||
name: row.feature_name,
|
||||
createdAt: row.created_at,
|
||||
lastSeenAt: row.last_seen_at,
|
||||
stale: row.stale,
|
||||
impressionData: row.impression_data,
|
||||
environments: [FeatureStrategiesStore.getEnvironment(row)],
|
||||
};
|
||||
if (this.isNewTag(acc[row.feature_name], row)) {
|
||||
this.addTag(acc[row.feature_name], row);
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
async getStrategyById(id: string): Promise<IFeatureStrategy> {
|
||||
const strat = await this.db(T.featureStrategies).where({ id }).first();
|
||||
if (strat) {
|
||||
|
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user