51 lines
2.1 KiB
TypeScript
51 lines
2.1 KiB
TypeScript
import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
||
import { PrismaClient } from '@prisma/client';
|
||
import { getRequestContext } from '../common/context/request-context.js';
|
||
|
||
/** 不带 tenantCode 的模型(租户表自身)。 */
|
||
const TENANT_FREE = new Set(['Tenant', 'Agency', 'SvcNational', 'SvcLocal', 'SvcMapping', 'LocConfig']);
|
||
/** 软删模型:读操作统一注入 deletedAt IS NULL。 */
|
||
const SOFT_DELETE = new Set(['User', 'Role', 'Resource', 'Org', 'DictType', 'DictItem', 'Config', 'Notice', 'Staff', 'SvcOrg', 'Elder', 'Plan', 'Order', 'ElderSvc']);
|
||
const READ_OPS = new Set(['findMany', 'findFirst', 'findUnique', 'count', 'aggregate', 'groupBy']);
|
||
/** 没有 where 子句的操作(create 的租户由 service 在 data 里显式写入)。 */
|
||
const NO_WHERE_OPS = new Set(['create', 'createMany']);
|
||
|
||
/**
|
||
* Prisma 客户端封装:统一注入多租户过滤(tenantCode)与软删过滤(deletedAt)。
|
||
* 通过 `this.prisma.client` 访问扩展后的客户端。
|
||
*/
|
||
@Injectable()
|
||
export class PrismaService implements OnModuleInit, OnModuleDestroy {
|
||
readonly client: PrismaClient;
|
||
/** 未扩展的裸客户端(无租户/软删注入),供 seed/租户模板等跨租户初始化使用。 */
|
||
readonly raw: PrismaClient;
|
||
|
||
constructor() {
|
||
this.raw = new PrismaClient();
|
||
this.client = this.raw.$extends({
|
||
query: {
|
||
$allModels: {
|
||
async $allOperations({ model, operation, args, query }: any) {
|
||
const ctx = getRequestContext();
|
||
if (ctx && !TENANT_FREE.has(model) && !NO_WHERE_OPS.has(operation)) {
|
||
args.where = { ...(args.where ?? {}), tenantCode: ctx.tenantCode };
|
||
}
|
||
if (SOFT_DELETE.has(model) && READ_OPS.has(operation)) {
|
||
args.where = { ...(args.where ?? {}), deletedAt: null };
|
||
}
|
||
return query(args);
|
||
},
|
||
},
|
||
},
|
||
}) as unknown as PrismaClient;
|
||
}
|
||
|
||
async onModuleInit(): Promise<void> {
|
||
await this.client.$connect();
|
||
}
|
||
|
||
async onModuleDestroy(): Promise<void> {
|
||
await this.client.$disconnect();
|
||
}
|
||
}
|