use std::path::Path;
use std::sync::Arc;
use rusqlite::Connection;
use thiserror::Error;
use tokio::sync::Mutex;
use crate::cache::CacheError;
use crate::cnft::store::StoreError;
use crate::webhooks::WebhookError;
const SCHEMA: &str = include_str!("sqlite_schema.sql");
#[derive(Clone)]
pub struct SqliteBackend {
pub(crate) conn: Arc<Mutex<Connection>>,
}
#[derive(Debug, Error)]
pub enum BackendError {
#[error("sqlite: {0}")]
Sqlite(#[from] rusqlite::Error),
#[error("io: {0}")]
Io(#[from] std::io::Error),
}
impl SqliteBackend {
pub fn open(path: impl AsRef<Path>) -> Result<Self, BackendError> {
let path_ref = path.as_ref();
if path_ref.as_os_str() != ":memory:" {
if let Some(parent) = path_ref.parent() {
if !parent.as_os_str().is_empty() {
std::fs::create_dir_all(parent)?;
}
}
}
let conn = Connection::open(path_ref)?;
Self::initialize(conn)
}
pub fn open_in_memory() -> Result<Self, BackendError> {
let conn = Connection::open_in_memory()?;
Self::initialize(conn)
}
fn initialize(conn: Connection) -> Result<Self, BackendError> {
conn.execute_batch(SCHEMA)?;
conn.pragma_update(None, "journal_mode", "WAL")?;
conn.pragma_update(None, "synchronous", "NORMAL")?;
Ok(Self {
conn: Arc::new(Mutex::new(conn)),
})
}
}
impl From<BackendError> for StoreError {
fn from(e: BackendError) -> Self {
Self::UnknownTree {
tree: format!("sqlite backend: {e}"),
}
}
}
impl From<BackendError> for CacheError {
fn from(e: BackendError) -> Self {
Self::Backend(e.to_string())
}
}
impl From<BackendError> for WebhookError {
fn from(e: BackendError) -> Self {
Self::BadRequest(format!("sqlite backend: {e}"))
}
}