- Published on
Prisma
- Authors
- Name
- Inhwan Cho
Prisma
Prisma는 오픈소스 ORM(Object-relational mapping) 중 하나입니다.
ORM이란? DB데이터를 객체로 매핑해 주는 역할을 하는 것입니다.
즉, SQL문법을 사용하지 않고, 다른 언어(파이썬,자바스크립트 ...)를 사용하여 데이터베이스를 수정할 수 있도록 연결해주는(번역 역할) 서비스입니다.
사용 방법
- 설치
- 데이터베이스가 어떻게 생겼는지 schema를 작성하여 알려주기.
- schema를 기반으로 자동완성 사용 가능.
- prisma studio를 통해 관리 가능.
# 설치
npm install prisma
# 시작
npx prisma init
# prisma schema 설정하기 - 아래 글 Prisma Schema 참조
# 모델을 적용하기(db마다 다름)
npx prisma init --datasource-provider sqlite
# 만든 schema를 sqlite로 생성하기 - lite가 아닌 실제 db를 사용하는 경우 생략.
npx prisma migrate dev --name init
Prisma Schema
- prisma 폴더에
schema.prisma
라고 생성되며 크게 3가지 설정을 해줘야한다. - VS code를 사용하고 있다면
extension에서 prisma를 설치
하면 보기 편합니다.
데이터 소스: 연결될 데이터 소스에 대한 세부사항을 명시한다.
생성자: 어떤 클라이언트가 생성되어야 하는지에 대해 설명한다.
데이터 모델: 모델을 설정한다.
Prisma 테스트해보기(설치 + 사용)
# 테스트용 폴더 만들기
mkdir prismatest
# 폴더로 이동
cd prismatest
# 패키지 설치 및 세팅
npm i typescript ts-node @types/node -D
npx tsc --init
npm i prisma
# 만약, datasource를 다른 db로 설정 시 .env파일 및 다수의 파일 수정 필요.
# 하지만 테스트용으로 `sqlite` 생성 시 따로 설정할게 거의 없기에 `sqlite`로 생성.
npx prisma init --datasource-provider sqlite
code .
# VS코드에서 prisma/schema.prisma로 이동해서
# schema.prisma 설정하기
// prisma/schema.prisma
//생성자 - 어떤 클라이언트가 생성되어야 하는지에 대해 설명
generator client {
provider = "prisma-client-js"
}
//데이터소스(db) - 연결될 데이터 소스에 대한 세부사항을 명시
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// 모델 작성해야 합니다.
// 데이터 모델 - 모델을 설정.
model User {
// id,email,name,article을 가지고있는 object생성
id Int @id @default(autoincrement())
email String @unique
name String?
// articles은 Article이라는 모델(생성 필요)
articles Article[]
}
model Article {
id Int @id @default(autoincrement())
title String
body String?
author User @relation(fields: [authorId], references: [id])
authorId Int
}
npx prisma migrate dev --name init
으로 해당 스키마를 migate.
-- schema의 형식에 따라 생성된 파일은 다음과 같습니다.
-- prisma/migrations/202311....../miration.sql을 보시면 다음과 같은 파일이 생성되어 있습니다.
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"email" TEXT NOT NULL,
"name" TEXT
);
-- CreateTable
CREATE TABLE "Article" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" TEXT NOT NULL,
"body" TEXT,
"authorId" INTEGER NOT NULL,
CONSTRAINT "Article_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
index.ts
파일을 생성-> user를 만들고 테스트 해보기
// /index.ts
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
// prisma query
// create user
const user = await prisma.user.create({
data :{
name: 'inhwan',
email: 'inhwan@gmail.com',
},
});
const users = await prisma.user.findMany();
console.log(users)
}
main()
.then(async ()=>{
await prisma.$disconnect();
})
.catch(async (error)=>{
console.log(error)
await prisma.$disconnect();
process.exit(1);
})
npx ts-node index.ts
를 입력하여 콘솔창에 생성된 object가 잘 나오는지 확인해보기.
프리즈마 주요 명령어
npx prisma generate
: 프리즈마 스키마에서 위에 언급된 모든 정보를 읽는다. npx prisma migrate dev
: data sources 와 data model 정의를 읽는다.
npx prisma introspect
: Database의 구조를 자동으로 Prisma schema 로 불러올 수 있습니다.
npx prisma migrate
: 스키마를 migrate하는 명령어입니다.
npx prisma client
: Database를 변경하는 기능입니다.
npx prisma studio
: GUI로 Database를 편집할 수 있는 명령어입니다.
@@index 사용 예시
model User {
id Int @id @default(autoincrement())
name String
email String @unique
@@index(name: "name_aaa_index", [name, email])
}
// name과 email에 대해 index를 정의함. index 이름은 name_aaa_index
// 파라미터 순서는 상관 없음.
참고
유튜브 - prisma crash course
Prisma Docs
phone Int == Int 타입으로 필수로 할당되어야함.
phone Int? == phone 있다면 Int 타입으로 할당 되어야 하지만 값이 없을 수도 있음.
@id == 아이디(식별자 코드) 값 - 유니크함
@unique == 유니크한 값 - 식별자 코드는 아님(이메일 주소 같은 값)
@default == 설정을 안했을 때의 기본 값
autoincrement() == 따로 설정을 하지 않으면 값이 1씩 증가해서 할당
now() == 생성되었을 때의 시간을 할당
@relation == (fields)는 현재 모델에서 관계있는 값, (references)는 현재 모델과 관계있는 값
(onDelete)는 관계있는 데이터가 삭제됬을때 같이 삭제할것인지 여부.
만약, relation fields가 동일한 2개가 있는 경우 (name)을 입력해줘야합니다.
@updatedAt == 업데이트가 될때마다 변경.
@@index == 데이터베이스 인덱스를 정의할 때 사용
- 동일한 모델의 값을 참조하는 경우
// 만약, relation fields가 동일한 2개가 있는 경우 name을 입력
model User {
id Int @id @default(autoincrement())
phone String? @unique
reviewsBy Review[] @relation(name: "writtenReviews")
reviewsFor Review[] @relation(name: "receivedReviews")
}
model Review {
id Int @id @default(autoincrement())
createdBy User @relation(name: "writtenReviews", fields: [createdById], references: [id], onDelete: Cascade)
createdFor User @relation(name: "receivedReviews", fields: [createdForId], references: [id], onDelete: Cascade)
review String @db.MediumText
createdById Int
createdForId Int
@@index([createdById])
@@index([createdForId])
}
- 동일한 값을 가진 모델을 생성하고 싶은 경우
enum
을 사용. - String과 유사하나 오타를 방지하여 선택권을 강제함.
// 또한, 동일한 모델을 생성하고 싶은 경우 'enum'을 사용하면 좋습니다.
// 여기서는 'Purchase'와 'Sale'의 동일한 내용의 모델을 생성하는 겁니다.
model User {
...
records Review[]
}
model Record {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id])
product Product @relation(fields: [productId], references: [id])
userId Int
createAt DateTime @default(now())
updateAt DateTime @updatedAt
productId Int
kind Kind
@@index([userId])
@@index([productId])
}
enum Kind {
Purchase
Sale
}
- 추후 작업하다가 데이터베이스에서 required 옵션에 대한 충돌이 날 경우 아래와 같은 방법으로 해결.
- 기존 데이터 베이스를 지운 후 생성
- 새로 추가되는 필드를 옵셔널하게 생성(ex. String? Int?)
- default value를 입력하여 기존 데이터에도 추가되도록 설정(ex. default(5))
- 기존의 데이터를 초기화 하고 싶을 경우(전체 데이터 제거)
$ npx prisma migrate reset
$ npx prisma db push
@@index
model Product {
user User @relation(fields: [userId], references: [id])
...
@@index([userId])
}
db와 분리된 데이터 구조
입니다. 계속해서 흔적과 위치를 추적합니다.
예를들어, userId 1인 유저가 있다면 새로운 상품을 등록하면 db에도 등록이 되고, index도 업데이트가 됩니다. 그 후 Id 1 유저를 조회하면 db 전체를 조회하는 대신 index를 조회하여 시간과 비용을 줄일 수 있습니다.