이번 글에서는 Prisma에서 Schema 변경 후 다시 이전 상태의 Schema로 돌아갈 수 있는 Down Migration을 생성해 보려 한다.
Prisma에서는 Schema 변경 후 Migration 파일을 생성할 때 자동으로 Down Migration을 생성해 주지 않으므로 별도로 생성해야 한다.
만약 생성된 Migration에서 데이터를 옮기거나 추가적인 SQL문을 작성하는 부분이 있으면 해당 부분까지는 생성해 주지 않지만, 이전 Schema로 돌아갈 수 있게 해주므로 안전한 기능이라고 생각한다.
그럼 한 단계씩 살펴보자.
Prisma에 대한 기본 세팅은 해당 글에서는 다루지 않습니다.
먼저, Schema 파일에 User와 Cart를 정의해 보자.
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
name String
phoneNumber String @map("phone_number")
cart Cart?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("user")
}
model Cart {
id Int @id @default(autoincrement())
userId Int @unique @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
@@map("cart")
}
그리고 Migration 파일을 하나 만들어줘야 하는데,
그전에 Test DB 하나를 띄워보자. (해당 글에서는 docker compose)
name: test-db
services:
postgresql:
container_name: test-postgresql
image: postgres
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: test1234
POSTGRES_DB: test
그리고 npx prisma migrate dev
를 입력하여 Migration 파일을 만든다.
생성된 Migration 파일을 살펴보면 알맞게 생성이 된 것으로 볼 수 있다.
-- CreateTable
CREATE TABLE "user" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"phone_number" TEXT NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "user_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cart" (
"id" SERIAL NOT NULL,
"user_id" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "cart_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "cart_user_id_key" ON "cart"("user_id");
-- AddForeignKey
ALTER TABLE "cart" ADD CONSTRAINT "cart_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Migration 파일 하나지만 여기까지 개발했다고 치고, 새로운 User 테이블에 email
컬럼과 추가로 Post
테이블을 추가해 보자.
model User {
id Int @id @default(autoincrement())
name String
phoneNumber String @map("phone_number")
email String <----------추가
cart Cart?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
posts Post[]
@@map("user")
}
model Post { <----------추가
id Int @id @default(autoincrement())
userId Int
user User @relation(fields: [userId], references: [id])
}
model Cart {
id Int @id @default(autoincrement())
userId Int @unique @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
@@map("cart")
}
Down Migration 파일은 새로운 Schema가 반영되는 Migration 파일을 생성하기 전에 미리 생성을 해놓아야 한다.
왜냐하면 Down Migration은 지금까지의 Migration history와 위에 작성된 최신 Schema를 비교해서 생성되기 때문이다.
해당 시점에서는 Migration history가 최신 Schema를 작성하기 전까지의 기록이므로
그리고 migrate diff
를 통해 생성해보자.
npx prisma migrate diff \
--from-schema-datamodel prisma/schema.prisma \
--to-migrations prisma/migrations \
--shadow-database-url ${SHADOW_DATABASE_URL}/shadow_test \
--script > down.sql
여기서 옵션들을 잠깐 살펴보면
만약 Shadow Database를 사용하지 않으려면 아래와 같은 다른 대안이 있으나, 해당 글에서는 위의 방법으로 진행해 보자.
npx prisma migrate diff \
--from-schema-datamodel prisma/schema.prisma \
--to-schema-datasource prisma/schema.prisma \
--script > down.sql
Shadow Database를 위해 추가 DB를 작성하고, 해당 url을 작성해보자.
name: test-db-setup
services:
postgresql:
container_name: test-postgresql
image: postgres
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: test1234
POSTGRES_DB: test
shadow-postgresql:
container_name: shadow-postgresql
image: postgres
command: -p 5433
ports:
- "5433:5433"
environment:
POSTGRES_PASSWORD: test1234
POSTGRES_DB: shadow_test
npx prisma migrate diff \
--from-schema-datamodel prisma/schema.prisma \
--to-migrations prisma/migrations \
--shadow-database-url postgresql://postgres:test1234@localhost:5433/shadow_test \
--script > down.sql
그리고 프로젝트 루트위치에 생성되는 down.sql 파일에 알맞게 작성됐는지 확인한다.
-- DropForeignKey
ALTER TABLE "Post" DROP CONSTRAINT "Post_userId_fkey";
-- AlterTable
ALTER TABLE "user" DROP COLUMN "email";
-- DropTable
DROP TABLE "Post";
Down Migration 파일도 생성했으니 먼저 변경된 Schema를 반영해보자.
이제 생성해놨던 down.sql 파일을 db execute
를 통해 db에 실행시켜보자.
file의 위치와 schema의 위치는 다른곳에 저장해두었으면 해당 위치를 작성하면 된다.
prisma 문서에는 이후 단계로 migrate resolve
를 통해 해당 Migration이 롤백 후 해결된 상태로 표시하는 단계를 알려주고 있다.
만약 Migration 과정 중 오류가 나서 실패한 경우라면 해당 과정을 수행하면 되지만,
성공적으로 Migration이 수행됐는데 다시 돌아가고 싶은 경우라면 Migration이 실패한 상태가 아니기에 해당 과정은 오류가 난다.