Prisma Client 扩展(预览版)支持许多新的用例。本文将探讨使用扩展为 Prisma Client 添加自定义功能的各种方法。
目录
引言
Prisma Client 扩展提供了一种强大且类型安全的新方法来为 Prisma 添加功能。借助它们,您将能够为 ORM 尚未原生支持的问题创建简单、灵活的解决方案。您可以在 TypeScript 或 JavaScript 中定义扩展,组合它们,甚至创建多个具有不同扩展的轻量级 Prisma Client 实例。
准备就绪后,您可以将您的扩展作为代码片段或通过打包并发布到 npm 来与社区共享。本文将向您展示使用扩展可能实现的功能,并希望激励您创建和分享自己的扩展!
注意:我们相信 Prisma Client 扩展在使用 Prisma 时将开辟许多新的可能性。然而,仅仅因为一个问题可以用扩展解决,并不意味着它将来不会通过一流的功能来解决。我们的目标之一是与社区一起试验和探索解决方案,然后再将其原生集成到 Prisma 中。
使用 Prisma Client 扩展
要使用 Prisma Client 扩展,您首先需要在 Prisma Schema 文件中启用 clientExtensions
预览功能
然后,您可以在 Prisma Client 实例上调用 $extends
方法。这将返回一个新的“扩展”客户端实例,而不修改原始实例。您可以链式调用 $extends
来使用多个扩展,并创建具有不同扩展的独立实例。
扩展的组成部分
一个扩展可以包含四种不同类型的组成部分
- Model 组件允许您向模型添加新方法。这是在
findMany
、create
等默认方法之外添加新操作的便捷方式。您可以将其用作常用查询方法的仓库,封装模型的业务逻辑,或执行您在类上使用静态方法可以完成的任何操作。 - Client 组件可用于向 Prisma Client 本身添加新的顶级方法。使用此组件可以扩展客户端的功能,而这些功能不依赖于特定的模型。
- Query 组件允许您挂接到查询生命周期,以类型安全的方式执行副作用、修改查询参数或更改结果。它们是middleware 的替代方案,提供完整的类型安全,并且可以即时应用于不同的扩展客户端实例。
- Result 组件向查询结果对象添加自定义字段和方法。这些组件允许您实现虚拟/计算字段,在单个位置定义模型实例的业务逻辑,以及转换查询返回的数据。
一个扩展可以包含一个或多个组件,以及一个可选的名称,用于在错误消息中显示
要查看定义每种扩展组件类型的完整语法,请参阅文档。
共享扩展
您可以使用 Prisma.defineExtension
工具来定义一个可以与其他用户共享的扩展
在将共享扩展发布到 npm 时,我们建议使用 prisma-extension-<package-name>
约定。这将使用户更容易在他们的应用程序中找到并安装您的扩展。
例如,如果您发布一个包名为 prisma-extension-find-or-create
的扩展,用户可以这样安装它
然后在他们的应用程序中使用该扩展
阅读我们关于共享扩展的文档以获取更多详情。
示例用例
我们整理了一系列可以用扩展解决的用例,并创建了一些示例来展示如何编写这些扩展。让我们来看一看这些用例及其实现方式
注意:Prisma Client 扩展仍处于预览版阶段,下方的一些示例可能存在一些限制。已知的问题已在 GitHub 上的示例
README
文件中列出。
示例:计算字段
在 GitHub 上查看完整示例
此示例演示了如何创建一个 Prisma Client 扩展,将虚拟/计算字段添加到 Prisma 模型。这些字段不包含在数据库中,而是在运行时计算得出。
计算字段是类型安全的,可以返回从简单值到复杂对象,甚至可以作为模型实例方法的函数。计算字段必须指定它们依赖于哪些其他字段,并且可以被其他计算字段组合/重用。
示例:转换字段
在 GitHub 上查看完整示例
此示例展示了如何使用 Prisma Client 扩展来转换 Prisma 查询返回结果中的字段。在此示例中,一个 date
字段被转换为特定区域设置的相对字符串。
这展示了在应用程序的数据访问层实现国际化(i18n)的一种方法。然而,此技术可用于实现查询结果字段的任何类型的自定义转换或序列化/反序列化。
示例:混淆字段
在 GitHub 上查看完整示例
此示例是前一个“转换字段”示例的特殊情况。它使用一个扩展来隐藏 User
模型上的敏感 password
字段。password
列不包含在底层 SQL 查询的选中列中,当在用户结果对象上访问时,它将解析为 undefined
。它也可以解析为任何其他值,例如混淆后的字符串,如 "********"
。
示例:实例方法
在 GitHub 上查看完整示例
此示例展示了如何为 Prisma 结果对象添加类似 Active Record 的接口。它使用一个 result
扩展将 save
和 delete
方法直接添加到 Prisma Client 方法返回的 User
模型对象。
此技术可用于通过行为自定义 Prisma 结果对象,类似于向模型类添加实例方法。
示例:静态方法
在 GitHub 上查看完整示例
此示例演示了如何创建一个 Prisma Client 扩展,向 User 模型添加 signUp()
和 findManyByDomain()
方法。
此技术可用于抽象常用查询/操作的逻辑,创建类似仓库的接口,或执行您使用静态类方法可以完成的任何操作。
示例:模型过滤器
在 GitHub 上查看完整示例
此示例演示了一个 Prisma Client 扩展,该扩展为模型添加了可重用过滤器,这些过滤器可以组合并传递给查询的 where
条件。复杂且常用的过滤条件可以编写一次,并通过扩展的 Prisma Client 实例在许多查询中访问。
示例:只读客户端
在 GitHub 上查看完整示例
此示例创建了一个只允许读取操作(如 findMany
和 count
)的客户端,而不允许写入操作(如 create
或 update
)。调用写入操作将在运行时和 TypeScript 编译时产生错误。
示例:输入转换
在 GitHub 上查看完整示例
此示例创建一个扩展的客户端实例,该实例修改查询参数以仅包含 published
状态的帖子。
由于 query
扩展允许修改查询参数,因此可以通过此方法应用各种默认过滤器。
示例:输入验证
在 GitHub 上查看完整示例
此示例使用 Prisma Client 扩展在创建和更新数据库对象时执行自定义运行时验证。它使用 Zod 运行时 schema 来检查传递给 Prisma 写入方法的数据是否有效。
这可以用于清理用户输入或拒绝不符合您业务逻辑规则定义的某些条件的修改操作。
示例:JSON 字段类型
在 GitHub 上查看完整示例
下一个示例结合了“输入验证”和“转换字段”示例中展示的方法,为 Json
字段提供静态和运行时类型。它使用 Zod 解析字段数据并推断静态 TypeScript 类型。
此示例包含一个 User
模型,其中有一个 JSON 个人资料字段,其结构稀疏,可能因用户而异。此扩展包含两部分
- 一个
result
扩展,添加一个计算字段profile
。此字段使用Profile
Zod schema 解析底层无类型的profile
字段。TypeScript 从解析器推断静态数据类型,因此查询结果同时具有静态和运行时类型安全。 - 一个
query
扩展,用于解析User
模型写入方法(如create
和update
)输入数据中的profile
字段。
示例:查询日志记录
在 GitHub 上查看完整示例
此示例展示了如何使用 Prisma Client 扩展来执行类似于middleware 的任务。在此示例中,一个 query
扩展跟踪完成每个查询所需的时间,并将结果以及查询和参数本身记录下来。
此技术可用于执行通用日志记录、发出事件、跟踪使用情况等。
注意:您可能对 OpenTelemetry tracing 和 Metrics 功能(两者均处于预览版)感兴趣,它们提供了关于性能以及 Prisma 如何与数据库交互的详细洞察。
示例:重试事务
在 GitHub 上查看完整示例
此示例展示了如何使用 Prisma Client 扩展来自动重试由于写入冲突/死锁超时而失败的事务。失败的事务将使用指数回退和抖动进行重试,以减少高流量下的资源竞争。
示例:无回调交互式事务
在 GitHub 上查看完整示例
此示例展示了一个 Prisma Client 扩展,它为启动交互式事务提供了新的 API,无需使用回调。
这为您提供了交互式事务的全部功能(例如读-修改-写周期),但采用了一种更具命令式的 API。在某些场景下,这可能比常规的交互式事务回调式 API 更方便。
示例:审计日志上下文
在 GitHub 上查看完整示例
此示例展示了如何使用 Prisma Client 扩展,将当前应用程序用户的 ID 作为上下文提供给 Postgres 中的审计日志触发器。用户 ID 被包含在审计跟踪中,记录表中的每一行更改。
此解决方案的详细解释可以在 GitHub 上示例的 README
文件中找到。
示例:行级安全性
在 GitHub 上查看完整示例
此示例展示了如何使用 Prisma Client 扩展,通过 Postgres 中的行级安全性(RLS)在多租户应用程序中隔离租户之间的数据。
此解决方案的详细解释可以在 GitHub 上示例的 README
文件中找到。
告诉我们您的想法
我们希望您和我们一样对 Prisma Client 扩展带来的可能性感到兴奋!
💡 您可以在此 GitHub Issue 中与我们分享您的反馈。
不要错过下一篇文章!
订阅 Prisma 新闻通讯