擴展
Prisma Client 擴展自 4.16.0 及更高版本起正式發布。它們在 4.7.0 版本中以預覽形式推出。如果您執行的版本早於 4.16.0,請確保啟用 clientExtensions
預覽功能標誌。
您可以使用 Prisma Client 擴展將功能新增至您的模型、結果物件和查詢,或新增用戶端層級方法。
您可以使用以下一或多種類型元件來建立擴展
model
:將自訂方法或欄位新增至您的模型client
:將用戶端層級方法新增至 Prisma Clientquery
:建立自訂 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 } })
},
},
},
})
擴展用戶端中用戶端層級方法的使用方式
用戶端層級方法 不一定存在於擴展用戶端上。對於這些用戶端,您需要先檢查是否存在,然後才能使用。
const xPrisma = new PrismaClient().$extends(...);
if (xPrisma.$connect) {
xPrisma.$connect()
}
與巢狀作業的使用方式
query
擴展類型不支援巢狀讀取和寫入作業。