iT邦幫忙

2024 iThome 鐵人賽

DAY 1
1
Modern Web

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

Day01. 一些讓你看來很強的 ORM - prisma (初探)

  • 分享至 

  • xImage
  •  

介紹

這次的鐵人賽想跟大家分享一套自己在平常開發中很常用到的一套 ORM 就是 prisma,會想用他的原因是因為,去年鐵人賽在介紹 TRPC 的時候有用到 prisma ,但一直沒有更深入的去理解它,那今年我們就來完成筆者的心願吧~接下來的 30 天會再好好的跟大家補齊一些你不知道的 prisma 功能,就請大家好好期待一下~

優點

大致上先簡單列出,目前筆者覺得 prisma 的優勢,之後也會一一跟大家介紹以下的內容~

  • 生態系強大
  • 良好的 DX 體驗。
  • 完整的 auto generate type
  • 強大且豐富的 plugin

雖然目前市面上很多 ORM 也符合下面的優勢,例如 drizzle 他也是一套有強大的 type safeORM 甚至 DX 也不輸給 prisma 筆者其實也很喜歡 XD ,但還是想先整理一下 prisma 筆記哈哈,如果讀者有興趣可以來對我指教~

開始之前先認識 ORM 吧

在學習 ORM 之前筆者先簡單介紹一下使用 ORM 的優勢與好處~如圖所見, ORM 就是一層 DBClient 的中介層,注意一下這邊的 Client 並不是 front enduser 使用的 client ,這邊得 client 指的是 application 的部分,也就是你在哪邊使用 prisma clientapi,因為 primsa 可以使用的地方,除了 backend application 甚至還可以用在 serverless applicationsmicroservices 等等,所以這邊才會泛指 client ~ 那因為我們的 client 有非常多種的內容,所以可能會遇到的點是,在不同的 client 端點中,每次都要寫一些重複性的 SQL 指令而且還要考慮不同 client 中是否能順利的連到 DB,所以對開法者來說,如果有一套 tool 可以涵蓋所有的內容,同時簡化 DB 語法的話,對於整體的開法效率也會大大提升~於是 ORM 得概念就出現了,但同時 ORM 就會遇到一個問題是,因為他要對 DB 的操作去做映射,所以對 SQL 語法的支援度就相當重要,所以這也是在技術選型時,要考量的其中一個因素。
https://ithelp.ithome.com.tw/upload/images/20240915/20145677tIlovvUJcI.jpg

圖片來源

這邊想補充一點就是 primsa 支援使用原生 SQL 的指令,例如以下的 queryRaw 或是 executeRaw 等等,所以如果你發現有些 DB 中能沒有支援在 prisma 使用時,也可以當做備用方案~

$queryRaw

const email = 'emelie@prisma.io'
const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`

$executeRaw

const result: number =
  await prisma.$executeRaw`UPDATE User SET active = true WHERE emailValidated = true`

schema

這邊要介紹 ORM 中最重要的一個部分就是定 schemaprimsa 很厲害的地方就是它同時支援 SQL 以及 NoSQL ,甚至對於不同 SQL 中有不同的 Schema 訂定的方式~

Relational databases

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

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: 定義你的 dbmodels

DB pull

prisma 除了可以訂新的 models 外,也可以同步已存在的 models 到你的 prisma schema 中,只要打以下的 cli

> npx prisma db pull

然後你就會發現你的 schema 就多了一些原本 dbmodels 了~

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[] 來表達是一對一、一對多,或是多對多的關係。

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 safeORM ,所以每次做完 DB pull 或是 DB migration 後,prisma 都會在你 localnode_modules 中自動產生所有你需要的 type
https://ithelp.ithome.com.tw/upload/images/20240915/20145677CfsjrnINdT.png

migrate

如果 DB 需要添加新的欄位可以直接在 schema 中加上。

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
  phone String? // add new filed
}

之後跑 migration cli 就會跑出下列的訊息,然後會要求你描述這次 migrationname 有點像是 git 在提交 commit 一樣。

> 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

✔ 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

然後仔細觀察 migrations folder 就會記錄每次 migration 的紀錄,主要是產生原生 SQL 指令。
https://ithelp.ithome.com.tw/upload/images/20240915/20145677B6aEZazXU3.png

prisma studio

prisma 很貼心的提供 studio 去查看專案中用到的所有 model ,首先先打下方的 cli

> 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
https://ithelp.ithome.com.tw/upload/images/20240915/20145677LS37T183Ja.png

然後點進去各自的 model 會看到會用到的欄位有哪些,以及目前有哪些資料,那因為還沒有加資料,所以內容會是空的。
https://ithelp.ithome.com.tw/upload/images/20240915/201456771atTR6FF4S.png

然後你也可以直接在 studio 中直接加資料。
https://ithelp.ithome.com.tw/upload/images/20240915/20145677OtP4xEvZcM.png

加完之後我們可以簡單測試拿資料。

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 了。

[
  {
    id: 1,
    email: "some@gmail.com",
    name: "Danny",
    phone: null,
  }
]

今天大致上先初探 prisma 的內容,明天我們繼續介紹,為何你需要用 prisma ,感謝各位讀者的觀看我們明天見~

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

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


下一篇
Day02. 一些讓你看來很強的 ORM - prisma (比較)
系列文
一些讓你看來很強的 ORM - prisma30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言