add base subscriber

This commit is contained in:
liuyi 2025-06-04 16:13:25 +08:00
parent 3fa9ecc33a
commit 38208a57e8
4 changed files with 115 additions and 8 deletions

View File

@ -1,21 +1,20 @@
import { DataSource, EventSubscriber } from 'typeorm'; import { DataSource, EventSubscriber, ObjectType } from 'typeorm';
import { PostBodyType } from '@/modules/content/constants'; import { PostBodyType } from '@/modules/content/constants';
import { PostEntity } from '@/modules/content/entities/post.entity'; import { PostEntity } from '@/modules/content/entities/post.entity';
import { PostRepository } from '@/modules/content/repositories/post.repository'; import { PostRepository } from '@/modules/content/repositories/post.repository';
import { SanitizeService } from '@/modules/content/services/SanitizeService'; import { SanitizeService } from '@/modules/content/services/SanitizeService';
import { BaseSubscriber } from '@/modules/database/base/subscriber';
@EventSubscriber() @EventSubscriber()
export class PostSubscriber { export class PostSubscriber extends BaseSubscriber<PostEntity> {
protected entity: ObjectType<PostEntity> = PostEntity;
constructor( constructor(
protected dataSource: DataSource, protected dataSource: DataSource,
protected sanitizeService: SanitizeService, protected sanitizeService: SanitizeService,
protected postRepository: PostRepository, protected postRepository: PostRepository,
) { ) {
dataSource.subscribers.push(this); super(dataSource);
}
listenTo() {
return PostEntity;
} }
async afterLoad(entity: PostEntity) { async afterLoad(entity: PostEntity) {

View File

@ -0,0 +1,76 @@
import { Optional } from '@nestjs/common';
import { isNil } from 'lodash';
import {
DataSource,
EntitySubscriberInterface,
EntityTarget,
EventSubscriber,
InsertEvent,
ObjectLiteral,
ObjectType,
RecoverEvent,
RemoveEvent,
SoftRemoveEvent,
TransactionCommitEvent,
TransactionRollbackEvent,
TransactionStartEvent,
UpdateEvent,
} from 'typeorm';
import { RepositoryType } from '../types';
import { getCustomRepository } from '../utils';
type SubscriberEvent<T extends ObjectLiteral> =
| InsertEvent<T>
| UpdateEvent<T>
| SoftRemoveEvent<T>
| RemoveEvent<T>
| RecoverEvent<T>
| TransactionStartEvent
| TransactionCommitEvent
| TransactionRollbackEvent;
@EventSubscriber()
export abstract class BaseSubscriber<T extends ObjectLiteral>
implements EntitySubscriberInterface<T>
{
protected abstract entity: ObjectType<T>;
protected constructor(@Optional() protected dataSource?: DataSource) {
if (!isNil(this.dataSource)) {
this.dataSource.subscribers.push(this);
}
}
protected getDataSource(event: SubscriberEvent<T>) {
return this.dataSource ?? event.connection;
}
protected getManage(event: SubscriberEvent<T>) {
return this.dataSource ? this.dataSource.manager : event.manager;
}
listenTo() {
return this.entity;
}
async afterLoad(entity: any) {
if ('parent' in entity && isNil(entity.depth)) {
entity.depth = 0;
}
}
protected getRepository<
C extends ClassType<P>,
P extends RepositoryType<T>,
R extends EntityTarget<ObjectLiteral>,
>(event: SubscriberEvent<T>, respository?: C, entity?: R) {
return isNil(respository)
? this.getDataSource(event).getRepository(entity ?? this.entity)
: getCustomRepository<P, T>(this.getDataSource(event), respository);
}
protected isUpdated(cloumn: keyof T, event: UpdateEvent<T>) {
return !!event.updatedColumns.find((o) => o.propertyName === cloumn);
}
}

View File

@ -1,7 +1,16 @@
import { FindTreeOptions, ObjectLiteral, SelectQueryBuilder } from 'typeorm'; import {
FindTreeOptions,
ObjectLiteral,
SelectQueryBuilder,
Repository,
TreeRepository,
} from 'typeorm';
import { OrderType, SelectTrashMode } from '@/modules/database/constants'; import { OrderType, SelectTrashMode } from '@/modules/database/constants';
import { BaseRepository } from './base/repository';
import { BaseTreeRepository } from './base/tree.repository';
export type QueryHook<Entity> = ( export type QueryHook<Entity> = (
qb: SelectQueryBuilder<Entity>, qb: SelectQueryBuilder<Entity>,
) => Promise<SelectQueryBuilder<Entity>>; ) => Promise<SelectQueryBuilder<Entity>>;
@ -52,3 +61,9 @@ export type ServiceListQueryOptionNotWithTrashed<T extends ObjectLiteral> = Omit
export type ServiceListQueryOption<T extends ObjectLiteral> = export type ServiceListQueryOption<T extends ObjectLiteral> =
| ServiceListQueryOptionNotWithTrashed<T> | ServiceListQueryOptionNotWithTrashed<T>
| ServiceListQueryOptionWithTrashed<T>; | ServiceListQueryOptionWithTrashed<T>;
export type RepositoryType<T extends ObjectLiteral> =
| Repository<T>
| TreeRepository<T>
| BaseRepository<T>
| BaseTreeRepository<T>;

View File

@ -1,8 +1,10 @@
import { isArray, isNil } from 'lodash'; import { isArray, isNil } from 'lodash';
import { ObjectLiteral, SelectQueryBuilder } from 'typeorm'; import { DataSource, ObjectLiteral, ObjectType, Repository, SelectQueryBuilder } from 'typeorm';
import { OrderQueryType, PaginateOptions, PaginateReturn } from '@/modules/database/types'; import { OrderQueryType, PaginateOptions, PaginateReturn } from '@/modules/database/types';
import { CUSTOM_REPOSITORY_METADATA } from './constants';
export const paginate = async <T extends ObjectLiteral>( export const paginate = async <T extends ObjectLiteral>(
qb: SelectQueryBuilder<T>, qb: SelectQueryBuilder<T>,
options: PaginateOptions, options: PaginateOptions,
@ -80,3 +82,18 @@ export const getOrderByQuery = <T extends ObjectLiteral>(
} }
return qb.orderBy(`${alias}.${(orderBy as any).name}`, (orderBy as any).order); return qb.orderBy(`${alias}.${(orderBy as any).name}`, (orderBy as any).order);
}; };
export const getCustomRepository = <P extends Repository<T>, T extends ObjectLiteral>(
dataSource: DataSource,
Repo: ClassType<P>,
): P => {
if (isNil(Repo)) {
return null;
}
const entity = Reflect.getMetadata(CUSTOM_REPOSITORY_METADATA, Repo);
if (!entity) {
return null;
}
const base = dataSource.getRepository<ObjectType<any>>(entity);
return new Repo(base.target, base.manager, base.queryRunner) as P;
};