見出し画像

Supabaseでマイグレーションとかロールバックとかやってみる

こんにちは。
今回はSupabaseという人気のあるBaaS(Backend as a Service)を試してみたいと思います。

● Supabaseとは?
ほぼFirebaseですが、Firebaseの代替として位置づけられており、大きな違いは、FirebaseがNoSQLデータベースを使用するのに対し、SupabaseではRDB(リレーショナルデータベース)であるPostgreSQLを使用する点です。

Firebaseを使用していて最も困難だった点は、NoSQLを使用することでした。
NoSQLではJOIN操作ができない、データ構造の変更にコストがかかるなどの課題があります。
特にビジネスプランの変更や仕様変更によるデータ構造の変更が頻繁に行われる開発フェーズでは、柔軟にデータ構造を変更できることや、リレーションを柔軟に扱えることが重要です。

そのため、RDB版のFirebaseがあればと考えていたところにSupabaseが登場しました。

1.Migrationしてみる

まず、円滑なデータベースの運用のために、Migrationに関連する仕組みを構築してみたいと考えています。

今回はReactからSupabaseを利用することを想定しているため、Node.jsから操作できる環境を構築する必要があります。

Node.jsでは、RailsでいうところのActiveRecordのようなORMが存在しないか探していました。
その中で、Prismaが候補に挙がりました。

● Prismaとは?
Prismaは「Next-generation Node.js and TypeScript ORM」とされており、Node.jsからデータベースにアクセスするためのORMです。モダンなアプローチで設計されています。

これでいいじゃん、完璧じゃん、と思っていましたがまさかの盲点がありました。
これまでの開発では、テーブルの新しい構造を反映するためにはMigrationを「Up」し、一つ前の構造に戻すためにはMigrationを「Down」することが一般的でした。
しかし、Prismaではスキーマを一つ前の状態に戻すことができないという盲点がありました。

「な、な、な、なんだってー」

公式の回答は「Seedを使用してデータをリセットする」というものですが、実際の運用ではこれは難しいと感じました。
Prismaでは他に適切な方法があるのか、または別のアプローチがあるのか知りたいと思います。
もしPrismaに関するより良い方法をご存知の方がいらっしゃれば、教えていただけると幸いです。

● 2021.12.14 追記
出典先でも議論されていますが、そもそも本番環境ではロールバックあまりしないよね?開発環境ならresetしてseedするのも自由だからmigration downなくてもいいよね 、ロールバックするのではなく、ロールフォワードを推奨だよ、という感じですかね。

本番で必要無くなったスキーマはロールバックするという方法ではなく、このスキーマを削除するという内容をmigration upしてねという感じでした。

https://github.com/prisma/prisma/discussions/4617

2.Supabaseで本番用のDBをつくる

まずは、DBの環境として「development環境」と「production環境」を作成したいと考えています。

本番用のDB環境を作るのは簡単で、Supabaseの管理画面から「New Project」を選択します。
プロジェクトが作成されると、Production環境で使用するためのDBのアクセス情報も生成されるので、管理画面で確認しましょう。

3.Supabaseで開発用のDBをつくる

次に、development環境を作成します。
まずはローカルに適当なReactの開発環境を構築します。
開発環境が構築できたら、次にSupabaseをnpmでインストールします。

$ npm install -g supabase

これにより、Supabaseコマンドを実行できるようになります。

$ supabase init

✔ Port for Supabase URL: · 8000
✔ Port for PostgreSQL database: · 5432
✔ Port for email testing interface: · 9000
✔ Project initialized.

Supabase URL: http://localhost:8000
Supabase Key (anon, public): eyJ0eXAiOiJKV1Q...
Supabase Key (service_role, private): eyJ0eXAiOiJKV1Q...
Database URL: postgres://postgres:postgres@localhost:5432/postgres
Email testing interface URL: http://localhost:9000

Run supabase start to start local Supabase.

supabase initを実行すると、プロジェクト内にDocker環境が構築されます。

.supabase/docker/

構築されたDockerのコンテナ内にSupabaseが存在するので、それを起動してみましょう。

$ supabase start

これにより、SupabaseのAuthやDatabaseのサービスがローカルで利用できるようになります。
Supabaseを起動すると、コンテナ内でPostgreSQLが実行されるため、SQLクライアントやReactなどから接続することができます。

スクリーンショット 2021-10-24 22.03.34

4.開発用と本番用を管理する

次に、ORMを導入して環境を効果的に管理したいと考えています。Prismaには不安要素があるため、安定して稼働する可能性が高いSequelizeを導入することにしました。

$ npm install --save sequelize-cli
$ npm install --save sequelize

導入が完了したら初期化します。

$ npx sequelize-cli init

そうすると、複数のディレクトリが生成されます。

● seeders - シードを定義するファイルを管理
● models - テーブルの構造を定義するファイルを管理
● migrations - マイグレーションファイルを管理
● config - DBの設定をするファイルを管理

configディレクトリにDBの設定を書きます。

{
 // supbase initしたときのローカルのDB情報を入れる
 "development": {
   "username""postgres",
   "password""postgres",
   "database""postgres",
   "host""localhost",
   "dialect""postgres"
 },
 
 // 今回は使わないがstaging環境などある場合に使用する
 "test": {
   "username""root",
   "password"null,
   "database""database_test",
   "host""127.0.0.1",
   "dialect""mysql"
 },
 
 // supabaseでNewProjectしたDB情報を入れる
 "production": { 
   "username"// supabaseの管理画面から記載,
   "password"// supabaseの管理画面から記載,
   "database"// supabaseの管理画面から記載,
   "host"// supabaseの管理画面から記載,
   "dialect"// supabaseの管理画面から記載
 }
}

developmentとproductionの設定に情報を記載します。
ここではUsersモデルの設定を行い、マイグレーションを実行してみたいと思います。

$ npx sequelize-cli migration:generate --name Users

Usersモデルの生成が完了し、modelsディレクトリにUsers.jsファイルが生成されます。
ここに追加したいテーブル構造を定義していきます。

'use strict';

module.exports = {
 up: (queryInterface, Sequelize) => {
   return queryInterface.createTable('Users', {
     id: {
       allowNull: false,
       autoIncrement: true,
       primaryKey: true,
       type: Sequelize.INTEGER
     },
     name: {
       type: Sequelize.STRING
     },
     email: {
       type: Sequelize.STRING
     },
     password: {
       type: Sequelize.STRING
     },
     createdAt: {
       allowNull: false,
       type: Sequelize.DATE
     },
     updatedAt: {
       allowNull: false,
       type: Sequelize.DATE
     }
   });
 },

 down: (queryInterface, Sequelize) => {
   return queryInterface.dropTable('Users');
 }
};

記載が完了したら、最後にマイグレーションを実行するだけです。

$ npx sequelize-cli db:migrate --env development

環境ごとに実行する場合は、--envオプションを指定して実行すれば各環境に反映できます。

Sequelizeを使用すると、一つ前のスキーマにロールバックすることも可能なため、柔軟に開発を進めることができます。
Sequelizeのコマンドの詳細については、公式ドキュメントをご確認ください。

これにより、Supabaseから開発用と本番用のPostgreSQLを構築し、マイグレーションやロールバックを実行することで、実際の運用に近い形での開発環境が整いました。

このように簡単に構築できる点はFirebaseとほぼ同じで、非常に便利ですね。
Supabaseは様々な機能を提供してくれるBaaSであり、DBの中身はただのPostgreSQLですので、RDBの経験がある方は簡単に開発を進めることができるでしょう。

それでは。

この記事が気に入ったらサポートをしてみませんか?