# prisma day1 ## 介紹 這次的鐵人賽想跟大家分享一套自己在平常開發中很常用到的一套 `ORM` 就是 `prisma`,會想用他的原因是因為,去年鐵人賽在介紹 `TRPC` 的時候有用到 `prisma` ,但一直沒有更深入的去理解它,那今年我們就來完成筆者的心願吧~接下來的 30 天會再好好的跟大家補齊一些你不知道的 `prisma` 功能(X,就請大家好好期待一下~ ## 優點 大致上先簡單列出,目前筆者覺得 `prisma` 的優勢,之後也會一一跟大家介紹以下的內容~ * 生態系強大 * 良好的 DX 體驗。 * 完整的 `auto generate type` * 強大且豐富的 `plugin` 雖然目前市面上很多 `orm` 也符合下面的優勢,例如 `drizzle` 他也是一套有強大的 `type safe` 的 `orm` 甚至 `DX` 也不輸給 `prisma` 筆者其實也很喜歡 XD ,但還是想先整理一下 `prisma` 筆記哈哈,如果讀者有興趣可以來對我指教~ ## 開始之前先認識 ORM 吧 在學習 `ORM` 之前筆者先簡單介紹一下使用 `ORM` 的優勢與好處~如圖所見, `ORM` 就是一層 `DB` 跟 `Client` 的中介層,注意一下這邊的 `Client` 並不是 `front end` 中 `user` 使用的 `client` ,這邊得 `client` 指的是 `application` 的地方,也就是你在哪邊使用 `prisma orm` 的語法,因為 `primsa` 可以使用的地方,除了 `backend application` 甚至還可以用在 `serverless applications` 和 `microservices` 等等,所以這邊才會泛指 `client` ~ 那因為我們的 `client` 有非常多種的內容,所以可能會遇到的點是,在不同的 `client` 端點中,彼此需要使用到的 `DB` 功能可能不盡相同,所以對開法者來說,如果有一套 `tool` 可以涵蓋所有的內容,同時簡化 `DB` 語法的話,對於整體的開法效率也會大大提升~於是 `ORM` 得概念就出現了,但同時 `ORM` 就會遇到一個問題是,因為他要對 `DB` 的操作去做映射,所以對 `DB` 功能的支援度就相當重要,所以這也是在技術選型時,要考量的其中一個因素。  [圖片來源](https://www.prisma.io/orm) 這邊想補充一點就是 `primsa` 支援使用原生 `SQL` 的指令,例如以下的 `queryRaw` 或是 `executeRaw` 等等,所以如果你發現有些 `DB` 中能沒有支援在 `prisma` 使用時,也可以當做備用方案~ ### $queryRaw ```typescript const email = 'emelie@prisma.io' const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}` ``` ### $executeRaw ```typescript const result: number = await prisma.$executeRaw`UPDATE User SET active = true WHERE emailValidated = true` ``` ## schema 這邊要介紹 `ORM` 中最重要的一個部分就是定 `schema` , `primsa` 很厲害的地方就是它同時支援 `SQL` 以及 `NoSQL` ,甚至對於不同 `SQL` 中有不同的 `Schema` 訂定的方式~ ### Relational databases ```typescript datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model Post { id Int @id @default(autoincrement()) title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: [id]) authorId Int? } model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] } ``` ### MongoDB ```typescript datasource db { provider = "mongodb" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model Post { id String @id @default(auto()) @map("_id") @db.ObjectId title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: [id]) authorId String @db.ObjectId } model User { id String @id @default(auto()) @map("_id") @db.ObjectId email String @unique name String? posts Post[] } ``` 上面的 `schema` 可以簡單分成三個部分介紹。 * Data source: 你的 `DB connection` 以及你的 `DB type`。 * Generator: 你希望 `prisma` 怎麼去生成你的 `prisma client`。 * Data model: 定義你的 `db` 的 `models`。 ### DB pull `prisma` 除了可以訂新的 `models` 外,也可以同步已存在的 `models` 到你的 `prisma schema` 中,只要打以下的 `cli`。 ```typescript > npx prisma db pull ``` 然後你就會發現你的 `schema` 就多了一些原本 `db` 的 `models` 了~ ```typescript model Post { id String @id @default(auto()) @map("_id") @db.ObjectId title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: [id]) authorId String @db.ObjectId } ``` 在 `prisma` 中如果你需要表達關聯式,可以透過 `@relation` 、`[]` 來表達是一對一、一對多,或是多對多的關係。 ```typescript model Post { id String @id @default(auto()) @map("_id") @db.ObjectId title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: [id]) authorId String @db.ObjectId } model User { id String @id @default(auto()) @map("_id") @db.ObjectId email String @unique name String? posts Post[] } ``` ## auto type safe `prisma` 因為是一套有 `type safe` 的 `ORM` ,所以每次做完 `DB pull` 或是 `DB migration` 後,`prisma` 都會在你 `local` 的 `node_modules` 中自動產生所有你需要的 `type`。  ## migrate 如果 `DB` 需要添加新的欄位可以直接在 `schema` 中加上。 ```typescript model User { id Int @id @default(autoincrement()) email String @unique name String? posts Post[] phone String? // add new filed } ``` 之後跑 `migration cli` 就會跑出下列的訊息,然後會要求你描述這次 `migration` 的 `name` 有點像是 `git` 在提交 `commit` 一樣。 ```typescript > npx prisma migrate dev Environment variables loaded from .env Prisma schema loaded from prisma/schema.prisma Datasource "db": SQLite database "dev.db" at "file:./dev.db" ? Enter a name for the new migration: › add phone fields in User modal ``` 然後 `prisma` 就會跟你你提交的 `name` 自動在你的 `migration` 加新的 `folder` ```typescript ✔ Enter a name for the new migration: … add phone fields in User modal Applying migration `20240907043004_add_phone_fields_in_user_modal` The following migration(s) have been created and applied from new schema changes: migrations/ └─ 20240907043004_add_phone_fields_in_user_modal/ └─ migration.sql Your database is now in sync with your schema. ✔ Generated Prisma Client (v5.19.1) to ./node_modules/@prisma/client in 51ms ``` 然後仔細觀察 `mugrations folder` 就會記錄每次 `migration` 的紀錄,主要是產生原生 `SQL` 指令。  ## prisma studio `prisma` 很貼心的提供 `studio` 去查看專案中用到的所有 `model` ,首先先打下方的 `cli`。 ```typescript > npx prisma studio Environment variables loaded from .env Prisma schema loaded from prisma/schema.prisma Prisma Studio is up on http://localhost:5555 ``` 然後打開 `http://localhost:5555` ,你會看到這邊記錄著可以用到的 `model`。  然後點進去各自的 `model` 會看到會用到的欄位有哪些,以及目前有哪些資料,那因為還沒有加資料,所以內容會是空的。  然後你也可以直接在 `studio` 中直接加資料。  加完之後我們可以簡單測試拿資料。 ```typescript import { PrismaClient } from "@prisma/client"; const prismaClient = new PrismaClient() const main = async () => { const userLists = await prismaClient.user.findMany() console.log(userLists) } main() ``` 你會發現你在 `studio` 加的 `data`,也成功不再在你的 `client` 了。 ```typescript [ { id: 1, email: "some@gmail.com", name: "Danny", phone: null, } ] ``` 今天大致上先初探 `prisma` 的內容,明天我們繼續介紹,為何你需要用 `prisma` ,感謝各位讀者的觀看我們明天見~
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up