`result`:為查詢結果新增自訂欄位與方法
Prisma Client 擴充功能從 4.16.0 及更高版本起正式發布。它們在 4.7.0 版本中以預覽形式推出。如果您運行的版本早於 4.16.0,請確保啟用 `clientExtensions` 預覽功能標誌。
您可以使用 `result` Prisma Client 擴充功能組件類型,為查詢結果新增自訂欄位和方法。
使用 `$extends` 客戶端級別方法 來建立擴充客戶端。擴充客戶端是標準 Prisma Client 的變體,它被一個或多個擴充功能包裝。
若要為查詢結果新增自訂欄位或方法,請使用以下結構。在此範例中,我們將自訂欄位 `myComputedField` 新增至 `user` 模型查詢的結果。
const prisma = new PrismaClient().$extends({
name?: 'name',
result?: {
user: { // in this case, we extend the `user` model
myComputedField: { // the name of the new computed field
needs: { ... },
compute() { ... }
},
},
},
});
參數如下:
- `name`:(可選)指定擴充功能的名稱,該名稱會出現在錯誤日誌中。
- `result`:定義查詢結果的新欄位和方法。
- `needs`:一個物件,描述結果欄位的依賴關係。
- `compute`:一個方法,定義在存取虛擬欄位時如何計算。
為查詢結果新增自訂欄位
您可以使用 `result` 擴充功能組件,為查詢結果新增欄位。這些欄位在運行時計算,並且是類型安全的。
在以下範例中,我們將一個名為 `fullName` 的新虛擬欄位新增至 `user` 模型。
const prisma = new PrismaClient().$extends({
result: {
user: {
fullName: {
// the dependencies
needs: { firstName: true, lastName: true },
compute(user) {
// the computation logic
return `${user.firstName} ${user.lastName}`
},
},
},
},
})
const user = await prisma.user.findFirst()
// return the user's full name, such as "John Doe"
console.log(user.fullName)
在以上範例中,`compute` 的輸入 `user` 會根據 `needs` 中定義的物件自動輸入類型。`firstName` 和 `lastName` 的類型為 `string`,因為它們在 `needs` 中指定。如果它們未在 `needs` 中指定,則無法存取它們。
在另一個計算欄位中重複使用計算欄位
以下範例以類型安全的方式計算使用者的職稱和全名。`titleFullName` 是一個計算欄位,它重複使用了 `fullName` 計算欄位。
const prisma = new PrismaClient()
.$extends({
result: {
user: {
fullName: {
needs: { firstName: true, lastName: true },
compute(user) {
return `${user.firstName} ${user.lastName}`
},
},
},
},
})
.$extends({
result: {
user: {
titleFullName: {
needs: { title: true, fullName: true },
compute(user) {
return `${user.title} (${user.fullName})`
},
},
},
},
})
欄位的考量
-
基於效能考量,Prisma Client 在存取時計算結果,而不是在檢索時計算。
-
您只能建立基於純量欄位的計算欄位。
-
您只能將計算欄位與 `select` 一起使用,並且無法聚合它們。例如
const user = await prisma.user.findFirst({
select: { email: true },
})
console.log(user.fullName) // undefined
為結果物件新增自訂方法
您可以使用 `result` 組件,為查詢結果新增方法。以下範例將一個名為 `save` 的新方法新增至結果物件。
const prisma = new PrismaClient().$extends({
result: {
user: {
save: {
needs: { id: true },
compute(user) {
return () =>
prisma.user.update({ where: { id: user.id }, data: user })
},
},
},
},
})
const user = await prisma.user.findUniqueOrThrow({ where: { id: someId } })
user.email = 'mynewmail@mailservice.com'
await user.save()
將 `omit` 查詢選項與 `result` 擴充功能組件一起使用
您可以將 `omit` (預覽) 選項 與 自訂欄位 和自訂欄位所需的欄位一起使用。
從查詢結果中 `omit` 自訂欄位所需的欄位
如果您 `omit` 作為自訂欄位依賴項的欄位,即使它不會包含在查詢結果中,它仍然會從資料庫中讀取。
以下範例省略了 `password` 欄位,它是自訂欄位 `sanitizedPassword` 的依賴項
const xprisma = prisma.$extends({
result: {
user: {
sanitizedPassword: {
needs: { password: true },
compute(user) {
return sanitize(user.password)
},
},
},
},
})
const user = await xprisma.user.findFirstOrThrow({
omit: {
password: true,
},
})
在這種情況下,儘管 `password` 從結果中省略,但它仍然會從資料庫中查詢,因為它是 `sanitizedPassword` 自訂欄位的依賴項。
從查詢結果中 `omit` 自訂欄位和依賴項
為了確保完全不從資料庫中查詢省略的欄位,您必須同時省略自訂欄位及其依賴項。
以下範例同時省略了自訂欄位 `sanitizedPassword` 和依賴項 `password` 欄位
const xprisma = prisma.$extends({
result: {
user: {
sanitizedPassword: {
needs: { password: true },
compute(user) {
return sanitize(user.password)
},
},
},
},
})
const user = await xprisma.user.findFirstOrThrow({
omit: {
sanitizedPassword: true,
password: true,
},
})
在這種情況下,省略 `password` 和 `sanitizedPassword` 都會將兩者從結果中排除,並防止從資料庫中讀取 `password` 欄位。
限制
目前,Prisma Client 的 result 擴充功能組件尚不支援關係欄位。這表示您無法基於關係關聯中的相關模型或欄位(例如,user.posts、post.author)建立自訂欄位或方法。needs 參數只能參考同一模型內的純量欄位。請關注 GitHub 上的 issue #20091。
const prisma = new PrismaClient().$extends({
result: {
user: {
postsCount: {
needs: { posts: true }, // This will not work because posts is a relation field
compute(user) {
return user.posts.length; // Accessing a relation is not allowed
},
},
},
},
})