mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
feat: now it is possible to search events by group id (#10275)
Now when you put group ID as query param, it will filter based on transaction id. I am not sure if its best naming, whether it should be groupId or transactionId, I will leave as group for now, but its simple change later. 
This commit is contained in:
parent
a251a9808a
commit
7e85de8f65
@ -73,6 +73,7 @@ export const useEventLogSearch = (
|
||||
type: FilterItemParam,
|
||||
environment: FilterItemParam,
|
||||
id: StringParam,
|
||||
groupId: StringParam,
|
||||
...extraParameters(logType),
|
||||
};
|
||||
|
||||
|
@ -222,6 +222,11 @@ export default class EventService {
|
||||
if (parsed) queryParams.push(parsed);
|
||||
}
|
||||
|
||||
if (params.groupId) {
|
||||
const parsed = parseSearchOperatorValue('group_id', params.groupId);
|
||||
if (parsed) queryParams.push(parsed);
|
||||
}
|
||||
|
||||
['project', 'type', 'environment', 'id'].forEach((field) => {
|
||||
if (params[field]) {
|
||||
const parsed = parseSearchOperatorValue(field, params[field]);
|
||||
|
@ -22,6 +22,17 @@ export const eventSearchQueryParameters = [
|
||||
'Filter by event ID using supported operators: IS, IS_ANY_OF.',
|
||||
in: 'query',
|
||||
},
|
||||
{
|
||||
name: 'groupId',
|
||||
schema: {
|
||||
type: 'string',
|
||||
example: 'IS:123',
|
||||
pattern: '^(IS|IS_ANY_OF):(.*?)(,([0-9]+))*$',
|
||||
},
|
||||
description:
|
||||
'Filter by group ID using supported operators: IS, IS_ANY_OF.',
|
||||
in: 'query',
|
||||
},
|
||||
{
|
||||
name: 'feature',
|
||||
schema: {
|
||||
|
@ -7,6 +7,7 @@ import type { IQueryParam } from '../../features/feature-toggle/types/feature-to
|
||||
|
||||
export interface IEventSearchParams {
|
||||
id?: string;
|
||||
groupId?: string;
|
||||
project?: string;
|
||||
query?: string;
|
||||
feature?: string;
|
||||
|
@ -16,6 +16,8 @@ import {
|
||||
import { createEventsService } from '../../../../lib/features/index.js';
|
||||
import { createTestConfig } from '../../../config/test-config.js';
|
||||
import { FEATURE_CREATED, USER_CREATED } from '../../../../lib/events/index.js';
|
||||
import { withTransactional } from '../../../../lib/db/transaction.js';
|
||||
import { EventStore } from '../../../../lib/features/events/event-store.js';
|
||||
|
||||
let app: IUnleashTest;
|
||||
let db: ITestDb;
|
||||
@ -718,3 +720,140 @@ test('should filter events by multiple IDs using IS_ANY_OF', async () => {
|
||||
);
|
||||
expect(returnedIds).not.toContain(feature2Event.id);
|
||||
});
|
||||
|
||||
test('should filter events by group ID', async () => {
|
||||
const eventStoreService = withTransactional(
|
||||
(db) => new EventStore(db, getLogger),
|
||||
db.rawDatabase,
|
||||
);
|
||||
|
||||
const events = [
|
||||
{
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { name: 'feature1' },
|
||||
createdBy: 'test-user',
|
||||
createdByUserId: TEST_USER_ID,
|
||||
ip: '127.0.0.1',
|
||||
},
|
||||
{
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { name: 'feature2' },
|
||||
createdBy: 'test-user',
|
||||
createdByUserId: TEST_USER_ID,
|
||||
ip: '127.0.0.1',
|
||||
},
|
||||
];
|
||||
|
||||
await eventStoreService.transactional(
|
||||
async (transactionalEventStore) => {
|
||||
await transactionalEventStore.batchStore(events);
|
||||
},
|
||||
{ type: 'transaction', id: '1' },
|
||||
);
|
||||
|
||||
await eventService.storeEvent({
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { name: 'feature3' },
|
||||
createdBy: 'test-user',
|
||||
createdByUserId: TEST_USER_ID,
|
||||
ip: '127.0.0.1',
|
||||
});
|
||||
|
||||
const { body } = await searchEvents({ groupId: 'IS:1' });
|
||||
|
||||
expect(body.total).toBe(2);
|
||||
expect(body.events).toHaveLength(2);
|
||||
expect(body.events.every((e: any) => e.groupId === '1')).toBe(true);
|
||||
});
|
||||
|
||||
test('should filter events by multiple group IDs using IS_ANY_OF', async () => {
|
||||
const eventStoreService = withTransactional(
|
||||
(db) => new EventStore(db, getLogger),
|
||||
db.rawDatabase,
|
||||
);
|
||||
|
||||
const event1 = {
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { name: 'feature1' },
|
||||
createdBy: 'test-user',
|
||||
createdByUserId: TEST_USER_ID,
|
||||
ip: '127.0.0.1',
|
||||
};
|
||||
const event2 = {
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { name: 'feature2' },
|
||||
createdBy: 'test-user',
|
||||
createdByUserId: TEST_USER_ID,
|
||||
ip: '127.0.0.1',
|
||||
};
|
||||
const event3 = {
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { name: 'feature3' },
|
||||
createdBy: 'test-user',
|
||||
createdByUserId: TEST_USER_ID,
|
||||
ip: '127.0.0.1',
|
||||
};
|
||||
|
||||
await eventStoreService.transactional(
|
||||
async (transactionalEventStore) => {
|
||||
await transactionalEventStore.store(event1);
|
||||
},
|
||||
{ type: 'transaction', id: '10' },
|
||||
);
|
||||
|
||||
await eventStoreService.transactional(
|
||||
async (transactionalEventStore) => {
|
||||
await transactionalEventStore.store(event2);
|
||||
},
|
||||
{ type: 'transaction', id: '20' },
|
||||
);
|
||||
|
||||
await eventStoreService.transactional(
|
||||
async (transactionalEventStore) => {
|
||||
await transactionalEventStore.store(event3);
|
||||
},
|
||||
{ type: 'transaction', id: '30' },
|
||||
);
|
||||
|
||||
const { body } = await searchEvents({ groupId: 'IS_ANY_OF:10,30' });
|
||||
|
||||
expect(body.total).toBe(2);
|
||||
expect(body.events).toHaveLength(2);
|
||||
|
||||
const returnedGroupIds = body.events.map((e: any) => e.groupId);
|
||||
expect(returnedGroupIds).toContain('10');
|
||||
expect(returnedGroupIds).toContain('30');
|
||||
expect(returnedGroupIds).not.toContain('20');
|
||||
});
|
||||
|
||||
test('Should return empty result when filtering by non-existent group ID', async () => {
|
||||
const eventStoreService = withTransactional(
|
||||
(db) => new EventStore(db, getLogger),
|
||||
db.rawDatabase,
|
||||
);
|
||||
|
||||
await eventStoreService.transactional(
|
||||
async (transactionalEventStore) => {
|
||||
await transactionalEventStore.store({
|
||||
type: FEATURE_CREATED,
|
||||
project: 'default',
|
||||
data: { name: 'feature1' },
|
||||
createdBy: 'test-user',
|
||||
createdByUserId: TEST_USER_ID,
|
||||
ip: '127.0.0.1',
|
||||
});
|
||||
},
|
||||
{ type: 'transaction', id: '1' },
|
||||
);
|
||||
|
||||
const { body } = await searchEvents({ groupId: 'IS:999' });
|
||||
|
||||
expect(body.total).toBe(0);
|
||||
expect(body.events).toHaveLength(0);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user