use crate::{
error::StoreError,
read_transform,
readwrite::{
Readable,
Writer,
},
value::Value,
};
use lmdb::{
Cursor,
Database,
Iter as LmdbIter,
RoCursor,
WriteFlags,
};
#[derive(Copy, Clone)]
pub struct MultiStore {
db: Database,
}
pub struct Iter<'env> {
iter: LmdbIter<'env>,
cursor: RoCursor<'env>,
}
impl MultiStore {
pub(crate) fn new(db: Database) -> MultiStore {
MultiStore {
db,
}
}
pub fn get<T: Readable, K: AsRef<[u8]>>(self, reader: &T, k: K) -> Result<Iter, StoreError> {
let mut cursor = reader.open_ro_cursor(self.db)?;
let iter = cursor.iter_dup_of(k);
Ok(Iter {
iter,
cursor,
})
}
pub fn get_first<T: Readable, K: AsRef<[u8]>>(self, reader: &T, k: K) -> Result<Option<Value>, StoreError> {
reader.get(self.db, &k)
}
pub fn put<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
writer.put(self.db, &k, v, WriteFlags::empty())
}
pub fn put_with_flags<K: AsRef<[u8]>>(
self,
writer: &mut Writer,
k: K,
v: &Value,
flags: WriteFlags,
) -> Result<(), StoreError> {
writer.put(self.db, &k, v, flags)
}
pub fn delete_all<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K) -> Result<(), StoreError> {
writer.delete(self.db, &k, None)
}
pub fn delete<K: AsRef<[u8]>>(self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> {
writer.delete(self.db, &k, Some(&v.to_bytes()?))
}
pub fn clear(self, writer: &mut Writer) -> Result<(), StoreError> {
writer.clear(self.db)
}
}
impl<'env> Iterator for Iter<'env> {
type Item = Result<(&'env [u8], Option<Value<'env>>), StoreError>;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(Ok((key, bytes))) => match read_transform(Ok(bytes)) {
Ok(val) => Some(Ok((key, val))),
Err(err) => Some(Err(err)),
},
Some(Err(err)) => Some(Err(StoreError::LmdbError(err))),
}
}
}