use crate::{err, ext, utils, Store, Object};
use std::collections::BTreeSet;
pub(crate) const TERMS_PREFIX: &'static [u8] = b"__house__\0terms\0";
pub struct Term<'a> {
pub field: &'a str,
pub value: &'a [u8],
}
impl<'a> Term<'a> {
pub(crate) fn flatten(self) -> Vec<u8> {
let mut out = Vec::with_capacity(self.field.len() + self.value.len() + 1);
out.extend(self.field.as_bytes());
out.push(0);
out.extend(self.value);
out
}
}
pub trait Queryable {
fn query_terms(&self) -> Vec<Term>;
}
pub trait TransactionalQuery<T: ext::MaybeTransactional> {
fn matching_ids(&self, tree: &T) -> Result<BTreeSet<u64>, T::Error>;
}
pub trait Query {
fn matching_ids(&self, tree: &sled::Tree) -> err::Result<BTreeSet<u64>>;
}
impl<U> Query for U where U: TransactionalQuery<sled::Tree> {
fn matching_ids(&self, tree: &sled::Tree) -> err::Result<BTreeSet<u64>> {
TransactionalQuery::matching_ids(self, tree).map_err(err::Error::from)
}
}
pub struct StrEquals<'a, D>(pub &'a str, pub D);
impl<'a, T, D> TransactionalQuery<T> for StrEquals<'a, D>
where T: ext::MaybeTransactional,
T::Error: From<err::Error>,
D: std::fmt::Display,
{
fn matching_ids(&self, tree: &T) -> Result<BTreeSet<u64>, T::Error> {
use std::io::Write;
let mut key = Vec::new();
write!(&mut key, "{}\0{}", &self.0, &self.1).map_err(err::Error::from)?;
let mut out = BTreeSet::new();
if let Some(val) = tree.get(key)? {
let mut ids: Vec<u64> = utils::deserialize(&val)?;
out.extend(&ids);
}
Ok(out)
}
}
pub struct Results<'a, T> {
pub(crate) store: &'a Store<T>,
pub(crate) matching_ids: BTreeSet<u64>,
}
impl<'a, T: Queryable + serde::Serialize + serde::de::DeserializeOwned> Results<'a, T> {
pub fn first(self) -> err::Result<Option<Object<T>>> {
let Self { store, matching_ids } = self;
Ok(matching_ids.into_iter().next()
.map(|id| store.find(id) )
.transpose()?
.and_then(|x| x))
}
pub fn all(self) -> err::Result<Vec<Object<T>>> {
let Self { store, matching_ids } = self;
let mut out = Vec::with_capacity(matching_ids.len());
for id in matching_ids.into_iter() {
if let Some(obj) = store.find(id)? {
out.push(obj);
}
}
Ok(out)
}
}
pub struct TransactionalResults<'a, T> {
pub(crate) store: &'a crate::TransactionalStore<'a, T>,
pub(crate) matching_ids: BTreeSet<u64>,
}
impl<'a, T: Queryable + serde::Serialize + serde::de::DeserializeOwned> TransactionalResults<'a, T> {
pub fn first(self) -> Result<Option<Object<T>>, sled::transaction::ConflictableTransactionError<err::Error>> {
let Self { store, matching_ids } = self;
Ok(matching_ids.into_iter().next()
.map(|id| store.find(id) )
.transpose()?
.and_then(|x| x))
}
pub fn all(self) -> Result<Vec<Object<T>>, sled::transaction::ConflictableTransactionError<err::Error>> {
let Self { store, matching_ids } = self;
let mut out = Vec::with_capacity(matching_ids.len());
for id in matching_ids.into_iter() {
if let Some(obj) = store.find(id)? {
out.push(obj);
}
}
Ok(out)
}
}