Skip to content

Commit

Permalink
feat: sorting by last seen, environments now working properly (#5376)
Browse files Browse the repository at this point in the history
Now calculates final ranks also, if there are some ranks missing from
duplicates.
  • Loading branch information
sjaanus committed Nov 21, 2023
1 parent a137275 commit 1429b54
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 14 deletions.
83 changes: 71 additions & 12 deletions src/lib/features/feature-search/feature.search.e2e.test.ts
Expand Up @@ -2,13 +2,14 @@ import dbInit, { ITestDb } from '../../../test/e2e/helpers/database-init';
import {
IUnleashTest,
setupAppWithAuth,
setupAppWithCustomConfig,
} from '../../../test/e2e/helpers/test-helper';
import getLogger from '../../../test/fixtures/no-logger';
import { FeatureSearchQueryParameters } from '../../openapi/spec/feature-search-query-parameters';
import { IUnleashStores } from '../../types';

let app: IUnleashTest;
let db: ITestDb;
let stores: IUnleashStores;

beforeAll(async () => {
db = await dbInit('feature_search', getLogger);
Expand All @@ -24,6 +25,7 @@ beforeAll(async () => {
},
db.rawDatabase,
);
stores = db.stores;

await app.request
.post(`/auth/demo/login`)
Expand Down Expand Up @@ -410,21 +412,78 @@ test('should paginate correctly when using tags', async () => {
await app.createFeature('my_feature_c');
await app.createFeature('my_feature_d');

await app.addTag('my_feature_b', { 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' });
await app.addTag('my_feature_b', {
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 } =
await searchFeaturesWithOffset({
query: 'feature',
offset: '2',
limit: '2',
});
const { body: secondPage } = await searchFeaturesWithOffset({
query: 'feature',
offset: '2',
limit: '2',
});

expect(secondPage).toMatchObject({
features: [{ name: 'my_feature_c' }, { name: 'my_feature_d' }],
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,
});
});
15 changes: 13 additions & 2 deletions src/lib/features/feature-toggle/feature-toggle-strategies-store.ts
Expand Up @@ -733,14 +733,25 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
.select(selectColumns)
.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(
'total_features',
this.db.raw('select max(rank) as total from ranked_features'),
this.db.raw('select count(*) as total from final_ranks'),
)
.select('*')
.from('ranked_features')
.innerJoin(
'final_ranks',
'ranked_features.feature_name',
'final_ranks.feature_name',
)
.joinRaw('CROSS JOIN total_features')
.whereBetween('rank', [offset + 1, offset + limit]);
.whereBetween('final_rank', [offset + 1, offset + limit]);

const rows = await finalQuery;

Expand Down

0 comments on commit 1429b54

Please sign in to comment.