サーバーレスなデータベースプラットフォームのPlanetScaleが面白そうだったので試してみた

## PlanetScale とは？

https://docs.planetscale.com/concepts/planetscale-workflow に全部書いてます。以下、日本語要約です。

* サーバーレスのDB、MySQL8.0が使われていて、OSSのVitessを使ってたった10秒でスケールされる
* 本番環境と開発環境用のブランチを作成することができて、スキーマの変更を試してみたり、本番環境のブランチをコピーして簡単にステージング環境用のデータベースを準備することができる
* CI/CDに組み込めて自動的にスキーマを管理することができたり、テーブルをブロックすることなく、変更を加えることができる
* ソースコードに対するプルリクエストのように、スキーマに対するプルリクエストを作ることができて、スキーマ変更に対するフィードバックが得やすくなる
* 承認されたプルリクエストがデプロイキューに入れられ、本番環境へ適応される。もし、コンフリクトがある場合は、適用されない。

ただ、外部キー制約についてはサポートしていないよう。https://docs.planetscale.com/learn/operating-without-foreign-key-constraints に詳しいことが書いてある (筆者は読んでいない)

## Get Startedをやる

### アカウント作成

GitHubのアカウントと連携するのが一番手っ取り早そうです。CLIでもできます。

### CLIのインストール

```bash
brew install planetscale/tap/pscale
```

### データベースを作る

`test` という名前のデータベースを作ってみます。

```bash
❯ pscale database create test
Error: not authenticated yet. Please run 'pscale auth login' or create a service token with 'pscale service-token create'
```

と出るので、(多分最初からCLIでアカウント作成すれば問題なかった気がする)

```bash
❯ pscale auth login
```

でログインする。もう一度、データベースを作成する。

```bash
❯ pscale database create test
Database test was successfully created.
```

デフォルトでは `US East` リージョンにデータベースが作成されるよう。色々CLIのオプションがある。東京リージョンで作るには `--region ap-northeast` のオプションを渡すとよさそう。

```bash
❯ pscale database create
Error: missing argument <database>

Usage:
  pscale database create <database> [flags]

Flags:
  -h, --help            help for create
      --notes string    notes for the database
      --region string   region for the database
  -w, --web             Create a database in your web browser

Global Flags:
      --api-token string          The API token to use for authenticating against the PlanetScale API.
      --api-url string            The base URL for the PlanetScale API. (default "https://api.planetscale.com/")
      --config string             Config file (default is $HOME/.config/planetscale/pscale.yml)
      --debug                     Enable debug mode
  -f, --format string             Show output in a specific format. Possible values: [human, json, csv] (default "human")
      --no-color                  Disable color output
      --org string                The organization for the current user
      --service-token string      Service Token for authenticating.
      --service-token-id string   The Service Token ID for authenticating.

❯ pscale region list
  NAME (6)                      SLUG           ENABLED
 ----------------------------- -------------- ---------
  US East - Northern Virginia   us-east        Yes
  US West - Oregon              us-west        Yes
  EU West - Dublin              eu-west        Yes
  Asia Pacific - Mumbai         ap-south       Yes
  Asia Pacific - Singapore      ap-southeast   Yes
  Asia Pacific - Tokyo          ap-northeast   Yes
```

### データをinsertしてみる

ブランチという概念があって、`ALTER TABLE` のような破壊的変更を加えてテスト環境等でテストすることができる。

デフォルトで作成されるブランチは `main` だけ。

```bash
❯ pscale branch ls test
  NAME   PARENT BRANCH   PRODUCTION   READY   CREATED AT       UPDATED AT
 ------ --------------- ------------ ------- ---------------- ---------------
  main   n/a             No           Yes     10 minutes ago   9 minutes ago
```

`test` データベースの `main` ブランチにログインして、テーブル作成、データ挿入を行う。

```bash
❯ pscale shell test main
test/main> CREATE TABLE `users` (
    ->   `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `email` varchar(255) NOT NULL,
  `first_name` varchar(255),
  `last_name` varchar(255)
);  `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->   `email` varchar(255) NOT NULL,
  `first_name` varchar(255),
  `last_name` varchar(255)
);  `email` varchar(255) NOT NULL,
    ->   `first_name` varchar(255),
  `last_name` varchar(255)
);  `first_name` varchar(255),
    ->   `last_name` varchar(255)
);  `last_name` varchar(255)
    -> ););
test/main> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| users          |
+----------------+
test/main> DESCRIBE users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | NO   | PRI | NULL    | auto_increment |
| email      | varchar(255) | NO   |     | NULL    |                |
| first_name | varchar(255) | YES  |     | NULL    |                |
| last_name  | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
test/main> INSERT INTO `users` (id, email, first_name, last_name) VALUES  (1, 'hp@test.com', 'Harry', 'Potter');
test/main> SELECT * FROM users;
+----+-------------+------------+-----------+
| id | email       | first_name | last_name |
+----+-------------+------------+-----------+
|  1 | hp@test.com | Harry      | Potter    |
+----+-------------+------------+-----------+
test/main> exit
```

