//! SQLite implementation of IAppSettingsRepository. use async_trait::async_trait; use sqlx::SqlitePool; use domain::{DomainError, DomainResult, IAppSettingsRepository}; pub struct SqliteAppSettingsRepository { pool: SqlitePool, } impl SqliteAppSettingsRepository { pub fn new(pool: SqlitePool) -> Self { Self { pool } } } #[async_trait] impl IAppSettingsRepository for SqliteAppSettingsRepository { async fn get(&self, key: &str) -> DomainResult> { sqlx::query_scalar::<_, String>("SELECT value FROM app_settings WHERE key = ?") .bind(key) .fetch_optional(&self.pool) .await .map_err(|e| DomainError::InfrastructureError(e.to_string())) } async fn set(&self, key: &str, value: &str) -> DomainResult<()> { sqlx::query("INSERT OR REPLACE INTO app_settings (key, value) VALUES (?, ?)") .bind(key) .bind(value) .execute(&self.pool) .await .map(|_| ()) .map_err(|e| DomainError::InfrastructureError(e.to_string())) } async fn get_all(&self) -> DomainResult> { sqlx::query_as::<_, (String, String)>("SELECT key, value FROM app_settings ORDER BY key") .fetch_all(&self.pool) .await .map_err(|e| DomainError::InfrastructureError(e.to_string())) } } #[cfg(test)] mod tests { use super::*; use sqlx::SqlitePool; use domain::IAppSettingsRepository; async fn setup() -> SqlitePool { let pool = SqlitePool::connect(":memory:").await.unwrap(); sqlx::query( "CREATE TABLE app_settings (key TEXT PRIMARY KEY, value TEXT NOT NULL)" ).execute(&pool).await.unwrap(); sqlx::query("INSERT INTO app_settings VALUES ('library_sync_interval_hours', '6')") .execute(&pool).await.unwrap(); pool } #[tokio::test] async fn get_returns_seeded_value() { let repo = SqliteAppSettingsRepository::new(setup().await); let val = repo.get("library_sync_interval_hours").await.unwrap(); assert_eq!(val, Some("6".to_string())); } #[tokio::test] async fn set_then_get() { let repo = SqliteAppSettingsRepository::new(setup().await); repo.set("library_sync_interval_hours", "12").await.unwrap(); let val = repo.get("library_sync_interval_hours").await.unwrap(); assert_eq!(val, Some("12".to_string())); } #[tokio::test] async fn get_all_returns_all_keys() { let repo = SqliteAppSettingsRepository::new(setup().await); let all = repo.get_all().await.unwrap(); assert!(!all.is_empty()); assert!(all.iter().any(|(k, _)| k == "library_sync_interval_hours")); } }