use std::{fmt, path::PathBuf}; use anyhow::Context; use diesel::{Connection, SqliteConnection}; use diesel_migrations::MigrationHarness; use schist_models::migrations::MIGRATIONS; pub struct DatabaseConnection { pub connection: diesel::SqliteConnection, pub file_path: PathBuf, } impl DatabaseConnection { pub fn establish(file_path: PathBuf) -> DatabaseConnectionResult { DatabaseConnectionResult { connection: Self::establish_sqlite_connection(&file_path), file_path: file_path, } } fn establish_sqlite_connection(file_path: &PathBuf) -> anyhow::Result { let file_path_str = file_path .to_str() .with_context(|| format!("Failed to get database path from {:?}", file_path))?; let mut connection = diesel::SqliteConnection::establish(&file_path_str) .with_context(|| format!("Failed to connect to database at {}", file_path_str))?; connection .run_pending_migrations(MIGRATIONS) .map_err(anyhow::Error::from_boxed) .with_context(|| { format!( "Failed to run pending migrations on database at {}", file_path_str ) })?; Ok(connection) } } impl fmt::Debug for DatabaseConnection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SqliteConnection") .field("file_path", &self.file_path) .finish() } } pub struct DatabaseConnectionResult { pub connection: anyhow::Result, pub file_path: PathBuf, } impl DatabaseConnectionResult { pub fn ok(self) -> Result { self.try_into() } } impl TryFrom for DatabaseConnection { type Error = (PathBuf, anyhow::Error); fn try_from(result: DatabaseConnectionResult) -> Result { result .connection .map(|connection| DatabaseConnection { connection, file_path: result.file_path.clone(), }) .map_err(|err| (result.file_path, err)) } }