跳至主要内容

扩展

info

Prisma Client 扩展从 4.16.0 及更高版本开始正式可用。它们在 4.7.0 版本中以预览形式推出。如果你使用的是早于 4.16.0 的版本,请确保启用 clientExtensions 预览功能标志。

你可以使用 Prisma Client 扩展为你的模型、结果对象和查询添加功能,或添加客户端级别的方法。

你可以使用以下一个或多个组件类型来创建扩展

例如,你可以创建一个使用 modelclient 组件类型的扩展。

关于 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 方法中,使用适当的扩展组件或组件 (modelclientresultquery)。

为错误日志命名扩展

你可以为你的扩展命名,以帮助在错误日志中识别它们。为此,请使用可选字段 name。例如

const prisma = new PrismaClient().$extends({
name: `signUp`, // (Optional) Extension name
model: {
user: { ... }
},
})

多个扩展

你可以通过两种方式之一将扩展与 扩展客户端 关联

  • 你可以将其与扩展客户端本身关联,或者
  • 你可以将扩展与其他扩展组合起来,并将所有这些扩展与扩展客户端关联。这些组合扩展的功能适用于同一个扩展客户端。注意: 组合扩展可能会发生冲突.

你可以将以上两种方法结合起来。例如,你可能会将一个扩展与其自己的扩展客户端关联,并将另外两个扩展与另一个扩展客户端关联。了解有关客户端实例如何交互的更多信息.

将多个扩展应用于扩展客户端

在以下示例中,假设你有两个扩展 extensionAextensionB。有两种方法可以将它们组合起来。

选项 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 } })
},
},
},
})

要了解更多信息,请参阅有关 $on$use 的文档。

在扩展客户端中使用客户端级方法

客户端级方法 不一定存在于扩展客户端上。对于这些客户端,您需要先检查是否存在,然后再使用。

const xPrisma = prisma.$extends(...);

if (xPrisma.$connect) {
xPrisma.$connect()
}

与嵌套操作一起使用

query 扩展类型不支持嵌套读写操作。