refactor(ports): CQRS split — UserRepository = UserReader + UserWriter supertrait
This commit is contained in:
@@ -45,10 +45,16 @@ pub trait EventConsumer: Send + Sync {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserRepository: Send + Sync {
|
||||
pub trait UserReader: Send + Sync {
|
||||
async fn find_by_id(&self, id: &UserId) -> Result<Option<User>, DomainError>;
|
||||
async fn find_by_username(&self, username: &Username) -> Result<Option<User>, DomainError>;
|
||||
async fn find_by_email(&self, email: &Email) -> Result<Option<User>, DomainError>;
|
||||
async fn list_with_stats(&self) -> Result<Vec<UserSummary>, DomainError>;
|
||||
async fn count(&self) -> Result<i64, DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserWriter: Send + Sync {
|
||||
async fn save(&self, user: &User) -> Result<(), DomainError>;
|
||||
async fn update_profile(
|
||||
&self,
|
||||
@@ -59,10 +65,13 @@ pub trait UserRepository: Send + Sync {
|
||||
header_url: Option<String>,
|
||||
custom_css: Option<String>,
|
||||
) -> Result<(), DomainError>;
|
||||
async fn list_with_stats(&self) -> Result<Vec<UserSummary>, DomainError>;
|
||||
async fn count(&self) -> Result<i64, DomainError>;
|
||||
}
|
||||
|
||||
/// Combined supertrait — `AppState.users` stays `Arc<dyn UserRepository>`.
|
||||
/// Blanket impl: any type implementing both sub-traits gets `UserRepository` for free.
|
||||
pub trait UserRepository: UserReader + UserWriter {}
|
||||
impl<T: UserReader + UserWriter> UserRepository for T {}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ThoughtRepository: Send + Sync {
|
||||
async fn save(&self, thought: &Thought) -> Result<(), DomainError>;
|
||||
|
||||
@@ -45,7 +45,7 @@ pub struct TestStore {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UserRepository for TestStore {
|
||||
impl UserReader for TestStore {
|
||||
async fn find_by_id(&self, id: &UserId) -> Result<Option<User>, DomainError> {
|
||||
Ok(self
|
||||
.users
|
||||
@@ -73,6 +73,22 @@ impl UserRepository for TestStore {
|
||||
.find(|u| u.email.as_str() == email.as_str())
|
||||
.cloned())
|
||||
}
|
||||
async fn list_with_stats(&self) -> Result<Vec<UserSummary>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn count(&self) -> Result<i64, DomainError> {
|
||||
Ok(self
|
||||
.users
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|u| u.local)
|
||||
.count() as i64)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UserWriter for TestStore {
|
||||
async fn save(&self, user: &User) -> Result<(), DomainError> {
|
||||
let mut g = self.users.lock().unwrap();
|
||||
g.retain(|u| u.id != user.id);
|
||||
@@ -103,18 +119,6 @@ impl UserRepository for TestStore {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn list_with_stats(&self) -> Result<Vec<UserSummary>, DomainError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
async fn count(&self) -> Result<i64, DomainError> {
|
||||
Ok(self
|
||||
.users
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|u| u.local)
|
||||
.count() as i64)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
Reference in New Issue
Block a user