70 lines
1.8 KiB
TypeScript
70 lines
1.8 KiB
TypeScript
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
import { PrismaClient, Prisma } from '@prisma/client';
|
|
|
|
// 定义事务客户端类型
|
|
export type TransactionClient = Omit<
|
|
PrismaClient,
|
|
'$connect' | '$disconnect' | '$on' | '$transaction' | '$use' | '$extends'
|
|
>;
|
|
|
|
@Injectable()
|
|
export class PrismaService
|
|
extends PrismaClient
|
|
implements OnModuleInit, OnModuleDestroy
|
|
{
|
|
constructor() {
|
|
super({
|
|
log:
|
|
process.env.NODE_ENV === 'development'
|
|
? ['query', 'info', 'warn', 'error']
|
|
: ['error'],
|
|
});
|
|
}
|
|
|
|
async onModuleInit() {
|
|
await this.$connect();
|
|
}
|
|
|
|
async onModuleDestroy() {
|
|
await this.$disconnect();
|
|
}
|
|
|
|
/**
|
|
* 执行数据库事务
|
|
* @param fn 事务回调函数
|
|
* @param options 事务选项
|
|
*/
|
|
async executeTransaction<T>(
|
|
fn: (tx: TransactionClient) => Promise<T>,
|
|
options?: {
|
|
maxWait?: number;
|
|
timeout?: number;
|
|
isolationLevel?: Prisma.TransactionIsolationLevel;
|
|
},
|
|
): Promise<T> {
|
|
return this.$transaction(fn, {
|
|
maxWait: options?.maxWait ?? 5000,
|
|
timeout: options?.timeout ?? 10000,
|
|
isolationLevel: options?.isolationLevel ?? Prisma.TransactionIsolationLevel.ReadCommitted,
|
|
});
|
|
}
|
|
|
|
async cleanDatabase() {
|
|
if (process.env.NODE_ENV !== 'test') {
|
|
throw new Error('cleanDatabase can only be used in test environment');
|
|
}
|
|
|
|
const tablenames = await this.$queryRaw<
|
|
Array<{ tablename: string }>
|
|
>`SELECT tablename FROM pg_tables WHERE schemaname='public'`;
|
|
|
|
for (const { tablename } of tablenames) {
|
|
if (tablename !== '_prisma_migrations') {
|
|
await this.$executeRawUnsafe(
|
|
`TRUNCATE TABLE "public"."${tablename}" CASCADE;`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|