🫰

RustからSupabase上のDBにアクセスする方法

2025/03/03に公開

こんにちは。カズマです。
ほぼ自分用のメモですが、共有させて頂きます。

SupabaseのデータベースをRustから利用するための手順を説明します。
最初にSupabaseでテーブルを作成し、次にRustからそのテーブルにアクセスする方法を見ていきましょう。

1. Supabaseの設定

Supabaseプロジェクトの作成

  1. Supabaseにアクセスし、アカウント作成・ログイン
  2. 「New Project」をクリックして新しいプロジェクトを作成
  3. プロジェクト名、パスワード、リージョンを設定して「Create new project」

テーブルの作成

  1. Supabaseダッシュボードで「Table Editor」に移動
  2. 「Create a new table」をクリック
  3. テーブル名とカラムを設定します(例:postsテーブル):
    • id: uuid, primary key
    • title: text, not null
    • content: text
    • created_at: timestamptz, default: now()
  4. 「Save」をクリックしてテーブルを作成

接続情報の取得

  1. ダッシュボードの「Connect」タブを開く
  2. 「Direct Connection」のURLをメモ

2. Rustプロジェクトのセットアップ

新しいプロジェクトの作成

cargo new supabase-test
cd supabase-test

必要なクレートの追加

Cargo.tomlに以下を追加:

[dependencies]
tokio = { version = "1", features = ["full"] }
sqlx = { version = "0.7", features = [
    "runtime-tokio-rustls",
    "postgres",
    "time",
    "uuid",
    "chrono",
] } # chrono機能を追加
serde = { version = "1", features = ["derive"] }
serde_json = "1"
dotenv = "0.15"
uuid = { version = "1.3", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }

環境変数ファイルの作成

プロジェクトルートに.envファイルを作成:

DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.[YOUR-PROJECT-ID].supabase.co:5432/postgres"

※Supabaseの接続文字列URIをコピーして貼り付けます。

3. Rustコードの実装

src/main.rsに以下のコードを実装します:

use serde::{Deserialize, Serialize};
use sqlx::{postgres::PgPoolOptions, FromRow};
use uuid::Uuid;

#[derive(Debug, Serialize, Deserialize, FromRow)]
struct Post {
    id: Uuid,
    title: String,
    content: Option<String>,
    created_at: Option<chrono::DateTime<chrono::Utc>>,
}

#[derive(Debug, Serialize, Deserialize)]
struct NewPost {
    title: String,
    content: Option<String>,
}

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // 環境変数の読み込み
    dotenv::dotenv().ok();
    let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    
    // データベース接続プールの作成
    let pool = PgPoolOptions::new()
        .max_connections(5)
        .connect(&database_url)
        .await?;
    
    println!("Connected to Supabase PostgreSQL!");
    
    // 新しい投稿の追加
    let new_post = NewPost {
        title: "Hello from Rust".to_string(),
        content: Some("This is my first post from Rust to Supabase!".to_string()),
    };
    
    let post = sqlx::query_as::<_, Post>(
        "INSERT INTO posts (title, content) VALUES ($1, $2) RETURNING id, title, content, created_at"
    )
    .bind(&new_post.title)
    .bind(&new_post.content)
    .fetch_one(&pool)
    .await?;
    
    println!("Created post: {:?}", post);
    
    // 全ての投稿を取得
    let posts = sqlx::query_as::<_, Post>("SELECT id, title, content, created_at FROM posts")
        .fetch_all(&pool)
        .await?;
    
    println!("All posts:");
    for post in posts {
        println!("- {:?}", post);
    }
    
    Ok(())
}

4. 実行とテスト

cargo run

無事にSupabaseに接続してデータを格納/参照することができました。

このコードを実行すると:

  1. Supabaseのデータベースに接続
  2. 新しい投稿をテーブルに追加
  3. すべての投稿を取得して表示

トラブルシューティング

  1. 接続エラー: Supabaseのファイアウォール設定を確認してください。デフォルトでは、すべてのIPからの接続が許可されています。

  2. 認証エラー: パスワードが正しいことを確認してください。また、Supabaseのダッシュボードで「Database」→「Connection Pooling」がオンになっているか確認してください。

  3. SQLxの準備エラー: クエリが正しいことを確認してください。Supabaseはデフォルトでcreated_atのようなタイムスタンプ列を自動的に追加します。

Discussion