use crate::cesr::Matter;
use crate::cesr::Parsable;
use crate::keri::db::dbing::LMDBer;
use crate::keri::db::errors::DBError;
use crate::keri::db::subing::{SuberBase, SuberError, ValueCodec};
use std::marker::PhantomData;
use std::sync::Arc;
pub struct CesrCodec<T: Matter> {
_phantom: PhantomData<T>,
}
impl<T: Matter> ValueCodec for CesrCodec<T> {
type Error = SuberError;
fn serialize<V: ?Sized + Clone + Into<Vec<u8>>>(val: &V) -> Result<Vec<u8>, SuberError> {
Ok(val.clone().into())
}
fn deserialize<V: TryFrom<Vec<u8>>>(bytes: &[u8]) -> Result<V, SuberError> {
match V::try_from(bytes.to_vec()) {
Ok(v) => Ok(v),
Err(_) => Err(SuberError::DeserializationError(
"Failed to deserialize value".to_string(),
)),
}
}
}
pub struct CesrSuberBase<'db, M: Matter> {
pub base: SuberBase<'db, CesrCodec<M>>,
_matter_type: PhantomData<M>,
}
#[allow(dead_code)]
impl<'db, M: Matter + Parsable> CesrSuberBase<'db, M> {
pub fn new(
db: Arc<&'db LMDBer>,
subkey: &str,
sep: Option<u8>,
verify: bool,
) -> Result<Self, SuberError> {
let base = SuberBase::<'db, CesrCodec<M>>::new(db, subkey, sep, verify, Some(false))?;
Ok(Self {
base,
_matter_type: PhantomData,
})
}
pub fn ser(&self, val: &M) -> Result<Vec<u8>, SuberError> {
Ok(val.qb64b())
}
pub fn des(&self, val: &[u8]) -> Result<M, SuberError> {
Ok(M::from_qb64b(&mut val.to_vec(), None)?)
}
pub fn to_key<K: AsRef<[u8]>>(&self, keys: &[K], topive: bool) -> Vec<u8> {
self.base.to_key(keys, topive)
}
pub fn put<K: AsRef<[u8]>>(&self, keys: &[K], val: &M) -> Result<bool, SuberError> {
let key = self.base.to_key(keys, false);
let val_bytes = self.ser(val)?;
Ok(self.base.db.put_val(&self.base.sdb, &key, &val_bytes)?)
}
pub fn put_val(&self, key: &[u8], val: &[u8]) -> Result<bool, DBError> {
self.base.db.put_val(&self.base.sdb, key, val)
}
pub fn set_val(&self, key: &[u8], val: &[u8]) -> Result<bool, DBError> {
self.base.db.set_val(&self.base.sdb, key, val)
}
pub fn pin<K: AsRef<[u8]>>(&self, keys: &[K], val: &M) -> Result<bool, SuberError> {
let key = self.base.to_key(keys, false);
let val_bytes = self.ser(val)?;
Ok(self.base.db.set_val(&self.base.sdb, &key, &val_bytes)?)
}
pub fn get<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<Option<M>, SuberError> {
let key = self.base.to_key(keys, false);
if let Some(val) = self.base.db.get_val(&self.base.sdb, &key)? {
Ok(Some(self.des(&val)?))
} else {
Ok(None)
}
}
pub fn rem<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<bool, SuberError> {
self.base.trim(keys, false)
}
pub fn trim<K: AsRef<[u8]>>(&self, keys: &[K], topive: bool) -> Result<bool, SuberError> {
Ok(self.base.trim(keys, topive)?)
}
pub fn get_full_item_iter<K: AsRef<[u8]>>(
&self,
keys: &[K],
topive: bool,
) -> Result<Vec<(Vec<Vec<u8>>, Vec<u8>)>, SuberError> {
Ok(self.base.get_full_item_iter(keys, topive)?)
}
pub fn get_item_iter<K: AsRef<[u8]>>(
&self,
keys: &[K],
topive: bool,
) -> Result<Vec<(Vec<Vec<u8>>, Vec<u8>)>, SuberError> {
Ok(self.base.get_item_iter(keys, topive)?)
}
pub fn cnt_all(&self) -> Result<usize, SuberError> {
Ok(self.base.cnt_all()?)
}
pub fn process_items(
&self,
items: Vec<(Vec<Vec<u8>>, Vec<u8>)>,
) -> Result<Vec<(Vec<Vec<u8>>, M)>, SuberError> {
items
.into_iter()
.map(|(keys, val)| {
let matter = self.des(&val)?;
Ok((keys, matter))
})
.collect()
}
}
pub struct CesrSuber<'db, M: Matter> {
base: CesrSuberBase<'db, M>,
}
impl<'db, M: Matter + Parsable> CesrSuber<'db, M> {
pub fn new(
db: Arc<&'db LMDBer>,
subkey: &str,
sep: Option<u8>,
verify: bool,
) -> Result<Self, SuberError> {
let base = CesrSuberBase::new(db, subkey, sep, verify)?;
Ok(Self { base })
}
pub fn pin<K: AsRef<[u8]>>(&self, keys: &[K], val: &M) -> Result<bool, SuberError> {
self.base.pin(keys, val)
}
pub fn put<K: AsRef<[u8]>>(&self, keys: &[K], val: &M) -> Result<bool, SuberError> {
self.base.put(keys, val)
}
pub fn get<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<Option<M>, SuberError> {
self.base.get(keys)
}
pub fn rem<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<bool, SuberError> {
self.base.rem(keys)
}
pub fn trim<K: AsRef<[u8]>>(&self, keys: &[K], topive: bool) -> Result<bool, SuberError> {
self.base.trim(keys, topive)
}
pub fn get_full_item_iter<K: AsRef<[u8]>>(
&self,
keys: &[K],
topive: bool,
) -> Result<Vec<(Vec<Vec<u8>>, Vec<u8>)>, SuberError> {
self.base.get_full_item_iter(keys, topive)
}
pub fn get_item_iter<K: AsRef<[u8]>>(
&self,
keys: &[K],
topive: bool,
) -> Result<Vec<(Vec<Vec<u8>>, Vec<u8>)>, SuberError> {
self.base.get_item_iter(keys, topive)
}
pub fn process_items(
&self,
items: Vec<(Vec<Vec<u8>>, Vec<u8>)>,
) -> Result<Vec<(Vec<Vec<u8>>, M)>, SuberError> {
self.base.process_items(items)
}
pub fn cnt_all(&self) -> Result<usize, SuberError> {
self.base.cnt_all()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use crate::cesr::diger::Diger;
use crate::cesr::indexing::siger::Siger;
use crate::cesr::{BaseMatter, Matter};
use crate::keri::db::dbing::LMDBer;
use crate::keri::db::subing::cesr::CesrSuber;
#[test]
fn test_cesr_suber() -> Result<(), SuberError> {
let lmdber = LMDBer::builder().name("test_db").temp(true).build()?;
assert_eq!(lmdber.name(), "test_db");
assert!(lmdber.opened());
let db_ref = Arc::new(&lmdber);
let sdb = CesrSuber::<BaseMatter>::new(db_ref, "bags.", None, true)?;
let pre0 = "BDzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc";
let val0 = BaseMatter::from_qb64(pre0)?;
let keys: &[&[u8]] = &[b"alpha".as_ref(), b"dog".as_ref()];
let result = sdb.put(keys, &val0)?;
assert!(result);
let actual = sdb.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val0.qb64());
let result = sdb.trim(keys, false)?;
assert!(result);
let actual = sdb.get(keys)?;
assert!(actual.is_none());
let result = sdb.put(keys, &val0)?;
assert!(result);
let actual = sdb.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val0.qb64());
let pre1 = "BHHzqZWzwE-Wk7K0gzQPYGGwTmuupUhPx5_y1x4ejhcc";
let val1 = BaseMatter::from_qb64(pre1)?;
let result = sdb.put(keys, &val1)?;
assert!(!result);
let actual = sdb.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val0.qb64());
let trim_result = sdb.trim(keys, false)?;
assert!(trim_result);
let put_result = sdb.put(keys, &val1)?;
assert!(put_result);
let actual = sdb.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val1.qb64());
let keys_str: &[&[u8]] = &[b"beta.fish".as_ref()];
let result = sdb.put(keys_str, &val1)?;
assert!(result);
let actual = sdb.get(keys_str)?.unwrap();
assert_eq!(actual.qb64(), val1.qb64());
let result = sdb.trim(keys_str, false)?;
assert!(result);
let actual = sdb.get(keys_str)?;
assert!(actual.is_none());
let bad_key: &[&[u8]] = &[b"badkey".as_ref()];
let actual = sdb.get(bad_key)?;
assert!(actual.is_none());
let db_ref = Arc::new(&lmdber);
let sdb_pugs = CesrSuber::<BaseMatter>::new(db_ref, "pugs.", None, true)?;
let keys_a1: &[&[u8]] = &[b"a".as_ref(), b"1".as_ref()];
let keys_a2: &[&[u8]] = &[b"a".as_ref(), b"2".as_ref()];
assert!(sdb_pugs.put(keys_a1, &val0)?);
assert!(sdb_pugs.put(keys_a2, &val1)?);
let empty: [&[u8]; 0] = [];
let items = sdb_pugs.get_item_iter(&empty, false)?;
let processed_items = sdb_pugs.process_items(items)?;
let mut result_items = Vec::new();
for (keys_vec, val) in processed_items {
let keys_tuple: Vec<String> = keys_vec
.into_iter()
.map(|k| String::from_utf8(k).unwrap())
.collect();
result_items.push((keys_tuple, val.qb64()));
}
assert_eq!(result_items.len(), 2);
assert_eq!(result_items[0].0, vec!["a".to_string(), "1".to_string()]);
assert_eq!(result_items[0].1, val0.qb64());
assert_eq!(result_items[1].0, vec!["a".to_string(), "2".to_string()]);
assert_eq!(result_items[1].1, val1.qb64());
let db_ref = Arc::new(&lmdber);
let sdb_diger = CesrSuber::<Diger>::new(db_ref, "pigs.", None, true)?;
let dig0 = "EAPYGGwTmuupWzwEHHzq7K0gzUhPx5_yZ-Wk1x4ejhcc";
let val0 = Diger::from_qb64(dig0)?;
let keys: &[&[u8]] = &[b"alpha".as_ref(), b"dog".as_ref()];
assert!(sdb_diger.put(keys, &val0)?);
let actual = sdb_diger.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val0.qb64());
assert!(sdb_diger.trim(keys, false)?);
let actual = sdb_diger.get(keys)?;
assert!(actual.is_none());
assert!(sdb_diger.put(keys, &val0)?);
let actual = sdb_diger.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val0.qb64());
let pre1 = "EHHzqZWzwE-Wk7K0gzQPYGGwTmuupUhPx5_y1x4ejhcc";
let val1 = BaseMatter::from_qb64(pre1)?;
let trim_result = sdb_diger.trim(keys, false)?;
assert!(trim_result);
let val1_diger = Diger::from_qb64(pre1)?;
let put_result = sdb_diger.put(keys, &val1_diger)?;
assert!(put_result);
let actual = sdb_diger.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val1_diger.qb64());
let db_ref = Arc::new(&lmdber);
let sdb_figs = CesrSuber::<Diger>::new(db_ref, "figs.", None, true)?;
let keys_a1: &[&[u8]] = &[b"a".as_ref(), b"1".as_ref()];
let keys_a2: &[&[u8]] = &[b"a".as_ref(), b"2".as_ref()];
assert!(sdb_figs.put(keys_a1, &val0)?);
assert!(sdb_figs.put(keys_a2, &val1_diger)?);
let items = sdb_figs.get_item_iter(&empty, false)?;
let processed_items = sdb_figs.process_items(items)?;
let mut result_items = Vec::new();
for (keys_vec, val) in processed_items {
let keys_tuple: Vec<String> = keys_vec
.into_iter()
.map(|k| String::from_utf8(k).unwrap())
.collect();
result_items.push((keys_tuple, val.qb64()));
}
assert_eq!(result_items.len(), 2);
assert_eq!(result_items[0].0, vec!["a".to_string(), "1".to_string()]);
assert_eq!(result_items[0].1, val0.qb64());
assert_eq!(result_items[1].0, vec!["a".to_string(), "2".to_string()]);
assert_eq!(result_items[1].1, val1_diger.qb64());
let keys_b1: &[&[u8]] = &[b"b".as_ref(), b"1".as_ref()];
let keys_b2: &[&[u8]] = &[b"b".as_ref(), b"2".as_ref()];
let keys_bc1: &[&[u8]] = &[b"bc".as_ref(), b"1".as_ref()];
assert!(sdb_figs.put(keys_b1, &val0)?);
assert!(sdb_figs.put(keys_b2, &val1_diger)?);
assert!(sdb_figs.put(keys_bc1, &val0)?);
let top_keys: &[&[u8]] = &[b"b".as_ref(), b"".as_ref()];
let items = sdb_figs.get_item_iter(top_keys, true)?;
let processed_items = sdb_figs.process_items(items)?;
let mut result_items = Vec::new();
for (keys_vec, val) in processed_items {
let keys_tuple: Vec<String> = keys_vec
.into_iter()
.map(|k| String::from_utf8(k).unwrap())
.collect();
result_items.push((keys_tuple, val.qb64()));
}
assert_eq!(result_items.len(), 2);
assert_eq!(result_items[0].0, vec!["b".to_string(), "1".to_string()]);
assert_eq!(result_items[0].1, val0.qb64());
assert_eq!(result_items[1].0, vec!["b".to_string(), "2".to_string()]);
assert_eq!(result_items[1].1, val1_diger.qb64());
let db_ref = Arc::new(&lmdber);
let sdb_siger = CesrSuber::<Siger>::new(db_ref.clone(), "pigs.", None, true).unwrap();
let sig0 = "AACdI8OSQkMJ9r-xigjEByEjIua7LHH3AOJ22PQKqljMhuhcgh9nGRcKnsz5KvKd7K_H9-1298F4Id1DxvIoEmCQ";
let val0 = Siger::from_qb64(sig0, None)?;
let keys: &[&[u8]] = &[b"zeta".as_ref(), b"cat".as_ref()];
assert!(sdb_siger.put(keys, &val0)?);
let actual = sdb_siger.get(keys)?.unwrap();
assert_eq!(actual.qb64(), val0.qb64());
Ok(())
}
}