Skip to main content

共享 Prisma 客户端扩展

你可以将 Prisma 客户端扩展 作为包或模块与其他用户共享,并将其他用户创建的扩展导入到你的项目中。

¥You can share your Prisma Client extensions with other users, either as packages or as modules, and import extensions that other users create into your project.

如果你想构建可共享的扩展,我们还建议使用 prisma-client-extension-starter 模板。

¥If you would like to build a shareable extension, we also recommend using the prisma-client-extension-starter template.

要探索 Prisma 官方客户端扩展的示例以及社区制作的扩展,请访问 this 页面。

¥To explore examples of Prisma's official Client extensions and those made by the community, visit this page.

安装共享的打包扩展

¥Install a shared, packaged extension

在你的项目中,你可以安装其他用户已发布到 npm 的任何 Prisma 客户端扩展。为此,请运行以下命令:

¥In your project, you can install any Prisma Client extension that another user has published to npm. To do so, run the following command:

npm install prisma-extension-<package-name>

例如,如果可用扩展的包名称是 prisma-extension-find-or-create,你可以按如下方式安装它:

¥For example, if the package name for an available extension is prisma-extension-find-or-create, you could install it as follows:

npm install prisma-extension-find-or-create

要从上面的示例导入 find-or-create 扩展,并用它封装你的客户端实例,你可以使用以下代码。此示例假设分机名称为 findOrCreate

¥To import the find-or-create extension from the example above, and wrap your client instance with it, you could use the following code. This example assumes that the extension name is findOrCreate.

import findOrCreate from 'prisma-extension-find-or-create'

const prisma = new PrismaClient().$extends(findOrCreate)
const user = await prisma.user.findOrCreate()

当你调用扩展中的方法时,请使用 $extends 语句中的常量名称,而不是 prisma。上面的例子中,xprisma.user.findOrCreate 可以工作,但是 prisma.user.findOrCreate 不行,因为原来的 prisma 没有被修改。

¥When you call a method in an extension, use the constant name from your $extends statement, not prisma. In the above example,xprisma.user.findOrCreate works, but prisma.user.findOrCreate does not, because the original prisma is not modified.

创建可共享的扩展

¥Create a shareable extension

当你想要创建其他用户可以使用的扩展,并且不仅仅针对你的模式定制的扩展时,Prisma ORM 提供了实用程序来允许你创建可共享的扩展。

¥When you want to create extensions other users can use, and that are not tailored just for your schema, Prisma ORM provides utilities to allow you to create shareable extensions.

要创建可共享的扩展:

¥To create a shareable extension:

  1. 使用 Prisma.defineExtension 将扩展定义为模块

    ¥Define the extension as a module using Prisma.defineExtension

  2. 使用以 $all 前缀开头的方法之一,例如 $allModels$allOperations

    ¥Use one of the methods that begin with the $all prefix such as $allModels or $allOperations

定义扩展

¥Define an extension

使用 Prisma.defineExtension 方法使你的扩展可共享。你可以使用它来打包扩展,以便将扩展分离到单独的文件中,或者作为 npm 包与其他用户共享。

¥Use the Prisma.defineExtension method to make your extension shareable. You can use it to package the extension to either separate your extensions into a separate file or share it with other users as an npm package.

Prisma.defineExtension 的好处是它为开发中的扩展作者和共享扩展的用户提供严格的类型检查和自动补齐。

¥The benefit of Prisma.defineExtension is that it provides strict type checks and auto completion for authors of extension in development and users of shared extensions.

使用通用方法

¥Use a generic method

包含 $allModels 下方法的扩展适用于每个模型,而不是特定模型。类似地,$allOperations 下的方法适用于整个客户端实例,而不适用于命名组件,例如 resultquery

¥Extensions that contain methods under $allModels apply to every model instead of a specific one. Similarly, methods under $allOperations apply to a client instance as a whole and not to a named component, e.g. result or query.

你不需要将 $all 前缀与 client 组件一起使用,因为 client 组件始终适用于客户端实例。

¥You do not need to use the $all prefix with the client component, because the client component always applies to the client instance.

例如,通用扩展可能采用以下形式:

¥For example, a generic extension might take the following form:

export default Prisma.defineExtension({
name: 'prisma-extension-find-or-create', //Extension name
model: {
$allModels: {
// new method
findOrCreate(/* args */) {
/* code for the new method */
return query(args)
},
},
},
})

请参阅以下页面了解修改 Prisma 客户端操作的不同方法:

¥Refer to the following pages to learn the different ways you can modify Prisma Client operations:

For versions earlier than 4.16.0

Prisma 导入可从以下代码片段中显示的不同路径获得:

¥The Prisma import is available from a different path shown in the snippet below:

import { Prisma } from '@prisma/client/scripts/default-index'

export default Prisma.defineExtension({
name: 'prisma-extension-<extension-name>',
})

将可共享扩展发布到 npm

¥Publishing the shareable extension to npm

然后你可以在 npm 上共享该扩展。当你选择软件包名称时,我们建议你使用 prisma-extension-<package-name> 约定,以便于查找和安装。

¥You can then share the extension on npm. When you choose a package name, we recommend that you use the prisma-extension-<package-name> convention, to make it easier to find and install.

从打包的扩展中调用客户端级方法

¥Call a client-level method from your packaged extension

警告

目前,引用 PrismaClient 并调用客户端级方法的扩展存在限制,如下例所示。

¥There's currently a limitation for extensions that reference a PrismaClient and call a client-level method, like the example below.

如果你从 transaction(交互式或批处理)内部触发扩展,扩展代码将在新连接中触发查询并忽略当前事务上下文。

¥If you trigger the extension from inside a transaction (interactive or batched), the extension code will issue the queries in a new connection and ignore the current transaction context.

在 GitHub 上的本期中了解更多信息:需要使用客户端级方法的客户端扩展会默默忽略事务

¥Learn more in this issue on GitHub: Client extensions that require use of a client-level method silently ignore transactions.

在以下情况下,你需要引用你的扩展封装的 Prisma Client 实例:

¥In the following situations, you need to refer to a Prisma Client instance that your extension wraps:

  • 当你想在打包的扩展中使用 客户级方法(例如 $queryRaw)时。

    ¥When you want to use a client-level method, such as $queryRaw, in your packaged extension.

  • 当你想要在打包的扩展中链接多个 $extends 调用时。

    ¥When you want to chain multiple $extends calls in your packaged extension.

但是,当有人在他们的项目中包含你打包的扩展时,你的代码无法知道 Prisma 客户端实例的详细信息。

¥However, when someone includes your packaged extension in their project, your code cannot know the details of the Prisma Client instance.

你可以按如下方式引用该客户端实例:

¥You can refer to this client instance as follows:

Prisma.defineExtension((client) => {
// The Prisma Client instance that the extension user applies the extension to
return client.$extends({
name: 'prisma-extension-<extension-name>',
})
})

例如:

¥For example:

export default Prisma.defineExtension((client) => {
return client.$extends({
name: 'prisma-extension-find-or-create',
query: {
$allModels: {
async findOrCreate({ args, query, operation }) {
return (await client.$transaction([query(args)]))[0]
},
},
},
})
})

高级类型安全性:用于定义通用扩展的类型实用程序

¥Advanced type safety: type utilities for defining generic extensions

你可以使用 类型实用程序 提高共享扩展的类型安全性。

¥You can improve the type-safety of your shared extensions using type utilities.