共享的 Prisma 客户端扩展
你可以将你的 Prisma 客户端扩展 作为包或模块与他人共享,也可以将其他用户创建的扩展导入到你的项目中。
如果你想构建一个可共享的扩展,我们也推荐使用 prisma-client-extension-starter
模板。
要探索 Prisma 官方客户端扩展和社区制作的扩展示例,请访问此页面。
安装一个共享的打包扩展
在你的项目中,你可以安装任何其他用户已发布到 npm
的 Prisma 客户端扩展。为此,请运行以下命令
npm install prisma-extension-<package-name>
例如,如果一个可用扩展的包名为 prisma-extension-find-or-create
,你可以按如下方式安装它
npm install prisma-extension-find-or-create
要从上面的示例中导入 find-or-create
扩展,并用它包装你的客户端实例,你可以使用以下代码。此示例假定扩展名为 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
未被修改。
创建可共享的扩展
当你想要创建其他用户可以使用且不只为你的模式定制的扩展时,Prisma ORM 提供了实用工具来帮助你创建可共享的扩展。
要创建可共享的扩展
- 使用
Prisma.defineExtension
将扩展定义为模块 - 使用以
$all
前缀开头的方法,例如$allModels
或$allOperations
定义扩展
使用 Prisma.defineExtension
方法使你的扩展可共享。你可以用它来打包扩展,以便将你的扩展分离到单独的文件中,或者作为 npm 包与其它用户共享。
Prisma.defineExtension
的好处在于它为开发中的扩展作者和共享扩展的用户提供了严格的类型检查和自动补全功能。
使用通用方法
包含 $allModels
下方法的扩展适用于每个模型,而不是特定的模型。同样,$allOperations
下的方法适用于整个客户端实例,而不是命名组件,例如 result
或 query
。
你不需要在 client
组件中使用 $all
前缀,因为 client
组件始终适用于客户端实例。
例如,一个通用扩展可能采用以下形式
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 客户端操作的不同方式
对于早于 4.16.0 的版本
Prisma
导入可从以下代码片段中显示的不同路径获取
import { Prisma } from '@prisma/client/scripts/default-index'
export default Prisma.defineExtension({
name: 'prisma-extension-<extension-name>',
})
将可共享的扩展发布到 npm
然后你可以在 npm
上共享该扩展。选择包名时,我们建议你使用 prisma-extension-<package-name>
约定,以便于查找和安装。
从你的打包扩展中调用客户端级别方法
目前,对于引用 PrismaClient
并调用客户端级别方法的扩展存在限制,如下例所示。
如果你从 事务 内部触发扩展(交互式或批处理),扩展代码将在新连接中发出查询,并忽略当前的事务上下文。
在 GitHub 上的此问题中了解更多:需要使用客户端级别方法的客户端扩展会静默忽略事务。
在以下情况下,你需要引用你的扩展所包装的 Prisma 客户端实例
- 当你想在打包的扩展中使用 客户端级别方法,例如
$queryRaw
时。 - 当你想在打包的扩展中链式调用多个
$extends
时。
然而,当有人在他们的项目中包含你的打包扩展时,你的代码无法知道 Prisma 客户端实例的详细信息。
你可以按如下方式引用此客户端实例
Prisma.defineExtension((client) => {
// The Prisma Client instance that the extension user applies the extension to
return client.$extends({
name: 'prisma-extension-<extension-name>',
})
})
例如
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]
},
},
},
})
})
高级类型安全:用于定义通用扩展的类型工具
你可以使用类型工具来提高共享扩展的类型安全。