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

如何为Prisma模型字段添加转换?实现createdAt返回luxon.DateTime

解决方案:自动将Prisma DateTime转换为luxon.DateTime

针对你希望Prisma返回的createdAt自动转为luxon.DateTime实例的需求,最符合DRY原则且能避免人为遗漏的方案是使用Prisma查询中间件,其次可以考虑Prisma Client扩展,以下是具体实现和对比:

方案一:Prisma查询中间件(推荐)

Prisma的查询中间件可以拦截所有查询操作,在返回结果前统一转换日期字段,无需手动调用工具函数,也不用实现大量Repository方法。

实现步骤

  1. 编写日期转换工具函数(支持嵌套对象/数组)
  2. 注册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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 16:13:21