### 本番環境用にしてみる

実はまだこの段階では `main` ブランチは開発用のブランチで、 `ALTER TABLE` 等の破壊的変更を直接行うことができる。本番環境のブランチはそういった変更を行えないようにしたければ、`main` ブランチをpromoteすることで本番環境用のブランチにすることができる。

```bash
❯ pscale branch promote test main
Branch main in test was successfully promoted.
```

これで `main` ブランチに直接破壊的変更を加えることができなくなった (後でチェックする)。

### アプリからデータを取得してみる

サンプルアプリがあるので使ってみる。

```bash
git clone https://github.com/planetscale/express-example.git
cd express-example
yarn install
```

データベースとアプリを接続してみる。

```bash
❯ pscale connect test main --execute 'node app.js'
Secure connection to database test and branch main is established!.

Local address to connect your application: 127.0.0.1:3306 (press ctrl-c to quit)
Example app listening at http://localhost:3000
```

http://localhost:3000 を開くとデータが取得できていることがわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349999/bed0c247-842f-f380-594f-bec1fe670ae1.png)

ちゃんとデータが取得できていることが確かめられた。

### `ALTER TABLE` を実行したい時

`first_name` のカラムが `DEFAULT NULL` になっているので、 `NOT NULL` にしてみる。 `main` にログインして、直接 `ALTER TABLE` してみるも、エラーが返ってきて実行できなくなっている。

```bash
❯ pscale shell test main
test/main> DESCRIBE users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | NO   | PRI | NULL    | auto_increment |
| email      | varchar(255) | NO   |     | NULL    |                |
| first_name | varchar(255) | YES  |     | NULL    |                |
| last_name  | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
test/main> ALTER TABLE users MODIFY first_name varchar(255) NOT NULL;
ERROR 1105 (HY000): direct DDL is disabled
test/main> exit
```

`main` から新しいブランチを作成してスキーマを変えてみる。

```bash
❯ pscale branch create test alter-table --from main
Branch alter-table was successfully created.
```

作成したブランチに対して、 `ALTER TABLE` を実行する。

```bash
❯ pscale shell test alter-table
test/alter-table> SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| users          |
+----------------+
test/alter-table> DESCRIBE users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | NO   | PRI | NULL    | auto_increment |
| email      | varchar(255) | NO   |     | NULL    |                |
| first_name | varchar(255) | YES  |     | NULL    |                |
| last_name  | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
test/alter-table> ALTER TABLE users MODIFY first_name varchar(255) NOT NULL;
test/alter-table> exit
```

deploy requestというものを作成する。プルリクエストと同じ概念。

```bash
❯ pscale deploy-request create test alter-table
Deploy request #1 successfully created.
```

作成されたdeploy requestがどんなものか確認してみる。

```bash
❯ pscale deploy-request diff test 1
-- users --
CREATE TABLE `users` (
   `id` int NOT NULL AUTO_INCREMENT,
   `email` varchar(255) NOT NULL,
-  `first_name` varchar(255) DEFAULT NULL,
+  `first_name` varchar(255) NOT NULL,
   `last_name` varchar(255) DEFAULT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
```

`DEFAULT NULL` だったのが `NOT NULL` に変更されていることが確認できる。web consoleでもPRを確認することができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349999/6640932c-46c4-d013-914f-7ce5177adf5c.png)



### 本番環境 (`main`) に適用

```bash
❯ pscale deploy-request deploy test 1
Successfully queued 8dxeo05eph4l from alter-table for deployment to main.

❯ pscale shell test main
test/|⚠ main ⚠|> DESCRIBE users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int          | NO   | PRI | NULL    | auto_increment |
| email      | varchar(255) | NO   |     | NULL    |                |
| first_name | varchar(255) | NO   |     | NULL    |                |
| last_name  | varchar(255) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
test/|⚠ main ⚠|> exit
```

`main` のブランチの `users` テーブルのスキーマが変更されていることが確認できた。

### まとめ

- データベースやテーブルへのスキーマ変更をプルリクエストのような形で確認できるのはよさそう。
  - 開発時は開発ブランチに色々PR作ってapplyして、そのデータベースとアプリを接続するようにするみたいな運用が簡単にできそう
- 外部キー制約がサポートしていないのが気になった
- Audit logとかクエリの統計とかも取ってくれるからよさそう
- GitHub Actionsとかと組み合わせればスキーマ管理が楽になりそうかも