use crate::error::NetabaseError;
use crate::traits::definition::NetabaseDefinitionTrait;
use crate::traits::model::{NetabaseModelTrait, NetabaseModelTraitKey};
use redb::{
MultimapTableDefinition, MultimapValue, ReadTransaction, ReadableTable, ReadableTableMetadata,
TableDefinition, WriteTransaction,
};
use std::marker::PhantomData;
pub struct RedbTreeMut<'txn, 'db, D, M>
where
D: NetabaseDefinitionTrait,
M: NetabaseModelTrait<D>,
{
pub(crate) txn: &'txn mut WriteTransaction,
#[allow(dead_code)]
pub(crate) discriminant: D::Discriminant,
pub(crate) table_name: &'static str,
pub(crate) secondary_table_name: &'static str,
pub(crate) _phantom: PhantomData<(&'db D, M)>,
}
impl<'txn, 'db, D, M> RedbTreeMut<'txn, 'db, D, M>
where
D: NetabaseDefinitionTrait,
M: NetabaseModelTrait<D>,
M::Keys: NetabaseModelTraitKey<D>,
{
fn table_def(
&self,
) -> TableDefinition<'static, M::Keys, super::super::redb_store::BincodeWrapper<M>> {
TableDefinition::new(self.table_name)
}
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(&mut self, model: M) -> Result<(), NetabaseError> {
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let primary_key = model.primary_key();
let secondary_keys = model.secondary_keys();
let wrapped_key = M::Keys::from(primary_key.clone());
let mut table = self.txn.open_table(table_def)?;
table.insert(wrapped_key, super::super::redb_store::BincodeWrapper(model))?;
if !secondary_keys.is_empty() {
let mut sec_table = self.txn.open_multimap_table(sec_table_def)?;
for sec_key in secondary_keys.values() {
sec_table.insert(sec_key.clone(), primary_key.clone())?;
}
}
Ok(())
}
pub fn put_many(&mut self, models: Vec<M>) -> Result<(), NetabaseError> {
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let mut table = self.txn.open_table(table_def)?;
let mut sec_table = self.txn.open_multimap_table(sec_table_def)?;
for model in models {
let primary_key = model.primary_key();
let secondary_keys = model.secondary_keys();
let wrapped_key = M::Keys::from(primary_key.clone());
table.insert(wrapped_key, super::super::redb_store::BincodeWrapper(model))?;
if !secondary_keys.is_empty() {
for sec_key in secondary_keys.values() {
sec_table.insert(sec_key.clone(), primary_key.clone())?;
}
}
}
Ok(())
}
pub fn get(
&self,
key: &<M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
) -> Result<Option<M>, NetabaseError> {
let table_def = self.table_def();
let table = self.txn.open_table(table_def)?;
let wrapped_key = M::Keys::from(key.clone());
match table.get(wrapped_key)? {
Some(guard) => {
let model: M = guard.value(); Ok(Some(model))
}
None => Ok(None),
}
}
pub fn remove(
&mut self,
key: <M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
) -> Result<Option<M>, NetabaseError> {
let table_def = self.table_def();
let sec_table_def = self.secondary_table_def();
let wrapped_key = M::Keys::from(key.clone());
let mut table = self.txn.open_table(table_def)?;
let model = match table.get(wrapped_key.clone())? {
Some(guard) => {
let model: M = guard.value(); Some(model)
}
None => None,
};
table.remove(wrapped_key)?;
if let Some(ref m) = model {
let secondary_keys = m.secondary_keys();
if !secondary_keys.is_empty() {
let mut sec_table = self.txn.open_multimap_table(sec_table_def)?;
for sec_key in secondary_keys.values() {
sec_table.remove(sec_key.clone(), key.clone())?;
}
}
}
Ok(model)
}
pub fn remove_many(
&mut self,
keys: Vec<<M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey>,
) -> Result<Vec<Option<M>>, NetabaseError> {
let mut results = Vec::with_capacity(keys.len());
for key in keys {
results.push(self.remove(key)?);
}
Ok(results)
}
pub fn len(&self) -> Result<usize, NetabaseError> {
let table_def = self.table_def();
match self.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(&mut self) -> Result<(), NetabaseError>
where
<M as NetabaseModelTrait<D>>::Keys: std::borrow::Borrow<
<<<M as NetabaseModelTrait<D>>::Keys as NetabaseModelTraitKey<D>>::SecondaryKey as redb::Value>::SelfType<'db>
>
{
let table_def = self.table_def();
let mut table = self.txn.open_table(table_def)?;
while let Some((key, _)) = table.pop_first()? {
drop(key);
}
Ok(())
}
}
pub struct RedbTree<'txn, 'db, D, M>
where
D: NetabaseDefinitionTrait,
M: NetabaseModelTrait<D>,
{
pub(crate) txn: &'txn ReadTransaction,
#[allow(dead_code)]
pub(crate) discriminant: D::Discriminant,
pub(crate) table_name: &'static str,
pub(crate) secondary_table_name: &'static str,
pub(crate) _phantom: PhantomData<(&'db D, M)>,
}
impl<'txn, 'db, D, M> RedbTree<'txn, 'db, D, M>
where
D: NetabaseDefinitionTrait,
M: NetabaseModelTrait<D>,
M::Keys: NetabaseModelTraitKey<D>,
{
fn table_def(
&self,
) -> TableDefinition<'static, M::Keys, super::super::redb_store::BincodeWrapper<M>> {
TableDefinition::new(self.table_name)
}
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 get(
&self,
key: &<M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
) -> Result<Option<M>, NetabaseError> {
let table_def = self.table_def();
let table = self.txn.open_table(table_def)?;
let wrapped_key = M::Keys::from(key.clone());
match table.get(wrapped_key)? {
Some(guard) => {
let model: M = guard.value(); Ok(Some(model))
}
None => Ok(None),
}
}
pub fn get_by_secondary_key(
&'txn self,
sec_key: &<M::Keys as NetabaseModelTraitKey<D>>::SecondaryKey,
) -> Result<MultimapValue<'txn, <M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey>, NetabaseError>
where
for<'a> &'a <<M as NetabaseModelTrait<D>>::Keys as NetabaseModelTraitKey<D>>::SecondaryKey:
std::borrow::Borrow<
<<<M as NetabaseModelTrait<D>>::Keys as NetabaseModelTraitKey<D>>::SecondaryKey as redb::Value>::SelfType<'a>
>
{
let sec_table_def = self.secondary_table_def();
let sec_table = self.txn.open_multimap_table(sec_table_def)?;
sec_table
.get(sec_key)
.map_err(NetabaseError::RedbStorageError)
}
pub fn len(&self) -> Result<usize, NetabaseError> {
let table_def = self.table_def();
match self.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)
}
}