扩展
Prisma Client 扩展从 4.16.0 及更高版本开始正式可用。它们在 4.7.0 版本中以预览形式推出。如果你使用的是早于 4.16.0 的版本,请确保启用 clientExtensions
预览功能标志。
你可以使用 Prisma Client 扩展为你的模型、结果对象和查询添加功能,或添加客户端级别的方法。
你可以使用以下一个或多个组件类型来创建扩展
- `model`: 为你的模型添加自定义方法或字段
- `client`: 为 Prisma Client 添加客户端级别的方法
- `query`: 创建自定义 Prisma Client 查询
- `result`: 为你的查询结果添加自定义字段
例如,你可以创建一个使用 model
和 client
组件类型的扩展。
关于 Prisma Client 扩展
当你使用 Prisma Client 扩展时,你创建了一个扩展客户端。扩展客户端是标准 Prisma Client 的一个轻量级变体,它被一个或多个扩展包装。标准客户端不会被修改。你可以在你的项目中添加任意数量的扩展客户端。了解有关扩展客户端的更多信息.
你可以将一个或多个扩展与扩展客户端关联。了解有关多个扩展的更多信息.
你可以 与其他 Prisma ORM 用户共享你的 Prisma Client 扩展,以及 将其他用户开发的 Prisma Client 扩展导入你的 Prisma ORM 项目。
扩展客户端
扩展客户端以以下方式相互交互,以及与标准客户端交互
- 每个扩展客户端都在一个隔离的实例中独立运行。
- 扩展客户端不能互相冲突,也不能与标准客户端冲突。
- 所有扩展客户端和标准客户端都与同一个 Prisma ORM 查询引擎 通信。
- 所有扩展客户端和标准客户端共享同一个连接池。
注意: 扩展的作者可以修改此行为,因为他们能够作为扩展的一部分运行任意代码。例如,扩展实际上可能创建一个全新的
PrismaClient
实例(包括它自己的查询引擎和连接池)。请务必查看你正在使用的扩展的文档,了解它可能实现的任何特定行为。
扩展客户端的示例用例
由于扩展客户端在隔离的实例中运行,因此它们可能是以下操作的一种好方法,例如
- 实现行级安全 (RLS),其中每个 HTTP 请求都有自己的客户端,并有自己的 RLS 扩展,并使用会话数据进行自定义。这可以使每个用户完全独立,每个用户都在一个单独的客户端中。
- 为
User
模型添加一个user.current()
方法来获取当前登录的用户。 - 如果设置了调试 cookie,则启用更详细的请求日志记录。
- 将唯一的请求 ID 附加到所有日志中,以便你以后关联它们,例如帮助你分析 Prisma Client 执行的操作。
- 从模型中删除
delete
方法,除非应用调用了管理员端点,并且用户具有必要的权限。
向 Prisma Client 添加扩展
你可以使用两种主要方式创建扩展
-
使用客户端级别的
$extends
方法const xprisma = prisma.$extends({
name: 'signUp', // Optional: name appears in error logs
model: { // This is a `model` component
user: { ... } // The extension logic for the `user` model goes inside the curly braces
},
}) -
使用
Prisma.defineExtension
方法定义扩展并将其分配给一个变量,然后将扩展传递给客户端级别的$extends
方法import { Prisma } from '@prisma/client'
// Define the extension
const myExtension = Prisma.defineExtension({
name: 'signUp', // Optional: name appears in error logs
model: { // This is a `model` component
user: { ... } // The extension logic for the `user` model goes inside the curly braces
},
})
// Pass the extension to a Prisma Client instance
const xprisma = prisma.$extends(myExtension)tip此模式对于希望将扩展分离到项目中的多个文件或目录中时很有用。
上面的示例使用 model
扩展组件 来扩展 User
模型。
在你的 $extends
方法中,使用适当的扩展组件或组件 (model
、client
、result
或 query
)。
为错误日志命名扩展
你可以为你的扩展命名,以帮助在错误日志中识别它们。为此,请使用可选字段 name
。例如
const prisma = new PrismaClient().$extends({
name: `signUp`, // (Optional) Extension name
model: {
user: { ... }
},
})
多个扩展
你可以通过两种方式之一将扩展与 扩展客户端 关联
- 你可以将其与扩展客户端本身关联,或者
- 你可以将扩展与其他扩展组合起来,并将所有这些扩展与扩展客户端关联。这些组合扩展的功能适用于同一个扩展客户端。注意: 组合扩展可能会发生冲突.
你可以将以上两种方法结合起来。例如,你可能会将一个扩展与其自己的扩展客户端关联,并将另外两个扩展与另一个扩展客户端关联。了解有关客户端实例如何交互的更多信息.
将多个扩展应用于扩展客户端
在以下示例中,假设你有两个扩展 extensionA
和 extensionB
。有两种方法可以将它们组合起来。
选项 1: 在一行代码中声明新的客户端
使用此选项,你可以在一行代码中将两个扩展应用于新的客户端。
// First of all, store your original Prisma Client in a variable as usual
const prisma = new PrismaClient()
// Declare an extended client that has an extensionA and extensionB
const prismaAB = prisma.$extends(extensionA).$extends(extensionB)
然后你可以在你的代码中引用 prismaAB
,例如 prismaAB.myExtensionMethod()
。
选项 2: 声明多个扩展客户端
此选项的优点是可以分别调用任何扩展客户端。
// First of all, store your original Prisma Client in a variable as usual
const prisma = new PrismaClient()
// Declare an extended client that has extensionA applied
const prismaA = prisma.$extends(extensionA)
// Declare an extended client that has extensionB applied
const prismaB = prisma.$extends(extensionB)
// Declare an extended client that is a combination of clientA and clientB
const prismaAB = prismaA.$extends(extensionB)
在你的代码中,你可以分别调用任何这些客户端,例如 prismaA.myExtensionMethod()
、prismaB.myExtensionMethod()
或 prismaAB.myExtensionMethod()
。
组合扩展中的冲突
当你将两个或多个扩展组合到一个扩展客户端中时,你最后声明的扩展在任何冲突中优先。在上面选项 1 的示例中,假设在 extensionA
中定义了一个名为 myExtensionMethod()
的方法,在 extensionB
中定义了一个名为 myExtensionMethod()
的方法。当你调用 prismaAB.myExtensionMethod()
时,Prisma Client 将使用在 extensionB
中定义的 myExtensionMethod()
。
扩展客户端的类型
你可以使用 typeof
实用程序来推断扩展 Prisma Client 实例的类型,如下所示
const extendedPrismaClient = new PrismaClient().$extends({
/** extension */
})
type ExtendedPrismaClient = typeof extendedPrismaClient
如果您将 Prisma Client 作为单例使用,您可以使用 `typeof` 和 ReturnType
实用程序获取扩展的 Prisma Client 实例的类型,如下所示
function getExtendedClient() {
return new PrismaClient().$extends({
/* extension */
})
}
type ExtendedPrismaClient = ReturnType<typeof getExtendedClient>
限制
在扩展客户端中使用 `$on` 和 `$use`
扩展客户端中无法使用 `$on` 和 `$use`。如果您希望继续使用这些 客户端级方法 与扩展客户端一起使用,您需要在扩展客户端之前将其连接起来。
const prisma = new PrismaClient()
prisma.$use(async (params, next) => {
console.log('This is middleware!')
return next(params)
})
const xPrisma = prisma.$extends({
name: 'myExtension',
model: {
user: {
async signUp(email: string) {
await prisma.user.create({ data: { email } })
},
},
},
})
在扩展客户端中使用客户端级方法
客户端级方法 不一定存在于扩展客户端上。对于这些客户端,您需要先检查是否存在,然后再使用。
const xPrisma = prisma.$extends(...);
if (xPrisma.$connect) {
xPrisma.$connect()
}
与嵌套操作一起使用
query
扩展类型不支持嵌套读写操作。