개인프로젝트를 하다가 prisma를 사용해봤는데,
원래 타입설정하는것이 불편한데, prisma 스키마로 만들어져있는 타입을 그냥 가져와서 쓴다는게 너무 편리했다.
초기 문턱은 높지만, 조금 익숙해지면 너무 편하게 사용할 수 있을것 같아서 정리를 해본다. 어렵지만 뭔가 재밌는 느낌.
npm i -D prisma
npm prisma init
prisma 폴더 생성, 설정파일이 생긴다.
schema.prisma 파일에 모델 및 코드 작성.
schema.prisma파일이 수정될때마다 generate 명령어는 실행해줘야하고
npx prisma generate
스키마 파일을 기반으로 최신 클라이언트를 생성.
npx prisma db push
스키마 파일의 내용을 데이터베이스에 저장
npx prisma studio 로 웹에서 확인도 가능하다.
prisma 를 전역으로 사용할 수 잇도록 db.ts파일을 설정해줘야하는데, 아래에서 코드로 살펴보자
.env에서 db설정을 해줘야하고
db설정은 무료플랜들이 없어서 supabase로 설정을 해줬다.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
model Profile {
id String @id @default(uuid())
userId String @unique
name String
imageUrl String @db.Text
email String @db.Text
servers Server[]
members Member[]
channels Channel[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Server {
id String @id @default(uuid())
name String
imageUrl String @db.Text
inviteCode String @db.Text
profileId String
profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
members Member[]
channels Channel[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([profileId])
}
enum MembershipRole {
ADMIN
MODERATOR
GUEST
}
model Member {
id String @id @default(uuid())
role MembershipRole @default(GUEST)
profileId String
profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
serverId String
server Server @relation(fields: [serverId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([profileId])
@@index([serverId])
}
전역에서 사용할 수 있도록
import { PrismaClient } from "@prisma/client";
declare global {
var prisma: PrismaClient | undefined;
}
// 전역 변수에 PrismaClient 인스턴스가 이미 존재하면 그것을 사용하고,
// 그렇지 않으면 새로운 PrismaClient 인스턴스를 생성합니다.
export const db = global.prisma || new PrismaClient();
// 개발 환경에서는 전역 변수에 PrismaClient 인스턴스를 할당합니다.
// 이를 통해 개발 중 핫 리로딩이 발생해도 기존 인스턴스를 재사용할 수 있습니다.
if (process.env.NODE_ENV !== "production") {
global.prisma = db;
}
generator client {
provider = "prisma-client-js"
}
Prisma Client를 생성하는 부분. prisma-client-js는 Prisma가 JavaScript/TypeScript 클라이언트를 생성하도록 지정.
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
데이터베이스 연결 설정입니다.
provider: 데이터베이스 유형을 지정, 여기서는 PostgreSQL을 사용. supabase에 mysql이 없어서url: 데이터베이스 URL을 환경 변수 DATABASE_URL에서 가져온다.relationMode: Prisma의 관계 모드를 사용하며 이는 Prisma가 외래 키 관계를 어떻게 처리할지를 지정.model Profile {
id String @id @default(uuid())
userId String @unique
name String
imageUrl String @db.Text
email String @db.Text
servers Server[]
members Member[]
channels Channel[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
Mysql만 주구장창 쓰다가 비슷한듯 달라서 좀 생소하긴한데, 익숙해지면 개발속도도 빨라질 것 같고, 궁금해지는 기술이다.
model Profile {
...
servers Server[]
...
}
model Server {
...
profileId String
profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
members Member[]
channels Channel[]
...
@@index([profileId])
}
model Profile와 Server이 존재하는데
@relation 어노테이션은 모델간의 관계를 정의할 때 사용된다.
profileId String
profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
설정뒤에는 migrate해주면된다.
익숙하지는 않지만, 확실히 뭔가 간결함이 느껴진다.
const profile = await db.profile.findUnique({
where: { userId: user.id },
});
const newProfile = await db.profile.create({
data: {
userId: user.id,
name: `${user.firstName} ${user.lastName}`,
imageUrl: user.imageUrl,
email: user.emailAddresses[0].emailAddress,
},
});
방을 만든사람은 방을 떠날수없고, 방을 삭제시켜야한다는 조건.
const server = await db.server.update({
where: { // 조건
id: params.serverId,
profileId: {
not: profile.id, // 서버장과 아이디가 달라야한다.
},
members: { // 외래키 members참조
some: {
profileId: profile.id, // 서버장이 아닌 유저인가?
},
},
},
data: { // 위의 조건에 맞는 서버데이터를 찾았다면, 그 서버의 member중에 현재 유저를 제거한다.
members: {
deleteMany: {
profileId: profile.id,
},
},
},
});