-
Notifications
You must be signed in to change notification settings - Fork 0
Description
期末テストが終わったらやりましょう。
やりたいこと
UserId
型とArticleId
型の定義- 既存の
User
型,Article
型のフィールドを Idの型と Dataの型に分ける User
やArticle
は Idの型と Dataの型をフィールドで持つようにするUserRepository
ArticleRepository
などのメソッドの型を変える
UserId
型と ArticleId
型の定義
現状、ユーザーのIdと記事のIdが同じく ObjectId
になっていて、型名からはどちらの Id
か判断できなくなっているので ObjectId
をラップする型として UserId
と ArticleId
型を定義したい。
↓イメージ
#[derive(Clone)]
pub struct UserId {
inner: ObjectId
}
UserId
, ArticleId
のSerialize
Deserialize
は derive
するのでなく、手書きで impl
することでシリアライズ結果は変わらないようにする。
↓イメージ
impl Serialize for UserId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.inner.serialize(serializer)
}
}
既存の User
型, Article
型のフィールドを Idの型と Dataの型に分ける。 User
や Article
は Idの型と Dataの型をフィールドで持つようにする
↓既存の User
型
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct User {
#[serde(rename = "_id")]
pub id: ObjectId,
pub name: UserName, // ユーザー名
pub display_name: String,
pub intro: String,
pub email: String,
pub show_email: bool,
pub pw_hash: Vec<u8>, // ハッシュ化されたパスワード
pub created_at: DateTime<Utc>
}
↓変更後のイメージ
#[derive(Clone, PartialEq, Eq)]
pub struct User {
id: UserId
data: UserData,
}
#[optfield(OptionalUserData)]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct UserData {
pub name: UserName, // ユーザー名
pub display_name: String,
pub intro: String,
pub email: String,
pub show_email: bool,
pub pw_hash: Vec<u8>, // ハッシュ化されたパスワード
pub created_at: DateTime<Utc>
}
新しい User
の Serialize
, Deserialize
も手書き impl
して、シリアライズ結果は変わらないようにしても良いと思うし、面倒くさければ普通に derive
しても良いと思う。
#[optfield(OptionalUserData)]
は optfieldクレート のフィールドを全て Option
でラップした型を作るマクロ。 OptionalUserData
の用途は後述。
UserData
という名前は微妙かも知れない。(Data
という言葉の意味が広すぎるような気もするので)
AritcleData
についての説明は、 UserData
と同様なので割愛。
UserRepository
ArticleRepository
などのメソッドの型を変える
現状の UserRepository
の .add_user
.update_user
の型
async fn add_user(&self, name: String, display_name: String, intro: String, email: String, show_email: bool, pw_hash: Vec<u8>) -> Result<User, UserServiceError>;
async fn update_user(&self, id: ObjectId, name: Option<String>, display_name: Option<String>, intro: Option<String>, email: Option<String>, show_email: Option<bool>, pw_hash: Option<Vec<u8>>) -> Result<User, UserServiceError>;
これを、こんな感じに変えたい(イメージ)。
async fn add_user(&self, data: UserData) -> Result<User, UserService>;
async fn update_user(&self, user_id: UserId, data: OptionalUserData) -> Result<User, UserServiceError>;
関数の引数の数が減ってシンプルになるし、抽象度が高くなる。
また現状だと、これらのメソッドは User
型を返しているが、データは手元にあるので User
型を返す必要はないかも。
こんな感じにしても良いかも知れない。
async fn add_user(&self, data: UserData) -> Result<UserId, UserService>;
async fn update_user(&self, user_id: UserId, data: OptionalUserData) -> Result<(), UserServiceError>;
ArticleRepository
などのトレイトのメソッドについても、同様なので割愛。