今天要來補充 schema 的進階用法,延續昨天在 prisma 中使用 DB adapter 的 schema 根據不同的 connect pool 去執行 DB 的內容,但你會發現一件事情,那就是每當你要切換不同的 schema 都要更改 DATABASE_URL 的 .env 。
甚至你的 adapter 也需要去調整
const adapter = new PrismaPg(pool, {
schema: 'test'
})
但如果今天專案一大起來,你有多個 schema ,同時你需要共用不同 schema 的 table 去關聯資料的話,顯然昨日單個 schema 這樣的切換是無法做到的,那今天內容就來教大家如何在 prisma 中使用多個 schema 然後關聯不同 schema 的 table~
在 prisma 中要使用 multiple database schema 必須要設定 preview feature 在 generator client 這邊,跟昨天的 driverAdapters 一樣
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters", "multiSchema"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
我們除了可以在 DB 自己新增 schema 外,也可以透過 schema.prisma 去幫我們 generate ,只需要在 datasource db 中去指定哪些 schema 需要被使用
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters", "multiSchema"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schemas = ["base", "transactional"]
}
同時你的 DATABASE_URL 也不需要去加上 schema 的 parameter ,完全不需要更動
//.env
DATABASE_URL="postgresql://root:****@***.***.zeabur.com:***/zeabur"
這時候你會發現當擬定好共用的 schema 後,假設你要新增一個 model ,此時 prisma 會跳一個 error 說他不知道這個 model 屬於哪個 schema 的範疇
所以每當新建一個 model 都會需要用 @@schema 去告訴 prisma 這個 model 屬於哪個 schema 使用,然後除了 model ,enum 也可以指定 schema ~
model User {
id Int @id
orders Order[]
@@schema("base")
}
model Order {
id Int @id
user User @relation(fields: [id], references: [id])
user_id Int
@@schema("transactional")
}
enum Size {
Small
Medium
Large
@@schema("transactional")
}
執行完後我們就把 model migrate 到 DB
>npx prisma migrate dev --name init
然後當你查看現在的 schema 時,你會發現已經成功加進去了~
>zeabur=# \dn;
List of schemas
Name | Owner
---------------+-------------------
base | root
public | pg_database_owner
transactional | root
(3 rows)
那因為預設的 schema 是在 public 所以會沒有 table 是正常的
>zeabur=# \dt;
List of relations
Schema | Name | Type | Owner
--------+--------------------+-------+-------
public | _prisma_migrations | table | root
(1 row)
之後切換 schema 查看 table,你會發現 prisma 已經成功幫我們區分不同的 table 到各自的 schema 中了~
>zeabur=# SET SEARCH_PATH=base;
SET
>zeabur=# \dt;
List of relations
Schema | Name | Type | Owner
--------+---------+-------+-------
base | User | table | root
(3 rows)
另外有一種情形是,如果你需要不同的 schema 有相同的 table name 也是可行的喔,你只需要改變一下 model name ,然後 @@map 到 table name 以及加上 @@schema 就可以
model BaseConfig {
id Int @id @default(autoincrement())
name String
@@map("config")
@@schema("base")
}
model TransactionalConfig {
id Int @id @default(autoincrement())
name String
@@map("config")
@@schema("transactional")
}
之後我們 migrate 到 DB
>npx prisma migrate dev --name add_profile
你會發現不管是 base Schema 或是 transactional Schema 都有 config 這個 table 了
>zeabur=# SET SEARCH_PATH=base;
SET
>zeabur=# \dt;
List of relations
Schema | Name | Type | Owner
--------+---------+-------+-------
base | User | table | root
base | config | table | root
>zeabur=# SET SEARCH_PATH=transactional;
SET
>zeabur=# \dt;
List of relations
Schema | Name | Type | Owner
---------------+--------+-------+-------
transactional | Order | table | root
transactional | config | table | root
(2 rows)
最後我們在 studio 加上 data 到 BaseConfig 跟 TransactionalConfig
然後執行 index.ts
>tsx watch index.ts
//index.ts
import { Pool } from 'pg'
import { PrismaPg } from '@prisma/adapter-pg'
import { PrismaClient } from '@prisma/client'
const connectionString = `${process.env.DATABASE_URL}`
const pool = new Pool({ connectionString })
const adapter = new PrismaPg(pool)
const prisma = new PrismaClient({ adapter })
const main = async () => {
const data = await prisma.baseConfig.findMany({})
const data2 = await prisma.transactionalConfig.findMany({})
console.log(data, data2)
}
你會發現我們成功拿到兩個 schema 中的資料了~
[ { id: 1, name: 'baseConfig' } ] [ { id: 1, name: 'transactionalConfig' } ]
甚至因為 schema.prisma 有 previewFeatures ,所以 adapter 的 schema 就可以直接拿掉了~
// before
const adapter = new PrismaPg(pool, {
schema:'test'
})
// after
const adapter = new PrismaPg(pool)
甚至用了 @@schema 也是可以做關聯資料的~
model User {
id Int @id
orders Order[]
profile Profile?
@@schema("base")
}
model Profile {
id Int @id @default(autoincrement())
bio String
user User @relation(fields: [userId], references: [id])
userId Int @unique
@@schema("base")
}
model Order {
id Int @id
user User @relation(fields: [id], references: [id])
user_id Int
@@schema("transactional")
}
enum Size {
Small
Medium
Large
@@schema("transactional")
}
query data 也跟以往的方式一樣沒變化~
const orders = await prisma.order.findMany({
where: {
user: {
id: 1,
},
},
})
以上就是所有 schema 的內容,總共花了三天來介紹這個,希望大家可以學到,謝謝大家耐心地閱讀到這邊~
✅ 前端社群 :
https://lihi3.cc/kBe0Y