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

なお、今回紹介するソースコードはこちらにあります。
また、RustのデスクトップアプリライブラリであるTauriで簡単なTodoアプリ作成を記事にしています。
【Tauri入門】Next.js × Tauriで軽量デスクトップアプリ開発を始めよう – Todoアプリを作る①

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

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(())
}