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) 组件允许您钩入查询生命周期并执行副作用、修改查询参数或以类型安全的方式更改结果。这些是 中间件 的替代方案,它们提供完全的类型安全性,并且可以临时应用于不同的扩展客户端实例。
- 结果 (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 扩展直接向 Prisma Client 方法返回的 User 模型对象添加 save 和 delete 方法。
这种技术可用于使用行为自定义 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 运行时模式来检查传递给 Prisma 写入方法的数据是否有效。
这可用于清除用户输入或以其他方式拒绝不符合您的业务逻辑规则定义的某些条件的更改。
示例:JSON 字段类型
在 GitHub 上查看完整示例
此下一个示例结合了输入验证和转换字段示例中所示的方法,为 Json 字段提供静态和运行时类型。它使用 Zod 解析字段数据并推断静态 TypeScript 类型。
此示例包含一个带有 JSON profile 字段的 User 模型,该字段具有稀疏结构,可能因用户而异。扩展分为两部分
- 一个
result扩展,它添加了一个计算的profile字段。此字段使用ProfileZod 模式解析底层无类型profile字段。TypeScript 从解析器推断静态数据类型,因此查询结果具有静态和运行时类型安全性。 - 一个
query扩展,它解析User模型的写入方法(如create和update)的输入数据中的profile字段。
示例:查询日志记录
在 GitHub 上查看完整示例
此示例展示了如何使用 Prisma Client 扩展执行与 中间件 类似的任务。在此示例中,query 扩展跟踪完成每个查询所需的时间,并记录结果以及查询和参数本身。
此技术可用于执行通用日志记录、发出事件、跟踪使用情况等。
注意:您可能对 OpenTelemetry 跟踪 和 指标 功能(均处于预览版)感兴趣,它们提供了对性能以及 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 问题中与我们分享您的反馈。
不要错过下一篇文章!
订阅 Prisma 新闻通讯