use std::path::PathBuf;
use std::sync::Arc;
use parking_lot::RwLock;
use velesdb_core::Database;
use crate::error::{Error, Result};
pub struct VelesDbState {
db: Arc<RwLock<Option<Arc<Database>>>>,
path: PathBuf,
}
impl VelesDbState {
#[must_use]
pub fn new(path: PathBuf) -> Self {
Self {
db: Arc::new(RwLock::new(None)),
path,
}
}
pub fn open(&self) -> Result<()> {
let mut db_guard = self.db.write();
if db_guard.is_none() {
let db = Arc::new(Database::open(&self.path)?);
*db_guard = Some(db);
tracing::info!("VelesDB opened at {:?}", self.path);
}
Ok(())
}
pub fn get_db(&self) -> Result<Arc<RwLock<Option<Arc<Database>>>>> {
{
let db_guard = self.db.read();
if db_guard.is_none() {
drop(db_guard);
self.open()?;
}
}
Ok(Arc::clone(&self.db))
}
pub fn with_db<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(Arc<Database>) -> Result<T>,
{
self.open()?;
let db_guard = self.db.read();
let db = db_guard
.as_ref()
.ok_or_else(|| Error::InvalidConfig("Database not initialized".to_string()))?;
f(Arc::clone(db))
}
#[must_use]
pub fn path(&self) -> &PathBuf {
&self.path
}
}
impl Default for VelesDbState {
fn default() -> Self {
Self::new(PathBuf::from("./velesdb_data"))
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn test_state_new() {
let path = PathBuf::from("/tmp/test_db");
let state = VelesDbState::new(path.clone());
assert_eq!(state.path(), &path);
}
#[test]
fn test_state_default() {
let state = VelesDbState::default();
assert_eq!(state.path(), &PathBuf::from("./velesdb_data"));
}
#[test]
fn test_state_open_and_access() {
let dir = tempdir().expect("Failed to create temp dir");
let state = VelesDbState::new(dir.path().to_path_buf());
let result = state.open();
assert!(result.is_ok());
}
#[test]
fn test_state_with_db() {
let dir = tempdir().expect("Failed to create temp dir");
let state = VelesDbState::new(dir.path().to_path_buf());
let result = state.with_db(|db| {
let collections = db.list_collections();
Ok(collections.len())
});
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0); }
#[test]
fn test_state_multiple_opens_idempotent() {
let dir = tempdir().expect("Failed to create temp dir");
let state = VelesDbState::new(dir.path().to_path_buf());
let result1 = state.open();
let result2 = state.open();
let result3 = state.open();
assert!(result1.is_ok());
assert!(result2.is_ok());
assert!(result3.is_ok());
}
}