mod array_agg;
mod avg;
pub mod compiled;
mod count;
mod first;
mod last;
mod max;
mod min;
mod statistics;
mod string_agg;
mod sum;
pub use array_agg::ArrayAggFunction;
pub use avg::AvgFunction;
pub use compiled::CompiledAggregate;
pub use count::CountFunction;
pub use first::FirstFunction;
pub use last::LastFunction;
pub use max::MaxFunction;
pub use min::MinFunction;
pub use statistics::{
MedianFunction, StddevFunction, StddevPopFunction, StddevSampFunction, VarPopFunction,
VarSampFunction, VarianceFunction,
};
pub use string_agg::{GroupConcatFunction, StringAggFunction};
pub use sum::SumFunction;
use crate::core::Value;
use std::collections::HashSet;
fn value_to_distinct_key(value: &Value) -> Option<String> {
if value.is_null() {
return None; }
match value {
Value::Null(_) => None,
Value::Integer(i) => Some(format!("i:{}", i)),
Value::Float(f) => Some(format!("f:{}", f)),
Value::Text(s) => Some(format!("s:{}", s)),
Value::Boolean(b) => Some(format!("b:{}", b)),
Value::Timestamp(t) => Some(format!("t:{}", t)),
Value::Json(j) => Some(format!("j:{}", j)),
}
}
#[derive(Default, Debug)]
pub struct DistinctTracker {
seen: HashSet<String>,
}
impl DistinctTracker {
pub fn check_and_add(&mut self, value: &Value) -> bool {
if let Some(key) = value_to_distinct_key(value) {
self.seen.insert(key)
} else {
false }
}
pub fn count(&self) -> usize {
self.seen.len()
}
pub fn reset(&mut self) {
self.seen.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_distinct_tracker() {
let mut tracker = DistinctTracker::default();
assert!(tracker.check_and_add(&Value::Integer(1)));
assert!(!tracker.check_and_add(&Value::Integer(1))); assert!(tracker.check_and_add(&Value::Integer(2)));
assert!(tracker.check_and_add(&Value::text("hello")));
assert_eq!(tracker.count(), 3);
tracker.reset();
assert_eq!(tracker.count(), 0);
}
#[test]
fn test_null_handling() {
let mut tracker = DistinctTracker::default();
assert!(!tracker.check_and_add(&Value::null_unknown())); assert!(!tracker.check_and_add(&Value::null_unknown())); assert_eq!(tracker.count(), 0); }
}