use crate::{
db::predicate::{CoercionSpec, CompareOp, TextOp, compare_eq, compare_order, compare_text},
value::Value,
};
use std::cmp::Ordering;
pub(in crate::db) fn eval_compare_values(
actual: &Value,
op: CompareOp,
value: &Value,
coercion: &CoercionSpec,
) -> bool {
match op {
CompareOp::Eq => compare_eq(actual, value, coercion).unwrap_or(false),
CompareOp::Ne => compare_eq(actual, value, coercion).is_some_and(|v| !v),
CompareOp::Lt => compare_order(actual, value, coercion).is_some_and(Ordering::is_lt),
CompareOp::Lte => compare_order(actual, value, coercion).is_some_and(Ordering::is_le),
CompareOp::Gt => compare_order(actual, value, coercion).is_some_and(Ordering::is_gt),
CompareOp::Gte => compare_order(actual, value, coercion).is_some_and(Ordering::is_ge),
CompareOp::In => in_list(actual, value, coercion).unwrap_or(false),
CompareOp::NotIn => in_list(actual, value, coercion).is_some_and(|matched| !matched),
CompareOp::Contains => contains(actual, value, coercion),
CompareOp::StartsWith => {
compare_text(actual, value, coercion, TextOp::StartsWith).unwrap_or(false)
}
CompareOp::EndsWith => {
compare_text(actual, value, coercion, TextOp::EndsWith).unwrap_or(false)
}
}
}
pub(in crate::db::predicate::runtime) const fn is_empty_value(value: &Value) -> bool {
match value {
Value::Text(text) => text.is_empty(),
Value::List(items) => items.is_empty(),
_ => false,
}
}
fn in_list(actual: &Value, list: &Value, coercion: &CoercionSpec) -> Option<bool> {
let Value::List(items) = list else {
return None;
};
let mut saw_valid = false;
for item in items {
match compare_eq(actual, item, coercion) {
Some(true) => return Some(true),
Some(false) => saw_valid = true,
None => {}
}
}
saw_valid.then_some(false)
}
fn contains(actual: &Value, needle: &Value, coercion: &CoercionSpec) -> bool {
if matches!(actual, Value::Text(_)) {
return false;
}
let Value::List(items) = actual else {
return false;
};
items
.iter()
.any(|item| compare_eq(item, needle, coercion).unwrap_or(false))
}