use crate::core::Value;
use crate::functions::{
AggregateFunction, FunctionDataType, FunctionInfo, FunctionSignature, FunctionType,
};
#[derive(Default)]
pub struct MinFunction {
min_value: Option<Value>,
}
impl AggregateFunction for MinFunction {
fn name(&self) -> &str {
"MIN"
}
fn info(&self) -> FunctionInfo {
FunctionInfo::new(
"MIN",
FunctionType::Aggregate,
"Returns the minimum value of all non-NULL values in the specified column",
FunctionSignature::new(
FunctionDataType::Any, vec![FunctionDataType::Any],
1,
1,
),
)
}
fn accumulate(&mut self, value: &Value, _distinct: bool) {
if value.is_null() {
return;
}
if self.min_value.is_none() {
self.min_value = Some(value.clone());
return;
}
if is_less_than(value, self.min_value.as_ref().unwrap()) {
self.min_value = Some(value.clone());
}
}
fn result(&self) -> Value {
self.min_value.clone().unwrap_or_else(Value::null_unknown)
}
fn reset(&mut self) {
self.min_value = None;
}
fn clone_box(&self) -> Box<dyn AggregateFunction> {
Box::new(MinFunction::default())
}
}
fn is_less_than(a: &Value, b: &Value) -> bool {
match (a, b) {
(Value::Null(_), _) | (_, Value::Null(_)) => false,
(Value::Integer(a), Value::Integer(b)) => a < b,
(Value::Float(a), Value::Float(b)) => a < b,
(Value::Integer(a), Value::Float(b)) => (*a as f64) < *b,
(Value::Float(a), Value::Integer(b)) => *a < (*b as f64),
(Value::Text(a), Value::Text(b)) => a < b,
(Value::Boolean(a), Value::Boolean(b)) => !a && *b, (Value::Timestamp(a), Value::Timestamp(b)) => a < b,
_ => false, }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_min_integers() {
let mut min = MinFunction::default();
min.accumulate(&Value::Integer(5), false);
min.accumulate(&Value::Integer(2), false);
min.accumulate(&Value::Integer(8), false);
assert_eq!(min.result(), Value::Integer(2));
}
#[test]
fn test_min_floats() {
let mut min = MinFunction::default();
min.accumulate(&Value::Float(5.5), false);
min.accumulate(&Value::Float(2.2), false);
min.accumulate(&Value::Float(8.8), false);
assert_eq!(min.result(), Value::Float(2.2));
}
#[test]
fn test_min_strings() {
let mut min = MinFunction::default();
min.accumulate(&Value::text("banana"), false);
min.accumulate(&Value::text("apple"), false);
min.accumulate(&Value::text("cherry"), false);
assert_eq!(min.result(), Value::text("apple"));
}
#[test]
fn test_min_ignores_null() {
let mut min = MinFunction::default();
min.accumulate(&Value::Integer(5), false);
min.accumulate(&Value::null_unknown(), false);
min.accumulate(&Value::Integer(2), false);
assert_eq!(min.result(), Value::Integer(2));
}
#[test]
fn test_min_empty() {
let min = MinFunction::default();
assert!(min.result().is_null());
}
#[test]
fn test_min_reset() {
let mut min = MinFunction::default();
min.accumulate(&Value::Integer(5), false);
min.accumulate(&Value::Integer(2), false);
min.reset();
assert!(min.result().is_null());
}
#[test]
fn test_min_single_value() {
let mut min = MinFunction::default();
min.accumulate(&Value::Integer(42), false);
assert_eq!(min.result(), Value::Integer(42));
}
#[test]
fn test_min_negative() {
let mut min = MinFunction::default();
min.accumulate(&Value::Integer(-5), false);
min.accumulate(&Value::Integer(10), false);
min.accumulate(&Value::Integer(-10), false);
assert_eq!(min.result(), Value::Integer(-10));
}
#[test]
fn test_min_booleans() {
let mut min = MinFunction::default();
min.accumulate(&Value::Boolean(true), false);
min.accumulate(&Value::Boolean(false), false);
min.accumulate(&Value::Boolean(true), false);
assert_eq!(min.result(), Value::Boolean(false));
}
}