iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
Modern Web

一些讓你看來很強的 ORM - prisma系列 第 17 篇

Day17. 一些讓你看來很強的 ORM - prisma (Validator)下

  • 分享至 

  • xImage
  •  

看完昨天的 prisma validator 的功能後,大家對 type safe 是不是又更了解了呢?今天補充一些情境讓你不得不用 prisma validator

介紹

以下是今天的 demo 會用到的 model,簡單加上一個 User 的 model 然後用一對多的關聯式去 relation Post

model User {
  id    Int     @id
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id
  author    User    @relation(fields: [userId], references: [id])
  title     String
  published Boolean @default(false)
  userId    Int
}

每當我們 migrate DB 後 prisma client 會自動產生以下的 type 這邊來說就是 User

export declare type User = {
  id: string
  email: string
  name: string | null
}

但這時我們可能會遇到一個情境會是,假設你有一個 function 然後需要定義 User return 的 type,但仔細看一下 User type 他並沒有任何關於 post 的內容 ,原因就是 prisma 預設不會 return relation 的 data ,同時也不會產生關於 post 的型別,所以這時候我們只能自己 customize 我們要的 User type 同時包含 post 的內容

所以你會去定義如以下的 UserWithPosts 以及 UserPersonalData 來區別 return 的 data 是否有 post

// 1: Define a type that includes the relation to `Post`
type UserWithPosts = {
  id: string
  email: string
  name: string | null
  posts: Post[]
}

// 2: Define a type that only contains a subset of the scalar fields
type UserPersonalData = {
  email: string
  name: string | null
}

以上的寫法雖然很有彈性,但其實對於日後維護會添加很多成本,原因是每當你重新 generate prisma client 都需要手動去 update UserWithPosts 跟 UserPersonalData 的型別,但其實你不用這麼麻煩,prisma 有提供 utils function 自動給你你要的 type

import { Prisma } from '@prisma/client'

// 1: Define a type that includes the relation to `Post`
const userWithPosts = Prisma.validator<Prisma.UserDefaultArgs>()({
  include: { posts: true },
})

// 2: Define a type that only contains a subset of the scalar fields
const userPersonalData = Prisma.validator<Prisma.UserDefaultArgs>()({
  select: { email: true, name: true },
})

// 3: This type will include a user and all their posts
type UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>

以上的寫法可以讓整體的 code 更乾淨,同時對於日後維護也更方便

Return Type

另外一個情境會是當我們使用 include 或是 select 的時候我們很難拿到 getUsersWithPosts 的 return type

async function getUsersWithPosts() {
  const users = await prisma.user.findMany({ include: { posts: true } })
  return users
}

所以常見的情況會是,我們要訂很多的 type 去拿到 getUsersWithPosts return 的型別

// Function definition that returns a partial structure
async function getUsersWithPosts() {
  const users = await prisma.user.findMany({ include: { posts: true } })
  return users
}

// Extract `UsersWithPosts` type with
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T
type UsersWithPosts = ThenArg<ReturnType<typeof getUsersWithPosts>>

// run inside `async` function
const usersWithPosts: UsersWithPosts = await getUsersWithPosts()

但其實我們可以直接用 Prisma.PromiseReturnType 就可以簡單拿到我們要的 type 了

import { Prisma } from '@prisma/client'

type UsersWithPosts = Prisma.PromiseReturnType<typeof getUsersWithPosts>

大家如果有問題可以來小弟的群組討論~

✅ 前端社群 :
https://lihi3.cc/kBe0Y


上一篇
Day16. 一些讓你看來很強的 ORM - prisma (Validator)上
下一篇
Day18. 一些讓你看來很強的 ORM - prisma (zod validate)
系列文
一些讓你看來很強的 ORM - prisma 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言