use domain::errors::DomainError; use sqlx::PgPool; mod diary; mod goals; mod image_ref; mod import_profile; mod import_session; mod models; mod movie; mod movie_dedup; mod persons; mod profile; mod profile_fields; mod refresh_sessions; mod review; mod stats; mod user_settings; mod users; mod watch_event; mod watchlist; mod wrapup; pub use diary::PostgresDiaryRepository; pub use image_ref::{PostgresImageRefAdapter, create_image_ref}; pub use import_profile::PostgresImportProfileRepository; pub use import_session::PostgresImportSessionRepository; pub use movie::PostgresMovieRepository; pub use movie_dedup::PostgresMovieDeduplicator; pub use persons::{PostgresPersonAdapter, create_person_adapter}; pub use postgres_federation::PostgresApContentQuery; pub use profile::PostgresMovieProfileRepository; pub use profile_fields::PostgresProfileFieldsRepository; pub use refresh_sessions::PostgresRefreshSessionAdapter; pub use review::PostgresReviewRepository; pub use stats::PostgresStatsRepository; pub use users::PostgresUserRepository; pub use watch_event::{PostgresWatchEventRepository, PostgresWebhookTokenRepository}; pub use watchlist::PostgresWatchlistRepository; pub use wrapup::{PostgresWrapUpRepository, PostgresWrapUpStatsQuery}; pub(crate) fn format_year_month(ym: &str) -> String { let parts: Vec<&str> = ym.splitn(2, '-').collect(); if parts.len() != 2 { return ym.to_string(); } let year = parts[0].get(2..).unwrap_or(parts[0]); let month = match parts[1] { "01" => "Jan", "02" => "Feb", "03" => "Mar", "04" => "Apr", "05" => "May", "06" => "Jun", "07" => "Jul", "08" => "Aug", "09" => "Sep", "10" => "Oct", "11" => "Nov", "12" => "Dec", _ => parts[1], }; format!("{} '{}", month, year) } pub async fn migrate(pool: &PgPool) -> Result<(), DomainError> { sqlx::migrate!("./migrations") .set_ignore_missing(true) .run(pool) .await .map_err(|e| DomainError::InfrastructureError(e.to_string())) } pub fn create_profile_fields_repo( pool: sqlx::PgPool, ) -> std::sync::Arc { std::sync::Arc::new(profile_fields::PostgresProfileFieldsRepository::new(pool)) } pub struct PostgresWireOutput { pub pool: PgPool, pub movie_command: std::sync::Arc, pub movie_query: std::sync::Arc, pub review: std::sync::Arc, pub diary: std::sync::Arc, pub stats: std::sync::Arc, pub user: std::sync::Arc, pub import_session: std::sync::Arc, pub import_profile: std::sync::Arc, pub movie_profile: std::sync::Arc, pub watchlist: std::sync::Arc, pub ap_content: std::sync::Arc, pub wrapup_repo: std::sync::Arc, pub wrapup_stats: std::sync::Arc, pub goal: std::sync::Arc, pub user_settings: std::sync::Arc, pub federation_settings: std::sync::Arc, pub remote_goal: std::sync::Arc, pub deduplicator: std::sync::Arc, } pub async fn wire(database_url: &str) -> anyhow::Result { use anyhow::Context; let pool = sqlx::PgPool::connect(database_url) .await .context("Failed to connect to PostgreSQL database")?; migrate(&pool) .await .map_err(|e| anyhow::anyhow!("{e}")) .context("Database migration failed")?; let user_settings_repo = std::sync::Arc::new( user_settings::PostgresUserSettingsRepository::new(pool.clone()), ); let movie_repo = std::sync::Arc::new(PostgresMovieRepository::new(pool.clone())); Ok(PostgresWireOutput { pool: pool.clone(), movie_command: movie_repo.clone() as _, movie_query: movie_repo as _, review: std::sync::Arc::new(PostgresReviewRepository::new(pool.clone())) as _, diary: std::sync::Arc::new(PostgresDiaryRepository::new(pool.clone())) as _, stats: std::sync::Arc::new(PostgresStatsRepository::new(pool.clone())) as _, user: std::sync::Arc::new(PostgresUserRepository::new(pool.clone())) as _, import_session: std::sync::Arc::new(PostgresImportSessionRepository::new(pool.clone())) as _, import_profile: std::sync::Arc::new(PostgresImportProfileRepository::new(pool.clone())) as _, movie_profile: std::sync::Arc::new(PostgresMovieProfileRepository::new(pool.clone())) as _, watchlist: std::sync::Arc::new(PostgresWatchlistRepository::new(pool.clone())) as _, ap_content: std::sync::Arc::new(PostgresApContentQuery::new(pool.clone())) as _, wrapup_repo: std::sync::Arc::new(PostgresWrapUpRepository::new(pool.clone())) as _, wrapup_stats: std::sync::Arc::new(PostgresWrapUpStatsQuery::new(pool.clone())) as _, goal: std::sync::Arc::new(goals::PostgresGoalRepository::new(pool.clone())) as _, user_settings: std::sync::Arc::clone(&user_settings_repo) as _, federation_settings: user_settings_repo as _, remote_goal: std::sync::Arc::new(postgres_federation::PostgresRemoteGoalRepository::new( pool.clone(), )) as _, deduplicator: std::sync::Arc::new(PostgresMovieDeduplicator::new(pool)) as _, }) }