1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: add operators for state filtering (#5497)

No changes in store needed, already utilizing reusable logic.
This commit is contained in:
Jaanus Sellin 2023-11-29 15:22:42 +02:00 committed by GitHub
parent 1aad9819cc
commit a743ca0df6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 3 deletions

View File

@ -77,6 +77,7 @@ export default class FeatureSearchController extends Controller {
type,
tag,
segment,
state,
status,
offset,
limit = '50',
@ -110,6 +111,7 @@ export default class FeatureSearchController extends Controller {
userId,
tag,
segment,
state,
status: normalizedStatus,
offset: normalizedOffset,
limit: normalizedLimit,

View File

@ -60,6 +60,16 @@ export class FeatureSearchService {
convertToQueryParams = (params: IFeatureSearchParams): IQueryParam[] => {
const queryParams: IQueryParam[] = [];
if (params.state) {
const parsedState = this.parseOperatorValue('stale', params.state);
if (parsedState) {
parsedState.values = parsedState.values.map((value) =>
value === 'active' ? 'false' : 'true',
);
queryParams.push(parsedState);
}
}
['tag', 'segment', 'project'].forEach((field) => {
if (params[field]) {
const parsed = this.parseOperatorValue(field, params[field]);

View File

@ -120,6 +120,12 @@ const filterFeaturesBySegment = async (segment: string, expectedCode = 200) => {
.expect(expectedCode);
};
const filterFeaturesByState = async (state: string, expectedCode = 200) => {
return app.request
.get(`/api/admin/search/features?state=${state}`)
.expect(expectedCode);
};
const filterFeaturesByEnvironmentStatus = async (
environmentStatuses: string[],
expectedCode = 200,
@ -756,3 +762,37 @@ test('should filter features by segment', async () => {
],
});
});
test('should search features by state with operators', async () => {
await app.createFeature({ name: 'my_feature_a', stale: false });
await app.createFeature({ name: 'my_feature_b', stale: true });
await app.createFeature({ name: 'my_feature_c', stale: true });
const { body } = await filterFeaturesByState('IS:active');
expect(body).toMatchObject({
features: [{ name: 'my_feature_a' }],
});
const { body: isNotBody } = await filterFeaturesByState('IS_NOT:active');
expect(isNotBody).toMatchObject({
features: [{ name: 'my_feature_b' }, { name: 'my_feature_c' }],
});
const { body: isAnyOfBody } = await filterFeaturesByState(
'IS_ANY_OF:active, stale',
);
expect(isAnyOfBody).toMatchObject({
features: [
{ name: 'my_feature_a' },
{ name: 'my_feature_b' },
{ name: 'my_feature_c' },
],
});
const { body: isNotAnyBody } = await filterFeaturesByState(
'IS_NOT_ANY_OF:active, stale',
);
expect(isNotAnyBody).toMatchObject({
features: [],
});
});

View File

@ -748,7 +748,7 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
)
.joinRaw('CROSS JOIN total_features')
.whereBetween('final_rank', [offset + 1, offset + limit]);
console.log(finalQuery.toQuery());
const rows = await finalQuery;
if (rows.length > 0) {

View File

@ -26,6 +26,7 @@ export interface IFeatureSearchParams {
searchParams?: string[];
project?: string;
segment?: string;
state?: string;
type?: string[];
tag?: string;
status?: string[][];

View File

@ -21,6 +21,17 @@ export const featureSearchQueryParameters = [
description: 'Id of the project where search and filter is performed',
in: 'query',
},
{
name: 'state',
schema: {
type: 'string',
example: 'IS:active',
pattern:
'^(IS|IS_NOT|IS_ANY_OF|IS_NOT_ANY_OF):(.*?)(,([a-zA-Z0-9_]+))*$',
},
description: 'The state of the feature active/stale',
in: 'query',
},
{
name: 'type',
schema: {

View File

@ -6,7 +6,11 @@ import { createTestConfig } from '../../config/test-config';
import { IAuthType, IUnleashConfig } from '../../../lib/types/option';
import { createServices } from '../../../lib/services';
import sessionDb from '../../../lib/middleware/session-db';
import { DEFAULT_PROJECT, IUnleashStores } from '../../../lib/types';
import {
DEFAULT_PROJECT,
FeatureToggleDTO,
IUnleashStores,
} from '../../../lib/types';
import { IUnleashServices } from '../../../lib/types/services';
import { Db } from '../../../lib/db/db';
import { IContextFieldDto } from 'lib/types/stores/context-field-store';
@ -121,7 +125,7 @@ function httpApis(
return request.post(url).send(postData).expect(expectStatusCode);
},
createFeature: (
feature: string | CreateFeatureSchema,
feature: string | FeatureToggleDTO,
project: string = DEFAULT_PROJECT,
expectedResponseCode: number = 201,
) => {