Rust Disel DBのデフォルト値を使いつつ、model bindと共存する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

fetch処理前提

例えば、select * from ...と全カラム取得する場合、bindするmodelの定義は

#[derive(Debug, Clone, Queryable, Identifiable)]
pub struct Account {
    pub id: String,
    pub name: String,
    pub email: String,
    pub password: String,
    pub avatar: String,
    pub created_at: NaiveDateTime,
    pub updated_at: NaiveDateTime,
}

のようにQueryableを指定して、dslに定義された全カラムのフィールド定義が必要。で、この時、insert時はcreated_atなんかをDBに定義したdefault値を使用したい。なんてケース。


insert用のモデルとfetch用のモデルを分ける

insert用のモデルとfetch用のモデルを分けるのが楽。

#[derive(Debug, Clone, Queryable, Identifiable)]
pub struct Account {
    pub id: String,
    pub name: String,
    pub email: String,
    pub password: String,
    pub avatar: String,
    pub created_at: NaiveDateTime,
    pub updated_at: NaiveDateTime,
}

#[derive(Default, Debug, Clone, Insertable)]
#[table_name = "accounts"]
pub struct NewAccount {
  pub id: String,
  pub name: String,
  pub email: String,
  pub password: String,
  pub avatar: String,
}

NewAccountはどのテーブルへのInsertableかがわからないので、#[table_name = "accounts"]を指定します。

これで単純に使い分けを行えばよい。


insert
let new_account = NewAccount{ ... };
insert_into(dsl::accounts)
    .values(account)
    .returning(dsl::id)
    .get_result(&conn)


fetch
dsl::accounts
    .filter(dsl::email.eq(email))
    .load::<Account>(&conn)


loadメソッドのNone時のassert確認

少しハマったので記録しておきます。

loadメソッドはQueryResult<Vec<T>>型が返されるんだけど、not found resultのテスト時に

assert_eq!( result.unwrap().first(), None );

とは書けなくて、

assert!( result.unwrap().first().is_none() );

と書くことで確認できる。