共享的 Prisma Client 扩展
你可以将你的 Prisma Client 扩展与其他用户共享,可以打包成包或模块,也可以将其他用户创建的扩展导入到你的项目中。
如果你想构建一个可共享的扩展,我们还建议使用 prisma-client-extension-starter
模板。
要探索 Prisma 官方 Client 扩展以及社区创建的扩展示例,请访问 此页面。
安装共享的打包扩展
在你的项目中,你可以安装任何其他用户发布到 npm
的 Prisma Client 扩展。为此,运行以下命令:
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
未被修改。
创建可共享的扩展
当你你想创建其他用户可以使用且不只是为你自己的 schema 定制的扩展时,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 Client 操作的不同方法:
对于早于 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 Client 实例:
- 当你想在打包扩展中使用客户端级别方法,例如
$queryRaw
时。 - 当你想在打包扩展中链式调用多个
$extends
时。
然而,当有人在其项目中包含你的打包扩展时,你的代码无法知道 Prisma Client 实例的详细信息。
你可以按如下方式引用这个客户端实例:
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]
},
},
},
})
})
高级类型安全:用于定义通用扩展的类型工具
你可以使用类型工具来提高共享扩展的类型安全性。