use sled::Db;
use crate::{relation::Relation, Entity, Result};
pub struct QueryBuilder<'a> {
ids: Vec<&'a [u8]>,
parent: Option<&'a [u8]>,
related_to: Vec<(&'a str, &'a [u8], Option<&'a str>)>,
}
impl<'a> QueryBuilder<'a> {
pub fn new() -> QueryBuilder<'a> {
QueryBuilder {
ids: Vec::new(),
parent: None,
related_to: Vec::new(),
}
}
pub fn with_ids(&mut self, ids: &mut Vec<&'a [u8]>) -> &mut QueryBuilder<'a> {
self.ids.append(ids);
self
}
pub fn with_id(&mut self, id: &'a [u8]) -> &mut QueryBuilder<'a> {
self.ids.push(id);
self
}
pub fn with_parent(&mut self, id: &'a [u8]) -> &mut QueryBuilder<'a> {
self.parent = Some(id);
self
}
pub fn with_named_relation_to<OT: Entity>(
&mut self,
id: &'a [u8],
name: &'a str,
) -> &mut QueryBuilder<'a> {
self.related_to.push((OT::store_name(), id, Some(name)));
self
}
pub fn with_relation_to<OT: Entity>(&mut self, id: &'a [u8]) -> &mut QueryBuilder<'a> {
self.related_to.push((OT::store_name(), id, None));
self
}
pub fn get<T : Entity>(&self, db : &Db) -> Result<Vec<T>> {
Ok(T::get_each_u8(&self.get_ids::<T>(db)?, db))
}
pub fn get_single<T : Entity>(&self, db : &Db) -> Result<Option<T>> {
T::get_from_u8_array(&self.get_ids::<T>(db)?[0],db)
}
fn get_ids<T : Entity>(&self, db: &Db) -> Result<Vec<Vec<u8>>> {
let target_ids = match (self.ids.len(), self.related_to.len(), self.parent) {
(0, 0, None) => {
return Ok(Vec::new());
}
(0, 0, Some(p)) => {
let mut result: Vec<Vec<u8>> = Vec::new();
T::get_tree(db)?.scan_prefix(p).for_each(|elem| {
if let Ok((key, _)) = elem {
result.push(key.to_vec());
}
});
return Ok(result);
}
(0, _, _) => {
self.get_related_ids::<T>(db)?
}
(_, _, _) => {
let related_ids = self.get_related_ids::<T>(db)?;
let mut target_ids = Vec::new();
for related_id in related_ids {
if self.ids.contains(&related_id.as_ref()) {
target_ids.push(related_id.clone());
}
}
target_ids
}
};
if let Some(parent) = self.parent {
Ok(target_ids.iter().filter(|id| id.starts_with(parent)).cloned().collect())
}
else {
Ok(target_ids)
}
}
fn get_related_ids<T : Entity>(&self, db: &Db) -> Result<Vec<Vec<u8>>> {
let mut target_ids = Vec::new();
for (tree_name, id, relation_name) in &self.related_to {
let descriptor = Relation::get_descriptor_with_key_and_tree_name(tree_name, id, db)?;
if let Some(list) = descriptor.related_entities.get(T::store_name()) {
for rel in list {
if rel.name.as_deref() == relation_name.as_deref() {
target_ids.push(rel.key.clone());
}
}
}
}
Ok(target_ids)
}
}