From a419b8e098c44dc3a911b09afffed2853feb9de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20G=C3=B3is?= Date: Tue, 27 May 2025 16:19:10 +0100 Subject: [PATCH] chore: prefer searchEvents over deprecated methods (#10031) https://linear.app/unleash/issue/2-3577/prefer-the-new-searchevents-method-over-deprecated-methods We should favor our new `searchEvents` method over the other deprecated methods. This PR removes these deprecated methods, replaces them with the new `searchEvents` and `searchEventsCount` methods, and marks the old endpoints as deprecated. Follow-up to: https://github.com/Unleash/unleash/pull/10030 --- .../models/deprecatedSearchEventsSchema.ts | 34 ---- .../deprecatedSearchEventsSchemaType.ts | 178 ------------------ frontend/src/openapi/models/index.ts | 2 - src/lib/features/events/event-service.ts | 19 +- src/lib/features/events/event-store.test.ts | 17 +- src/lib/features/events/event-store.ts | 101 ++-------- .../instance-stats/instance-stats-service.ts | 24 ++- .../spec/deprecated-search-events-schema.ts | 55 ------ src/lib/openapi/spec/index.ts | 1 - src/lib/routes/admin-api/event.ts | 39 ++-- src/lib/types/stores/event-store.ts | 13 +- src/test/e2e/services/setting-service.test.ts | 64 +++++-- src/test/e2e/stores/event-store.e2e.test.ts | 32 +++- src/test/fixtures/fake-event-store.ts | 14 +- 14 files changed, 153 insertions(+), 440 deletions(-) delete mode 100644 frontend/src/openapi/models/deprecatedSearchEventsSchema.ts delete mode 100644 frontend/src/openapi/models/deprecatedSearchEventsSchemaType.ts delete mode 100644 src/lib/openapi/spec/deprecated-search-events-schema.ts diff --git a/frontend/src/openapi/models/deprecatedSearchEventsSchema.ts b/frontend/src/openapi/models/deprecatedSearchEventsSchema.ts deleted file mode 100644 index 46a2eed6bc..0000000000 --- a/frontend/src/openapi/models/deprecatedSearchEventsSchema.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Generated by Orval - * Do not edit manually. - * See `gen:api` script in package.json - */ -import type { DeprecatedSearchEventsSchemaType } from './deprecatedSearchEventsSchemaType.js'; - -/** - * - Search for events by type, project, feature, free-text query, - or a combination thereof. Pass an empty object to fetch all events. - - */ -export interface DeprecatedSearchEventsSchema { - /** Find events by feature flag name (case-sensitive). */ - feature?: string; - /** - * The maximum amount of events to return in the search result - * @minimum 1 - * @maximum 100 - */ - limit?: number; - /** - * Which event id to start listing from - * @minimum 0 - */ - offset?: number; - /** Find events by project ID (case-sensitive). */ - project?: string; - /** Find events by a free-text search query. The query will be matched against the event type, the username or email that created the event (if any), and the event data payload (if any). */ - query?: string; - /** Find events by event type (case-sensitive). */ - type?: DeprecatedSearchEventsSchemaType; -} diff --git a/frontend/src/openapi/models/deprecatedSearchEventsSchemaType.ts b/frontend/src/openapi/models/deprecatedSearchEventsSchemaType.ts deleted file mode 100644 index f837404163..0000000000 --- a/frontend/src/openapi/models/deprecatedSearchEventsSchemaType.ts +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Generated by Orval - * Do not edit manually. - * See `gen:api` script in package.json - */ - -/** - * Find events by event type (case-sensitive). - */ -export type DeprecatedSearchEventsSchemaType = - (typeof DeprecatedSearchEventsSchemaType)[keyof typeof DeprecatedSearchEventsSchemaType]; - -// eslint-disable-next-line @typescript-eslint/no-redeclare -export const DeprecatedSearchEventsSchemaType = { - 'application-created': 'application-created', - 'feature-created': 'feature-created', - 'feature-deleted': 'feature-deleted', - 'feature-updated': 'feature-updated', - 'feature-metadata-updated': 'feature-metadata-updated', - 'feature-variants-updated': 'feature-variants-updated', - 'feature-environment-variants-updated': - 'feature-environment-variants-updated', - 'feature-project-change': 'feature-project-change', - 'feature-archived': 'feature-archived', - 'feature-revived': 'feature-revived', - 'feature-import': 'feature-import', - 'feature-tagged': 'feature-tagged', - 'feature-tag-import': 'feature-tag-import', - 'feature-strategy-update': 'feature-strategy-update', - 'feature-strategy-add': 'feature-strategy-add', - 'feature-strategy-remove': 'feature-strategy-remove', - 'feature-type-updated': 'feature-type-updated', - 'feature-completed': 'feature-completed', - 'feature-uncompleted': 'feature-uncompleted', - 'feature-link-added': 'feature-link-added', - 'feature-link-removed': 'feature-link-removed', - 'feature-link-updated': 'feature-link-updated', - 'strategy-order-changed': 'strategy-order-changed', - 'drop-feature-tags': 'drop-feature-tags', - 'feature-untagged': 'feature-untagged', - 'feature-stale-on': 'feature-stale-on', - 'feature-stale-off': 'feature-stale-off', - 'drop-features': 'drop-features', - 'feature-environment-enabled': 'feature-environment-enabled', - 'feature-environment-disabled': 'feature-environment-disabled', - 'strategy-created': 'strategy-created', - 'strategy-deleted': 'strategy-deleted', - 'strategy-deprecated': 'strategy-deprecated', - 'strategy-reactivated': 'strategy-reactivated', - 'strategy-updated': 'strategy-updated', - 'strategy-import': 'strategy-import', - 'drop-strategies': 'drop-strategies', - 'context-field-created': 'context-field-created', - 'context-field-updated': 'context-field-updated', - 'context-field-deleted': 'context-field-deleted', - 'project-access-added': 'project-access-added', - 'project-access-user-roles-updated': 'project-access-user-roles-updated', - 'project-access-group-roles-updated': 'project-access-group-roles-updated', - 'project-access-user-roles-deleted': 'project-access-user-roles-deleted', - 'project-access-group-roles-deleted': 'project-access-group-roles-deleted', - 'project-access-updated': 'project-access-updated', - 'project-created': 'project-created', - 'project-updated': 'project-updated', - 'project-deleted': 'project-deleted', - 'project-archived': 'project-archived', - 'project-revived': 'project-revived', - 'project-import': 'project-import', - 'project-user-added': 'project-user-added', - 'project-user-removed': 'project-user-removed', - 'project-user-role-changed': 'project-user-role-changed', - 'project-group-role-changed': 'project-group-role-changed', - 'project-group-added': 'project-group-added', - 'project-group-removed': 'project-group-removed', - 'role-created': 'role-created', - 'role-updated': 'role-updated', - 'role-deleted': 'role-deleted', - 'drop-projects': 'drop-projects', - 'tag-created': 'tag-created', - 'tag-deleted': 'tag-deleted', - 'tag-import': 'tag-import', - 'drop-tags': 'drop-tags', - 'tag-type-created': 'tag-type-created', - 'tag-type-deleted': 'tag-type-deleted', - 'tag-type-updated': 'tag-type-updated', - 'tag-type-import': 'tag-type-import', - 'drop-tag-types': 'drop-tag-types', - 'addon-config-created': 'addon-config-created', - 'addon-config-updated': 'addon-config-updated', - 'addon-config-deleted': 'addon-config-deleted', - 'db-pool-update': 'db-pool-update', - 'user-created': 'user-created', - 'user-updated': 'user-updated', - 'user-deleted': 'user-deleted', - 'drop-environments': 'drop-environments', - 'environment-import': 'environment-import', - 'environment-created': 'environment-created', - 'environment-updated': 'environment-updated', - 'environment-deleted': 'environment-deleted', - 'segment-created': 'segment-created', - 'segment-updated': 'segment-updated', - 'segment-deleted': 'segment-deleted', - 'group-created': 'group-created', - 'group-updated': 'group-updated', - 'group-deleted': 'group-deleted', - 'group-user-added': 'group-user-added', - 'group-user-removed': 'group-user-removed', - 'setting-created': 'setting-created', - 'setting-updated': 'setting-updated', - 'setting-deleted': 'setting-deleted', - 'client-metrics': 'client-metrics', - 'client-register': 'client-register', - 'pat-created': 'pat-created', - 'pat-deleted': 'pat-deleted', - 'public-signup-token-created': 'public-signup-token-created', - 'public-signup-token-user-added': 'public-signup-token-user-added', - 'public-signup-token-updated': 'public-signup-token-updated', - 'change-request-created': 'change-request-created', - 'change-request-discarded': 'change-request-discarded', - 'change-added': 'change-added', - 'change-discarded': 'change-discarded', - 'change-edited': 'change-edited', - 'change-request-rejected': 'change-request-rejected', - 'change-request-approved': 'change-request-approved', - 'change-request-approval-added': 'change-request-approval-added', - 'change-request-cancelled': 'change-request-cancelled', - 'change-request-sent-to-review': 'change-request-sent-to-review', - 'change-request-schedule-suspended': 'change-request-schedule-suspended', - 'change-request-applied': 'change-request-applied', - 'change-request-scheduled': 'change-request-scheduled', - 'change-request-scheduled-application-success': - 'change-request-scheduled-application-success', - 'change-request-scheduled-application-failure': - 'change-request-scheduled-application-failure', - 'change-request-configuration-updated': - 'change-request-configuration-updated', - 'api-token-created': 'api-token-created', - 'api-token-updated': 'api-token-updated', - 'api-token-deleted': 'api-token-deleted', - 'feature-favorited': 'feature-favorited', - 'feature-unfavorited': 'feature-unfavorited', - 'project-favorited': 'project-favorited', - 'project-unfavorited': 'project-unfavorited', - 'features-exported': 'features-exported', - 'features-imported': 'features-imported', - 'service-account-created': 'service-account-created', - 'service-account-deleted': 'service-account-deleted', - 'service-account-updated': 'service-account-updated', - 'feature-potentially-stale-on': 'feature-potentially-stale-on', - 'feature-dependency-added': 'feature-dependency-added', - 'feature-dependency-removed': 'feature-dependency-removed', - 'feature-dependencies-removed': 'feature-dependencies-removed', - 'banner-created': 'banner-created', - 'banner-updated': 'banner-updated', - 'banner-deleted': 'banner-deleted', - 'project-environment-added': 'project-environment-added', - 'project-environment-removed': 'project-environment-removed', - 'default-strategy-updated': 'default-strategy-updated', - 'segment-import': 'segment-import', - 'signal-endpoint-created': 'signal-endpoint-created', - 'signal-endpoint-updated': 'signal-endpoint-updated', - 'signal-endpoint-deleted': 'signal-endpoint-deleted', - 'signal-endpoint-token-created': 'signal-endpoint-token-created', - 'signal-endpoint-token-updated': 'signal-endpoint-token-updated', - 'signal-endpoint-token-deleted': 'signal-endpoint-token-deleted', - 'actions-created': 'actions-created', - 'actions-updated': 'actions-updated', - 'actions-deleted': 'actions-deleted', - 'release-plan-template-created': 'release-plan-template-created', - 'release-plan-template-updated': 'release-plan-template-updated', - 'release-plan-template-deleted': 'release-plan-template-deleted', - 'release-plan-template-archived': 'release-plan-template-archived', - 'release-plan-added': 'release-plan-added', - 'release-plan-removed': 'release-plan-removed', - 'release-plan-milestone-started': 'release-plan-milestone-started', - 'user-preference-updated': 'user-preference-updated', - 'scim-users-deleted': 'scim-users-deleted', - 'scim-groups-deleted': 'scim-groups-deleted', -} as const; diff --git a/frontend/src/openapi/models/index.ts b/frontend/src/openapi/models/index.ts index 247d67e78d..6a94c07a44 100644 --- a/frontend/src/openapi/models/index.ts +++ b/frontend/src/openapi/models/index.ts @@ -577,8 +577,6 @@ export * from './deprecateStrategy403.js'; export * from './deprecateStrategy404.js'; export * from './deprecatedProjectOverviewSchema.js'; export * from './deprecatedProjectOverviewSchemaMode.js'; -export * from './deprecatedSearchEventsSchema.js'; -export * from './deprecatedSearchEventsSchemaType.js'; export * from './disableBanner401.js'; export * from './disableBanner403.js'; export * from './disableBanner404.js'; diff --git a/src/lib/features/events/event-service.ts b/src/lib/features/events/event-service.ts index 8a1eb154d8..8ec37385e0 100644 --- a/src/lib/features/events/event-service.ts +++ b/src/lib/features/events/event-service.ts @@ -6,7 +6,6 @@ import type { IEventStore, } from '../../types/stores/event-store.js'; import type { IApiUser, IUser } from '../../types/index.js'; -import type { DeprecatedSearchEventsSchema } from '../../openapi/index.js'; import type EventEmitter from 'node:events'; import { ApiTokenType } from '../../types/model.js'; import { EVENTS_CREATED_BY_PROCESSED } from '../../metric-events.js'; @@ -67,18 +66,6 @@ export default class EventService { }; } - async deprecatedSearchEvents( - search: DeprecatedSearchEventsSchema, - ): Promise { - const totalEvents = - await this.eventStore.deprecatedFilteredCount(search); - const events = await this.eventStore.deprecatedSearchEvents(search); - return { - events, - totalEvents, - }; - } - async searchEvents( search: IEventSearchParams, userId: number, @@ -96,12 +83,8 @@ export default class EventService { queryParams.push(...projectFilter); const totalEvents = await this.eventStore.searchEventsCount( - { - limit: search.limit, - offset: search.offset, - query: search.query, - }, queryParams, + search.query, ); const events = await this.eventStore.searchEvents( { diff --git a/src/lib/features/events/event-store.test.ts b/src/lib/features/events/event-store.test.ts index 1603089e9a..3933c5ed0d 100644 --- a/src/lib/features/events/event-store.test.ts +++ b/src/lib/features/events/event-store.test.ts @@ -3,6 +3,7 @@ import EventStore from './event-store.js'; import getLogger from '../../../test/fixtures/no-logger.js'; import { subHours, formatRFC3339 } from 'date-fns'; import dbInit from '../../../test/e2e/helpers/database-init.js'; +import { APPLICATION_CREATED } from '../../events/index.js'; beforeAll(() => { getLogger.setMuteError(true); @@ -27,9 +28,19 @@ test('Trying to get events by name if db fails should yield empty list', async ( client: 'pg', }); const store = new EventStore(db, getLogger); - const events = await store.deprecatedSearchEvents({ - type: 'application-created', - }); + const events = await store.searchEvents( + { + offset: 0, + limit: 10, + }, + [ + { + field: 'type', + operator: 'IS', + values: [APPLICATION_CREATED], + }, + ], + ); expect(events).toBeTruthy(); expect(events.length).toBe(0); await db.destroy(); diff --git a/src/lib/features/events/event-store.ts b/src/lib/features/events/event-store.ts index 3491ff7891..8bcddc0e8b 100644 --- a/src/lib/features/events/event-store.ts +++ b/src/lib/features/events/event-store.ts @@ -24,10 +24,7 @@ import { SYSTEM_USER, SYSTEM_USER_ID, } from '../../types/index.js'; -import type { - DeprecatedSearchEventsSchema, - ProjectActivitySchema, -} from '../../openapi/index.js'; +import type { ProjectActivitySchema } from '../../openapi/index.js'; import type { IQueryParam } from '../feature-toggle/types/feature-toggle-strategies-store-type.js'; import { applyGenericQueryParams } from '../feature-search/search-utils.js'; import type { ITag } from '../../tags/index.js'; @@ -142,36 +139,12 @@ class EventStore implements IEventStore { } } - async deprecatedFilteredCount( - eventSearch: DeprecatedSearchEventsSchema, - ): Promise { - let query = this.db(TABLE); - if (eventSearch.type) { - query = query.andWhere({ type: eventSearch.type }); - } - if (eventSearch.project) { - query = query.andWhere({ project: eventSearch.project }); - } - if (eventSearch.feature) { - query = query.andWhere({ feature_name: eventSearch.feature }); - } - const count = await query.count().first(); - if (!count) { - return 0; - } - if (typeof count.count === 'string') { - return Number.parseInt(count.count, 10); - } else { - return count.count; - } - } - async searchEventsCount( - params: IEventSearchParams, queryParams: IQueryParam[], + query?: IEventSearchParams['query'], ): Promise { - const query = this.buildSearchQuery(params, queryParams); - const count = await query.count().first(); + const searchQuery = this.buildSearchQuery(queryParams, query); + const count = await searchQuery.count().first(); if (!count) { return 0; } @@ -397,7 +370,7 @@ class EventStore implements IEventStore { queryParams: IQueryParam[], options?: { withIp?: boolean }, ): Promise { - const query = this.buildSearchQuery(params, queryParams) + const query = this.buildSearchQuery(queryParams, params.query) .select(options?.withIp ? [...EVENT_COLUMNS, 'ip'] : EVENT_COLUMNS) .orderBy('created_at', 'desc') .limit(Number(params.limit) ?? 100) @@ -415,23 +388,23 @@ class EventStore implements IEventStore { } private buildSearchQuery( - params: IEventSearchParams, queryParams: IQueryParam[], + query?: IEventSearchParams['query'], ) { - let query = this.db.from(TABLE); + let searchQuery = this.db.from(TABLE); - applyGenericQueryParams(query, queryParams); + applyGenericQueryParams(searchQuery, queryParams); - if (params.query) { - query = query.where((where) => + if (query) { + searchQuery = searchQuery.where((where) => where - .orWhereRaw('data::text ILIKE ?', `%${params.query}%`) - .orWhereRaw('tags::text ILIKE ?', `%${params.query}%`) - .orWhereRaw('pre_data::text ILIKE ?', `%${params.query}%`), + .orWhereRaw('data::text ILIKE ?', `%${query}%`) + .orWhereRaw('tags::text ILIKE ?', `%${query}%`) + .orWhereRaw('pre_data::text ILIKE ?', `%${query}%`), ); } - return query; + return searchQuery; } async getEventCreators(): Promise> { @@ -483,52 +456,6 @@ class EventStore implements IEventStore { })); } - async deprecatedSearchEvents( - search: DeprecatedSearchEventsSchema = {}, - ): Promise { - let query = this.db - .select(EVENT_COLUMNS) - .from(TABLE) - .limit(search.limit ?? 100) - .offset(search.offset ?? 0) - .orderBy('created_at', 'desc'); - - if (search.type) { - query = query.andWhere({ - type: search.type, - }); - } - - if (search.project) { - query = query.andWhere({ - project: search.project, - }); - } - - if (search.feature) { - query = query.andWhere({ - feature_name: search.feature, - }); - } - - if (search.query) { - query = query.where((where) => - where - .orWhereRaw('type::text ILIKE ?', `%${search.query}%`) - .orWhereRaw('created_by::text ILIKE ?', `%${search.query}%`) - .orWhereRaw('data::text ILIKE ?', `%${search.query}%`) - .orWhereRaw('tags::text ILIKE ?', `%${search.query}%`) - .orWhereRaw('pre_data::text ILIKE ?', `%${search.query}%`), - ); - } - - try { - return (await query).map(this.rowToEvent); - } catch (err) { - return []; - } - } - rowToEvent(row: IEventTable): IEvent { return { id: row.id, diff --git a/src/lib/features/instance-stats/instance-stats-service.ts b/src/lib/features/instance-stats/instance-stats-service.ts index fad69a77f5..7b1338d752 100644 --- a/src/lib/features/instance-stats/instance-stats-service.ts +++ b/src/lib/features/instance-stats/instance-stats-service.ts @@ -492,18 +492,26 @@ export class InstanceStatsService { } featuresExported(): Promise { - return this.memorize('deprecatedFilteredCountFeaturesExported', () => - this.eventStore.deprecatedFilteredCount({ - type: FEATURES_EXPORTED, - }), + return this.memorize('searchEventsCountFeaturesExported', () => + this.eventStore.searchEventsCount([ + { + field: 'type', + operator: 'IS', + values: [FEATURES_EXPORTED], + }, + ]), ); } featuresImported(): Promise { - return this.memorize('deprecatedFilteredCountFeaturesImported', () => - this.eventStore.deprecatedFilteredCount({ - type: FEATURES_IMPORTED, - }), + return this.memorize('searchEventsCountFeaturesImported', () => + this.eventStore.searchEventsCount([ + { + field: 'type', + operator: 'IS', + values: [FEATURES_IMPORTED], + }, + ]), ); } diff --git a/src/lib/openapi/spec/deprecated-search-events-schema.ts b/src/lib/openapi/spec/deprecated-search-events-schema.ts deleted file mode 100644 index 7f2aad07a9..0000000000 --- a/src/lib/openapi/spec/deprecated-search-events-schema.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { FromSchema } from 'json-schema-to-ts'; -import { IEventTypes } from '../../events/index.js'; - -export const deprecatedSearchEventsSchema = { - $id: '#/components/schemas/deprecatedSearchEventsSchema', - type: 'object', - description: ` - Search for events by type, project, feature, free-text query, - or a combination thereof. Pass an empty object to fetch all events. - `, - properties: { - type: { - type: 'string', - description: 'Find events by event type (case-sensitive).', - enum: IEventTypes, - example: 'feature-created', - }, - project: { - type: 'string', - description: 'Find events by project ID (case-sensitive).', - example: 'default', - }, - feature: { - type: 'string', - description: 'Find events by feature flag name (case-sensitive).', - example: 'my.first.flag', - }, - query: { - type: 'string', - description: `Find events by a free-text search query. The query will be matched against the event type, the username or email that created the event (if any), and the event data payload (if any).`, - example: 'admin@example.com', - }, - limit: { - type: 'integer', - description: - 'The maximum amount of events to return in the search result', - minimum: 1, - maximum: 100, - default: 100, - example: 50, - }, - offset: { - description: 'Which event id to start listing from', - type: 'integer', - minimum: 0, - default: 0, - example: 100, - }, - }, - components: {}, -} as const; - -export type DeprecatedSearchEventsSchema = FromSchema< - typeof deprecatedSearchEventsSchema ->; diff --git a/src/lib/openapi/spec/index.ts b/src/lib/openapi/spec/index.ts index 6e48e00126..be6c1f84f3 100644 --- a/src/lib/openapi/spec/index.ts +++ b/src/lib/openapi/spec/index.ts @@ -64,7 +64,6 @@ export * from './date-schema.js'; export * from './dependencies-exist-schema.js'; export * from './dependent-feature-schema.js'; export * from './deprecated-project-overview-schema.js'; -export * from './deprecated-search-events-schema.js'; export * from './dora-features-schema.js'; export * from './edge-token-schema.js'; export * from './email-schema.js'; diff --git a/src/lib/routes/admin-api/event.ts b/src/lib/routes/admin-api/event.ts index c6def62596..548226fbea 100644 --- a/src/lib/routes/admin-api/event.ts +++ b/src/lib/routes/admin-api/event.ts @@ -1,4 +1,4 @@ -import type { Request, Response } from 'express'; +import type { Response } from 'express'; import type { IUnleashConfig } from '../../types/option.js'; import type { IUnleashServices } from '../../services/index.js'; import type EventService from '../../features/events/event-service.js'; @@ -24,6 +24,7 @@ import { eventCreatorsSchema, type ProjectFlagCreatorsSchema, } from '../../openapi/index.js'; +import { extractUserIdFromUser } from '../../util/index.js'; const ANON_KEYS = ['email', 'username', 'createdBy']; const version = 1 as const; @@ -53,6 +54,7 @@ export default class EventController extends Controller { permission: ADMIN, middleware: [ openApiService.validPath({ + deprecated: true, operationId: 'getEvents', tags: ['Events'], responses: { @@ -84,6 +86,7 @@ export default class EventController extends Controller { permission: NONE, middleware: [ openApiService.validPath({ + deprecated: true, operationId: 'getEventsForToggle', tags: ['Events'], responses: { @@ -127,15 +130,21 @@ export default class EventController extends Controller { } async getEvents( - req: Request, + req: IAuthRequest, res: Response, ): Promise { - const { project } = req.query; + const { user, query } = req; + const { project } = query; let eventList: IEventList; if (project) { - eventList = await this.eventService.deprecatedSearchEvents({ - project, - }); + eventList = await this.eventService.searchEvents( + { + project: `IS:${project}`, + offset: 0, + limit: 50, + }, + extractUserIdFromUser(user), + ); } else { eventList = await this.eventService.getEvents(); } @@ -155,17 +164,23 @@ export default class EventController extends Controller { } async getEventsForToggle( - req: Request<{ featureName: string }>, + req: IAuthRequest<{ featureName: string }>, res: Response, ): Promise { - const feature = req.params.featureName; - const eventList = await this.eventService.deprecatedSearchEvents({ - feature, - }); + const { user, params } = req; + const { featureName } = params; + const eventList = await this.eventService.searchEvents( + { + feature: `IS:${featureName}`, + offset: 0, + limit: 50, + }, + extractUserIdFromUser(user), + ); const response = { version, - toggleName: feature, + toggleName: featureName, events: serializeDates(this.maybeAnonymiseEvents(eventList.events)), totalEvents: eventList.totalEvents, }; diff --git a/src/lib/types/stores/event-store.ts b/src/lib/types/stores/event-store.ts index 55884ffcd8..0ee004b0e8 100644 --- a/src/lib/types/stores/event-store.ts +++ b/src/lib/types/stores/event-store.ts @@ -1,9 +1,6 @@ import type { IBaseEvent, IEvent } from '../../events/index.js'; import type { Store } from './store.js'; -import type { - DeprecatedSearchEventsSchema, - ProjectActivitySchema, -} from '../../openapi/index.js'; +import type { ProjectActivitySchema } from '../../openapi/index.js'; import type EventEmitter from 'events'; import type { IQueryOperations } from '../../features/events/event-store.js'; import type { IQueryParam } from '../../features/feature-toggle/types/feature-toggle-strategies-store-type.js'; @@ -29,16 +26,10 @@ export interface IEventStore batchStore(events: IBaseEvent[]): Promise; getEvents(): Promise; count(): Promise; - deprecatedFilteredCount( - search: DeprecatedSearchEventsSchema, - ): Promise; searchEventsCount( - params: IEventSearchParams, queryParams: IQueryParam[], + query?: IEventSearchParams['query'], ): Promise; - deprecatedSearchEvents( - search: DeprecatedSearchEventsSchema, - ): Promise; searchEvents( params: IEventSearchParams, queryParams: IQueryParam[], diff --git a/src/test/e2e/services/setting-service.test.ts b/src/test/e2e/services/setting-service.test.ts index a8261f8dbe..834ec2f242 100644 --- a/src/test/e2e/services/setting-service.test.ts +++ b/src/test/e2e/services/setting-service.test.ts @@ -36,9 +36,19 @@ test('Can create new setting', async () => { expect(actual).toStrictEqual(someData); const { eventStore } = stores; - const createdEvents = await eventStore.deprecatedSearchEvents({ - type: SETTING_CREATED, - }); + const createdEvents = await eventStore.searchEvents( + { + offset: 0, + limit: 10, + }, + [ + { + field: 'type', + operator: 'IS', + values: [SETTING_CREATED], + }, + ], + ); expect(createdEvents).toHaveLength(1); expect(createdEvents[0].data).toEqual({ id: 'some-setting', some: 'blob' }); }); @@ -51,9 +61,19 @@ test('Can delete setting', async () => { const actual = await service.get('some-setting'); expect(actual).toBeUndefined(); const { eventStore } = stores; - const createdEvents = await eventStore.deprecatedSearchEvents({ - type: SETTING_DELETED, - }); + const createdEvents = await eventStore.searchEvents( + { + offset: 0, + limit: 10, + }, + [ + { + field: 'type', + operator: 'IS', + values: [SETTING_DELETED], + }, + ], + ); expect(createdEvents).toHaveLength(1); }); @@ -66,9 +86,19 @@ test('Sentitive SSO settings are redacted in event log', async () => { const actual = await service.get(property); const { eventStore } = stores; - const updatedEvents = await eventStore.deprecatedSearchEvents({ - type: SETTING_UPDATED, - }); + const updatedEvents = await eventStore.searchEvents( + { + offset: 0, + limit: 10, + }, + [ + { + field: 'type', + operator: 'IS', + values: [SETTING_UPDATED], + }, + ], + ); expect(updatedEvents[0].preData).toEqual({ hideEventDetails: true }); await service.delete(property, TEST_AUDIT_USER); }); @@ -83,9 +113,19 @@ test('Can update setting', async () => { TEST_AUDIT_USER, false, ); - const updatedEvents = await eventStore.deprecatedSearchEvents({ - type: SETTING_UPDATED, - }); + const updatedEvents = await eventStore.searchEvents( + { + offset: 0, + limit: 10, + }, + [ + { + field: 'type', + operator: 'IS', + values: [SETTING_UPDATED], + }, + ], + ); expect(updatedEvents).toHaveLength(1); expect(updatedEvents[0].data).toEqual({ id: 'updated-setting', diff --git a/src/test/e2e/stores/event-store.e2e.test.ts b/src/test/e2e/stores/event-store.e2e.test.ts index d54169d6aa..1b1b507dbd 100644 --- a/src/test/e2e/stores/event-store.e2e.test.ts +++ b/src/test/e2e/stores/event-store.e2e.test.ts @@ -243,13 +243,33 @@ test('Should get all events of type', async () => { return eventStore.store(event); }), ); - const featureCreatedEvents = await eventStore.deprecatedSearchEvents({ - type: FEATURE_CREATED, - }); + const featureCreatedEvents = await eventStore.searchEvents( + { + offset: 0, + limit: 10, + }, + [ + { + field: 'type', + operator: 'IS', + values: [FEATURE_CREATED], + }, + ], + ); expect(featureCreatedEvents).toHaveLength(3); - const featureDeletedEvents = await eventStore.deprecatedSearchEvents({ - type: FEATURE_DELETED, - }); + const featureDeletedEvents = await eventStore.searchEvents( + { + offset: 0, + limit: 10, + }, + [ + { + field: 'type', + operator: 'IS', + values: [FEATURE_DELETED], + }, + ], + ); expect(featureDeletedEvents).toHaveLength(3); }); diff --git a/src/test/fixtures/fake-event-store.ts b/src/test/fixtures/fake-event-store.ts index f18d8fb589..67916940a3 100644 --- a/src/test/fixtures/fake-event-store.ts +++ b/src/test/fixtures/fake-event-store.ts @@ -2,10 +2,7 @@ import type { IEventStore } from '../../lib/types/stores/event-store.js'; import type { IBaseEvent, IEvent } from '../../lib/events/index.js'; import { sharedEventEmitter } from '../../lib/util/anyEventEmitter.js'; import type { IQueryOperations } from '../../lib/features/events/event-store.js'; -import type { - DeprecatedSearchEventsSchema, - ProjectActivitySchema, -} from '../../lib/openapi/index.js'; +import type { ProjectActivitySchema } from '../../lib/openapi/index.js'; import type EventEmitter from 'events'; class FakeEventStore implements IEventStore { @@ -81,12 +78,6 @@ class FakeEventStore implements IEventStore { return Promise.resolve(0); } - deprecatedFilteredCount( - search: DeprecatedSearchEventsSchema, - ): Promise { - return Promise.resolve(0); - } - destroy(): void {} async exists(key: number): Promise { @@ -101,9 +92,6 @@ class FakeEventStore implements IEventStore { return this.events; } - async deprecatedSearchEvents(): Promise { - throw new Error('Method not implemented.'); - } async searchEvents(): Promise { throw new Error('Method not implemented.'); }