如何在NestJS的Drizzle自定义列中注入ConfigService?
问题描述
我有一个集成Drizzle的NestJS应用,目前运行正常,但遇到一个问题:需要将NestJS的ConfigService注入到可自动加解密内容的自定义列中,示例代码如下:
export const encryptedColumn = customType<{ data: string }>({ dataType() { return "text"; }, fromDriver(value: unknown) { //Encryption goes here }, toDriver(value: string) { //Decryption goes here } });
我需要在fromDriver和toDriver函数中通过ConfigService获取加解密密钥。当前NestJS与Drizzle的集成很简单,包含一个基础模块:
@Module({ providers: [DrizzleProvider], exports: [DrizzleProvider], }) export class DrizzleModule {}
以及一个可在应用中注入的提供者:
import * as DbSchema from './schema'; export const DrizzleModuleProvider = 'DrizzleModuleProvider'; export const DrizzleProvider = { provide: DrizzleModuleProvider, useFactory: async () => { const pool = new Pool({ connectionString: process.env.DB_CONN_STRING_GOES_HERE, ssl: { rejectUnauthorized: false }, }); const db = drizzle(pool, { schema: DbSchema, }); return db; } };
schema.ts文件汇总了各模块中Drizzle实体声明的表结构,这些实体文件与NestJS无直接关联,只是单纯的表声明类。
我该如何正确地将ConfigService注入到自定义列定义中?将定义包裹在@Injectable()类中不可行,因为Drizzle实体不依赖NestJS,无法注入;也无法通过闭包传递ConfigService,因为实体文件本身无法访问它。求无需大幅重构应用的简洁实现方案。
解决方案
方案1:动态构建Schema传递密钥(推荐)
通过DrizzleProvider的工厂函数注入ConfigService,将密钥传递给自定义列的工厂函数,动态构建Schema,完全不破坏原有实体结构:
- 重构自定义列为工厂函数:
// encrypted-column.ts export const createEncryptedColumn = (encryptionKey: string) => customType<{ data: string }>({ dataType() { return "text"; }, fromDriver(value: unknown) { // 使用传入的密钥解密 if (!value) return value; return decrypt(value as string, encryptionKey); // 替换为你的解密逻辑 }, toDriver(value: string) { // 使用传入的密钥加密 return encrypt(value, encryptionKey); // 替换为你的加密逻辑 } });
- 修改Schema为动态构建函数:
// schema.ts import { createEncryptedColumn } from './encrypted-column'; export const buildSchema = (encryptionKey: string) => { const encryptedColumn = createEncryptedColumn(encryptionKey); // 这里定义你的所有表结构,使用encryptedColumn const users = pgTable('users', { id: serial('id').primaryKey(), sensitiveData: encryptedColumn('sensitive_data'), // 其他列... }); return { users }; // 返回所有表 };
- 更新DrizzleProvider注入ConfigService并构建Schema:
import { ConfigService } from '@nestjs/config'; import * as DbSchemaBuilder from './schema'; export const DrizzleProvider = { provide: DrizzleModuleProvider, useFactory: async (configService: ConfigService) => { const encryptionKey = configService.get<string>('ENCRYPTION_KEY'); const pool = new Pool({ connectionString: configService.get<string>('DB_CONN_STRING_GOES_HERE'), ssl: { rejectUnauthorized: false }, }); const schema = DbSchemaBuilder.buildSchema(encryptionKey); const db = drizzle(pool, { schema }); return db; }, inject: [ConfigService], // 注入ConfigService }
方案2:全局挂载密钥(简易快速版)
如果不需要严格的隔离性,可在NestJS启动时将密钥挂载到全局对象,自定义列直接读取:
- 在main.ts中加载密钥:
import { ConfigService } from '@nestjs/config'; async function bootstrap() { const app = await NestFactory.create(AppModule); const configService = app.get(ConfigService); globalThis.ENCRYPTION_KEY = configService.get<string>('ENCRYPTION_KEY'); await app.listen(3000); } bootstrap();
- 自定义列中直接使用:
export const encryptedColumn = customType<{ data: string }>({ dataType() { return "text"; }, fromDriver(value: unknown) { const key = globalThis.ENCRYPTION_KEY; // 解密逻辑 }, toDriver(value: string) { const key = globalThis.ENCRYPTION_KEY; // 加密逻辑 } });
该方案无需改动Schema结构,但全局变量存在一定安全风险,适合内部系统或快速验证场景。
内容的提问来源于stack exchange,提问作者Some Dev Guy
相关产品推荐
相关产品推荐

