use crate::error::NetabaseError;
use crate::traits::definition::NetabaseDefinitionTrait;
use crate::traits::model::{NetabaseModelTrait, NetabaseModelTraitKey};
use redb::{
Database, MultimapTableDefinition, ReadableDatabase, ReadableTable, ReadableTableMetadata,
TableDefinition,
};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::Arc;
use strum::IntoDiscriminant;
use super::types::BincodeWrapper;
pub struct RedbStoreTree<'db, D, M>
where
D: NetabaseDefinitionTrait,
M: NetabaseModelTrait<D>,
<D as IntoDiscriminant>::Discriminant: crate::DiscriminantBounds,
{
pub(crate) db: Arc<Database>,
pub discriminant: D::Discriminant,
pub(crate) table_name: &'static str,
pub(crate) secondary_table_name: &'static str,
pub(crate) _phantom_d: PhantomData<D>,
pub(crate) _phantom_m: PhantomData<M>,
pub(crate) _phantom_db: PhantomData<&'db ()>,
}
impl<'db, D, M> RedbStoreTree<'db, D, M>
where
D: NetabaseDefinitionTrait,
M: NetabaseModelTrait<D> + Debug + bincode::Decode<()>,
M::Keys: Debug + bincode::Decode<()> + Ord + PartialEq,
<D as IntoDiscriminant>::Discriminant: crate::DiscriminantBounds,
{
pub(crate) fn new(db: Arc<Database>, discriminant: D::Discriminant) -> Self {
let table_name = discriminant.to_string();
let table_name_static: &'static str = Box::leak(table_name.into_boxed_str());
let sec_name = format!("{}_secondary", discriminant.as_ref());
let sec_name_static: &'static str = Box::leak(sec_name.into_boxed_str());
Self {
db,
discriminant,
table_name: table_name_static,
secondary_table_name: sec_name_static,
_phantom_d: PhantomData,
_phantom_m: PhantomData,
_phantom_db: PhantomData,
}
}
pub(crate) fn table_def(
&self,
) -> TableDefinition<'static, BincodeWrapper<M::Keys>, BincodeWrapper<M>> {
TableDefinition::new(self.table_name)
}
pub(crate) fn secondary_table_def(
&self,
) -> MultimapTableDefinition<
'static,
<M::Keys as NetabaseModelTraitKey<D>>::SecondaryKey,
<M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
> {
MultimapTableDefinition::new(self.secondary_table_name)
}
pub fn put(&self, model: M) -> Result<(), NetabaseError> {
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let key = model.key();
let primary_key = model.primary_key();
let secondary_keys = model.secondary_keys();
let write_txn = self.db.as_ref().begin_write()?;
{
let mut table = write_txn.open_table(table_def)?;
table.insert(&key, &model)?;
if !secondary_keys.is_empty() {
let mut sec_table = write_txn.open_multimap_table(sec_table_def)?;
for sec_key in secondary_keys.values() {
sec_table.insert(sec_key.clone(), primary_key.clone())?;
}
}
}
write_txn.commit()?;
Ok(())
}
pub fn get(&self, key: M::Keys) -> Result<Option<M>, NetabaseError> {
let table_def = self.table_def();
let read_txn = self.db.as_ref().begin_read()?;
let table = match read_txn.open_table(table_def) {
Ok(table) => table,
Err(redb::TableError::TableDoesNotExist(_)) => return Ok(None),
Err(e) => return Err(NetabaseError::RedbTableError(e)),
};
match table.get(&key)? {
Some(model_guard) => {
let model: M = model_guard.value();
Ok(Some(model))
}
None => Ok(None),
}
}
pub fn remove(&self, key: M::Keys) -> Result<Option<M>, NetabaseError> {
let model = self.get(key.clone())?;
if model.is_none() {
return Ok(None);
}
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let write_txn = self.db.as_ref().begin_write()?;
{
let mut table = write_txn.open_table(table_def)?;
table.remove(&key)?;
if let Some(ref m) = model {
let primary_key = m.primary_key();
let secondary_keys = m.secondary_keys();
if !secondary_keys.is_empty() {
let mut sec_table = write_txn.open_multimap_table(sec_table_def)?;
for sec_key in secondary_keys.values() {
sec_table.remove(sec_key.clone(), primary_key.clone())?;
}
}
}
}
write_txn.commit()?;
Ok(model)
}
pub fn put_many(&self, models: Vec<M>) -> Result<(), NetabaseError> {
if models.is_empty() {
return Ok(());
}
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let write_txn = self.db.as_ref().begin_write()?;
{
let mut table = write_txn.open_table(table_def)?;
let mut sec_table = write_txn.open_multimap_table(sec_table_def)?;
for model in models {
let key = model.key();
table.insert(&key, &model)?;
let primary_key = model.primary_key();
let secondary_keys = model.secondary_keys();
if !secondary_keys.is_empty() {
for sec_key in secondary_keys.values() {
sec_table.insert(sec_key.clone(), primary_key.clone())?;
}
}
}
}
write_txn.commit()?;
Ok(())
}
pub fn get_many(&self, keys: Vec<M::Keys>) -> Result<Vec<Option<M>>, NetabaseError> {
if keys.is_empty() {
return Ok(Vec::new());
}
let table_def = self.table_def();
let read_txn = self.db.as_ref().begin_read()?;
let table = match read_txn.open_table(table_def) {
Ok(table) => table,
Err(redb::TableError::TableDoesNotExist(_)) => {
return Ok(vec![None; keys.len()]);
}
Err(e) => return Err(NetabaseError::RedbTableError(e)),
};
let mut results = Vec::with_capacity(keys.len());
for key in keys {
let model = table.get(&key)?.map(|model_guard| model_guard.value());
results.push(model);
}
Ok(results)
}
pub fn iter(&self) -> Result<Vec<(M::Keys, M)>, NetabaseError> {
let table_def = self.table_def();
let read_txn = self.db.as_ref().begin_read()?;
let table = match read_txn.open_table(table_def) {
Ok(table) => table,
Err(redb::TableError::TableDoesNotExist(_)) => return Ok(Vec::new()),
Err(e) => return Err(NetabaseError::RedbTableError(e)),
};
let mut results = Vec::new();
for item in table.iter()? {
let (key_guard, value_guard) = item?;
let key: M::Keys = key_guard.value();
let model: M = value_guard.value();
results.push((key, model));
}
Ok(results)
}
pub fn len(&self) -> Result<usize, NetabaseError> {
let table_def = self.table_def();
let read_txn = self.db.as_ref().begin_read()?;
match read_txn.open_table(table_def) {
Ok(table) => Ok(table.len()? as usize),
Err(redb::TableError::TableDoesNotExist(_)) => Ok(0),
Err(e) => Err(NetabaseError::RedbTableError(e)),
}
}
pub fn is_empty(&self) -> Result<bool, NetabaseError> {
Ok(self.len()? == 0)
}
pub fn clear(&self) -> Result<(), NetabaseError> {
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let write_txn = self.db.as_ref().begin_write()?;
{
match write_txn.open_table(table_def) {
Ok(mut table) => {
let keys: Vec<M::Keys> = table
.iter()?
.filter_map(|item| item.ok())
.map(|(k, _)| k.value())
.collect();
for key in keys {
table.remove(&key)?;
}
}
Err(redb::TableError::TableDoesNotExist(_)) => {
}
Err(e) => return Err(NetabaseError::RedbTableError(e)),
}
match write_txn.open_multimap_table(sec_table_def) {
Ok(sec_table) => {
drop(sec_table);
}
Err(redb::TableError::TableDoesNotExist(_)) => {
}
Err(e) => return Err(NetabaseError::RedbTableError(e)),
}
}
write_txn.commit()?;
Ok(())
}
pub fn get_by_secondary_key(
&self,
secondary_key: <M::Keys as NetabaseModelTraitKey<D>>::SecondaryKey,
) -> Result<Vec<M>, NetabaseError>
where
M::Keys: for<'a> From<<M::PrimaryKey as redb::Value>::SelfType<'a>>,
{
let sec_table_def = self.secondary_table_def();
let read_txn = self.db.as_ref().begin_read()?;
let sec_table = match read_txn.open_multimap_table(sec_table_def) {
Ok(table) => table,
Err(redb::TableError::TableDoesNotExist(_)) => return Ok(Vec::new()),
Err(e) => return Err(NetabaseError::RedbTableError(e)),
};
let mut results = Vec::new();
for item in sec_table.get(secondary_key)? {
let prim_key_guard = item?;
let prim_key = prim_key_guard.value();
let keys = M::Keys::from(prim_key);
if let Some(model) = self.get(keys)? {
results.push(model);
}
}
Ok(results)
}
pub fn get_many_by_secondary_keys(
&self,
secondary_keys: Vec<<M::Keys as NetabaseModelTraitKey<D>>::SecondaryKey>,
) -> Result<Vec<Vec<M>>, NetabaseError>
where
M::Keys: for<'a> From<<M::PrimaryKey as redb::Value>::SelfType<'a>>,
{
if secondary_keys.is_empty() {
return Ok(Vec::new());
}
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let read_txn = self.db.as_ref().begin_read()?;
let sec_table = match read_txn.open_multimap_table(sec_table_def) {
Ok(table) => table,
Err(redb::TableError::TableDoesNotExist(_)) => {
return Ok(vec![Vec::new(); secondary_keys.len()]);
}
Err(e) => return Err(NetabaseError::RedbTableError(e)),
};
let table = match read_txn.open_table(table_def) {
Ok(table) => table,
Err(redb::TableError::TableDoesNotExist(_)) => {
return Ok(vec![Vec::new(); secondary_keys.len()]);
}
Err(e) => return Err(NetabaseError::RedbTableError(e)),
};
let mut all_results = Vec::with_capacity(secondary_keys.len());
for secondary_key in secondary_keys {
let mut results = Vec::new();
for item in sec_table.get(secondary_key)? {
let prim_key_guard = item?;
let prim_key = prim_key_guard.value();
let keys = M::Keys::from(prim_key);
if let Some(model_guard) = table.get(&keys)? {
results.push(model_guard.value());
}
}
all_results.push(results);
}
Ok(all_results)
}
}