use std::cmp::Ordering;
use nodedb_types::Value;
pub fn value_replaces(candidate: &Value, current: Option<&Value>, want_max: bool) -> bool {
let Some(current) = current else {
return true;
};
let order = crate::value_ops::numeric_order(candidate, current)
.unwrap_or_else(|| crate::value_ops::compare_values(candidate, current));
let wanted = if want_max {
Ordering::Greater
} else {
Ordering::Less
};
order == wanted
}
pub fn extremum_direction(func_name: &str) -> Option<bool> {
match func_name {
"min" => Some(false),
"max" => Some(true),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn integers_above_2_pow_53_compare_exactly() {
let a = Value::Integer(9_007_199_254_740_993);
let b = Value::Integer(9_007_199_254_740_992);
assert!(value_replaces(&b, Some(&a), false));
assert!(!value_replaces(&b, Some(&a), true));
assert!(value_replaces(&a, Some(&b), true));
}
#[test]
fn value_nan_is_the_largest_extreme() {
let one = Value::Integer(1);
let nan = Value::Float(f64::NAN);
assert!(!value_replaces(&nan, Some(&one), false));
assert!(value_replaces(&nan, Some(&one), true));
assert!(value_replaces(&one, Some(&nan), false));
assert!(!value_replaces(&one, Some(&nan), true));
assert!(!value_replaces(&nan, Some(&nan), true));
let inf = Value::Float(f64::INFINITY);
assert!(value_replaces(&nan, Some(&inf), true));
}
#[test]
fn decimal_text_max_compares_exactly() {
let low = Value::String("12345678901234567.01".into());
let high = Value::String("12345678901234567.02".into());
assert!(value_replaces(&high, Some(&low), true));
assert!(!value_replaces(&low, Some(&high), true));
assert!(value_replaces(&low, Some(&high), false));
let low_dec = Value::Decimal(rust_decimal::Decimal::new(1_234_567_890_123_456_701, 2));
let high_dec = Value::Decimal(rust_decimal::Decimal::new(1_234_567_890_123_456_702, 2));
assert!(value_replaces(&high_dec, Some(&low_dec), true));
assert!(!value_replaces(&low_dec, Some(&high_dec), true));
assert!(value_replaces(&high, Some(&low_dec), true));
}
#[test]
fn value_mixed_int_float_compare_exactly() {
let big = Value::Integer(9_007_199_254_740_993);
let float = Value::Float(9_007_199_254_740_992.0);
assert!(value_replaces(&big, Some(&float), true));
assert!(!value_replaces(&big, Some(&float), false));
assert!(value_replaces(&float, Some(&big), false));
}
}