refactor: remaining MEDIUM — CQRS splits, DI Deps, profile dedup, event Value, response enum

M1: MovieRepository→MovieCommand/MovieQuery, WatchEventRepository→
WatchEventCommand/WatchEventQuery
M2: goals/ and import/ use Deps structs
M7: extract upload_image helper in update_profile
M8: FederationDeliveryRequested activity_json String→serde_json::Value
M11: UserProfileResponse uses ProfileViewData enum
This commit is contained in:
2026-07-10 03:50:43 +02:00
parent 12da356a40
commit dee013c7eb
99 changed files with 1262 additions and 896 deletions

View File

@@ -18,8 +18,9 @@ use crate::{
},
ports::{
GoalRepository, ImportProfileRepository, ImportSessionRepository, MovieProfileRepository,
MovieRepository, RefreshSessionRepository, ReviewRepository, UserFederationSettingsQuery,
UserProfileFieldsRepository, UserRepository, UserSettingsRepository, WatchEventRepository,
MovieCommand, MovieQuery, RefreshSessionRepository, ReviewRepository,
UserFederationSettingsQuery, UserProfileFieldsRepository, UserRepository,
UserSettingsRepository, WatchEventCommand, WatchEventQuery,
WatchlistRepository, WebhookTokenRepository,
},
value_objects::{
@@ -47,7 +48,23 @@ impl InMemoryMovieRepository {
}
#[async_trait]
impl MovieRepository for InMemoryMovieRepository {
impl MovieCommand for InMemoryMovieRepository {
async fn upsert_movie(&self, movie: &Movie) -> Result<(), DomainError> {
self.store
.lock()
.unwrap()
.insert(movie.id().value(), movie.clone());
Ok(())
}
async fn delete_movie(&self, movie_id: &MovieId) -> Result<(), DomainError> {
self.store.lock().unwrap().remove(&movie_id.value());
Ok(())
}
}
#[async_trait]
impl MovieQuery for InMemoryMovieRepository {
async fn get_movie_by_external_id(
&self,
external_metadata_id: &ExternalMetadataId,
@@ -80,19 +97,6 @@ impl MovieRepository for InMemoryMovieRepository {
.collect())
}
async fn upsert_movie(&self, movie: &Movie) -> Result<(), DomainError> {
self.store
.lock()
.unwrap()
.insert(movie.id().value(), movie.clone());
Ok(())
}
async fn delete_movie(&self, movie_id: &MovieId) -> Result<(), DomainError> {
self.store.lock().unwrap().remove(&movie_id.value());
Ok(())
}
async fn existing_external_ids(
&self,
ids: &[ExternalMetadataId],
@@ -526,7 +530,7 @@ impl InMemoryWatchEventRepository {
}
#[async_trait]
impl WatchEventRepository for InMemoryWatchEventRepository {
impl WatchEventCommand for InMemoryWatchEventRepository {
async fn save(&self, event: &WatchEvent) -> Result<(), DomainError> {
self.store.lock().unwrap().push(event.clone());
Ok(())
@@ -540,6 +544,27 @@ impl WatchEventRepository for InMemoryWatchEventRepository {
Ok(())
}
async fn update_status_batch(
&self,
ids: &[WatchEventId],
_status: WatchEventStatus,
) -> Result<u64, DomainError> {
Ok(ids.len() as u64)
}
async fn delete_non_pending_older_than(
&self,
before: NaiveDateTime,
) -> Result<u64, DomainError> {
let mut store = self.store.lock().unwrap();
let before_len = store.len();
store.retain(|e| *e.status() == WatchEventStatus::Pending || *e.created_at() >= before);
Ok((before_len - store.len()) as u64)
}
}
#[async_trait]
impl WatchEventQuery for InMemoryWatchEventRepository {
async fn list_pending(&self, user_id: &UserId) -> Result<Vec<WatchEvent>, DomainError> {
let store = self.store.lock().unwrap();
Ok(store
@@ -566,14 +591,6 @@ impl WatchEventRepository for InMemoryWatchEventRepository {
.collect())
}
async fn update_status_batch(
&self,
ids: &[WatchEventId],
_status: WatchEventStatus,
) -> Result<u64, DomainError> {
Ok(ids.len() as u64)
}
async fn find_duplicate(
&self,
user_id: &UserId,
@@ -588,15 +605,6 @@ impl WatchEventRepository for InMemoryWatchEventRepository {
}))
}
async fn delete_non_pending_older_than(
&self,
before: NaiveDateTime,
) -> Result<u64, DomainError> {
let mut store = self.store.lock().unwrap();
let before_len = store.len();
store.retain(|e| *e.status() == WatchEventStatus::Pending || *e.created_at() >= before);
Ok((before_len - store.len()) as u64)
}
}
// ── InMemoryImportSessionRepository ─────────────────────────────────────────

View File

@@ -371,44 +371,56 @@ impl crate::ports::FederatedProfileQuery for PanicFederatedProfileQuery {
}
}
pub struct PanicWatchEventRepository;
pub struct PanicWatchEventCommand;
#[async_trait]
impl crate::ports::WatchEventRepository for PanicWatchEventRepository {
impl crate::ports::WatchEventCommand for PanicWatchEventCommand {
async fn save(&self, _: &crate::models::WatchEvent) -> Result<(), DomainError> {
panic!("PanicWatchEventRepository called")
panic!("PanicWatchEventCommand called")
}
async fn update_status(
&self,
_: &crate::value_objects::WatchEventId,
_: crate::models::WatchEventStatus,
) -> Result<(), DomainError> {
panic!("PanicWatchEventRepository called")
}
async fn list_pending(
&self,
_: &UserId,
) -> Result<Vec<crate::models::WatchEvent>, DomainError> {
panic!("PanicWatchEventRepository called")
}
async fn get_by_id(
&self,
_: &crate::value_objects::WatchEventId,
) -> Result<Option<crate::models::WatchEvent>, DomainError> {
panic!("PanicWatchEventRepository called")
}
async fn get_by_ids(
&self,
_: &[crate::value_objects::WatchEventId],
) -> Result<Vec<crate::models::WatchEvent>, DomainError> {
panic!("PanicWatchEventRepository called")
panic!("PanicWatchEventCommand called")
}
async fn update_status_batch(
&self,
_: &[crate::value_objects::WatchEventId],
_: crate::models::WatchEventStatus,
) -> Result<u64, DomainError> {
panic!("PanicWatchEventRepository called")
panic!("PanicWatchEventCommand called")
}
async fn delete_non_pending_older_than(
&self,
_: chrono::NaiveDateTime,
) -> Result<u64, DomainError> {
panic!("PanicWatchEventCommand called")
}
}
pub struct PanicWatchEventQuery;
#[async_trait]
impl crate::ports::WatchEventQuery for PanicWatchEventQuery {
async fn list_pending(
&self,
_: &UserId,
) -> Result<Vec<crate::models::WatchEvent>, DomainError> {
panic!("PanicWatchEventQuery called")
}
async fn get_by_id(
&self,
_: &crate::value_objects::WatchEventId,
) -> Result<Option<crate::models::WatchEvent>, DomainError> {
panic!("PanicWatchEventQuery called")
}
async fn get_by_ids(
&self,
_: &[crate::value_objects::WatchEventId],
) -> Result<Vec<crate::models::WatchEvent>, DomainError> {
panic!("PanicWatchEventQuery called")
}
async fn find_duplicate(
&self,
@@ -416,13 +428,7 @@ impl crate::ports::WatchEventRepository for PanicWatchEventRepository {
_: &str,
_: chrono::NaiveDateTime,
) -> Result<bool, DomainError> {
panic!("PanicWatchEventRepository called")
}
async fn delete_non_pending_older_than(
&self,
_: chrono::NaiveDateTime,
) -> Result<u64, DomainError> {
panic!("PanicWatchEventRepository called")
panic!("PanicWatchEventQuery called")
}
}