Closed9

Rustの新しいORM「SeaORM」を試す

yukiyuki

Rust ではながらく ORM としては Diesel しか選択肢がなかったが、async 対応がまだなど少し課題を抱えていた。最近になって新しく ORM が登場してきて、選択肢が増えた。それを触ってみる。

https://github.com/SeaQL/sea-orm

yukiyuki

Diesel はコンパイルタイムでできる限りのことを解決するスタイルで、SeaORM はランタイムで解決する方に倒している感じらしい。静的 vs 動的、な違いがあるみたい。動的側に倒すとパフォーマンスは多少劣化するが、型解決が楽になるなどのメリットがいくつかある。「使いやすい方」に倒しているライブラリだと思われる。

https://www.sea-ql.org/SeaORM/docs/internal-design/diesel

yukiyuki

ようやくMySQLに接続できた。下記のようなサンプルの MySQL サーバーを立てて起動してみたところ、接続できたらしい。

use sea_orm::Database;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = Database::connect("mysql://user:password@localhost:3306/test").await?;
    Ok(())
}

docker-compose の設定。

version: "3.9"

services:
  db:
    image: mysql:5.7
    volumes:
      - ./db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    command: mysqld --explicit_defaults_for_timestamp
    ports:
      - 3306:3306
volumes:
  db_data: {}
yukiyuki

うーん、なんか期待していろいろ書いてみてるけど、正直 Diesel の方が100倍くらいわかりやすいかな。。。

Slick に近い。Slick を思い出してだいぶ厳しい気持ちになっている。

yukiyuki

まず軽くエンティティを用意しようと思っただけなのに、ボイラープレートがここまで発生する。

use sea_orm::entity::prelude::*;

#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;

impl EntityName for Entity {
    fn table_name(&self) -> &str {
        "room"
    }
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
    Id,
    Name,
}

#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
    Id,
}

impl PrimaryKeyTrait for PrimaryKey {
    type ValueType = String;

    fn auto_increment() -> bool {
        false
    }
}

impl ColumnTrait for Column {
    type EntityName = Entity;

    fn def(&self) -> ColumnDef {
        match self {
            Self::Id => ColumnType::Integer.def(),
            Self::Name => ColumnType::String(None).def(),
        }
    }
}

#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
pub struct Model {
    #[sea_orm(primary_key)]
    pub id: String,
    pub name: String,
}

impl ActiveModelBehavior for ActiveModel {}

欲しいのは、単に下記の構造体に対応するテーブルなだけなんだけど。今のところリレーションは不要だし、単に find_by_id したいだけなのに、ここまでのボイラープレートが求められてしまうとちょっと…

pub struct Room {
    id: String, // これがプライマリキー
    name: String
}
yukiyuki

エンティティのボイラープレート生成がなんとかなればあとは普通の ORM なので、そうした ORM 的なよさを期待して使うのはよさそうな気はする。デフォルトで async/await 対応しているし。

Billy ChanBilly Chan

Hi Yuki, thank you for trying our library. I'm one of the core member in sea-orm. Just to let you know that we have introduced the compact entity format which greatly reduce the amount of boilerplate codes.

Demo: compact format vs expanded format
For more details please check the documentation.

yukiyuki

Hi, thank you for your comment! I missed the demo. I'll check it.

このスクラップは2021/10/11にクローズされました