【Prisma】マイグレーションを試してみた

# スキーマファイル作成

本章は下記ドキュメントを参照した.

https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-mysql

プロジェクトディレクトリを作成し, 必要なパッケージをインストールする.

```shell
# プロジェクトディレクトリ作成
mkdir hello-prisma
cd hello-prisma

# パッケージインストール
npm init -y
npm install prisma --save-dev
```

スキーマファイルを作成する.

```shell
npx prisma init
```

このときのディレクトリ構造は以下のようになる：

```shell
./hello-prisma/
├── .env # データベース接続情報の環境変数ファイル
├── .gitignore
├── package-lock.json
├── package.json
└── prisma
    └── schema.prisma # スキーマファイル
```

データベース接続情報を編集する.

```.env
DATABASE_URL="mysql://db_user:db_password@db_host:db_port/your_database"
```

# 最初のマイグレーション

本章は下記ドキュメントを参考にした.

https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/using-prisma-migrate-typescript-mysql

最初に作成するテーブルを `schema.prisma` に記載する.

```js:prisma.schema
// 初期状態で記載されている
generator client {
  provider = "prisma-client-js"
}

// 初期状態で記載されている
datasource db {
  provider = "mysql" // postgresqlからmysqlに変更した
  url      = env("DATABASE_URL")
}

// 最初に作成するテーブル
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
}
```

最初のマイグレーションを行う.

```shell
npx prisma migrate dev --name init
```

このときのディレクトリ構造は以下のようになる：

```shell
./hello-prisma/
├── .env
├── .gitignore
├── package-lock.json
├── package.json
└── prisma
    ├── migrations # マイグレーション実行後, このディレクトリが作成される
    │   ├── 20240721114612_init
    │   │   └── migration.sql # マイグレーション用のSQLファイル
    │   └── migration_lock.toml
    └── schema.prisma
```

:::note info
Note
マイグレーションを実行すると自動で `@prisma/client` がインストールされる.
:::

# 2回目のマイグレーション

本章は下記ドキュメントを参考にした.

https://www.prisma.io/docs/orm/prisma-migrate/workflows/generating-down-migrations

`prisma.schema` に `Profile` テーブルを追加し, `User` テーブルの `id` 列を外部キーとする.

```js:schema.prisma
// 初期状態で記載されている
generator client {
  provider = "prisma-client-js"
}

// 初期状態で記載されている
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

// 最初に作成するテーブル
model User {
  id      Int      @id @default(autoincrement())
  email   String   @unique
  name    String?
  Profile Profile?
}

// 2回目のマイグレーション
model Profile {
  id     Int     @id @default(autoincrement())
  bio    String?
  user   User    @relation(fields: [userId], references: [id])
  userId Int     @unique
}
```

ロールバック用の SQL ファイル `down.sql` を作成する.

```shell
npx prisma migrate diff \
--from-schema-datamodel prisma/schema.prisma \
--to-schema-datasource prisma/schema.prisma \
--script > down.sql
```

2 回目のマイグレーションを行う.

```shell
npx prisma migrate dev --name add_profile
```

このときのディレクトリ構造は以下のようになる：

```shell
./hello-prisma/
├── .env
├── .gitignore
├── down.sql # ロールバック用のSQLファイル
├── package-lock.json
├── package.json
└── prisma
    ├── migrations
    │   ├── 20240721115414_init
    │   │   └── migration.sql
    │   ├── 20240721121601_add_profile # 2回目のマイグレーション用のSQLファイル
    │   │   └── migration.sql
    │   └── migration_lock.toml
    └── schema.prisma
```

最後にマイグレーション用のSQLファイルを今回のマイグレーションディレクトリにコピーする.

```shell
cp down.sql prisma/migrations/20240721121601_add_profile/
```

このときのディレクトリ構造は以下のようになる：

```shell
./hello-prisma/
├── .env
├── .gitignore
├── down.sql
├── package-lock.json
├── package.json
└── prisma
    ├── migrations
    │   ├── 20240721115414_init
    │   │   └── migration.sql
    │   ├── 20240721121601_add_profile
    │   │   ├── down.sql # マイグレーション用のSQLファイルをこのディレクトリにコピー
    │   │   └── migration.sql
    │   └── migration_lock.toml
    └── schema.prisma
```

# 2回目のマイグレーションをロールバックする

マイグレーション用のSQLファイル `down.sql` を実行し, `Profile` テーブルを削除する.

```shell
npx prisma db execute --file ./down.sql --schema prisma/schema.prisma
```

ロールバックをマイグレーション履歴に反映する.

```shell
npx prisma migrate resolve --rolled-back 20240721121601_add_profile
```

:::note alert
警告

ロールバックをマイグレーション履歴に反映できなかった.
> Migration `20240721121601_add_profile` cannot be rolled back because it is not in a failed state.
:::

マイグレーションステータスが関係しているらしい.

# その他

`schema.prisma` を編集する際, 下記の拡張機能が便利だった.

```setting.json
  "[prisma]": {
    "editor.defaultFormatter": "Prisma.prisma"
  }
```

https://marketplace.visualstudio.com/items?itemName=Prisma.prisma

# 参考

https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-mysql

https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/using-prisma-migrate-typescript-mysql

https://www.prisma.io/docs/orm/prisma-migrate/workflows/generating-down-migrations