use crate::error::NetabaseError;
use crate::traits::convert::ToIVec;
use crate::traits::definition::NetabaseDefinitionTrait;
use crate::traits::model::NetabaseModelTrait;
use crate::{MaybeSend, MaybeSync, NetabaseModelTraitKey};
use std::marker::PhantomData;
use std::str::FromStr;
use strum::IntoDiscriminant;
use super::iterator::SledIter;
pub struct SledStoreTree<'db, D, M>
where
D: NetabaseDefinitionTrait,
M: NetabaseModelTrait<D>,
<D as IntoDiscriminant>::Discriminant: Clone
+ Copy
+ std::fmt::Debug
+ std::fmt::Display
+ PartialEq
+ Eq
+ std::hash::Hash
+ strum::IntoEnumIterator
+ MaybeSend
+ MaybeSync
+ 'static
+ FromStr,
<D as strum::IntoDiscriminant>::Discriminant: std::marker::Copy,
<D as strum::IntoDiscriminant>::Discriminant: std::fmt::Debug,
<D as strum::IntoDiscriminant>::Discriminant: std::hash::Hash,
<D as strum::IntoDiscriminant>::Discriminant: std::cmp::Eq,
<D as strum::IntoDiscriminant>::Discriminant: std::fmt::Display,
<D as strum::IntoDiscriminant>::Discriminant: FromStr,
<D as strum::IntoDiscriminant>::Discriminant: MaybeSync,
<D as strum::IntoDiscriminant>::Discriminant: MaybeSend,
<D as strum::IntoDiscriminant>::Discriminant: strum::IntoEnumIterator,
<D as strum::IntoDiscriminant>::Discriminant: std::convert::AsRef<str>,
{
pub(crate) tree: sled::Tree,
pub(crate) secondary_tree: sled::Tree,
pub db: sled::Db,
pub(crate) _phantom_d: PhantomData<D>,
pub(crate) _phantom_m: PhantomData<M>,
pub(crate) _phantom_db: PhantomData<&'db ()>,
}
impl<'db, D, M> SledStoreTree<'db, D, M>
where
D: NetabaseDefinitionTrait + TryFrom<M> + ToIVec,
M: NetabaseModelTrait<D> + TryFrom<D> + Into<D>,
<D as IntoDiscriminant>::Discriminant: Clone
+ Copy
+ std::fmt::Debug
+ std::fmt::Display
+ PartialEq
+ Eq
+ std::hash::Hash
+ strum::IntoEnumIterator
+ MaybeSend
+ MaybeSync
+ 'static
+ FromStr,
<D as strum::IntoDiscriminant>::Discriminant: std::marker::Copy,
<D as strum::IntoDiscriminant>::Discriminant: std::fmt::Debug,
<D as strum::IntoDiscriminant>::Discriminant: std::hash::Hash,
<D as strum::IntoDiscriminant>::Discriminant: std::cmp::Eq,
<D as strum::IntoDiscriminant>::Discriminant: std::fmt::Display,
<D as strum::IntoDiscriminant>::Discriminant: FromStr,
<D as strum::IntoDiscriminant>::Discriminant: MaybeSync,
<D as strum::IntoDiscriminant>::Discriminant: MaybeSend,
<D as strum::IntoDiscriminant>::Discriminant: strum::IntoEnumIterator,
<D as strum::IntoDiscriminant>::Discriminant: std::convert::AsRef<str>,
{
pub(crate) fn new(db: &sled::Db, tree_name: D::Discriminant) -> Self {
let tree = db
.open_tree(tree_name.to_string())
.expect("Failed to open tree");
let sec_tree_name = format!("{}_secondary", M::discriminant_name());
let secondary_tree = db
.open_tree(sec_tree_name)
.expect("Failed to open secondary tree");
Self {
tree,
secondary_tree,
db: db.clone(),
_phantom_d: PhantomData,
_phantom_m: PhantomData,
_phantom_db: PhantomData,
}
}
pub fn put(&self, model: M) -> Result<(), NetabaseError>
where
D: From<M>,
{
let primary_key = model.primary_key();
let secondary_keys = model.secondary_keys();
let key_bytes = bincode::encode_to_vec(&primary_key, bincode::config::standard())
.map_err(crate::error::EncodingDecodingError::from)?;
let definition: D = model.into();
let value_bytes = definition.to_ivec()?;
let mut batch = sled::Batch::default();
batch.insert(key_bytes, value_bytes.as_ref());
self.tree.apply_batch(batch)?;
if !secondary_keys.is_empty() {
let mut sec_batch = sled::Batch::default();
for sec_key in secondary_keys.values() {
let composite_key = self.build_composite_key(sec_key, &primary_key)?;
sec_batch.insert(composite_key, &[] as &[u8]);
}
self.secondary_tree.apply_batch(sec_batch)?;
}
Ok(())
}
pub fn get(
&self,
key: <M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
) -> Result<Option<M>, NetabaseError> {
let key_bytes = bincode::encode_to_vec(&key, bincode::config::standard())
.map_err(crate::error::EncodingDecodingError::from)?;
match self.tree.get(key_bytes)? {
Some(ivec) => {
let definition = D::from_ivec(&ivec)?;
match M::try_from(definition) {
Ok(model) => Ok(Some(model)),
Err(_) => Ok(None),
}
}
None => Ok(None),
}
}
pub fn remove(
&self,
key: <M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
) -> Result<Option<M>, NetabaseError> {
let key_bytes = bincode::encode_to_vec(&key, bincode::config::standard())
.map_err(crate::error::EncodingDecodingError::from)?;
match self.tree.remove(key_bytes)? {
Some(ivec) => {
let definition = D::from_ivec(&ivec)?;
match M::try_from(definition) {
Ok(model) => {
let secondary_keys = model.secondary_keys();
if !secondary_keys.is_empty() {
let mut sec_batch = sled::Batch::default();
for sec_key in secondary_keys.values() {
let composite_key = self.build_composite_key(sec_key, &key)?;
sec_batch.remove(composite_key);
}
self.secondary_tree.apply_batch(sec_batch)?;
}
Ok(Some(model))
}
Err(_) => Ok(None),
}
}
None => Ok(None),
}
}
pub fn len(&self) -> usize {
self.tree.len()
}
pub fn is_empty(&self) -> bool {
self.tree.is_empty()
}
pub fn clear(&self) -> Result<(), NetabaseError> {
self.tree.clear()?;
Ok(())
}
pub fn get_by_secondary_key(
&self,
secondary_key: <M::Keys as crate::traits::model::NetabaseModelTraitKey<D>>::SecondaryKey,
) -> Result<Vec<M>, NetabaseError>
where
<M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey: bincode::Decode<()>,
{
let sec_key_bytes = bincode::encode_to_vec(&secondary_key, bincode::config::standard())
.map_err(crate::error::EncodingDecodingError::from)?;
let mut results = Vec::new();
for item in self.secondary_tree.scan_prefix(&sec_key_bytes) {
let (composite_key, _) = item?;
let prim_key_start = sec_key_bytes.len();
if composite_key.len() > prim_key_start {
let (primary_key, _) = bincode::decode_from_slice::<
<M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
_,
>(
&composite_key[prim_key_start..],
bincode::config::standard(),
)
.map_err(crate::error::EncodingDecodingError::from)?;
if let Some(model) = self.get(primary_key)? {
results.push(model);
}
}
}
Ok(results)
}
pub fn iter(&self) -> SledIter<D, M> {
SledIter {
inner: self.tree.iter(),
_phantom_d: PhantomData,
_phantom_m: PhantomData,
}
}
pub(crate) fn build_composite_key(
&self,
secondary_key: &<M::Keys as NetabaseModelTraitKey<D>>::SecondaryKey,
primary_key: &<M::Keys as NetabaseModelTraitKey<D>>::PrimaryKey,
) -> Result<Vec<u8>, NetabaseError> {
let mut composite_key = bincode::encode_to_vec(secondary_key, bincode::config::standard())
.map_err(crate::error::EncodingDecodingError::from)?;
let prim_key_bytes = bincode::encode_to_vec(primary_key, bincode::config::standard())
.map_err(crate::error::EncodingDecodingError::from)?;
composite_key.extend_from_slice(&prim_key_bytes);
Ok(composite_key)
}
}