在 Prisma API 中没人谈论的问题

发布: (2026年1月17日 GMT+8 16:49)
5 min read
原文: Dev.to

Source: Dev.to

重复查询逻辑问题

随着需求的增长,端点需要:

  • 过滤
  • 搜索
  • 排序
  • 分页
  • 软删除检查
  • 查询校验

典型的临时解决方案看起来像这样:

if (query.isActive) {
  where.isActive = query.isActive === "true";
}

if (query.search) {
  where.OR = [
    { firstName: { contains: query.search, mode: "insensitive" } },
    { email: { contains: query.search, mode: "insensitive" } }
  ];
}

if (query.sort === "createdAt") {
  orderBy.createdAt = "desc";
}

每个端点最终都会拥有自己稍有不同的同一套逻辑。
起初这种重复看似无害,但久而久之会出现:

  • 一个端点允许无效过滤器,另一个却拒绝它们
  • 排序行为不一致
  • 布尔值在某些地方被正确处理,在其他地方却被当作字符串

这些细微的不一致会导致长时间的调试,即使实际上没有任何技术上的错误。

为什么简单的助手函数不够

常见的做法是把重复代码抽取到一个助手函数中。实际上,这类助手往往会变成:

  • 过于灵活 —— 不安全且难以推理
  • 过于严格 —— 无法在不同端点之间复用
  • 难以扩展 —— 当出现新需求时容易脆弱

有些助手甚至会直接执行 Prisma 查询,导致服务层失去对执行流程的控制。

用意图编码而不是重复逻辑

真正的问题不在于查询本身,而是缺少一种明确的方式来 编码意图——哪些字段可以被过滤、搜索、排序或拒绝。

于是出现了 Prisma Query Builder(prisma‑qb),一个小型库,允许你一次性配置这些规则,并生成安全的 Prisma 查询对象。

使用示例

import { buildPrismaQuery } from "prisma-qb";

const { where, orderBy } = buildPrismaQuery({
  query: req.query,
  searchFields: [
    { field: "firstName" },
    { field: "email" }
  ],
  filterFields: [
    { key: "isActive", field: "isActive", type: "boolean" }
  ],
  sortFields: [
    { key: "createdAt", field: "createdAt" }
  ],
  defaultSort: { key: "createdAt", order: "desc" }
});

该函数仅返回 Prisma 的 whereorderBy 对象——不执行查询。你的服务层仍然负责实际运行查询。

好处

  • 可预测的 API —— 无效的查询参数、意外的过滤以及未检查的排序会立即被拦截。
  • 类型感知的搜索 —— 数字不会被误当作字符串。
  • 没有隐藏的执行 —— 库永远不会为你运行 Prisma,因而你保持完整控制。
  • 对混乱输入的稳健 —— 只有你明确允许的字段会参与查询。

它不包装 Prisma,也不隐藏 Prisma,更不会发明新的查询概念;它只是负责任地构建 Prisma 查询。

谁该使用它?

  • 构建 真实 API 的开发者,而非仅仅演示项目
  • 重视 长期一致性 的团队
  • 任何 讨厌在各端点重复相同逻辑 的人
  • 需要让服务 可读且易于维护 的项目

如果这些描述让你产生共鸣,你可能已经体会到重复查询处理的痛苦。Prisma 解决了数据库访问;Prisma Query Builder 解决了 API 层剩余的重复工作。

获取方式

🔗 npm package – prisma‑qb

试一试吧,如果你不喜欢,欢迎告诉我。反馈有助于打造更好的工具。 😉

Back to Blog

相关文章

阅读更多 »