跳至主要内容

扩展

信息

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 prisma = new PrismaClient().$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 prisma = new PrismaClient().$extends(myExtension)
    提示

    此模式在你想将扩展分离到项目中的多个文件或目录中时很有用。

以上示例使用 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 用作单例,则可以使用 typeofReturnType 工具获取扩展的 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 = new PrismaClient().$extends(...);

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

嵌套操作的使用

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