You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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,完全不破坏原有实体结构:

  1. 重构自定义列为工厂函数:
// 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); // 替换为你的加密逻辑
    }
});
  1. 修改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 }; // 返回所有表
};
  1. 更新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启动时将密钥挂载到全局对象,自定义列直接读取:

  1. 在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();
  1. 自定义列中直接使用:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:27:36