Supabase

Supabase で直接PostgreSQLを実行し、マイグレーション履歴を消去する

以前に「Supabase CLI」に関する記事を書きました。

Supabase CLI」には様々なコマンドがあり、手軽にDB操作ができます。
またデータベースも管理サイトから操作することもできますが、今回は「ターミナル」から操作する方法をまとめます。
といってもPostgresqlの操作する「psql」を使用するだけですが、実際にどこに何を接続すればいいかわかりません。
また今回の想定は開発の初期によく使うマイグレーションを初期化する処理を行います。
実際に自分がデータベース開発を行う際に、テーブル作成 → テーブル修正 → テーブル削除 → テーブル再構築と繰り返すことが多く
それをスクリプトで実行するようにしておりました。

0. 環境

  • Mac 15.5
  • – Homebrew 4.5.3
  • – psql (PostgreSQL) 14.18 (Homebrew)

1. PostgreSQLのインストール

まずは「brew」から「postgresql」をインストールして「psql」コマンドを実行しましょう。

brew install postgresql

以下のコマンドでインストールを確認する

psql --version

バージョンが表示されたらインストール完了となります。

psql (PostgreSQL) 14.18 (Homebrew)

2. psqlでリモート側のデータベースに接続する

接続情報の取得

それでは「psql」でリモート側のデータベースに接続しデータを取得します。
こちらの接続先の情報を管理画面から取得します。
管理画面の上部にある「Connect」ボタンから取得します。

接続情報のダイアログから「Session pooler」の部分にある「View parameters」を確認します。

接続情報は以下のような感じとなっているはずです。

ホスト名aws-0-ap-northeast-1.pooler.supabase.com
ポート番号5432
ユーザーIDpostgres.[PROJECT_id]
パスワード初期に設定したパスワード
データベース名postgres

こちらの情報を取っておきましょう

データベースの接続スクリプト

それでは接続確認するためのシェルスクリプトで「psql」で「users」テーブル一覧を取得するSQLを実行します。

#!/bin/bash

# .envファイルを読み込む (スクリプトと同じディレクトリにある想定)
if command -v dotenv &> /dev/null
then
    dotenv -f ./.env bash
else
    echo "dotenvコマンドが見つかりません。代わりに 'source ./.env' を使用します。"
    source ./.env
fi

# 取得したいテーブル名を設定
# .envファイルから読み込むようにすることも可能 (例: TABLE_NAME="users")
TARGET_TABLE="users"

echo "データを取得します..."

# PGPASSWORD環境変数を設定することで、パスワードを直接コマンドラインに書かずに済む
export PGPASSWORD="$DB_PASSWORD"

# SQLクエリを定義
SQL_QUERY="SELECT * FROM public.${TARGET_TABLE};"

echo "Connecting to $DB_HOST:$DB_PORT/$DB_NAME as user $DB_USER to fetch data from '${TARGET_TABLE}'..."

# 接続文字列に sslmode=require と gssencmode=disable を直接パラメータとして追加
# options='-c ...' は削除
psql "postgresql://${DB_USER}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=require&gssencmode=disable" -c "$SQL_QUERY"

# 環境変数をクリアする (セキュリティのため)
unset PGPASSWORD

echo "exit"

また上記のスクリプトは「.env」ファイルを読み込んで実行するため同じ階層に「.env」ファイルを作成してください。
接続情報は上記で取得した情報となります。

DB_HOST="aws-0-ap-northeast-1.pooler.supabase.com" # Supabaseのホスト名
DB_USER="postgres.[PROJECT_id]" # データベースユーザー名
DB_PASSWORD="初期に設定したパスワード" # データベースパスワード
DB_PORT="5432" # Supabaseのポート番号
DB_NAME="postgres" # データベース名

このスクリプトを実行します。

sh select_supabase.sh

以下のようにデータが取れたら成功となります。

Connecting to aws-0-ap-northeast-1.pooler.supabase.com:5432/postgres as user postgres.cdulkonuuachfbpcjqjd to fetch data from 'users'...
               user_id                |   name   |        email         |          created_at           |          updated_at           | deleted_at 
