PlanetScale外部キー制約対応したからPrismaのrelationMode = "prisma"記述不要になったってこと？

:::note info
この記事はZOZO Advent Calendar 2023 シリーズ9の13日目の記事です。
:::

## はじめに
最近よく名前を聞くような気がする`PlanetScale`ですが、みなさん使っていますでしょうか？
自分は先日行われた開発合宿で初めて使用し、開発体験の良さに思わず感動してしまいました。
その時作成したアプリの記事も書いていますのでよければご覧ください！

https://qiita.com/kensiiwasaki/items/c53364676e669258f140

`PlanetScale`は元々、外部キー制約をサポートしておらず、それが理由で触るのを避けてきた人も多いのではないでしょうか？
しかしつい先日、ついに[外部キー制約がサポート](https://planetscale.com/blog/announcing-foreign-key-constraints-support)されました！
現在ベータ版ではあるもののフリープランでも試すことはできるので、今回は`Prisma`を使って試してみようと思います！

※外部キー制約そのものについては詳しく触れません🙇‍♂️

## PlanetScaleとは
https://planetscale.com/

`PlanetScale`はサーバレスなMySQLプラットフォームです。
DBのブランチ機能があったり、ダウンタイムなしのマイグレーション、productionにデプロイ後３０分以内であればスキーマの変更をrevertできるなどの特徴があります。

## PlanetScaleで外部キー制約がサポートされた背景
上記でも述べたように、`PlanetScale`では元々、外部キー制約をサポートしておりませんでした。
内部で使用されている[Vitess](https://vitess.io/)が外部キー制約をサポートしていなかったことなどが理由です。

以下の記事に外部キー制約をサポートしていなかった理由についてわかりやすくまとまっておりましたのでぜひご参考にしてみてください。

https://zenn.dev/tak_iwamoto/articles/b27151d22d9e6a


しかし、2023年11月`Vitess`[v18](https://planetscale.com/blog/announcing-vitess-18)にて外部キー制約がサポートされたことにより、同年12月より`PlanetScale`でも[外部キー制約がサポート](https://planetscale.com/blog/announcing-foreign-key-constraints-support)されました。


## 実際に確かめてみる
### PlanetScaleとPrismaの準備
アカウントを作成しログインしたら、以下のような画面になるので"Create a new database"からデータベースを作成します。

![スクリーンショット 2023-12-13 3.41.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1602210/94b3fe4c-3918-3828-f71e-9fdc13119043.png)


詳しい手順は今回は省略しますが、画面に沿っていくだけで簡単にデータベースを作成できます。
途中使用するフレームワークが選択できるので今回は`Prisma`を選択します。

![スクリーンショット 2023-12-13 1.48.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1602210/03adff01-60c5-19ae-a8e3-55c90be25390.png)

そうすると、画面に`Prisma`用の設定手順が出てきます。

![スクリーンショット 2023-12-13 1.50.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1602210/1183b347-2932-fc4e-620c-b7f758aa34c8.png)

その下あたりにenvファイルに記述情報が出てくるので、ご自身の.envファイルにコピペしてください。
(今回自分は自分で作った超最小構成な[Remixのテンプレート](https://github.com/kensiiwasaki/remix-tailwind-small-template)を使用しています。)

```.env
DATABASE_URL='mysql://XXXXXXXXXXXXXXXX
```

これで`Prisma`と`PlanetScale`の連携は完了です。

### 現在はベータ版なのでそのままだと外部キー制約は使えない
現在はベータ版なのでそのままだと外部キー制約は使えません。
実際に試してみます。

```prisma/scheme.prisma
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int      @id @default(autoincrement())
  name  String
  posts Post[]
}

model Post {
  id      Int      @id @default(autoincrement())
  title   String
  content String
  userId  Int
  user    User     @relation(fields: [userId], references: [id])
}
```

以上のようなスキーマを用意して、データベースにプッシュしてみます。

```
npx prisma db push
```

すると、「外部キー制約サポートしてないよ」というエラーが出ます。

```
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "foreign-key-test" at "aws.connect.psdb.cloud"
Error: VT10001: foreign key constraints are not allowed
   0: sql_schema_connector::apply_migration::migration_step
           with step=AddForeignKey { foreign_key_id: ForeignKeyId(0) }
             at schema-engine/connectors/sql-schema-connector/src/apply_migration.rs:21
   1: sql_schema_connector::apply_migration::apply_migration
             at schema-engine/connectors/sql-schema-connector/src/apply_migration.rs:10
   2: schema_core::state::SchemaPush
             at schema-engine/core/src/state.rs:436
```

そのため今までは、[外部キー制約を作成せずにエミュレートするモード](https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/relation-mode#emulate-relations-in-prisma-with-the-prisma-relation-mode)を使う必要がありました。

```diff:prisma/schema.prisma
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
+ relationMode = "prisma"
　}
```

この一文を追加することでデータベースにプッシュすることは可能になります。

### 現在はベータ版の機能を利用して外部キー制約が使えるか試してみる
少し長くなってしまいましたが、ここからが本題です！
まずはベータ版の機能を利用できるように設定する必要があります。
詳しくは[公式ドキュメント](https://planetscale.com/docs/concepts/foreign-key-constraints)に書いてありますが、ここでも簡単に説明します。

`PlanetScale`の管理画面から
"Settings" → "Beta features"と進み "Foreign key constraints"をEnrollします。

![スクリーンショット 2023-12-13 2.28.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1602210/99617de5-6d4f-e46a-5bef-879dacc5b2b5.png)

これだけで利用できるようになったので、実際に先ほどエラーが出てしまったスキーマをデータベースにプッシュしてみます。

```prisma/scheme.prisma
datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int      @id @default(autoincrement())
  name  String
  posts Post[]
}

model Post {
  id      Int      @id @default(autoincrement())
  title   String
  content String
  userId  Int
  user    User     @relation(fields: [userId], references: [id])
}
```

```
npx prisma db push
```

すると問題なくプッシュが成功し、`relationMode = "prisma"`の記述も必要なくなったのが確認できました！

```
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "foreign-key-test" at "aws.connect.psdb.cloud"

🚀  Your database is now in sync with your Prisma schema. Done in 612ms

Running generate... (Use --skip-generate to skip the generators)

changed 43 packages, and audited 867 packages in 2s

250 packages are looking for funding
  run `npm fund` for details

1 moderate severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

✔ Generated Prisma Client (v5.7.0) to ./node_modules/@prisma/client in 51ms
```

一応`Prisma Studio`で確認してみても、問題なくテーブルが作成できていました。

![スクリーンショット 2023-12-13 2.30.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1602210/4e4cdbae-a492-5113-b511-22e7e175a181.png)


## まとめ
今回は実際に`PlanetScale`での外部キー制約のサポートを確認してみました！
ドキュメント等読んでる中で、アプリケーションによっては[外部キー制約を推奨しない](https://planetscale.com/docs/learn/operating-without-foreign-key-constraints#why-does-planetscale-not-recommend-constraints-)場合などもあるようで、その辺の知識ももっとつけないとなと痛感しました。。。

`PlanetScale`を利用した開発体験はかなりいいので、外部キー制約をサポートしたことでより人気が出ると思っております。
今後も色々試してみて、新たな気づきや発見がありましたら発信していこうと思います！

興味が湧きましたら、みなさまも是非触ってみてはいかがでしょうか？！

## おわりに
内容について誤り等ございましたらご指摘いただけますと大変幸いでございます。
何卒よろしくお願いいたします。

最後まで読んでいただきましてありがとうございました！