use std::{collections::BTreeMap, path::Path};
use derive_more::{Debug, Deref};
use fjall::{Database, DatabaseBuilder, Keyspace, KeyspaceCreateOptions, PersistMode};
use crate::{
migration,
snapshot::Snapshot,
utils::{DbInfo, Persist},
};
#[derive(Debug, Clone, Deref)]
pub struct Db {
#[debug(skip)]
#[deref]
pub db: Database,
pub db_info: Persist<DbInfo>,
pub path: String,
#[debug(skip)]
pub(crate) seq_tree: Keyspace,
}
impl Db {
pub fn new<P>(path: P) -> Self
where
P: AsRef<Path>,
{
let builder = Self::builder(path.as_ref());
Self::with_builder(path, builder)
}
pub fn builder<P: AsRef<Path>>(path: P) -> DatabaseBuilder<Database> {
let db_path = path.as_ref().join("db");
Database::builder(&db_path)
}
pub fn with_builder<P: AsRef<Path>>(path: P, config: DatabaseBuilder<Database>) -> Self {
let db = config.open().expect("Failed to open keyspace");
let meta_path = path.as_ref().join("db.info");
let db_info = Persist::<DbInfo>::open(meta_path);
let seq_tree = db
.keyspace("__seq_tree", KeyspaceCreateOptions::default)
.expect("Failed to open __seq_tree tree");
Self {
db,
db_info,
path: path.as_ref().to_string_lossy().into_owned(),
seq_tree,
}
}
pub fn open_tree(&self, name: &str, options: Option<KeyspaceCreateOptions>) -> Keyspace {
self.db
.keyspace(name, || options.unwrap_or_default())
.expect("Failed to open tree")
}
pub fn get_keyspace(&self, name: &str) -> Option<Keyspace> {
if !self.db.keyspace_exists(name) {
return None;
}
self.db
.keyspace(name, KeyspaceCreateOptions::default)
.inspect_err(|err| {
error!("{err}");
})
.ok()
}
pub fn get_all_keyspaces(&self) -> BTreeMap<String, Keyspace> {
self.db_info
.cloned()
.collections
.into_iter()
.filter_map(|(name, info)| {
let versioned = migration::collection_name(&name, info.version);
self.get_keyspace(&versioned).map(|ks| (name, ks))
})
.collect()
}
pub fn snapshot(&self) -> Snapshot {
let inner = self.db.snapshot();
Snapshot { inner }
}
#[instrument(skip(self), name = "Database::close", fields(path = self.path))]
pub fn close(&self) {
self.db_info.save();
self.db
.persist(PersistMode::SyncAll)
.expect("Failed to persist");
}
}