refactor(ports): CQRS split — UserRepository = UserReader + UserWriter supertrait

This commit is contained in:
2026-05-15 13:43:43 +02:00
parent a902154777
commit 8ed7f3d5bc
17 changed files with 113 additions and 97 deletions

View File

@@ -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>;