今天的主題比較特別是本人非常喜歡的一個功能 Prisma validator
,他可以幫你自動 generate type
然後產生一個具有 type safe
的 object
根據你 model
的欄位
在沒有 Prisma validator
之前假設你有一個 userEmail
的 object
你希望重複利用這個 object
去 queries
你要的 model data
,通常我們會用 prisma client
generate
的 type
去定義這個 object
的型別, 如以下的 userEmail
:
import { Prisma } from '@prisma/client'
const userEmail: Prisma.UserSelect = {
email: true,
}
// Run inside async function
const user = await prisma.user.findUnique({
where: {
id: 3,
},
select: userEmail,
})
這個 query
是希望我們去找到 id
是 3 的 user
並在 return data
的時候只 return
email
這個欄位,如果沒有這個 user
則 return null
//index.ts
const getUser = async () => {
const userEmail: Prisma.UserSelect = {
email: true
}
const user = await prismaClient.user.findFirst({
where: {
id: 3
},
select: userEmail
})
console.log(user)
}
當我們執行 index.ts
會發現確實只有 email
欄位~
> tsx watch index.ts
{ email: 'hiunji64@gmail.com' }
看起來是蠻順利的結果也如預期,但是當你 hover
後你會發現 userEmail
並沒有 type infer
出整個 object
有用到的 key type
如果 userEmail
這個 object
只給 user.findFirst
使用倒是沒關係,但如果你把 userEmail
export
出去給其他的 model
去 select data
,就會有問題,因為目前的 object
並沒有限定只給 user.findFirst
使用,引用錯誤可能會導致存取到其他 model
的欄位,同時我們也無法知道 userEmail
他裡面 key type
到底有什麼,甚至也無法知道這個 object
有用過哪些 key
假設我們需要更改 input
的 select
結果,因為上圖 type
不明確,導致我們修改到錯誤的欄位
const userEmail: Prisma.UserSelect = {
email: true
}
userEmail.name = true
const user = await prismaClient.user.findFirst({
where: {
id: 3
},
select: userEmail
})
console.log(user)
}
如此我們就不小心存取到其他的欄位了,而且也不會爆 type error
,顯然這是非常危險的
{ email: 'hiunji64@gmail.com', name: 'Danny' }
小結
所以使用 prisma client
提供的型別,他只是有 typed
但不是 type-safe
的,所以 prisma
為了解決這個問題,提供一個 Prisma validator
的功能~
使用 Prisma.validator
很簡單你只需要直接使用 prisma.validator
的 utils function
就好,同時需要提供哪個 model
的泛型
import { Prisma } from '@prisma/client'
//before
const userEmail: Prisma.UserSelect = {
email: true,
}
//after
const userEmail = Prisma.validator<Prisma.UserSelect>()({
email: true,
})
// Run inside async function
const user = await prisma.user.findUnique({
where: {
id: 3,
},
select: userEmail,
})
或這你可以再更詳細的定義這個 validator
用在哪個 model
哪個 methods
中
import { Prisma } from '@prisma/client'
import prisma from './lib/prisma'
const userEmail = Prisma.validator(
prisma,
'user',
'findUnique',
'select'
)({
email: true,
})
如此現在 userEmail
hover
上次後你會發現會自動看到哪些欄位是有使用到的了~
最後我們我們根據今天的內容寫一個小範例~
//schema
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
published Boolean @default(true)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
const createUserAndPost = (
name: string,
email: string,
title: string,
) => {
return Prisma.validator<Prisma.UserCreateInput>()({
name,
email,
posts: {
create: {
title
}
}
})
}
const findSpecificUser = (email: string) => {
return Prisma.validator<Prisma.UserWhereInput>()({
email
})
}
const createUser = async () => {
await prismaClient.user.create({
data: createUserAndPost(
'Rich',
'rich@boop.com',
'Life of Pie',
)
})
}
const getUser = async () => {
const user = await prismaClient.user.findUnique({
where: findSpecificUser('rich@boop.com')
})
console.log(user)
}
create User
的 validator
User.findUnique
的 validator
findSpecificUser
的 validator
去 get data
讀者可以根據 demo
的內容試著自己寫一遍,最終你會看到 getUser
的 response
~
{ id: 1, name: 'Rich', email: 'rich@boop.com' }
✅ 前端社群 :
https://lihi3.cc/kBe0Y