--------------------------------------+----------+----------------------+-------------------------------+-------------------------------+------------
 20a37792-e4b6-0fb2-ef2b-65804b4486db | Kikuchi  | sample-1@example.com | 2025-06-01 14:52:48.687468+00 | 2025-06-01 14:52:48.687468+00 | 
 5b20492c-8e2f-098f-048e-aefe82c9789a | Arai     | sample-2@example.com | 2025-06-01 14:52:48.687468+00 | 2025-06-01 14:52:48.687468+00 | 
 02dd7c37-2f2d-749f-57f7-b0a00c5513c6 | Yamamoto | sample-3@example.com | 2025-06-01 14:52:48.687468+00 | 2025-06-01 14:52:48.687468+00 | 
(3 rows)

これで「psql」で接続までが確認できました。

migration履歴の削除

冒頭で記述したように当初の目的は開発開始時にデータベースの設計と再構築を繰り返すため、一度マイグレーションを実行すると管理画面にアクセスせずにスクリプトで実行したいものでした。
この場合のスクリプトを記述します。

#!/bin/bash

# .envファイルを読み込む (スクリプトと同じディレクトリにある想定)
if command -v dotenv &> /dev/null
then
    dotenv -f ./.env bash
else
    echo "dotenvコマンドが見つかりません。代わりに 'source ./.env' を使用します。"
    source ./.env
fi

# 操作対象のテーブル名(今回は強制削除対象のテーブル)
TARGET_SCHEMA="supabase_migrations"
TARGET_TABLE="schema_migrations" # 強制削除するテーブル

# 実行前の確認メッセージ
echo "========================================================================"
echo "!!!!!! 警告: このスクリプトはリモートデータベースのマイグレーション履歴"
echo "!!!!!! '${TARGET_SCHEMA}.${TARGET_TABLE}' テーブルのデータを強制削除します。"
echo "!!!!!! これはデータベースの状態とCLIの履歴の間に不整合を引き起こす可能性があります。"
echo "!!!!!! 本番環境や重要な環境では絶対に実行しないでください。"
echo "========================================================================"
echo ""
echo "続行してよろしいでしょうか? (y/N):"
read -r CONFIRMATION

# ユーザーの入力をチェック
if [[ "$CONFIRMATION" =~ ^[yY]$ ]]; then
    echo "処理を開始します..."

    # PGPASSWORD環境変数を設定 (セキュリティのため)
    export PGPASSWORD="$DB_PASSWORD"

    # SSL接続を強制する (推奨)
    export PGSSLMODE="require"

    # 強制削除するSQLクエリ
    # TRUNCATE TABLE は高速で、RESTART IDENTITY CASCADE は関連シーケンスをリセットします。
    SQL_COMMAND="TRUNCATE TABLE ${TARGET_SCHEMA}.${TARGET_TABLE} RESTART IDENTITY CASCADE;"

    echo "Connecting to $DB_HOST:$DB_PORT/$DB_NAME as user $DB_USER to truncate '${TARGET_SCHEMA}.${TARGET_TABLE}'..."

    # psqlを実行してSQLクエリを実行
    # -X オプションを追加して、psqlのスタートアップファイルを読み込まないようにする (クリーンな実行のため)
    psql "postgresql://${DB_USER}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=require&gssencmode=disable" \
         -X \
         -c "$SQL_COMMAND"

    # 環境変数をクリアする (セキュリティのため)
    unset PGPASSWORD
    unset PGSSLMODE

    # supabaseのテーブルを再構築
    supabase db push

    echo "スクリプトが完了しました。'${TARGET_SCHEMA}.${TARGET_TABLE}' のデータが削除されました。"
else
    echo "実行をキャンセルしました。"
fi

これはマイグレーション履歴を削除し、さらに「supabase db push」によりSQL内にDROPとCREATEと同時に行うようになっております。
これで「ERFlute」で作成したDDLと組み合わせてデータベース設計のやり直しが短絡化できます。

もちろん開発がある程度進んだ段階では、この処理は行わずあくまで開発初期段階のものとなります。
これでいちいち画面にアクセスせずにすみました。