use crate::migrations;
use orbok_core::{OrbokError, OrbokResult};
use rusqlite::Connection;
use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard};
pub const CATALOG_FILE_NAME: &str = "orbok-catalog.sqlite3";
pub const CACHE_FILE_NAME: &str = "orbok-cache.sqlite3";
pub struct Catalog {
conn: Mutex<Connection>,
path: PathBuf,
}
impl Catalog {
pub fn open(path: impl AsRef<Path>) -> OrbokResult<Self> {
let path = path.as_ref().to_path_buf();
let conn = Connection::open(&path).map_err(db_err)?;
Self::from_connection(conn, path)
}
pub fn open_in_memory() -> OrbokResult<Self> {
let conn = Connection::open_in_memory().map_err(db_err)?;
Self::from_connection(conn, PathBuf::from(":memory:"))
}
fn from_connection(conn: Connection, path: PathBuf) -> OrbokResult<Self> {
conn.pragma_update(None, "foreign_keys", "ON").map_err(db_err)?;
let _ = conn.pragma_update(None, "journal_mode", "WAL");
conn.pragma_update(None, "synchronous", "NORMAL").map_err(db_err)?;
conn.pragma_update(None, "temp_store", "MEMORY").map_err(db_err)?;
let catalog = Self {
conn: Mutex::new(conn),
path,
};
migrations::run_pending(&catalog)?;
Ok(catalog)
}
pub fn lock(&self) -> MutexGuard<'_, Connection> {
self.conn
.lock()
.expect("catalog connection mutex poisoned — a repository panicked mid-write")
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn schema_version(&self) -> OrbokResult<i64> {
let conn = self.lock();
let version = conn
.query_row(
"SELECT COALESCE(MAX(version), 0) FROM schema_migrations",
[],
|row| row.get(0),
)
.map_err(db_err)?;
Ok(version)
}
}
pub(crate) fn db_err(e: rusqlite::Error) -> OrbokError {
OrbokError::Database(e.to_string())
}