跳到主要內容

擴展

資訊

Prisma Client 擴展自 4.16.0 及更高版本起正式發布。它們在 4.7.0 版本中以預覽形式推出。如果您執行的版本早於 4.16.0,請確保啟用 clientExtensions 預覽功能標誌。

您可以使用 Prisma Client 擴展將功能新增至您的模型、結果物件和查詢,或新增用戶端層級方法。

您可以使用以下一或多種類型元件來建立擴展

例如,您可以建立一個使用 modelclient 元件類型的擴展。

關於 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 方法中,使用適當的擴展元件或元件(modelclientresultquery)。

命名擴展以用於錯誤記錄

您可以命名您的擴展,以協助在錯誤記錄中識別它們。若要執行此操作,請使用選用欄位 name。例如

const prisma = new PrismaClient().$extends({
name: `signUp`, // (Optional) Extension name
model: {
user: { ... }
},
})

多個擴展

您可以透過兩種方式將擴展與擴展用戶端建立關聯

  • 您可以將其與擴展用戶端單獨建立關聯,或
  • 您可以將擴展與其他擴展結合,並將所有這些擴展與一個擴展用戶端建立關聯。這些組合擴展的功能適用於同一個擴展用戶端。注意:組合擴展可能會發生衝突

您可以結合上述兩種方法。例如,您可以將一個擴展與其自己的擴展用戶端建立關聯,並將另外兩個擴展與另一個擴展用戶端建立關聯。深入了解用戶端實例如何互動

將多個擴展套用至擴展用戶端

在以下範例中,假設您有兩個擴展,extensionAextensionB。有兩種方法可以組合這些擴展。

選項 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 用作單例模式,則可以使用 typeofReturnType 公用程式取得擴展 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 擴展類型不支援巢狀讀取和寫入作業。