🦀
[Rust]SeaORMを利用したRepositoryでのasyncの取り扱い
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