-
Notifications
You must be signed in to change notification settings - Fork 0
Description
期末テストが終わったらやりましょう。
やりたいこと
UserId型とArticleId型の定義- 既存の
User型,Article型のフィールドを Idの型と Dataの型に分ける UserやArticleは Idの型と Dataの型をフィールドで持つようにするUserRepositoryArticleRepositoryなどのメソッドの型を変える
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 などのトレイトのメソッドについても、同様なので割愛。