diff --git a/src/lib/features/feature-search/feature.search.e2e.test.ts b/src/lib/features/feature-search/feature.search.e2e.test.ts index f7fd45fbfa..d5be660db2 100644 --- a/src/lib/features/feature-search/feature.search.e2e.test.ts +++ b/src/lib/features/feature-search/feature.search.e2e.test.ts @@ -106,6 +106,26 @@ test('should search matching features by tag', async () => { }); }); +test('should return all feature tags', async () => { + await app.createFeature('my_feature_a'); + await app.addTag('my_feature_a', { type: 'simple', value: 'my_tag' }); + await app.addTag('my_feature_a', { type: 'simple', value: 'second_tag' }); + + const { body } = await searchFeatures({}); + + expect(body).toMatchObject({ + features: [ + { + name: 'my_feature_a', + tags: [ + { type: 'simple', value: 'my_tag' }, + { type: 'simple', value: 'second_tag' }, + ], + }, + ], + }); +}); + test('should return empty features', async () => { const { body } = await searchFeatures({ query: '' }); expect(body).toMatchObject({ features: [] }); diff --git a/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts b/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts index 91820e61fc..3bd6da4b9f 100644 --- a/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts +++ b/src/lib/features/feature-toggle/feature-toggle-strategies-store.ts @@ -105,18 +105,6 @@ 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, @@ -252,7 +240,10 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { environment: string, ): Promise { await this.db('feature_strategies') - .where({ feature_name: featureName, environment }) + .where({ + feature_name: featureName, + environment, + }) .del(); } @@ -295,8 +286,14 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { environment, }) .orderBy([ - { column: 'sort_order', order: 'asc' }, - { column: 'created_at', order: 'asc' }, + { + column: 'sort_order', + order: 'asc', + }, + { + column: 'created_at', + order: 'asc', + }, ]); stopTimer(); return rows.map(mapRow); @@ -637,7 +634,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { query = query.select(selectColumns); const rows = await query; if (rows.length > 0) { - const overview = this.getFeatureOverviewData(getUniqueRows(rows)); + const overview = this.getFeatureOverviewData(rows); return sortEnvironments(overview); } return []; @@ -752,7 +749,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { query = query.select(selectColumns); const rows = await query; if (rows.length > 0) { - const overview = this.getFeatureOverviewData(getUniqueRows(rows)); + const overview = this.getFeatureOverviewData(rows); return sortEnvironments(overview); } return []; @@ -761,9 +758,18 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { getFeatureOverviewData(rows): IFeatureOverview { return rows.reduce((acc, row) => { if (acc[row.feature_name] !== undefined) { - acc[row.feature_name].environments.push( - FeatureStrategiesStore.getEnvironment(row), + const environmentExists = acc[ + row.feature_name + ].environments.some( + (existingEnvironment) => + existingEnvironment.name === row.environment, ); + if (!environmentExists) { + acc[row.feature_name].environments.push( + FeatureStrategiesStore.getEnvironment(row), + ); + } + if (this.isNewTag(acc[row.feature_name], row)) { this.addTag(acc[row.feature_name], row); } @@ -779,6 +785,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { impressionData: row.impression_data, environments: [FeatureStrategiesStore.getEnvironment(row)], }; + if (this.isNewTag(acc[row.feature_name], row)) { this.addTag(acc[row.feature_name], row); } @@ -838,7 +845,10 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore { environment: String, ): Promise { await this.db(T.featureStrategies) - .where({ project_name: projectId, environment }) + .where({ + project_name: projectId, + environment, + }) .del(); }