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, ValueSet};
use std::cmp::Ordering;
pub(crate) fn compare_sort_keys(a: &[Value], b: &[Value], directions: &[bool]) -> Ordering {
for (i, (key_a, key_b)) in a.iter().zip(b.iter()).enumerate() {
let is_asc = directions.get(i).copied().unwrap_or(true);
let cmp = compare_values_for_sort(key_a, key_b);
if cmp != Ordering::Equal {
return if is_asc { cmp } else { cmp.reverse() };
}
}
Ordering::Equal
}
fn compare_values_for_sort(a: &Value, b: &Value) -> Ordering {
match (a, b) {
(Value::Null(_), Value::Null(_)) => Ordering::Equal,
(Value::Null(_), _) => Ordering::Greater,
(_, Value::Null(_)) => Ordering::Less,
(Value::Integer(a), Value::Integer(b)) => a.cmp(b),
(Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
(Value::Integer(a), Value::Float(b)) => {
(*a as f64).partial_cmp(b).unwrap_or(Ordering::Equal)
}
(Value::Float(a), Value::Integer(b)) => {
a.partial_cmp(&(*b as f64)).unwrap_or(Ordering::Equal)
}
(Value::Text(a), Value::Text(b)) => a.cmp(b),
(Value::Boolean(a), Value::Boolean(b)) => a.cmp(b),
(Value::Timestamp(a), Value::Timestamp(b)) => a.cmp(b),
_ => Ordering::Equal,
}
}
#[derive(Default, Debug)]
pub struct DistinctTracker {
seen: ValueSet,
}
impl DistinctTracker {
#[inline]
pub fn check_and_add(&mut self, value: &Value) -> bool {
self.seen.insert(value.clone())
}
#[inline]
pub fn check_and_add_with_null_check(&mut self, value: &Value) -> bool {
if value.is_null() {
return false;
}
self.seen.insert(value.clone())
}
#[inline]
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_with_null_check(&Value::null_unknown())); assert!(!tracker.check_and_add_with_null_check(&Value::null_unknown())); assert_eq!(tracker.count(), 0); }
}