use crate::core::Value;
use crate::functions::{
AggregateFunction, FunctionDataType, FunctionInfo, FunctionSignature, FunctionType,
};
#[derive(Default)]
pub struct FirstFunction {
first_value: Option<Value>,
}
impl AggregateFunction for FirstFunction {
fn name(&self) -> &str {
"FIRST"
}
fn info(&self) -> FunctionInfo {
FunctionInfo::new(
"FIRST",
FunctionType::Aggregate,
"Returns the first non-NULL value 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.first_value.is_none() {
self.first_value = Some(value.clone());
}
}
fn result(&self) -> Value {
self.first_value.clone().unwrap_or_else(Value::null_unknown)
}
fn reset(&mut self) {
self.first_value = None;
}
fn clone_box(&self) -> Box<dyn AggregateFunction> {
Box::new(FirstFunction::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_first_basic() {
let mut first = FirstFunction::default();
first.accumulate(&Value::Integer(1), false);
first.accumulate(&Value::Integer(2), false);
first.accumulate(&Value::Integer(3), false);
assert_eq!(first.result(), Value::Integer(1));
}
#[test]
fn test_first_ignores_null() {
let mut first = FirstFunction::default();
first.accumulate(&Value::null_unknown(), false);
first.accumulate(&Value::null_unknown(), false);
first.accumulate(&Value::Integer(3), false);
first.accumulate(&Value::Integer(4), false);
assert_eq!(first.result(), Value::Integer(3));
}
#[test]
fn test_first_empty() {
let first = FirstFunction::default();
assert!(first.result().is_null());
}
#[test]
fn test_first_all_null() {
let mut first = FirstFunction::default();
first.accumulate(&Value::null_unknown(), false);
first.accumulate(&Value::null_unknown(), false);
assert!(first.result().is_null());
}
#[test]
fn test_first_reset() {
let mut first = FirstFunction::default();
first.accumulate(&Value::Integer(1), false);
first.reset();
first.accumulate(&Value::Integer(5), false);
assert_eq!(first.result(), Value::Integer(5));
}
#[test]
fn test_first_string() {
let mut first = FirstFunction::default();
first.accumulate(&Value::text("hello"), false);
first.accumulate(&Value::text("world"), false);
assert_eq!(first.result(), Value::text("hello"));
}
}