mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
fix: pre/post validate event typing
This commit is contained in:
parent
6b7a5bf0a2
commit
943b2dd3d2
@ -7,24 +7,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import {
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
EventEmitter2,
|
|
||||||
IHookSettingsGroupLabelOperationMap,
|
|
||||||
} from '@nestjs/event-emitter';
|
|
||||||
import { InjectModel } from '@nestjs/mongoose';
|
import { InjectModel } from '@nestjs/mongoose';
|
||||||
import {
|
import {
|
||||||
Document,
|
Document,
|
||||||
FilterQuery,
|
FilterQuery,
|
||||||
Model,
|
Model,
|
||||||
Query,
|
|
||||||
Types,
|
Types,
|
||||||
UpdateQuery,
|
UpdateQuery,
|
||||||
UpdateWithAggregationPipeline,
|
UpdateWithAggregationPipeline,
|
||||||
} from 'mongoose';
|
} from 'mongoose';
|
||||||
|
|
||||||
import { I18nService } from '@/i18n/services/i18n.service';
|
import { I18nService } from '@/i18n/services/i18n.service';
|
||||||
import { BaseRepository, EHook } from '@/utils/generics/base-repository';
|
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
|
||||||
|
|
||||||
import { Setting } from '../schemas/setting.schema';
|
import { Setting } from '../schemas/setting.schema';
|
||||||
import { SettingType } from '../schemas/types';
|
import { SettingType } from '../schemas/types';
|
||||||
@ -42,62 +37,22 @@ export class SettingRepository extends BaseRepository<Setting> {
|
|||||||
async preCreateValidate(
|
async preCreateValidate(
|
||||||
doc: Document<unknown, unknown, Setting> &
|
doc: Document<unknown, unknown, Setting> &
|
||||||
Setting & { _id: Types.ObjectId },
|
Setting & { _id: Types.ObjectId },
|
||||||
filterCriteria: FilterQuery<Setting>,
|
|
||||||
updates: UpdateWithAggregationPipeline | UpdateQuery<Setting>,
|
|
||||||
) {
|
) {
|
||||||
this.validateSettingValue(doc.type, doc.value);
|
this.validateSettingValue(doc.type, doc.value);
|
||||||
if (filterCriteria && updates) {
|
|
||||||
this.eventEmitter.emit(
|
|
||||||
`hook:setting:${EHook.preUpdateValidate}`,
|
|
||||||
filterCriteria,
|
|
||||||
updates,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async preUpdateValidate(
|
async preUpdateValidate(
|
||||||
criteria: string | TFilterQuery<Setting>,
|
criteria: FilterQuery<Setting>,
|
||||||
dto: UpdateQuery<Setting>,
|
|
||||||
filterCriteria: FilterQuery<Setting>,
|
|
||||||
updates: UpdateWithAggregationPipeline | UpdateQuery<Setting>,
|
updates: UpdateWithAggregationPipeline | UpdateQuery<Setting>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const payload = dto.$set ? dto.$set : dto;
|
if (!Array.isArray(updates)) {
|
||||||
|
const payload = updates.$set;
|
||||||
if (typeof payload.value !== 'undefined') {
|
if (typeof payload.value !== 'undefined') {
|
||||||
const { type } =
|
const { type } =
|
||||||
'type' in payload ? payload : await this.findOne(criteria);
|
'type' in payload ? payload : await this.findOne(criteria);
|
||||||
this.validateSettingValue(type, payload.value);
|
this.validateSettingValue(type, payload.value);
|
||||||
this.eventEmitter.emit(
|
|
||||||
`hook:setting:${EHook.preUpdateValidate}`,
|
|
||||||
filterCriteria,
|
|
||||||
updates,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits an event after a `Setting` has been updated.
|
|
||||||
*
|
|
||||||
* This method is used to synchronize global settings by emitting an event
|
|
||||||
* based on the `group` and `label` of the `Setting`.
|
|
||||||
*
|
|
||||||
* @param _query The Mongoose query object used to find and update the document.
|
|
||||||
* @param setting The updated `Setting` object.
|
|
||||||
*/
|
|
||||||
async postUpdate(
|
|
||||||
_query: Query<
|
|
||||||
Document<Setting, any, any>,
|
|
||||||
Document<Setting, any, any>,
|
|
||||||
unknown,
|
|
||||||
Setting,
|
|
||||||
'findOneAndUpdate'
|
|
||||||
>,
|
|
||||||
setting: Setting,
|
|
||||||
) {
|
|
||||||
const group = setting.group as keyof IHookSettingsGroupLabelOperationMap;
|
|
||||||
const label = setting.label as '*';
|
|
||||||
|
|
||||||
// Sync global settings var
|
|
||||||
this.eventEmitter.emit(`hook:${group}:${label}`, setting);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -209,14 +209,10 @@ describe('BaseRepository', () => {
|
|||||||
await dummyRepository.updateOne(created.id, mockUpdate);
|
await dummyRepository.updateOne(created.id, mockUpdate);
|
||||||
|
|
||||||
expect(spyPreUpdateValidate).toHaveBeenCalledWith(
|
expect(spyPreUpdateValidate).toHaveBeenCalledWith(
|
||||||
created.id,
|
|
||||||
mockUpdate,
|
|
||||||
mockGetFilterValue,
|
mockGetFilterValue,
|
||||||
mockGetUpdateValue,
|
mockGetUpdateValue,
|
||||||
);
|
);
|
||||||
expect(spyPostUpdateValidate).toHaveBeenCalledWith(
|
expect(spyPostUpdateValidate).toHaveBeenCalledWith(
|
||||||
created.id,
|
|
||||||
mockUpdate,
|
|
||||||
mockGetFilterValue,
|
mockGetFilterValue,
|
||||||
mockGetUpdateValue,
|
mockGetUpdateValue,
|
||||||
);
|
);
|
||||||
@ -261,8 +257,6 @@ describe('BaseRepository', () => {
|
|||||||
).rejects.toThrow('Mocked error while validating dummy');
|
).rejects.toThrow('Mocked error while validating dummy');
|
||||||
|
|
||||||
expect(spyPreUpdateValidate).toHaveBeenCalledWith(
|
expect(spyPreUpdateValidate).toHaveBeenCalledWith(
|
||||||
created.id,
|
|
||||||
mockUpdate,
|
|
||||||
mockGetFilterValue,
|
mockGetFilterValue,
|
||||||
mockGetUpdateValue,
|
mockGetUpdateValue,
|
||||||
);
|
);
|
||||||
|
@ -39,19 +39,20 @@ export type DeleteResult = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export enum EHook {
|
export enum EHook {
|
||||||
|
preCreateValidate = 'preCreateValidate',
|
||||||
preCreate = 'preCreate',
|
preCreate = 'preCreate',
|
||||||
|
preUpdateValidate = 'preUpdateValidate',
|
||||||
preUpdate = 'preUpdate',
|
preUpdate = 'preUpdate',
|
||||||
preUpdateMany = 'preUpdateMany',
|
preUpdateMany = 'preUpdateMany',
|
||||||
preDelete = 'preDelete',
|
preDelete = 'preDelete',
|
||||||
preCreateValidate = 'preCreateValidate',
|
postCreateValidate = 'postCreateValidate',
|
||||||
postCreate = 'postCreate',
|
postCreate = 'postCreate',
|
||||||
|
postUpdateValidate = 'postUpdateValidate',
|
||||||
postUpdate = 'postUpdate',
|
postUpdate = 'postUpdate',
|
||||||
postUpdateMany = 'postUpdateMany',
|
postUpdateMany = 'postUpdateMany',
|
||||||
postDelete = 'postDelete',
|
postDelete = 'postDelete',
|
||||||
postCreateValidate = 'postCreateValidate',
|
|
||||||
preUpdateValidate = 'preUpdateValidate',
|
|
||||||
postUpdateValidate = 'postUpdateValidate',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ! ------------------------------------ Note --------------------------------------------
|
// ! ------------------------------------ Note --------------------------------------------
|
||||||
// Methods like `update()`, `updateOne()`, `updateMany()`, `findOneAndUpdate()`,
|
// Methods like `update()`, `updateOne()`, `updateMany()`, `findOneAndUpdate()`,
|
||||||
// `findByIdAndUpdate()`, `findOneAndReplace()`, `findOneAndDelete()`, and `findByIdAndDelete()`
|
// `findByIdAndUpdate()`, `findOneAndReplace()`, `findOneAndDelete()`, and `findByIdAndDelete()`
|
||||||
@ -476,8 +477,21 @@ export abstract class BaseRepository<
|
|||||||
);
|
);
|
||||||
const filterCriteria = query.getFilter();
|
const filterCriteria = query.getFilter();
|
||||||
const queryUpdates = query.getUpdate();
|
const queryUpdates = query.getUpdate();
|
||||||
await this.preUpdateValidate(criteria, dto, filterCriteria, queryUpdates);
|
|
||||||
await this.postUpdateValidate(criteria, dto, filterCriteria, queryUpdates);
|
await this.preUpdateValidate(filterCriteria, queryUpdates);
|
||||||
|
this.emitter.emit(
|
||||||
|
this.getEventName(EHook.preUpdateValidate),
|
||||||
|
filterCriteria,
|
||||||
|
queryUpdates,
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.postUpdateValidate(filterCriteria, queryUpdates);
|
||||||
|
this.emitter.emit(
|
||||||
|
this.getEventName(EHook.postUpdateValidate),
|
||||||
|
filterCriteria,
|
||||||
|
queryUpdates,
|
||||||
|
);
|
||||||
|
|
||||||
return await this.executeOne(query, this.cls);
|
return await this.executeOne(query, this.cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,18 +526,14 @@ export abstract class BaseRepository<
|
|||||||
// Nothing ...
|
// Nothing ...
|
||||||
}
|
}
|
||||||
|
|
||||||
async preUpdateValidate<D extends Partial<U>>(
|
async preUpdateValidate(
|
||||||
_criteria: string | TFilterQuery<T>,
|
|
||||||
_dto: UpdateQuery<D>,
|
|
||||||
_filterCriteria: FilterQuery<T>,
|
_filterCriteria: FilterQuery<T>,
|
||||||
_updates: UpdateWithAggregationPipeline | UpdateQuery<T>,
|
_updates: UpdateWithAggregationPipeline | UpdateQuery<T>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Nothing ...
|
// Nothing ...
|
||||||
}
|
}
|
||||||
|
|
||||||
async postUpdateValidate<D extends Partial<U>>(
|
async postUpdateValidate(
|
||||||
_criteria: string | TFilterQuery<T>,
|
|
||||||
_dto: UpdateQuery<D>,
|
|
||||||
_filterCriteria: FilterQuery<T>,
|
_filterCriteria: FilterQuery<T>,
|
||||||
_updates: UpdateWithAggregationPipeline | UpdateQuery<T>,
|
_updates: UpdateWithAggregationPipeline | UpdateQuery<T>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
38
api/types/event-emitter.d.ts
vendored
38
api/types/event-emitter.d.ts
vendored
@ -6,7 +6,7 @@
|
|||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Document, FilterQuery, Query } from 'mongoose';
|
import type { Document, Query } from 'mongoose';
|
||||||
import { type Socket } from 'socket.io';
|
import { type Socket } from 'socket.io';
|
||||||
|
|
||||||
import { type BotStats } from '@/analytics/schemas/bot-stats.schema';
|
import { type BotStats } from '@/analytics/schemas/bot-stats.schema';
|
||||||
@ -179,11 +179,13 @@ declare module '@nestjs/event-emitter' {
|
|||||||
type EventNamespaces = keyof IHookEntityOperationMap;
|
type EventNamespaces = keyof IHookEntityOperationMap;
|
||||||
|
|
||||||
/* pre hooks */
|
/* pre hooks */
|
||||||
type TPreValidate<T> = THydratedDocument<T>;
|
type TPreCreateValidate<T> = THydratedDocument<T>;
|
||||||
|
|
||||||
type TPreCreate<T> = THydratedDocument<T>;
|
type TPreCreate<T> = THydratedDocument<T>;
|
||||||
|
|
||||||
type TPreUpdate<T> = TFilterQuery<T> & object;
|
type TPreUpdateValidate<T> = FilterQuery<T>;
|
||||||
|
|
||||||
|
type TPreUpdate<T> = TFilterQuery<T>;
|
||||||
|
|
||||||
type TPreDelete<T> = Query<
|
type TPreDelete<T> = Query<
|
||||||
DeleteResult,
|
DeleteResult,
|
||||||
@ -195,27 +197,27 @@ declare module '@nestjs/event-emitter' {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
type TPreUnion<T> =
|
type TPreUnion<T> =
|
||||||
| TPreValidate<T>
|
| TPreCreateValidate<T>
|
||||||
| TPreCreate<T>
|
| TPreCreate<T>
|
||||||
|
| TPreUpdateValidate<T>
|
||||||
| TPreUpdate<T>
|
| TPreUpdate<T>
|
||||||
| TPreDelete<T>;
|
| TPreDelete<T>;
|
||||||
|
|
||||||
/* post hooks */
|
/* post hooks */
|
||||||
type TPostValidate<T> = THydratedDocument<T>;
|
type TPostCreateValidate<T> = THydratedDocument<T>;
|
||||||
|
|
||||||
type TPostCreate<T> = THydratedDocument<T>;
|
type TPostCreate<T> = THydratedDocument<T>;
|
||||||
|
|
||||||
|
type TPostUpdateValidate<T> = FilterQuery<T>;
|
||||||
|
|
||||||
type TPostUpdate<T> = THydratedDocument<T>;
|
type TPostUpdate<T> = THydratedDocument<T>;
|
||||||
|
|
||||||
type TPreUpdateValidate<T> = FilterQuery<T>;
|
|
||||||
|
|
||||||
type TPostUpdateValidate<T> = THydratedDocument<T>;
|
|
||||||
|
|
||||||
type TPostDelete = DeleteResult;
|
type TPostDelete = DeleteResult;
|
||||||
|
|
||||||
type TPostUnion<T> =
|
type TPostUnion<T> =
|
||||||
| TPostValidate<T>
|
| TPostCreateValidate<T>
|
||||||
| TPostCreate<T>
|
| TPostCreate<T>
|
||||||
|
| TPostUpdateValidate<T>
|
||||||
| TPostUpdate<T>
|
| TPostUpdate<T>
|
||||||
| TPostDelete;
|
| TPostDelete;
|
||||||
|
|
||||||
@ -251,11 +253,14 @@ declare module '@nestjs/event-emitter' {
|
|||||||
T = IHookEntityOperationMap[E]['schema'],
|
T = IHookEntityOperationMap[E]['schema'],
|
||||||
> =
|
> =
|
||||||
| {
|
| {
|
||||||
[EHook.preCreateValidate]: TPreValidate<T>;
|
[EHook.preCreateValidate]: TPreCreateValidate<T>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
[EHook.preCreate]: TPreCreate<T>;
|
[EHook.preCreate]: TPreCreate<T>;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
[EHook.preUpdateValidate]: TPreUpdateValidate<T>;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
[EHook.preUpdate]: TPreUpdate<T>;
|
[EHook.preUpdate]: TPreUpdate<T>;
|
||||||
}
|
}
|
||||||
@ -263,22 +268,19 @@ declare module '@nestjs/event-emitter' {
|
|||||||
[EHook.preDelete]: TPreDelete<T>;
|
[EHook.preDelete]: TPreDelete<T>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
[EHook.postCreateValidate]: TPostValidate<T>;
|
[EHook.postCreateValidate]: TPostCreateValidate<T>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
[EHook.postCreate]: TPostCreate<T>;
|
[EHook.postCreate]: TPostCreate<T>;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
[EHook.postUpdateValidate]: TPostUpdateValidate<T>;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
[EHook.postUpdate]: TPostUpdate<T>;
|
[EHook.postUpdate]: TPostUpdate<T>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
[EHook.postDelete]: TPostDelete;
|
[EHook.postDelete]: TPostDelete;
|
||||||
}
|
|
||||||
| {
|
|
||||||
[EHook.preUpdateValidate]: TPreUpdateValidate<T>;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
[EHook.postUpdateValidate]: TPostUpdateValidate<T>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type TNormalizedHook<E extends keyof IHookEntityOperationMap, O> = Extract<
|
type TNormalizedHook<E extends keyof IHookEntityOperationMap, O> = Extract<
|
||||||
|
Loading…
Reference in New Issue
Block a user