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

feat: sorting by last seen, environments now working properly (#5376)

Now calculates final ranks also, if there are some ranks missing from
duplicates.
This commit is contained in:
Jaanus Sellin 2023-11-21 15:19:06 +02:00 committed by GitHub
parent a137275e16
commit 1429b54957
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 14 deletions

View File

@ -2,13 +2,14 @@ import dbInit, { ITestDb } from '../../../test/e2e/helpers/database-init';
import { import {
IUnleashTest, IUnleashTest,
setupAppWithAuth, setupAppWithAuth,
setupAppWithCustomConfig,
} from '../../../test/e2e/helpers/test-helper'; } from '../../../test/e2e/helpers/test-helper';
import getLogger from '../../../test/fixtures/no-logger'; import getLogger from '../../../test/fixtures/no-logger';
import { FeatureSearchQueryParameters } from '../../openapi/spec/feature-search-query-parameters'; import { FeatureSearchQueryParameters } from '../../openapi/spec/feature-search-query-parameters';
import { IUnleashStores } from '../../types';
let app: IUnleashTest; let app: IUnleashTest;
let db: ITestDb; let db: ITestDb;
let stores: IUnleashStores;
beforeAll(async () => { beforeAll(async () => {
db = await dbInit('feature_search', getLogger); db = await dbInit('feature_search', getLogger);
@ -24,6 +25,7 @@ beforeAll(async () => {
}, },
db.rawDatabase, db.rawDatabase,
); );
stores = db.stores;
await app.request await app.request
.post(`/auth/demo/login`) .post(`/auth/demo/login`)
@ -410,21 +412,78 @@ test('should paginate correctly when using tags', async () => {
await app.createFeature('my_feature_c'); await app.createFeature('my_feature_c');
await app.createFeature('my_feature_d'); await app.createFeature('my_feature_d');
await app.addTag('my_feature_b', { type: 'simple', value: 'first_tag' }); await app.addTag('my_feature_b', {
await app.addTag('my_feature_b', { type: 'simple', value: 'second_tag' }); type: 'simple',
await app.addTag('my_feature_a', { type: 'simple', value: 'second_tag' }); value: 'first_tag',
await app.addTag('my_feature_c', { type: 'simple', value: 'second_tag' }); });
await app.addTag('my_feature_c', { type: 'simple', value: 'first_tag' }); await app.addTag('my_feature_b', {
type: 'simple',
value: 'second_tag',
});
await app.addTag('my_feature_a', {
type: 'simple',
value: 'second_tag',
});
await app.addTag('my_feature_c', {
type: 'simple',
value: 'second_tag',
});
await app.addTag('my_feature_c', {
type: 'simple',
value: 'first_tag',
});
const { body: secondPage, headers: secondHeaders } = const { body: secondPage } = await searchFeaturesWithOffset({
await searchFeaturesWithOffset({ query: 'feature',
query: 'feature', offset: '2',
offset: '2', limit: '2',
limit: '2', });
});
expect(secondPage).toMatchObject({ expect(secondPage).toMatchObject({
features: [{ name: 'my_feature_c' }, { name: 'my_feature_d' }], features: [{ name: 'my_feature_c' }, { name: 'my_feature_d' }],
total: 4, total: 4,
}); });
}); });
test('should not return duplicate entries when sorting by last seen', async () => {
await app.createFeature('my_feature_a');
await app.createFeature('my_feature_b');
await app.createFeature('my_feature_c');
await stores.environmentStore.create({
name: 'production',
type: 'production',
});
await app.linkProjectToEnvironment('default', 'production');
await app.enableFeature('my_feature_a', 'production');
await app.enableFeature('my_feature_b', 'production');
const { body } = await sortFeatures({
sortBy: 'environment:production',
sortOrder: 'desc',
});
expect(body).toMatchObject({
features: [
{ name: 'my_feature_a' },
{ name: 'my_feature_b' },
{ name: 'my_feature_c' },
],
total: 3,
});
const { body: ascendingBody } = await sortFeatures({
sortBy: 'environment:production',
sortOrder: 'asc',
});
expect(ascendingBody).toMatchObject({
features: [
{ name: 'my_feature_c' },
{ name: 'my_feature_a' },
{ name: 'my_feature_b' },
],
total: 3,
});
});

View File

@ -733,14 +733,25 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
.select(selectColumns) .select(selectColumns)
.denseRank('rank', this.db.raw(rankingSql)); .denseRank('rank', this.db.raw(rankingSql));
}) })
.with(
'final_ranks',
this.db.raw(
'select feature_name, row_number() over (order by min(rank)) as final_rank from ranked_features group by feature_name',
),
)
.with( .with(
'total_features', 'total_features',
this.db.raw('select max(rank) as total from ranked_features'), this.db.raw('select count(*) as total from final_ranks'),
) )
.select('*') .select('*')
.from('ranked_features') .from('ranked_features')
.innerJoin(
'final_ranks',
'ranked_features.feature_name',
'final_ranks.feature_name',
)
.joinRaw('CROSS JOIN total_features') .joinRaw('CROSS JOIN total_features')
.whereBetween('rank', [offset + 1, offset + limit]); .whereBetween('final_rank', [offset + 1, offset + limit]);
const rows = await finalQuery; const rows = await finalQuery;