如何为Prisma模型字段添加转换?实现createdAt返回luxon.DateTime
解决方案:自动将Prisma DateTime转换为luxon.DateTime
针对你希望Prisma返回的createdAt自动转为luxon.DateTime实例的需求,最符合DRY原则且能避免人为遗漏的方案是使用Prisma查询中间件,其次可以考虑Prisma Client扩展,以下是具体实现和对比:
方案一:Prisma查询中间件(推荐)
Prisma的查询中间件可以拦截所有查询操作,在返回结果前统一转换日期字段,无需手动调用工具函数,也不用实现大量Repository方法。
实现步骤
- 编写日期转换工具函数(支持嵌套对象/数组)
- 注册Prisma查询中间件,自动处理查询结果
import { PrismaClient } from '@prisma/client'; import { DateTime } from 'luxon'; const prisma = new PrismaClient(); // 定义需要转换的日期字段(可根据业务扩展其他模型的日期字段) const DATE_FIELDS = ['createdAt', 'updatedAt']; // 递归转换Date实例为luxon.DateTime function convertDates<T>(data: T): T { if (!data || typeof data !== 'object') return data; // 处理数组类型结果 if (Array.isArray(data)) { return data.map(convertDates) as unknown as T; } // 处理单个对象 const converted = { ...data }; for (const key of Object.keys(converted)) { if (DATE_FIELDS.includes(key) && converted[key] instanceof Date) { converted[key] = DateTime.fromJSDate(converted[key] as Date) as unknown as T[keyof T]; } else if (typeof converted[key] === 'object') { // 递归处理嵌套关联数据 converted[key] = convertDates(converted[key]); } } return converted; } // 注册查询中间件 prisma.$use(async (params, next) => { const result = await next(params); // 仅处理查询类操作,跳过创建/更新/删除等写操作 if (['findUnique', 'findFirst', 'findMany', 'findRaw', 'aggregate'].includes(params.action)) { return convertDates(result); } return result; });
优势
- 全局自动生效:所有查询返回的结果中指定日期字段都会自动转换,团队成员无需额外操作,避免遗漏
- 支持嵌套关联:如果User模型关联了其他含日期字段的模型(如Post),嵌套结果中的日期也会被转换
- 代码量少,维护成本低:只需维护DATE_FIELDS数组和转换函数
方案二:Prisma Client扩展
如果需要更灵活的控制(比如只为特定模型添加转换,或自定义查询方法),可以使用Prisma Client扩展:
实现示例
import { PrismaClient } from '@prisma/client'; import { DateTime } from 'luxon'; const prisma = new PrismaClient().$extends({ // 扩展结果字段,添加转换后的luxon日期 result: { user: { luxonCreatedAt: { // 指定需要依赖的原始字段 needs: { createdAt: true }, // 计算转换后的字段 compute(user) { return DateTime.fromJSDate(user.createdAt); }, }, }, }, // 或者扩展模型方法,返回已转换的结果 model: { user: { async findUniqueWithLuxon(args) { const user = await this.findUnique(args); if (!user) return null; return { ...user, createdAt: DateTime.fromJSDate(user.createdAt) }; }, }, }, });
使用方式
// 使用扩展的结果字段 const user = await prisma.user.findUnique({ where: { id: 'xxx' } }); console.log(user?.luxonCreatedAt); // 直接得到luxon.DateTime实例 // 使用扩展的自定义方法 const userWithLuxon = await prisma.user.findUniqueWithLuxon({ where: { id: 'xxx' } }); console.log(userWithLuxon?.createdAt); // luxon.DateTime实例
对比
- 灵活性更高,但需要团队成员使用扩展后的字段或方法,存在一定的学习成本
- 适合不需要全局转换,仅针对特定场景的需求
对现有方案的补充说明
- Repository接口实现:确实需要大量重复代码,维护成本极高,不推荐
- 服务层工具函数:依赖手动调用,容易因遗漏导致bug,中间件方案从根源上避免了这个问题
内容的提问来源于stack exchange,提问作者Aniket Kumar
相关产品推荐
相关产品推荐

