动态模块进阶:完成自定义PrismaModule模块
上一节完成了 createAsyncProviders 的实现,它的核心作用是产生一个内部常量 PRISMA_MODULE_OPTIONS,该常量对应工厂函数或用户自定义的 useFactory 方法,同时还能实例化用户传递的 useClass。本节将这些部分串联起来,完成完整的 forRootAsync 方法。
组装 forRootAsync
首先,在 forRootAsync 方法中调用 createAsyncProviders,使用扩展运算符将产生的 Provider 放入 providers 数组:
static forRootAsync(options: PrismaModuleAsyncOptions): DynamicModule {
const asyncProviders = this.createAsyncProviders(options);
const prismaClientProvider: Provider = {
provide: providerName,
useFactory: async (prismaModuleOptions: PrismaModuleOptions) => {
// 从注入的 options 中解构配置
const { datasourceUrl, ...restOptions } = prismaModuleOptions;
// 构建 newOptions 用于初始化 Client
const newOptions = {
datasources: {
db: { url: datasourceUrl },
},
...restOptions,
};
// 通过工厂函数创建 Client 实例
const client = prismaConnectionFactory(
newOptions,
prismaModuleOptions.name || PrismaClient.name
);
return client;
},
inject: [PRISMA_MODULE_OPTIONS],
};
return {
module: PrismaCoreModule,
providers: [...asyncProviders, prismaClientProvider],
exports: [prismaClientProvider],
};
}
typescript
同步 forRoot 与异步 forRootAsync 的差异
| 对比项 | forRoot(同步) | forRootAsync(异步) |
|---|---|---|
| 配置来源 | 直接传入 options 对象 | 通过 Provider 异步获取 |
| Client 连接 | 需要手动调用 client.$connect() | 不需要手动连接,首次查询时自动建立 |
| 断线重连 | 在 defer 中处理重连逻辑 | 同样在工厂函数中通过 prismaConnectionFactory 处理 |
| name 属性 | 在 Provider 中用 name 作为标识 | 在外层通过 providerName 统一管理 |
异步场景下 Prisma 的连接特性
Prisma 客户端有一个重要特性:不需要显式调用 connect() 方法。当 PrismaClient 实例被创建后,首次执行查询操作时会自动建立数据库连接。这与 TypeORM 的行为不同,TypeORM 通常需要显式调用初始化方法。
因此在 forRootAsync 的 useFactory 中,只需要创建并返回 Client 实例即可:
// 异步场景中的 defer 方法 -- 仅处理重连逻辑
const client = prismaConnectionFactory(newOptions, name);
// 无需 client.$connect()
// 无需在 defer 中处理连接
return client;
typescript
forRootAsync 的完整数据流
用户调用: PrismaModule.forRootAsync({ useClass: PrismaService })
|
v
createAsyncProviders(options)
|
+-> [场景: useFactory]
| 直接创建 PRISMA_MODULE_OPTIONS Provider
| { provide, useFactory: options.useFactory, inject: options.inject }
|
+-> [场景: useClass]
| 创建 PRISMA_MODULE_OPTIONS Provider + 注册 useClass
| 工厂函数调用 optionsFactory.createPrismaModuleOptions()
|
+-> [场景: useExisting]
| 创建 PRISMA_MODULE_OPTIONS Provider
| inject 已有的服务实例
|
v
PrismaClient Provider
| inject: [PRISMA_MODULE_OPTIONS]
| useFactory: options => prismaConnectionFactory(newOptions, name)
|
v
返回 PrismaClient 实例 -> 导出供其他模块使用
text
本节要点
createAsyncProviders的作用:生成PRISMA_MODULE_OPTIONS常量,提供配置的工厂函数或类实例- PrismaClient Provider 通过
inject: [PRISMA_MODULE_OPTIONS]获取异步配置,然后创建 Client 实例 - 异步场景不需要手动
connect():Prisma 在首次查询时自动建立连接 name属性在外层管理:异步方法中的useFactory不再用name提供 Provider 标识,改为在prismaClientProvider外层统一设置providerName- 最终导出的是
prismaClientProvider,其他模块注入后即可使用 PrismaClient 实例
完成这一步后,自定义 PrismaModule 的核心逻辑已全部实现。下一节将通过创建 PrismaService 来实现多租户数据库连接的测试。
↑