use crate::db_type::{check_key_type, check_range_key_range_bounds, ToKey};
use crate::db_type::{unwrap_item, Key, KeyRange, Result, ToInput};
use std::marker::PhantomData;
use std::ops::RangeBounds;
pub struct PrimaryScan<PrimaryTable, T: ToInput>
where
PrimaryTable: redb::ReadableTable<Key, &'static [u8]>,
{
pub(crate) primary_table: PrimaryTable,
pub(crate) _marker: PhantomData<T>,
}
impl<PrimaryTable, T: ToInput> PrimaryScan<PrimaryTable, T>
where
PrimaryTable: redb::ReadableTable<Key, &'static [u8]>,
{
pub(crate) fn new(table: PrimaryTable) -> Self {
Self {
primary_table: table,
_marker: PhantomData,
}
}
pub fn all(&self) -> Result<PrimaryScanIterator<T>> {
let range = self.primary_table.range::<Key>(..)?;
Ok(PrimaryScanIterator {
range,
_marker: PhantomData,
})
}
pub fn range<R: RangeBounds<impl ToKey>>(&self, range: R) -> Result<PrimaryScanIterator<T>> {
let model = T::native_db_model();
check_range_key_range_bounds(&model, &range)?;
let database_inner_key_value_range = KeyRange::new(range);
let range = self
.primary_table
.range::<Key>(database_inner_key_value_range)?;
Ok(PrimaryScanIterator {
range,
_marker: PhantomData,
})
}
pub fn start_with(&self, start_with: impl ToKey) -> Result<PrimaryScanIteratorStartWith<T>> {
let model = T::native_db_model();
check_key_type(&model, &start_with)?;
let start_with = start_with.to_key();
let range = self.primary_table.range::<Key>(start_with.clone()..)?;
Ok(PrimaryScanIteratorStartWith {
range,
start_with,
_marker: PhantomData,
})
}
}
pub struct PrimaryScanIterator<'a, T: ToInput> {
pub(crate) range: redb::Range<'a, Key, &'static [u8]>,
pub(crate) _marker: PhantomData<T>,
}
impl<'a, T: ToInput> Iterator for PrimaryScanIterator<'a, T> {
type Item = Result<T>;
fn next(&mut self) -> Option<Self::Item> {
match self.range.next() {
Some(Ok((_, v))) => unwrap_item(Some(v)),
_ => None,
}
}
}
impl<'a, T: ToInput> DoubleEndedIterator for PrimaryScanIterator<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
match self.range.next_back() {
Some(Ok((_, v))) => unwrap_item(Some(v)),
_ => None,
}
}
}
pub struct PrimaryScanIteratorStartWith<'a, T: ToInput> {
pub(crate) range: redb::Range<'a, Key, &'static [u8]>,
pub(crate) start_with: Key,
pub(crate) _marker: PhantomData<T>,
}
impl<'a, T: ToInput> Iterator for PrimaryScanIteratorStartWith<'a, T> {
type Item = Result<T>;
fn next(&mut self) -> Option<Self::Item> {
match self.range.next() {
Some(Ok((k, v))) => {
let k = k.value();
if k.as_slice().starts_with(self.start_with.as_slice()) {
unwrap_item(Some(v))
} else {
None
}
}
_ => None,
}
}
}