mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
feat: ability to search events by type with pagination
This commit is contained in:
parent
f588fbdfc4
commit
a402ad8c66
110
src/lib/features/events/event-search-by-type-read-model.test.ts
Normal file
110
src/lib/features/events/event-search-by-type-read-model.test.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import EventStore from './event-store.js';
|
||||
import getLogger from '../../../test/fixtures/no-logger.js';
|
||||
import dbInit, {
|
||||
type ITestDb,
|
||||
} from '../../../test/e2e/helpers/database-init.js';
|
||||
import {
|
||||
USER_CREATED,
|
||||
USER_DELETED,
|
||||
USER_UPDATED,
|
||||
} from '../../events/index.js';
|
||||
import { EventSearchByType } from './event-search-by-type-read-model.js';
|
||||
|
||||
let db: ITestDb;
|
||||
beforeAll(async () => {
|
||||
getLogger.setMuteError(true);
|
||||
db = await dbInit('event-search-by-type', getLogger);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
getLogger.setMuteError(false);
|
||||
});
|
||||
|
||||
test('Can read search events by type', async () => {
|
||||
const store = new EventStore(db.rawDatabase, getLogger);
|
||||
const readModel = new EventSearchByType(db.rawDatabase, getLogger);
|
||||
|
||||
await store.store({
|
||||
type: USER_CREATED,
|
||||
createdBy: 'test',
|
||||
ip: '127.0.0.1',
|
||||
createdByUserId: 1,
|
||||
});
|
||||
|
||||
const updatedEvents = await readModel.search({
|
||||
types: [USER_UPDATED],
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
});
|
||||
expect(updatedEvents).toBeTruthy();
|
||||
expect(updatedEvents.length).toBe(0);
|
||||
|
||||
const createdEvents = await readModel.search({
|
||||
types: [USER_CREATED],
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
});
|
||||
expect(createdEvents).toBeTruthy();
|
||||
expect(createdEvents.length).toBe(1);
|
||||
});
|
||||
|
||||
test('Events by type are sorted and can be paginated', async () => {
|
||||
const store = new EventStore(db.rawDatabase, getLogger);
|
||||
const readModel = new EventSearchByType(db.rawDatabase, getLogger);
|
||||
|
||||
await store.store({
|
||||
type: USER_DELETED,
|
||||
data: { id: 1 },
|
||||
createdBy: 'test',
|
||||
ip: '127.0.0.1',
|
||||
createdByUserId: 1,
|
||||
});
|
||||
await store.store({
|
||||
type: USER_UPDATED,
|
||||
data: { id: 2 },
|
||||
createdBy: 'test',
|
||||
ip: '127.0.0.1',
|
||||
createdByUserId: 1,
|
||||
});
|
||||
await store.store({
|
||||
type: USER_DELETED,
|
||||
data: { id: 3 },
|
||||
createdBy: 'test',
|
||||
ip: '127.0.0.1',
|
||||
createdByUserId: 1,
|
||||
});
|
||||
|
||||
const allEvents = await readModel.search({
|
||||
types: [USER_UPDATED, USER_DELETED],
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
});
|
||||
expect(allEvents).toBeTruthy();
|
||||
expect(allEvents.length).toBe(3);
|
||||
|
||||
const firstPage = await readModel.search({
|
||||
types: [USER_UPDATED, USER_DELETED],
|
||||
offset: 0,
|
||||
limit: 2,
|
||||
});
|
||||
expect(firstPage).toBeTruthy();
|
||||
expect(firstPage.length).toBe(2);
|
||||
|
||||
const secondPage = await readModel.search({
|
||||
types: [USER_UPDATED, USER_DELETED],
|
||||
offset: 2,
|
||||
limit: 2,
|
||||
});
|
||||
expect(secondPage).toBeTruthy();
|
||||
expect(secondPage.length).toBe(1);
|
||||
expect(secondPage[0].type).toBe(USER_DELETED);
|
||||
expect(secondPage[0].data.id).toBe(3);
|
||||
|
||||
const nonExistingPage = await readModel.search({
|
||||
types: [USER_UPDATED, USER_DELETED],
|
||||
offset: 4,
|
||||
limit: 2,
|
||||
});
|
||||
expect(nonExistingPage).toBeTruthy();
|
||||
expect(nonExistingPage.length).toBe(0);
|
||||
});
|
72
src/lib/features/events/event-search-by-type-read-model.ts
Normal file
72
src/lib/features/events/event-search-by-type-read-model.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import type { IEvent, IEventType } from '../../events/index.js';
|
||||
import type { Logger, LogProvider } from '../../logger.js';
|
||||
import type { Db } from '../../db/db.js';
|
||||
import type { IEventTable } from './event-store.js';
|
||||
|
||||
const EVENT_COLUMNS = [
|
||||
'id',
|
||||
'type',
|
||||
'created_by',
|
||||
'created_at',
|
||||
'created_by_user_id',
|
||||
'data',
|
||||
'pre_data',
|
||||
'tags',
|
||||
'feature_name',
|
||||
'project',
|
||||
'environment',
|
||||
] as const;
|
||||
|
||||
const TABLE = 'events';
|
||||
|
||||
export interface EventSearchByTypeQueryParams {
|
||||
types: string[];
|
||||
offset: number;
|
||||
limit: number;
|
||||
order?: 'asc' | 'desc'; // asc by default
|
||||
}
|
||||
|
||||
export interface EventSearchByTypeReadModel {
|
||||
search(params: EventSearchByTypeQueryParams): Promise<IEvent[]>;
|
||||
}
|
||||
|
||||
export class EventSearchByType implements EventSearchByTypeReadModel {
|
||||
private db: Db;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
// a new DB has to be injected per transaction
|
||||
constructor(db: Db, getLogger: LogProvider) {
|
||||
this.db = db;
|
||||
this.logger = getLogger('event-by-type');
|
||||
}
|
||||
|
||||
async search(params: EventSearchByTypeQueryParams): Promise<IEvent[]> {
|
||||
const query = this.db
|
||||
.select(EVENT_COLUMNS)
|
||||
.from(TABLE)
|
||||
.whereIn('type', params.types)
|
||||
.orderBy('id', params.order || 'asc')
|
||||
.offset(params.offset)
|
||||
.limit(params.limit);
|
||||
|
||||
const rows = await query;
|
||||
return rows.map(this.rowToEvent);
|
||||
}
|
||||
|
||||
rowToEvent(row: IEventTable): IEvent {
|
||||
return {
|
||||
id: row.id,
|
||||
type: row.type as IEventType,
|
||||
createdBy: row.created_by,
|
||||
createdAt: row.created_at,
|
||||
createdByUserId: row.created_by_user_id,
|
||||
data: row.data,
|
||||
preData: row.pre_data,
|
||||
tags: row.tags || [],
|
||||
featureName: row.feature_name,
|
||||
project: row.project,
|
||||
environment: row.environment,
|
||||
};
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ export interface IEventSearchParams {
|
||||
to?: string;
|
||||
createdBy?: string;
|
||||
type?: string;
|
||||
types?: string[];
|
||||
environment?: string;
|
||||
offset: number;
|
||||
limit: number;
|
||||
|
Loading…
Reference in New Issue
Block a user