Rust×SeaORMで学ぶORM入門:セットアップと基本操作を解説

Rust

はじめに

今回は、Rustの人気ORMパッケージであるSeaORMをインストールから、簡単なデータベース操作までを解説します。

SeaORM 🐚 An async & dynamic ORM for Rust
🐚 SeaORM is a relational ORM to help you build web services in Rust

なお、今回紹介するソースコードはこちらにあります。

sample-project/seaorm-sample at main · tkwest3143/sample-project
Contribute to tkwest3143/sample-project development by creating an account on GitHub.

また、RustのデスクトップアプリライブラリであるTauriで簡単なTodoアプリ作成を記事にしています。

【Tauri入門】Next.js × Tauriで軽量デスクトップアプリ開発を始めよう – Todoアプリを作る①

Tauri×Next.jsでのTodoアプリ作成
「Tauri×Next.jsでのTodoアプリ作成」の記事一覧です。

インストール方法

こちらを元にインストールを行なっていきます。

Database & Async Runtime | SeaORM 🐚 An async & dynamic ORM for Rust
Thank you for using SeaORM. Please star our GitHub repo! Your support is vital to the continued deve...

Cargo.tomlにパッケージを追加する

まずは、Cargo.tomlの[dependencies]の下に、こちらを追加します。

sea-orm = { version = "1.1.0", features = [ "sqlx-sqlite", "runtime-async-std-native-tls", "macros" ] }

今回は、SQLiteを使用するため、featuresに”sqlx-sqlite”を設定しています。

その他、使用するDBのドライバーに沿ったものを記載します。

設定値 使用するDB
Msqlx-mysql MySQL と MariaDB
sqlx-postgres PostgreSQL
sqlx-sqlite SQLite

また、”runtime-async-std-native-tls”には他に設定する値として、設定する項目はこの2つを選んで設定します。

  • 非同期ランタイム(ASYNC_RUNTIME)
    → Rustの非同期処理を支える仕組み
  • TLSライブラリ(TLS_LIB)
    → HTTPSなどの安全な通信を行うための仕組み

これらを組み合わせた形式(runtime-ASYNC_RUNTIME-TLS_LIB)で設定します。

なお、設定については下記の4点が設定できます。

設定値 説明
runtime-async-std-native-tls `async-std`ランタイム + OS依存のTLS
runtime-tokio-native-tls `tokio`ランタイム + OS依存のTLS
runtime-async-std-rustls `async-std`ランタイム + Rust実装のTLS
runtime-tokio-rustls `tokio`ランタイム + Rust実装のTLS

データベースのエンティティを作成する

新しく、データベースを作成します。

まずは、sea-orm-cliをインストールします。

cargo install sea-orm-cli@1.1.0

次に、初期化処理を行います。

sea-orm-cli migrate init

このコマンドを実行すると、migrationディレクトリが作成され、バージョンアップなどでテーブルが増えたり、カラムが変更されたりしても、マイグレーションを行うことができます。

migration/srcディレクトリ配下にm20220101_000001_create_table.rsのファイルが作成されて今。

このファイルでは、テーブルの定義ファイルでサンプルとしてPostテーブルを作成しており、カラムについても定義されています。

migration/Cargo.tomlに使用するドライバなどを記載する

次に、インストール時に追加した、使用するドライバとランタイムの設定を追加します。


[dependencies.sea-orm-migration]
version = "1.1.0"
features = [
  "sqlx-sqlite", "runtime-tokio-rustls",
]

 実際にデータベースを作成

今回は、sqliteを使っていますので、データベースファイルを作成します。

まずは、rustプロジェクトのルートディレクトリに.envファイルを作成し、DATABASE_URLを記載します。

DATABASE_URL="sqlite://db.sqlite?mode=rwc"

次は、migrateコマンドで実際にデータベースを作成しましょう。

sea-orm-cli migrate refresh

このコマンドを実行するとプロジェクトルート/db.sqliteが作成されます。

エンティティファイル作成

最後に、プロジェクトで使うためにエンティティファイルを作成します。

sea-orm-cli generate entity -o src/entities

なお、-oのオプションは、エンティティファイルを作成するディレクトリを指定します。
作成された、post.rsが実際にmigrationで定義したテーブル定義のエンティティファイルが作成されています。

データベースの読み書きを行う

これで、データベースを扱う準備が整いました。

では、実際にデータベースの読み書きを行なっていきます。

データベースに接続する

まず、データベースに接続します。

let db: DatabaseConnection = Database::connect("sqlite://db.sqlite?mode=rwc").await?;

その他のデータベースでは下記のようになります。

MySQL

let db: DatabaseConnection = Database::connect("mysql://username:password@host/database").await?;

PostgreSQL

let db: DatabaseConnection = Database::connect("postgres://username:password@host/database?currentSchema=my_schema").await?;

SQLite

メモリに保存する

let db: DatabaseConnection = Database::connect("sqlite::memory:").await?;

読み取り専用のデータベースとして使用する

let db: DatabaseConnection = Database::connect("sqlite://path/to/db.sqlite?mode=ro").await?;

 読み書きしてみる

今回は、非同期処理があるので、cargo.tomlにasync-std = { version = "1.12", features = ["attributes"] }を追加して非同期処理ができるようにしました。

use sea_orm::{Database, DatabaseConnection, EntityTrait};

pub mod entities;
fn main() {
    async_std::task::block_on(async {
        if let Err(e) = db_connection().await {
            eprintln!("DB error: {:?}", e);
        }
    });
}
async fn db_connection() -> Result<(), sea_orm::DbErr> {
    let db: DatabaseConnection = Database::connect("sqlite://db.sqlite?mode=rwc").await?;
    // 新しい投稿データを作成(titleとtextをセット、他のフィールドはデフォルト値)
    let data = entities::post::ActiveModel {
    title: sea_orm::ActiveValue::Set("Sample Title".to_owned()),
    text: sea_orm::ActiveValue::Set("Sample text content".to_owned()),
      ..Default::default()
    };
    // データベースに投稿を挿入
    entities::post::Entity::insert(data).exec(&db).await?;
    // 投稿テーブルから1件だけ取得
    let cheese: Option = entities::post::Entity::find().one(&db).await?;
    if let Some(post) = cheese {
        println!("Post found: {:?}", post);
    } else {
        println!("No post found.");
    }
    Ok(())
}
タイトルとURLをコピーしました