use ciborium::Value as CborValue;
use vantage_core::Result;
use crate::rhai::traverse::traverse;
use crate::{FilterOp, sort::SortDirection, vista::Vista};
#[derive(Clone, Debug)]
pub(crate) enum Step {
Where {
col: String,
op: FilterOp,
value: CborValue,
},
Sort {
col: String,
dir: SortDirection,
},
Search(String),
Limit(usize),
Offset(usize),
Ref(String),
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) struct RowWindow {
pub offset: usize,
pub limit: Option<usize>,
}
impl RowWindow {
pub(super) fn fold(self, step: &Step) -> RowWindow {
match step {
Step::Limit(n) => self.capped(Some(*n)),
Step::Offset(n) => RowWindow {
offset: self.offset.saturating_add(*n),
..self
},
_ => self,
}
}
pub(crate) fn capped(self, cap: Option<usize>) -> RowWindow {
let limit = match (self.limit, cap) {
(Some(a), Some(b)) => Some(a.min(b)),
(a, b) => a.or(b),
};
RowWindow { limit, ..self }
}
pub(crate) fn count(self, total: i64) -> i64 {
let skipped = i64::try_from(self.offset).unwrap_or(i64::MAX);
let rest = total.saturating_sub(skipped).max(0);
self.limit.map_or(rest, |n| rest.min(n as i64))
}
}
impl Step {
pub(super) fn apply(&self, mut vista: Vista, ref_window: RowWindow) -> Result<Vista> {
match self {
Step::Where { col, op, value } => vista.add_condition(col, *op, value.clone())?,
Step::Sort { col, dir } => vista.set_order(Some((col, *dir)))?,
Step::Search(text) => vista.set_search(Some(text))?,
Step::Limit(_) | Step::Offset(_) => {}
Step::Ref(rel) => return traverse(&vista, rel, ref_window),
}
Ok(vista)
}
pub(super) fn ref_window_after(&self, ref_window: RowWindow) -> RowWindow {
match self {
Step::Ref(_) => RowWindow::default(),
step => ref_window.fold(step),
}
}
pub(super) fn positional_verb(&self) -> Option<&'static str> {
match self {
Step::Limit(_) => Some("limit"),
Step::Offset(_) => Some("offset"),
_ => None,
}
}
}