use log::{info, warn};
use crate::error::Error;
use sqlx::migrate::Migrator;
pub use sqlx::sqlite::{SqliteConnectOptions, SqlitePool};
pub use sqlx::Acquire;
use std::time::Duration;
static MIGRATOR: Migrator = sqlx::migrate!();
async fn get_file_pool(filename: &std::path::Path) -> Result<SqlitePool, Error> {
use sqlx::sqlite::{SqlitePoolOptions, SqliteSynchronous};
use sqlx::ConnectOptions;
let timeout = Duration::from_secs(30);
info!("Opening SQLite database file: {}", filename.display());
let conn = SqliteConnectOptions::new()
.filename(filename)
.synchronous(SqliteSynchronous::Normal)
.busy_timeout(timeout)
.shared_cache(false)
.pragma("temp_store", "memory")
.log_statements(log::LevelFilter::Trace);
let pool = SqlitePoolOptions::new()
.min_connections(5)
.connect_with(conn)
.await?;
Ok(pool)
}
pub async fn run_migrations(pool: &SqlitePool) -> Result<(), Error> {
MIGRATOR.run(pool).await?;
Ok(())
}
pub struct SqlitePoolBuilder<'tempfile> {
path: Option<&'tempfile std::path::Path>,
migrate: bool,
}
impl<'tempfile> SqlitePoolBuilder<'tempfile> {
#[must_use]
pub fn new() -> Self {
Self {
path: None,
migrate: true,
}
}
#[must_use]
pub fn db_path(mut self, path: &'tempfile std::path::Path) -> Self {
self.path = Some(path);
self
}
#[must_use]
pub fn migrate(mut self, migrate: bool) -> Self {
self.migrate = migrate;
self
}
pub async fn build(self) -> Result<SqlitePool, Error> {
let db_path = self.path.expect("Must have a path");
let pool = get_file_pool(db_path).await?;
if self.migrate {
warn!("Running migrations on {:?}", &db_path);
run_migrations(&pool).await?;
}
Ok(pool)
}
}
impl<'tempfile> Default for SqlitePoolBuilder<'tempfile> {
fn default() -> Self {
Self::new()
}
}