🦀

[Rust]SeaORMを利用したRepositoryでのasyncの取り扱い

2023/01/14に公開

webシステムでDDD設計を採用してRepositoryクラスを作る場合、interfaceと実際の処理は分離するのが一般的です。

interface Hoge {
  find();
}

class HogeImpl implements Hoge {
  find() {
    // something
  }
}

これは言語を超えた基本的な考え型です。

しかし、現在のversionのrustではinterfaceに該当するtraitでasyncが定義できません。

なので、Sea-ORMをライブラリとして利用していると、traitと実際の処理が分離できません

なので、とるべき選択は

  • async-traitライブラリの利用
  • traitを使わない

になります。

設計に関する思想は色々な意見があると思いますが、私は

traitを使わない

というのがrustを利用する場合にはbetterな選択だと思います。

実際、Sea-ORMのexampleを見ると、async-traitは利用しないで、シンプルに処理を実装しています。

アークテクチャー原理主義の人だと気持ち悪く感じると思いますが、現在のrustのエコシステムだと、traitではasyncを使わないのが正しい選択になります。

なのでRepositoryのサンプルのコードを書くと以下のようになります。

infrastructures/repositories/users.rs
use sea_orm::{DatabaseConnection, EntityTrait, DbErr, QueryFilter, ColumnTrait};
use sea_orm::*;
use ::entity::{users, users::Entity as Users};

pub struct UsersRepository {
    pub con: DatabaseConnection,
}

impl UsersRepository {
    pub async fn find_by_id(&self, user_id: i32) -> Result<Option<users::Model>, DbErr> {
        return Users::find_by_id(user_id).one(&self.con).await;
    }

    pub async fn find_by_uuid(&self, uuid: &str) -> Result<Option<users::Model>, DbErr> {
        return Users::find().filter(users::Column::Uuid.eq(uuid)).one(&self.con).await;
    }

    pub async fn create(&self, form_data: users::Model,) -> Result<users::ActiveModel, DbErr> {
        users::ActiveModel {
          uuid: Set(form_data.uuid.to_owned()),
          ..Default::default()
        }
        .save(&self.con)
        .await
    }
}

conも参照で引数で渡したしたほうがよりbetterだと思いますが、この辺は好みでよいのではないでしょうか。

参考になれば。

お知らせ

web3利用者、開発者のためのdiscordをopenする予定です。
開発者でない、web3に興味があるだけの初心者でもOKです。
準備ができたらお知らせするので、ぜひご参加ください。

Discussion