use sqlx::sqlite::{
SqliteConnectOptions, SqliteJournalMode, SqlitePool as SqlxPool, SqlitePoolOptions,
SqliteSynchronous,
};
use std::str::FromStr;
use std::time::Duration;
use crate::storage::StorageError;
const DEFAULT_MAX_CONNECTIONS: u32 = 5;
const DEFAULT_CONNECT_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Clone)]
pub struct SqlitePool {
inner: SqlxPool,
}
impl std::fmt::Debug for SqlitePool {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SqlitePool").finish_non_exhaustive()
}
}
impl SqlitePool {
pub async fn connect(url: &str) -> Result<Self, StorageError> {
let options = SqliteConnectOptions::from_str(url)?
.journal_mode(SqliteJournalMode::Wal)
.synchronous(SqliteSynchronous::Normal)
.create_if_missing(true);
let pool = SqlitePoolOptions::new()
.max_connections(DEFAULT_MAX_CONNECTIONS)
.acquire_timeout(DEFAULT_CONNECT_TIMEOUT)
.connect_with(options)
.await?;
Ok(Self { inner: pool })
}
#[inline]
pub fn inner(&self) -> &SqlxPool {
&self.inner
}
pub async fn close(&self) {
self.inner.close().await;
}
pub fn is_closed(&self) -> bool {
self.inner.is_closed()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_sqlite_pool_connect() {
let pool = SqlitePool::connect("sqlite::memory:").await.unwrap();
assert!(!pool.is_closed());
let row: (i32,) = sqlx::query_as("SELECT 1")
.fetch_one(pool.inner())
.await
.unwrap();
assert_eq!(row.0, 1);
pool.close().await;
assert!(pool.is_closed());
}
#[tokio::test]
async fn test_sqlite_pool_wal_mode() {
let pool = SqlitePool::connect("sqlite::memory:").await.unwrap();
let row: (String,) = sqlx::query_as("PRAGMA journal_mode")
.fetch_one(pool.inner())
.await
.unwrap();
assert!(row.0 == "wal" || row.0 == "memory");
pool.close().await;
}
}