use directories::ProjectDirs;
use rusqlite::{Connection, Result as SqlResult};
use std::path::{Path, PathBuf};
use thiserror::Error;
use super::schema;
#[derive(Error, Debug)]
pub enum DatabaseError {
#[error("SQLite error: {0}")]
Sqlite(#[from] rusqlite::Error),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Home directory not found")]
NoHomeDirectory,
}
pub(super) type Result<T> = std::result::Result<T, DatabaseError>;
#[derive(Debug)]
pub struct Database {
conn: Connection,
path: PathBuf,
}
impl Database {
pub fn open_default() -> Result<Self> {
let path = Self::default_path()?;
Self::open(&path)
}
pub fn open(path: &Path) -> Result<Self> {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let conn = Connection::open(path)?;
schema::init_schema(&conn)?;
Ok(Self {
conn,
path: path.to_path_buf(),
})
}
pub fn default_path() -> Result<PathBuf> {
if let Some(proj_dirs) = ProjectDirs::from("network", "kogito", "warcraft-rs") {
let data_dir = proj_dirs.data_dir();
Ok(data_dir.join("mpq-hashes.db"))
} else {
Err(DatabaseError::NoHomeDirectory)
}
}
pub fn connection(&self) -> &Connection {
&self.conn
}
pub fn connection_mut(&mut self) -> &mut Connection {
&mut self.conn
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn transaction(&mut self) -> SqlResult<rusqlite::Transaction<'_>> {
self.conn.transaction()
}
pub fn execute_batch(&self, sql: &str) -> SqlResult<()> {
self.conn.execute_batch(sql)
}
}