Files
movies-diary/crates/adapters/postgres/src/lib.rs
Gabriel Kaszewski dee013c7eb 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
2026-07-10 03:50:43 +02:00

146 lines
5.8 KiB
Rust

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<dyn domain::ports::UserProfileFieldsRepository> {
std::sync::Arc::new(profile_fields::PostgresProfileFieldsRepository::new(pool))
}
pub struct PostgresWireOutput {
pub pool: PgPool,
pub movie_command: std::sync::Arc<dyn domain::ports::MovieCommand>,
pub movie_query: std::sync::Arc<dyn domain::ports::MovieQuery>,
pub review: std::sync::Arc<dyn domain::ports::ReviewRepository>,
pub diary: std::sync::Arc<dyn domain::ports::DiaryRepository>,
pub stats: std::sync::Arc<dyn domain::ports::StatsRepository>,
pub user: std::sync::Arc<dyn domain::ports::UserRepository>,
pub import_session: std::sync::Arc<dyn domain::ports::ImportSessionRepository>,
pub import_profile: std::sync::Arc<dyn domain::ports::ImportProfileRepository>,
pub movie_profile: std::sync::Arc<dyn domain::ports::MovieProfileRepository>,
pub watchlist: std::sync::Arc<dyn domain::ports::WatchlistRepository>,
pub ap_content: std::sync::Arc<dyn domain::ports::LocalApContentQuery>,
pub wrapup_repo: std::sync::Arc<dyn domain::ports::WrapUpRepository>,
pub wrapup_stats: std::sync::Arc<dyn domain::ports::WrapUpStatsQuery>,
pub goal: std::sync::Arc<dyn domain::ports::GoalRepository>,
pub user_settings: std::sync::Arc<dyn domain::ports::UserSettingsRepository>,
pub federation_settings: std::sync::Arc<dyn domain::ports::UserFederationSettingsQuery>,
pub remote_goal: std::sync::Arc<dyn domain::ports::RemoteGoalRepository>,
pub deduplicator: std::sync::Arc<dyn domain::ports::MovieDeduplicator>,
}
pub async fn wire(database_url: &str) -> anyhow::Result<PostgresWireOutput> {
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 _,
})
}