use std::sync::Arc; use anyhow::Context; use domain::ports::{ AuthService, ImageRefCommand, ImageRefQuery, LocalApContentQuery, MetadataClient, MovieDeduplicator, ObjectStorage, PasswordHasher, PosterFetcherClient, RefreshSessionRepository, UserProfileFieldsRepository, WatchEventCommand, WatchEventQuery, WebhookTokenRepository, }; pub enum DbPool { Sqlite(sqlx::SqlitePool), } pub struct DatabaseOutput { pub movie_command: Arc, pub movie_query: Arc, pub review: Arc, pub diary: Arc, pub stats: Arc, pub user: Arc, pub import_session: Arc, pub import_profile: Arc, pub movie_profile: Arc, pub watchlist: Arc, pub watch_event_command: Arc, pub watch_event_query: Arc, pub webhook_token: Arc, pub person_command: Arc, pub person_query: Arc, pub search_port: Arc, pub search_command: Arc, pub profile_fields: Arc, pub ap_content: Arc, pub wrapup_stats: Arc, pub wrapup_repo: Arc, pub insights: Arc, pub goal_command: Arc, pub goal_query: Arc, pub user_settings: Arc, pub federation_settings: std::sync::Arc, pub remote_goal: Arc, pub refresh_session: Arc, pub deduplicator: Arc, pub image_ref_command: Arc, pub image_ref_query: Arc, pub follow_command: Arc, pub follow_query: Arc, pub db_pool: DbPool, } pub async fn build_database_adapters( url: &str, instance: &domain::value_objects::InstanceIdentity, ) -> anyhow::Result { let w = sqlite::wire(url) .await .context("SQLite connection failed")?; assemble(w, instance) } /// Like [`build_database_adapters`], on a pool the caller already connected /// (migrations still run). Lets tests drive the real wiring on an in-memory pool. pub async fn build_database_adapters_on( pool: sqlx::SqlitePool, instance: &domain::value_objects::InstanceIdentity, ) -> anyhow::Result { let w = sqlite::wire_pool(pool) .await .context("SQLite wiring failed")?; assemble(w, instance) } fn assemble( w: sqlite::SqliteWireOutput, instance: &domain::value_objects::InstanceIdentity, ) -> anyhow::Result { let (image_ref_command, image_ref_query) = sqlite::create_image_ref(w.pool.clone()); let (pc, pq) = sqlite::create_person_adapter(w.pool.clone()); let (sc, sp) = sqlite::create_search_adapter(w.pool.clone()); let pf = sqlite::create_profile_fields_repo(w.pool.clone()); let we = Arc::new(sqlite::SqliteWatchEventRepository::new(w.pool.clone())); let wt: Arc = Arc::new(sqlite::SqliteWebhookTokenRepository::new(w.pool.clone())); let social = Arc::new(sqlite::SqliteSocialRepository::new( w.pool.clone(), instance.clone(), )); Ok(DatabaseOutput { movie_command: w.movie_command, movie_query: w.movie_query, review: w.review, diary: w.diary, stats: w.stats, user: w.user, import_session: w.import_session, import_profile: w.import_profile, movie_profile: w.movie_profile, watchlist: w.watchlist, watch_event_command: we.clone() as _, watch_event_query: we as _, webhook_token: wt, person_command: pc, person_query: pq, search_port: sp, search_command: sc, profile_fields: pf, ap_content: w.ap_content, wrapup_stats: w.wrapup_stats, wrapup_repo: w.wrapup_repo, insights: w.insights, goal_command: w.goal_command, goal_query: w.goal_query, user_settings: w.user_settings, federation_settings: w.federation_settings, remote_goal: w.remote_goal, refresh_session: Arc::new(sqlite::SqliteRefreshSessionAdapter::new(w.pool.clone())) as _, deduplicator: w.deduplicator, image_ref_command, image_ref_query, follow_command: Arc::clone(&social) as _, follow_query: social as _, db_pool: DbPool::Sqlite(w.pool), }) } pub fn build_auth_adapters( config: &config::AuthConfig, ) -> anyhow::Result<(Arc, Arc)> { auth::create(config) } pub fn build_metadata_client( config: &config::MetadataConfig, ) -> anyhow::Result> { metadata::create(config) } pub fn build_poster_fetcher( config: &config::MetadataConfig, ) -> anyhow::Result> { poster_fetcher::create(config) } pub fn build_object_storage( config: &config::StorageConfig, ) -> anyhow::Result> { object_storage::create(config) } pub fn build_profile_fields_repo( pool: &DbPool, ) -> anyhow::Result> { match pool { DbPool::Sqlite(pool) => Ok(sqlite::create_profile_fields_repo(pool.clone())), } } pub fn warn_if_database_backend_set() { if let Ok(v) = std::env::var("DATABASE_BACKEND") && v != "sqlite" { tracing::warn!("DATABASE_BACKEND is ignored; SQLite is the only backend"); } }