From 1e62f1290386a8f3719c2dedebaf9b4263b2e14f Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Thu, 11 Jun 2026 22:13:25 +0200 Subject: [PATCH] refactor(movies): EnrichMovieDeps, ReindexSearchDeps, SyncPosterDeps, SearchReindexHandler, EnrichmentStalenessJob --- .../tmdb-enrichment/src/movie_handler.rs | 22 ++++++---- .../src/jobs/enrichment_staleness.rs | 26 ++++++++---- crates/application/src/movies/deps.rs | 39 ++++++++++++++++++ crates/application/src/movies/enrich_movie.rs | 22 ++++------ .../src/movies/get_movie_profile.rs | 6 +-- crates/application/src/movies/get_movies.rs | 6 +-- crates/application/src/movies/mod.rs | 1 + .../application/src/movies/reindex_search.rs | 40 ++++++++---------- crates/application/src/movies/sync_poster.rs | 26 +++++------- .../src/movies/tests/enrich_movie.rs | 30 ++++++++------ .../src/movies/tests/get_movie_profile.rs | 20 +++++---- .../src/movies/tests/get_movies.rs | 13 +++--- .../src/movies/tests/sync_poster.rs | 41 +++++++++++++------ crates/presentation/src/handlers/movies.rs | 34 +++++++++++++-- crates/worker/src/main.rs | 23 +++++++++-- 15 files changed, 224 insertions(+), 125 deletions(-) create mode 100644 crates/application/src/movies/deps.rs diff --git a/crates/adapters/tmdb-enrichment/src/movie_handler.rs b/crates/adapters/tmdb-enrichment/src/movie_handler.rs index b90f795..8484431 100644 --- a/crates/adapters/tmdb-enrichment/src/movie_handler.rs +++ b/crates/adapters/tmdb-enrichment/src/movie_handler.rs @@ -1,6 +1,11 @@ use std::sync::Arc; -use application::movies::{commands::EnrichMovieCommand, enrich_movie, request_enrichment}; +use application::movies::{ + commands::EnrichMovieCommand, + deps::EnrichMovieDeps, + enrich_movie, + request_enrichment, +}; use async_trait::async_trait; use domain::{ errors::DomainError, @@ -89,13 +94,12 @@ impl EventHandler for MovieEnrichmentHandler { }; self.download_cast_photos(&profile).await; - enrich_movie::execute( - &self.movie_repository, - &self.profile_repo, - &self.person_command, - &self.search_command, - EnrichMovieCommand { movie_id, profile }, - ) - .await + let enrich_deps = EnrichMovieDeps { + movie: self.movie_repository.clone(), + movie_profile: self.profile_repo.clone(), + person_command: self.person_command.clone(), + search_command: self.search_command.clone(), + }; + enrich_movie::execute(&enrich_deps, EnrichMovieCommand { movie_id, profile }).await } } diff --git a/crates/application/src/jobs/enrichment_staleness.rs b/crates/application/src/jobs/enrichment_staleness.rs index c7cc8ef..27e0029 100644 --- a/crates/application/src/jobs/enrichment_staleness.rs +++ b/crates/application/src/jobs/enrichment_staleness.rs @@ -1,17 +1,27 @@ +use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; -use domain::{errors::DomainError, events::DomainEvent, ports::PeriodicJob}; - -use crate::context::AppContext; +use domain::{ + errors::DomainError, + events::DomainEvent, + ports::{EventPublisher, MovieProfileRepository, PeriodicJob}, +}; pub struct EnrichmentStalenessJob { - ctx: AppContext, + movie_profile: Arc, + event_publisher: Arc, } impl EnrichmentStalenessJob { - pub fn new(ctx: AppContext) -> Self { - Self { ctx } + pub fn new( + movie_profile: Arc, + event_publisher: Arc, + ) -> Self { + Self { + movie_profile, + event_publisher, + } } } @@ -22,7 +32,7 @@ impl PeriodicJob for EnrichmentStalenessJob { } async fn run(&self) -> Result<(), DomainError> { - let stale = self.ctx.repos.movie_profile.list_stale().await?; + let stale = self.movie_profile.list_stale().await?; if stale.is_empty() { return Ok(()); } @@ -32,7 +42,7 @@ impl PeriodicJob for EnrichmentStalenessJob { movie_id, external_metadata_id, }; - self.ctx.services.event_publisher.publish(&event).await?; + self.event_publisher.publish(&event).await?; } Ok(()) } diff --git a/crates/application/src/movies/deps.rs b/crates/application/src/movies/deps.rs new file mode 100644 index 0000000..46b96b0 --- /dev/null +++ b/crates/application/src/movies/deps.rs @@ -0,0 +1,39 @@ +use std::sync::Arc; + +use domain::ports::{ + EventPublisher, MetadataClient, MovieProfileRepository, MovieRepository, ObjectStorage, + PersonCommand, PersonQuery, PosterFetcherClient, SearchCommand, +}; + +pub struct GetMoviesDeps { + pub movie: Arc, +} + +pub struct GetMovieProfileDeps { + pub movie_profile: Arc, +} + +pub struct SyncPosterDeps { + pub movie: Arc, + pub movie_profile: Arc, + pub metadata: Arc, + pub poster_fetcher: Arc, + pub object_storage: Arc, + pub event_publisher: Arc, + pub search_command: Arc, +} + +pub struct EnrichMovieDeps { + pub movie: Arc, + pub movie_profile: Arc, + pub person_command: Arc, + pub search_command: Arc, +} + +pub struct ReindexSearchDeps { + pub movie: Arc, + pub movie_profile: Arc, + pub search_command: Arc, + pub person_command: Arc, + pub person_query: Arc, +} diff --git a/crates/application/src/movies/enrich_movie.rs b/crates/application/src/movies/enrich_movie.rs index 71eb5f9..888a67a 100644 --- a/crates/application/src/movies/enrich_movie.rs +++ b/crates/application/src/movies/enrich_movie.rs @@ -1,38 +1,30 @@ use std::collections::HashMap; -use std::sync::Arc; use domain::{ errors::DomainError, models::{CastMember, CrewMember, ExternalPersonId, IndexableDocument, Person, PersonId}, - ports::{MovieProfileRepository, MovieRepository, PersonCommand, SearchCommand}, }; -use crate::movies::commands::EnrichMovieCommand; +use crate::movies::{commands::EnrichMovieCommand, deps::EnrichMovieDeps}; -pub async fn execute( - movie_repository: &Arc, - profile_repository: &Arc, - person_command: &Arc, - search_command: &Arc, - cmd: EnrichMovieCommand, -) -> Result<(), DomainError> { +pub async fn execute(deps: &EnrichMovieDeps, cmd: EnrichMovieCommand) -> Result<(), DomainError> { // 1. Persist the enriched profile (also handles movie_cast, movie_crew, genres, keywords) - profile_repository.upsert(&cmd.profile).await?; + deps.movie_profile.upsert(&cmd.profile).await?; // 2. Upsert persons extracted from cast + crew (no reads — only upsert) let persons = extract_persons(&cmd.profile.cast, &cmd.profile.crew); if !persons.is_empty() { - person_command.upsert_batch(&persons).await?; + deps.person_command.upsert_batch(&persons).await?; } // 3. Fetch the movie for the search index document - let Some(movie) = movie_repository.get_movie_by_id(&cmd.movie_id).await? else { + let Some(movie) = deps.movie.get_movie_by_id(&cmd.movie_id).await? else { tracing::warn!(movie_id = %cmd.movie_id.value(), "enrich_movie: movie not found after profile upsert"); return Ok(()); }; // 4. Index the movie in search - search_command + deps.search_command .index(IndexableDocument::Movie { id: cmd.movie_id.clone(), movie: Box::new(movie), @@ -42,7 +34,7 @@ pub async fn execute( // 5. Index each unique person in search (no reads — persons built from in-memory data) for person in &persons { - search_command + deps.search_command .index(IndexableDocument::Person { id: person.id().clone(), person: Box::new(person.clone()), diff --git a/crates/application/src/movies/get_movie_profile.rs b/crates/application/src/movies/get_movie_profile.rs index 8c40dea..03335e6 100644 --- a/crates/application/src/movies/get_movie_profile.rs +++ b/crates/application/src/movies/get_movie_profile.rs @@ -5,7 +5,7 @@ use domain::{ }; use uuid::Uuid; -use crate::context::AppContext; +use crate::movies::deps::GetMovieProfileDeps; pub struct GetMovieProfileQuery { pub movie_id: Uuid, @@ -60,11 +60,11 @@ fn resolve_crew(member: &CrewMember) -> CrewMemberWithId { } pub async fn execute( - ctx: &AppContext, + deps: &GetMovieProfileDeps, query: GetMovieProfileQuery, ) -> Result, DomainError> { let movie_id = MovieId::from_uuid(query.movie_id); - let profile = ctx.repos.movie_profile.get_by_movie_id(&movie_id).await?; + let profile = deps.movie_profile.get_by_movie_id(&movie_id).await?; Ok(profile.map(|p| { let cast = p.cast.iter().map(resolve_cast).collect(); diff --git a/crates/application/src/movies/get_movies.rs b/crates/application/src/movies/get_movies.rs index b5ed2e2..b5f6963 100644 --- a/crates/application/src/movies/get_movies.rs +++ b/crates/application/src/movies/get_movies.rs @@ -4,10 +4,10 @@ use domain::{ models::{MovieFilter, MovieSummary}, }; -use crate::{context::AppContext, movies::queries::GetMoviesQuery}; +use crate::movies::{deps::GetMoviesDeps, queries::GetMoviesQuery}; pub async fn execute( - ctx: &AppContext, + deps: &GetMoviesDeps, query: GetMoviesQuery, ) -> Result, DomainError> { let page = PageParams::new(query.limit, query.offset)?; @@ -16,7 +16,7 @@ pub async fn execute( genre: query.genre, language: query.language, }; - ctx.repos.movie.list_movies(&page, &filter).await + deps.movie.list_movies(&page, &filter).await } #[cfg(test)] diff --git a/crates/application/src/movies/mod.rs b/crates/application/src/movies/mod.rs index 7223ce1..b82cdf7 100644 --- a/crates/application/src/movies/mod.rs +++ b/crates/application/src/movies/mod.rs @@ -1,4 +1,5 @@ pub mod commands; +pub mod deps; pub mod discovery_indexer; pub mod enrich_movie; pub mod get_movie_profile; diff --git a/crates/application/src/movies/reindex_search.rs b/crates/application/src/movies/reindex_search.rs index 389e403..442c947 100644 --- a/crates/application/src/movies/reindex_search.rs +++ b/crates/application/src/movies/reindex_search.rs @@ -7,7 +7,7 @@ use domain::{ }; use std::sync::atomic::{AtomicBool, Ordering}; -use crate::context::AppContext; +use crate::movies::deps::ReindexSearchDeps; const BATCH_SIZE: u32 = 500; @@ -17,10 +17,10 @@ pub struct ReindexResult { pub persons_backfilled: u64, } -pub async fn execute(ctx: &AppContext) -> Result { - let movies_indexed = reindex_movies(ctx).await?; - let persons_backfilled = backfill_persons(ctx).await?; - let persons_indexed = reindex_persons(ctx).await?; +pub async fn execute(deps: &ReindexSearchDeps) -> Result { + let movies_indexed = reindex_movies(deps).await?; + let persons_backfilled = backfill_persons(deps).await?; + let persons_indexed = reindex_persons(deps).await?; Ok(ReindexResult { movies_indexed, @@ -29,12 +29,11 @@ pub async fn execute(ctx: &AppContext) -> Result { }) } -async fn reindex_movies(ctx: &AppContext) -> Result { +async fn reindex_movies(deps: &ReindexSearchDeps) -> Result { let mut count: u64 = 0; let mut offset: u32 = 0; loop { - let page = ctx - .repos + let page = deps .movie .list_movies( &PageParams { @@ -47,10 +46,9 @@ async fn reindex_movies(ctx: &AppContext) -> Result { for summary in &page.items { let movie_id = summary.movie.id().clone(); - let profile = ctx.repos.movie_profile.get_by_movie_id(&movie_id).await?; + let profile = deps.movie_profile.get_by_movie_id(&movie_id).await?; - if let Err(e) = ctx - .repos + if let Err(e) = deps .search_command .index(IndexableDocument::Movie { id: movie_id.clone(), @@ -73,11 +71,10 @@ async fn reindex_movies(ctx: &AppContext) -> Result { Ok(count) } -async fn backfill_persons(ctx: &AppContext) -> Result { +async fn backfill_persons(deps: &ReindexSearchDeps) -> Result { let mut total = 0u64; loop { - let (count, has_more) = ctx - .repos + let (count, has_more) = deps .person_command .backfill_from_credits_batch(BATCH_SIZE) .await?; @@ -90,15 +87,14 @@ async fn backfill_persons(ctx: &AppContext) -> Result { Ok(total) } -async fn reindex_persons(ctx: &AppContext) -> Result { +async fn reindex_persons(deps: &ReindexSearchDeps) -> Result { let mut count: u64 = 0; let mut offset: u32 = 0; loop { - let persons = ctx.repos.person_query.list_page(BATCH_SIZE, offset).await?; + let persons = deps.person_query.list_page(BATCH_SIZE, offset).await?; for person in &persons { - if let Err(e) = ctx - .repos + if let Err(e) = deps .search_command .index(IndexableDocument::Person { id: person.id().clone(), @@ -121,14 +117,14 @@ async fn reindex_persons(ctx: &AppContext) -> Result { } pub struct SearchReindexHandler { - ctx: AppContext, + deps: ReindexSearchDeps, running: AtomicBool, } impl SearchReindexHandler { - pub fn new(ctx: AppContext) -> Self { + pub fn new(deps: ReindexSearchDeps) -> Self { Self { - ctx, + deps, running: AtomicBool::new(false), } } @@ -147,7 +143,7 @@ impl EventHandler for SearchReindexHandler { } tracing::info!("search reindex started"); - let result = execute(&self.ctx).await; + let result = execute(&self.deps).await; self.running.store(false, Ordering::SeqCst); let r = result?; diff --git a/crates/application/src/movies/sync_poster.rs b/crates/application/src/movies/sync_poster.rs index eb99dd7..d1104f1 100644 --- a/crates/application/src/movies/sync_poster.rs +++ b/crates/application/src/movies/sync_poster.rs @@ -5,12 +5,12 @@ use domain::{ value_objects::{MovieId, PosterPath}, }; -use crate::{context::AppContext, diary::commands::SyncPosterCommand}; +use crate::{diary::commands::SyncPosterCommand, movies::deps::SyncPosterDeps}; -pub async fn execute(ctx: &AppContext, cmd: SyncPosterCommand) -> Result<(), DomainError> { +pub async fn execute(deps: &SyncPosterDeps, cmd: SyncPosterCommand) -> Result<(), DomainError> { let movie_id = MovieId::from_uuid(cmd.movie_id); - let mut movie = match ctx.repos.movie.get_movie_by_id(&movie_id).await? { + let mut movie = match deps.movie.get_movie_by_id(&movie_id).await? { Some(m) => m, None => { tracing::warn!( @@ -30,8 +30,7 @@ pub async fn execute(ctx: &AppContext, cmd: SyncPosterCommand) -> Result<(), Dom })? .clone(); - let poster_url = match ctx - .services + let poster_url = match deps .metadata .get_poster_url(&external_metadata_id) .await @@ -44,20 +43,17 @@ pub async fn execute(ctx: &AppContext, cmd: SyncPosterCommand) -> Result<(), Dom } }; - let image_bytes = ctx - .services + let image_bytes = deps .poster_fetcher .fetch_poster_bytes(&poster_url) .await?; - let stored_path = ctx - .services + let stored_path = deps .object_storage .store(&movie_id.value().to_string(), &image_bytes) .await?; - if let Err(e) = ctx - .services + if let Err(e) = deps .event_publisher .publish(&DomainEvent::ImageStored { key: stored_path.clone(), @@ -70,19 +66,17 @@ pub async fn execute(ctx: &AppContext, cmd: SyncPosterCommand) -> Result<(), Dom let poster_path = PosterPath::new(stored_path)?; movie.update_poster(poster_path); - ctx.repos.movie.upsert_movie(&movie).await?; + deps.movie.upsert_movie(&movie).await?; // Refresh search index so the new poster_path is reflected immediately. // Fetch existing profile if available for a complete index document. - let profile = ctx - .repos + let profile = deps .movie_profile .get_by_movie_id(&movie_id) .await .ok() .flatten(); - if let Err(e) = ctx - .repos + if let Err(e) = deps .search_command .index(IndexableDocument::Movie { id: movie_id.clone(), diff --git a/crates/application/src/movies/tests/enrich_movie.rs b/crates/application/src/movies/tests/enrich_movie.rs index 3369e30..c604a74 100644 --- a/crates/application/src/movies/tests/enrich_movie.rs +++ b/crates/application/src/movies/tests/enrich_movie.rs @@ -11,15 +11,13 @@ use domain::{ value_objects::{MovieId, MovieTitle, ReleaseYear}, }; -use crate::movies::{commands::EnrichMovieCommand, enrich_movie}; +use crate::movies::{commands::EnrichMovieCommand, deps::EnrichMovieDeps, enrich_movie}; #[tokio::test] async fn stores_profile_and_indexes() { let movie_repo = InMemoryMovieRepository::new(); let profile_repo = InMemoryMovieProfileRepository::new(); - let search_cmd: Arc = Arc::new(FakeSearchCommand); // PanicPersonCommand is safe here — empty cast/crew means upsert_batch is never called - let person_cmd: Arc = Arc::new(PanicPersonCommand); let movie = Movie::new( None, @@ -51,11 +49,15 @@ async fn stores_profile_and_indexes() { enriched_at: Utc::now(), }; + let deps = EnrichMovieDeps { + movie: movie_repo as Arc<_>, + movie_profile: Arc::clone(&profile_repo) as Arc<_>, + person_command: Arc::new(PanicPersonCommand), + search_command: Arc::new(FakeSearchCommand), + }; + enrich_movie::execute( - &(movie_repo as Arc<_>), - &(profile_repo.clone() as Arc<_>), - &person_cmd, - &search_cmd, + &deps, EnrichMovieCommand { movie_id: movie_id.clone(), profile, @@ -96,8 +98,6 @@ impl domain::ports::PersonCommand for NoopPersonCommand { async fn extracts_and_indexes_persons() { let movie_repo = InMemoryMovieRepository::new(); let profile_repo = InMemoryMovieProfileRepository::new(); - let search_cmd: Arc = Arc::new(FakeSearchCommand); - let person_cmd: Arc = Arc::new(NoopPersonCommand); let movie = Movie::new( None, @@ -141,11 +141,15 @@ async fn extracts_and_indexes_persons() { enriched_at: Utc::now(), }; + let deps = EnrichMovieDeps { + movie: movie_repo as Arc<_>, + movie_profile: Arc::clone(&profile_repo) as Arc<_>, + person_command: Arc::new(NoopPersonCommand), + search_command: Arc::new(FakeSearchCommand), + }; + enrich_movie::execute( - &(movie_repo as Arc<_>), - &(profile_repo.clone() as Arc<_>), - &person_cmd, - &search_cmd, + &deps, EnrichMovieCommand { movie_id: movie_id.clone(), profile, diff --git a/crates/application/src/movies/tests/get_movie_profile.rs b/crates/application/src/movies/tests/get_movie_profile.rs index 1bd2a87..92aba40 100644 --- a/crates/application/src/movies/tests/get_movie_profile.rs +++ b/crates/application/src/movies/tests/get_movie_profile.rs @@ -10,17 +10,19 @@ use domain::{ value_objects::MovieId, }; -use crate::{ - movies::get_movie_profile::{self, GetMovieProfileQuery}, - test_helpers::TestContextBuilder, +use crate::movies::{ + deps::GetMovieProfileDeps, + get_movie_profile::{self, GetMovieProfileQuery}, }; #[tokio::test] async fn returns_none_when_no_profile() { - let ctx = TestContextBuilder::new().build(); + let deps = GetMovieProfileDeps { + movie_profile: InMemoryMovieProfileRepository::new(), + }; let result = get_movie_profile::execute( - &ctx, + &deps, GetMovieProfileQuery { movie_id: Uuid::new_v4(), }, @@ -69,12 +71,12 @@ async fn returns_profile_with_cast_and_crew() { }; profile_repo.upsert(&profile).await.unwrap(); - let ctx = TestContextBuilder::new() - .with_movie_profiles(Arc::clone(&profile_repo) as _) - .build(); + let deps = GetMovieProfileDeps { + movie_profile: Arc::clone(&profile_repo) as _, + }; let result = get_movie_profile::execute( - &ctx, + &deps, GetMovieProfileQuery { movie_id: movie_id.value(), }, diff --git a/crates/application/src/movies/tests/get_movies.rs b/crates/application/src/movies/tests/get_movies.rs index e2917a2..1e7573d 100644 --- a/crates/application/src/movies/tests/get_movies.rs +++ b/crates/application/src/movies/tests/get_movies.rs @@ -1,14 +1,15 @@ -use crate::{ - movies::{get_movies, queries::GetMoviesQuery}, - test_helpers::TestContextBuilder, -}; +use domain::testing::InMemoryMovieRepository; + +use crate::movies::{deps::GetMoviesDeps, get_movies, queries::GetMoviesQuery}; #[tokio::test] async fn returns_empty_when_no_movies() { - let ctx = TestContextBuilder::new().build(); + let deps = GetMoviesDeps { + movie: InMemoryMovieRepository::new(), + }; let result = get_movies::execute( - &ctx, + &deps, GetMoviesQuery { limit: None, offset: None, diff --git a/crates/application/src/movies/tests/sync_poster.rs b/crates/application/src/movies/tests/sync_poster.rs index d06e92f..a19ddd2 100644 --- a/crates/application/src/movies/tests/sync_poster.rs +++ b/crates/application/src/movies/tests/sync_poster.rs @@ -6,20 +6,33 @@ use domain::{ errors::DomainError, models::Movie, ports::{MetadataClient, MovieRepository}, - testing::InMemoryMovieRepository, + testing::{InMemoryMovieProfileRepository, InMemoryMovieRepository, NoopEventPublisher, NoopObjectStorage, FakeSearchCommand}, value_objects::{ExternalMetadataId, MovieTitle, PosterUrl, ReleaseYear}, }; use crate::{ - diary::commands::SyncPosterCommand, movies::sync_poster, test_helpers::TestContextBuilder, + diary::commands::SyncPosterCommand, + movies::{deps::SyncPosterDeps, sync_poster}, }; +fn default_deps() -> SyncPosterDeps { + SyncPosterDeps { + movie: InMemoryMovieRepository::new(), + movie_profile: InMemoryMovieProfileRepository::new(), + metadata: Arc::new(domain::testing::FakeMetadataClient), + poster_fetcher: Arc::new(domain::testing::FakePosterFetcher), + object_storage: Arc::new(NoopObjectStorage), + event_publisher: NoopEventPublisher::new(), + search_command: Arc::new(FakeSearchCommand), + } +} + #[tokio::test] async fn fails_when_movie_not_found() { - let ctx = TestContextBuilder::new().build(); + let deps = default_deps(); let result = sync_poster::execute( - &ctx, + &deps, SyncPosterCommand { movie_id: Uuid::new_v4(), }, @@ -42,11 +55,12 @@ async fn fails_when_no_external_id() { let movie_id = movie.id().value(); movies.upsert_movie(&movie).await.unwrap(); - let ctx = TestContextBuilder::new() - .with_movies(Arc::clone(&movies) as _) - .build(); + let deps = SyncPosterDeps { + movie: Arc::clone(&movies) as _, + ..default_deps() + }; - let result = sync_poster::execute(&ctx, SyncPosterCommand { movie_id }).await; + let result = sync_poster::execute(&deps, SyncPosterCommand { movie_id }).await; assert!(result.is_err()); } @@ -85,12 +99,13 @@ async fn syncs_poster_for_movie_with_external_id() { let movie_id = movie.id().value(); movies.upsert_movie(&movie).await.unwrap(); - let ctx = TestContextBuilder::new() - .with_movies(Arc::clone(&movies) as _) - .with_metadata_client(Arc::new(FakeMetaWithPoster) as _) - .build(); + let deps = SyncPosterDeps { + movie: Arc::clone(&movies) as _, + metadata: Arc::new(FakeMetaWithPoster) as _, + ..default_deps() + }; - sync_poster::execute(&ctx, SyncPosterCommand { movie_id }) + sync_poster::execute(&deps, SyncPosterCommand { movie_id }) .await .unwrap(); diff --git a/crates/presentation/src/handlers/movies.rs b/crates/presentation/src/handlers/movies.rs index 158ba5c..6c37293 100644 --- a/crates/presentation/src/handlers/movies.rs +++ b/crates/presentation/src/handlers/movies.rs @@ -12,7 +12,12 @@ use application::{ get_movie_social_page, get_review_history, queries::{GetMovieSocialPageQuery, GetReviewHistoryQuery}, }, - movies::{get_movies, queries::GetMoviesQuery, sync_poster}, + movies::{ + deps::{GetMovieProfileDeps, GetMoviesDeps, SyncPosterDeps}, + get_movies, + queries::GetMoviesQuery, + sync_poster, + }, watchlist::{is_on as is_on_watchlist, queries::IsOnWatchlistQuery}, }; use domain::services::review_history::Trend; @@ -47,7 +52,9 @@ pub async fn list_movies( Query(params): Query, ) -> Result, ApiError> { let page = get_movies::execute( - &state.app_ctx, + &GetMoviesDeps { + movie: state.app_ctx.repos.movie.clone(), + }, GetMoviesQuery { limit: params.limit, offset: params.offset, @@ -116,7 +123,19 @@ pub async fn sync_poster( _user: AuthenticatedUser, Path(movie_id): Path, ) -> Result { - sync_poster::execute(&state.app_ctx, SyncPosterCommand { movie_id }).await?; + sync_poster::execute( + &SyncPosterDeps { + movie: state.app_ctx.repos.movie.clone(), + movie_profile: state.app_ctx.repos.movie_profile.clone(), + metadata: state.app_ctx.services.metadata.clone(), + poster_fetcher: state.app_ctx.services.poster_fetcher.clone(), + object_storage: state.app_ctx.services.object_storage.clone(), + event_publisher: state.app_ctx.services.event_publisher.clone(), + search_command: state.app_ctx.repos.search_command.clone(), + }, + SyncPosterCommand { movie_id }, + ) + .await?; Ok(StatusCode::NO_CONTENT) } @@ -188,7 +207,14 @@ pub async fn get_movie_profile( ) -> impl IntoResponse { use application::movies::get_movie_profile; let query = get_movie_profile::GetMovieProfileQuery { movie_id }; - match get_movie_profile::execute(&state.app_ctx, query).await { + match get_movie_profile::execute( + &GetMovieProfileDeps { + movie_profile: state.app_ctx.repos.movie_profile.clone(), + }, + query, + ) + .await + { Ok(Some(result)) => { let p = result.profile; Json(MovieProfileResponse { diff --git a/crates/worker/src/main.rs b/crates/worker/src/main.rs index f776c7e..006aa44 100644 --- a/crates/worker/src/main.rs +++ b/crates/worker/src/main.rs @@ -9,6 +9,7 @@ use application::{ MovieDiscoveryIndexer, SearchCleanupHandler, SearchReindexHandler, config::AppConfig, context::{AppContext, Repositories, Services}, + movies::deps::ReindexSearchDeps, worker::WorkerService, }; use export::ExportAdapter; @@ -155,8 +156,10 @@ async fn main() -> anyhow::Result<()> { Some(person_enrichment_arc), Arc::clone(&ctx.repos.person_command), )) as Arc; - let job = Arc::new(application::jobs::EnrichmentStalenessJob::new(ctx.clone())) - as Arc; + let job = Arc::new(application::jobs::EnrichmentStalenessJob::new( + Arc::clone(&ctx.repos.movie_profile), + Arc::clone(&ctx.services.event_publisher), + )) as Arc; (Some(handler), Some(person_handler), Some(job)) } Err(e) => { @@ -234,7 +237,13 @@ async fn main() -> anyhow::Result<()> { application::wrapup::event_handler::WrapUpEventHandler::new(ctx.clone()), ) as Arc; let reindex_handler = - Arc::new(SearchReindexHandler::new(ctx.clone())) as Arc; + Arc::new(SearchReindexHandler::new(ReindexSearchDeps { + movie: Arc::clone(&ctx.repos.movie), + movie_profile: Arc::clone(&ctx.repos.movie_profile), + search_command: Arc::clone(&ctx.repos.search_command), + person_command: Arc::clone(&ctx.repos.person_command), + person_query: Arc::clone(&ctx.repos.person_query), + })) as Arc; let mut h = vec![ poster, cleanup, @@ -291,7 +300,13 @@ async fn main() -> anyhow::Result<()> { application::wrapup::event_handler::WrapUpEventHandler::new(ctx.clone()), ) as Arc; let reindex_handler = - Arc::new(SearchReindexHandler::new(ctx.clone())) as Arc; + Arc::new(SearchReindexHandler::new(ReindexSearchDeps { + movie: Arc::clone(&ctx.repos.movie), + movie_profile: Arc::clone(&ctx.repos.movie_profile), + search_command: Arc::clone(&ctx.repos.search_command), + person_command: Arc::clone(&ctx.repos.person_command), + person_query: Arc::clone(&ctx.repos.person_query), + })) as Arc; let mut h = vec![ poster, cleanup,