这是一种使用客户端扩展和异步alstorage(通过Nestjs-CLS)在Nestjs中进行多租户的简单方法。
本文描述了通用Nestjs实现的基础知识。查看this repo以获取一个完整且功能的示例应用程序。
步骤#1:使用bootstrap函数中使用nestjs-cls设置asynclocalstorage:
// main.ts
import {ClsMiddleware} from 'nestjs-cls';
async function bootstrap() {
// init app...
app.use(
new ClsMiddleware({
async setup(cls, req) {
cls.set('TENANT_ID', req.params('tenant_id'));
},
}).use
);
// etc
}
步骤#2:将ClsModule.forRoot({ global:true })
添加到您的应用模块(app.module.ts)导入。
步骤#3:创建一个导出自定义工厂提供商的文件,该文件返回扩展Prisma客户端。
// prisma-tenancy.provider.ts
import { PrismaModule, PrismaService } from 'nestjs-prisma';
import { ClsService } from 'nestjs-cls';
const useFactory = (prisma: PrismaService, store: ClsService) => {
return prisma.$extends({
query: {
$allModels: {
async $allOperations({ args, query }) {
const tenantId = store.get('TENANT_ID');
const [, result] = await prisma.$transaction([
prisma.$executeRaw`SELECT set_config('tenancy.tenant_id', ${`${tenantId || 0}`}, TRUE)`,
query(args),
]);
return result;
},
},
},
});
};
export type ExtendedTenantClient = ReturnType<typeof useFactory>;
export const TENANCY_CLIENT_TOKEN = Symbol('TENANCY_CLIENT_TOKEN');
export const PrismaTenancyClientProvider = {
provide: TENANCY_CLIENT_TOKEN,
imports: [PrismaModule],
inject: [PrismaService, ClsService],
useFactory
};
步骤#4:创建一个导出上述工厂提供商的模块
// prisma-tenancy.module.ts
import { Module, Global } from '@nestjs/common';
import { PrismaTenancyClientProvider, TENANCY_CLIENT_TOKEN } from './prisma-tenancy.provider';
import { PrismaModule } from 'nestjs-prisma';
@Global()
@Module({
imports: [PrismaModule],
providers: [PrismaTenancyClientProvider],
exports: [TENANCY_CLIENT_TOKEN]
})
export class PrismaTenancyModule { }
步骤#5:将上面的模块添加到root app.module.ts
导入。
现在,您可以使用代币为您的自定义提供商注入扩展客户端(在这种情况下为TENANCY_CLIENT_TOKEN
)。
import {Injectable, Inject} from "@nestjs/common";
import {
TENANCY_CLIENT_TOKEN,
ExtendedTenantClient,
} from "./prisma-tenancy.provider";
@Injectable()
export class SomeService {
constructor(
@Inject(TENANCY_CLIENT_TOKEN) private readonly prisma: ExtendedTenantClient
) {}
// etc
}