擴充套件
Prisma Client 擴充套件在 4.16.0 及更高版本中已正式釋出。它們在 4.7.0 版本中作為預覽功能引入。如果你的版本低於 4.16.0,請確保啟用 clientExtensions 預覽功能標誌。
你可以使用 Prisma Client 擴充套件為你的模型、結果物件和查詢新增功能,或新增客戶端級別的方法。
你可以使用以下一種或多種元件型別建立擴充套件
model:為你的模型新增自定義方法或欄位client:為 Prisma Client 新增客戶端級別方法query:建立自定義 Prisma Client 查詢result:為你的查詢結果新增自定義欄位
例如,你可以建立一個使用 model 和 client 元件型別的擴充套件。
關於 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 方法中,使用適當的擴充套件元件(model、client、result 或 query)。
為錯誤日誌命名擴充套件
你可以為擴充套件命名,以便在錯誤日誌中識別它們。為此,請使用可選欄位 name。例如
const prisma = new PrismaClient().$extends({
name: `signUp`, // (Optional) Extension name
model: {
user: { ... }
},
})
多個擴充套件
你可以透過兩種方式將擴充套件與擴充套件客戶端關聯
- 你可以將其單獨與一個擴充套件客戶端關聯,或者
- 你可以將此擴充套件與其他擴充套件結合,並將所有這些擴充套件與一個擴充套件客戶端關聯。這些組合擴充套件的功能適用於同一個擴充套件客戶端。注意:組合擴充套件可能會衝突。
你可以結合上述兩種方法。例如,你可以將一個擴充套件與其自己的擴充套件客戶端關聯,並將另外兩個擴充套件與另一個擴充套件客戶端關聯。瞭解更多關於客戶端例項如何互動的資訊。
將多個擴充套件應用於擴充套件客戶端
在以下示例中,假設你有兩個擴充套件,extensionA 和 extensionB。有兩種方法可以組合它們。
選項 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>
使用 Prisma.Result 擴充套件模型型別
你可以使用 Prisma.Result 型別工具擴充套件模型型別,以包含透過客戶端擴充套件新增的屬性。這允許你推斷擴充套件模型的型別,包括擴充套件屬性。
示例
以下示例演示瞭如何使用 Prisma.Result 擴充套件 User 模型型別,以包含透過客戶端擴充套件新增的 __typename 屬性。
import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient().$extends({
result: {
user: {
__typename: {
needs: {},
compute() {
return 'User'
},
},
},
},
})
type ExtendedUser = Prisma.Result<typeof prisma.user, { select: { id: true } }, 'findFirstOrThrow'>
async function main() {
const user: ExtendedUser = await prisma.user.findFirstOrThrow({
select: {
id: true,
__typename: true,
},
})
console.log(user.__typename) // Output: 'User'
}
main()
Prisma.Result 型別工具用於推斷擴充套件 User 模型的型別,包括透過客戶端擴充套件新增的 __typename 屬性。
限制
$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 擴充套件型別不支援巢狀讀寫操作。