use std::collections::HashMap;
use crate::catalog::ValType;
use crate::segment::{Cursor, Segment};
use crate::value::IndexValue;
use crate::value::ValueTest;
use kevy_text::{SortOrder, sorted_order};
use crate::segment_claused_merge::finish_facets;
pub use crate::segment_claused_merge::{
ColdEntryRow, claused_over, fold_facets, merge_claused, sort_facets, values_pass,
};
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct ScalarClauses<'a> {
pub filters: &'a [(usize, ValueTest)],
pub sort: Option<(usize, SortOrder, ValType)>,
pub distinct: Option<(usize, ValType)>,
pub facets: &'a [(usize, ValType)],
pub fetch: usize,
}
impl<'a> ScalarClauses<'a> {
pub fn new(fetch: usize) -> Self {
ScalarClauses { filters: &[], sort: None, distinct: None, facets: &[], fetch }
}
#[must_use]
pub fn with_filters(mut self, filters: &'a [(usize, ValueTest)]) -> Self {
self.filters = filters;
self
}
#[must_use]
pub fn with_sort(mut self, position: usize, order: SortOrder, ty: ValType) -> Self {
self.sort = Some((position, order, ty));
self
}
#[must_use]
pub fn with_distinct(mut self, position: usize, ty: ValType) -> Self {
self.distinct = Some((position, ty));
self
}
#[must_use]
pub fn with_facets(mut self, facets: &'a [(usize, ValType)]) -> Self {
self.facets = facets;
self
}
pub fn selects(&self) -> bool {
self.sort.is_some() || self.distinct.is_some() || !self.facets.is_empty()
}
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct ScalarHit {
pub key: Vec<u8>,
pub value: IndexValue,
pub okey: Option<Vec<u8>>,
pub dkey: Option<Vec<u8>>,
}
impl ScalarHit {
pub fn new(key: Vec<u8>, value: IndexValue) -> ScalarHit {
ScalarHit { key, value, okey: None, dkey: None }
}
}
pub type FacetBucket = (Vec<u8>, Vec<u8>, u64);
pub(crate) type FacetCounts = HashMap<Vec<u8>, (Vec<u8>, u64)>;
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct ClausedPage {
pub hits: Vec<ScalarHit>,
pub facets: Vec<Vec<FacetBucket>>,
pub cursor: Option<Cursor>,
}
impl Segment {
pub fn count_claused(
&self,
min: &IndexValue,
max: &IndexValue,
filters: &[(usize, ValueTest)],
) -> u64 {
if filters.is_empty() {
return self.count(min, max);
}
let mut w = self.range_walk(min, max, None);
let mut buf = Vec::new();
let mut n = 0;
while w.advance() {
n += u64::from(passes(&w, filters, &mut buf));
}
n
}
pub fn query_claused(
&self,
min: &IndexValue,
max: &IndexValue,
cursor: Option<&Cursor>,
c: &ScalarClauses<'_>,
) -> ClausedPage {
let mut facets: Vec<FacetCounts> = vec![HashMap::new(); c.facets.len()];
let mut hits: Vec<ScalarHit> = Vec::new();
let mut groups: HashMap<Vec<u8>, usize> = HashMap::new();
let full_walk = c.sort.is_some() || !c.facets.is_empty();
let mut w = self.range_walk(min, max, cursor);
let mut buf = Vec::new();
while w.advance() {
if !passes(&w, c.filters, &mut buf) {
continue;
}
count_facets(&w, c, &mut facets, &mut buf);
if !full_walk && hits.len() == c.fetch {
break;
}
select_hit(&mut w, c, &mut hits, &mut groups, &mut buf);
}
if let Some((_, order, _)) = c.sort {
hits.sort_by(|a, b| {
sorted_order((a.okey.as_deref(), &a.key), (b.okey.as_deref(), &b.key), order)
});
}
hits.truncate(c.fetch);
let cursor = filter_cursor(c, &hits);
ClausedPage { hits, facets: finish_facets(facets), cursor }
}
}
#[path = "segment_claused_select.rs"]
mod select;
use select::{count_facets, filter_cursor, passes, select_hit};
#[cfg(test)]
#[path = "segment_claused_tests.rs"]
mod tests;