use anyhow::Result; use diesel::prelude::*; use async_trait::async_trait; pub use std::sync::Arc; pub use tokio::sync::Mutex; use crate::repository::Repository; use crate::settings::Settings; pub use kordophone::api::TokenManagement; use kordophone::model::JwtToken; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); #[async_trait] pub trait DatabaseAccess { async fn with_repository(&mut self, f: F) -> R where F: FnOnce(&mut Repository) -> R + Send, R: Send; async fn with_settings(&mut self, f: F) -> R where F: FnOnce(&mut Settings) -> R + Send, R: Send; } pub struct Database { pub connection: SqliteConnection, } impl Database { pub fn new(path: &str) -> Result { let mut connection = SqliteConnection::establish(path)?; connection.run_pending_migrations(MIGRATIONS) .map_err(|e| anyhow::anyhow!("Error running migrations: {}", e))?; Ok(Self { connection }) } pub fn new_in_memory() -> Result { Self::new(":memory:") } } #[async_trait] impl DatabaseAccess for Database { async fn with_repository(&mut self, f: F) -> R where F: FnOnce(&mut Repository) -> R + Send, R: Send, { let mut repository = Repository::new(&mut self.connection); f(&mut repository) } async fn with_settings(&mut self, f: F) -> R where F: FnOnce(&mut Settings) -> R + Send, R: Send, { let mut settings = Settings::new(&mut self.connection); f(&mut settings) } } #[async_trait] impl DatabaseAccess for Arc> { async fn with_repository(&mut self, f: F) -> R where F: FnOnce(&mut Repository) -> R + Send, R: Send, { let mut database = self.lock().await; database.with_repository(f).await } async fn with_settings(&mut self, f: F) -> R where F: FnOnce(&mut Settings) -> R + Send, R: Send, { let mut database = self.lock().await; database.with_settings(f).await } } static TOKEN_KEY: &str = "token"; impl TokenManagement for Database { async fn get_token(&mut self) -> Option { self.with_settings(|settings| { let token: Result> = settings.get(TOKEN_KEY); match token { Ok(data) => data, Err(_) => None, } }).await } async fn set_token(&mut self, token: JwtToken) { self.with_settings(|settings| settings.put(TOKEN_KEY, &token).unwrap()).await; } }