use anyhow::Result;
use rusqlite::Connection;
use std::path::PathBuf;
use crate::storage::migrations::MIGRATIONS;
#[derive(Debug)]
pub struct DbConnection(Connection);
impl std::ops::Deref for DbConnection {
type Target = Connection;
fn deref(&self) -> &Self::Target {
&self.0
}
}
const DB_FILE_NAME: &str = "party.db";
fn db_path() -> Result<PathBuf> {
super::storage_dir().map(|p| p.join(DB_FILE_NAME))
}
impl DbConnection {
pub fn create() -> Result<Self> {
let db_path = db_path()?;
let conn = Connection::open(db_path)?;
conn.pragma_update(None, "journal_mode", "WAL")?;
conn.pragma_update(None, "foreign_keys", "ON")?;
let conn = Self(conn);
conn.run_migrations()?;
Ok(conn)
}
#[cfg(test)]
pub fn create_in_memory() -> Result<Self> {
let conn = Connection::open_in_memory()?;
conn.pragma_update(None, "journal_mode", "WAL")?;
conn.pragma_update(None, "foreign_keys", "ON")?;
let conn = Self(conn);
conn.run_migrations()?;
Ok(conn)
}
fn run_migrations(&self) -> Result<()> {
let current_version: u32 = self.pragma_query_value(None, "user_version", |r| r.get(0))?;
for (i, migration) in MIGRATIONS.iter().enumerate() {
let version = i as u32 + 1;
if version > current_version {
let tx = self.unchecked_transaction()?;
migration(self)?;
tx.execute(&format!("PRAGMA user_version = {version}"), [])?;
tx.commit()?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn migrations_run_on_fresh_db() {
let conn = DbConnection::create_in_memory();
conn.unwrap();
}
}