1use crate::executor::expression::ExpressionError;
4use linkrs_core::types::operators::AggregateFunction;
5use linkrs_core::value::list::List;
6use linkrs_core::value::NullType;
7use linkrs_core::Expression;
8use linkrs_core::Value;
9use serde::{Deserialize, Serialize};
10
11pub fn aggregate_from_str(func_name: &str) -> Result<AggregateFunction, ExpressionError> {
13 match func_name.to_uppercase().as_str() {
14 "COUNT" | "COUNT_DISTINCT" | "DISTINCT" => Ok(AggregateFunction::Count),
15 "SUM" => Ok(AggregateFunction::Sum),
16 "AVG" => Ok(AggregateFunction::Avg),
17 "MIN" => Ok(AggregateFunction::Min),
18 "MAX" => Ok(AggregateFunction::Max),
19 "COLLECT" => Ok(AggregateFunction::Collect),
20 "PERCENTILE" => Ok(AggregateFunction::Percentile),
21 "STDDEV_POP" => Ok(AggregateFunction::StddevPop),
22 "STDDEV_SAMP" => Ok(AggregateFunction::StddevSamp),
23 "PRODUCT" => Ok(AggregateFunction::Product),
24 "PERCENTILE_CONT" => Ok(AggregateFunction::PercentileCont),
25 "VARIANCE" => Ok(AggregateFunction::Variance),
26 "MEDIAN" => Ok(AggregateFunction::Median),
27 "MODE" => Ok(AggregateFunction::Mode),
28 "BOOL_AND" => Ok(AggregateFunction::BoolAnd),
29 "BOOL_OR" => Ok(AggregateFunction::BoolOr),
30 _ => Err(ExpressionError::function_error(format!(
31 "Unknown aggregate function: {}",
32 func_name
33 ))),
34 }
35}
36
37pub fn aggregate_from_str_with_args(
39 func_name: &str,
40 args: &[String],
41) -> Result<AggregateFunction, ExpressionError> {
42 match func_name.to_uppercase().as_str() {
43 "COUNT" | "COUNT_DISTINCT" | "DISTINCT" => Ok(AggregateFunction::Count),
44 "SUM" => {
45 if args.is_empty() {
46 return Err(ExpressionError::function_error(
47 "SUM function requires a field name".to_string(),
48 ));
49 }
50 Ok(AggregateFunction::Sum)
51 }
52 "AVG" => {
53 if args.is_empty() {
54 return Err(ExpressionError::function_error(
55 "AVG function requires a field name".to_string(),
56 ));
57 }
58 Ok(AggregateFunction::Avg)
59 }
60 "MIN" => {
61 if args.is_empty() {
62 return Err(ExpressionError::function_error(
63 "MIN function requires a field name".to_string(),
64 ));
65 }
66 Ok(AggregateFunction::Min)
67 }
68 "MAX" => {
69 if args.is_empty() {
70 return Err(ExpressionError::function_error(
71 "MAX function requires a field name".to_string(),
72 ));
73 }
74 Ok(AggregateFunction::Max)
75 }
76 "COLLECT" => {
77 if args.is_empty() {
78 return Err(ExpressionError::function_error(
79 "COLLECT function requires a field name".to_string(),
80 ));
81 }
82 Ok(AggregateFunction::Collect)
83 }
84 "PERCENTILE" => {
85 if args.len() < 2 {
86 return Err(ExpressionError::function_error(
87 "PERCENTILE function requires a field name and percentile value".to_string(),
88 ));
89 }
90 Ok(AggregateFunction::Percentile)
91 }
92 "PERCENTILE_CONT" => {
93 if args.len() < 2 {
94 return Err(ExpressionError::function_error(
95 "PERCENTILE_CONT function requires a field name and percentile value"
96 .to_string(),
97 ));
98 }
99 Ok(AggregateFunction::PercentileCont)
100 }
101 "VEC_SUM" => {
102 if args.is_empty() {
103 return Err(ExpressionError::function_error(
104 "VEC_SUM function requires a field name".to_string(),
105 ));
106 }
107 Ok(AggregateFunction::VecSum)
108 }
109 "VEC_AVG" => {
110 if args.is_empty() {
111 return Err(ExpressionError::function_error(
112 "VEC_AVG function requires a field name".to_string(),
113 ));
114 }
115 Ok(AggregateFunction::VecAvg)
116 }
117 "STDDEV_POP" => {
118 if args.is_empty() {
119 return Err(ExpressionError::function_error(
120 "STDDEV_POP function requires a field name".to_string(),
121 ));
122 }
123 Ok(AggregateFunction::StddevPop)
124 }
125 "STDDEV_SAMP" => {
126 if args.is_empty() {
127 return Err(ExpressionError::function_error(
128 "STDDEV_SAMP function requires a field name".to_string(),
129 ));
130 }
131 Ok(AggregateFunction::StddevSamp)
132 }
133 "PRODUCT" => {
134 if args.is_empty() {
135 return Err(ExpressionError::function_error(
136 "PRODUCT function requires a field name".to_string(),
137 ));
138 }
139 Ok(AggregateFunction::Product)
140 }
141 "VARIANCE" => {
142 if args.is_empty() {
143 return Err(ExpressionError::function_error(
144 "VARIANCE function requires a field name".to_string(),
145 ));
146 }
147 Ok(AggregateFunction::Variance)
148 }
149 "MEDIAN" => {
150 if args.is_empty() {
151 return Err(ExpressionError::function_error(
152 "MEDIAN function requires a field name".to_string(),
153 ));
154 }
155 Ok(AggregateFunction::Median)
156 }
157 "MODE" => {
158 if args.is_empty() {
159 return Err(ExpressionError::function_error(
160 "MODE function requires a field name".to_string(),
161 ));
162 }
163 Ok(AggregateFunction::Mode)
164 }
165 "BOOL_AND" => {
166 if args.is_empty() {
167 return Err(ExpressionError::function_error(
168 "BOOL_AND function requires a field name".to_string(),
169 ));
170 }
171 Ok(AggregateFunction::BoolAnd)
172 }
173 "BOOL_OR" => {
174 if args.is_empty() {
175 return Err(ExpressionError::function_error(
176 "BOOL_OR function requires a field name".to_string(),
177 ));
178 }
179 Ok(AggregateFunction::BoolOr)
180 }
181 _ => Err(ExpressionError::function_error(format!(
182 "Unknown aggregate function: {}",
183 func_name
184 ))),
185 }
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct AggregateExpression {
191 pub function: AggregateFunction,
192 pub argument: Box<Expression>,
193 pub distinct: bool,
194}
195
196impl AggregateExpression {
197 pub fn new(function: AggregateFunction, argument: Expression, distinct: bool) -> Self {
198 Self {
199 function,
200 argument: Box::new(argument),
201 distinct,
202 }
203 }
204
205 pub fn evaluate<C: crate::executor::expression::ExpressionContext>(
207 &self,
208 context: &mut C,
209 state: &mut AggregateState,
210 ) -> Result<Value, ExpressionError> {
211 let arg_value =
212 crate::executor::expression::evaluator::expression_evaluator::ExpressionEvaluator::evaluate(
213 &self.argument,
214 context,
215 )
216 .map_err(|e| ExpressionError::function_error(e.to_string()))?;
217
218 state.update(&self.function, &arg_value, self.distinct);
220
221 match &self.function {
223 AggregateFunction::Count => Ok(Value::BigInt(state.count)),
224 AggregateFunction::Sum => Ok(state.sum.clone()),
225 AggregateFunction::Min => Ok(state
226 .min
227 .clone()
228 .unwrap_or(Value::Null(linkrs_core::value::NullType::Null))),
229 AggregateFunction::Max => Ok(state
230 .max
231 .clone()
232 .unwrap_or(Value::Null(linkrs_core::value::NullType::Null))),
233 AggregateFunction::Avg => {
234 if state.count > 0 {
235 match &state.sum {
236 Value::SmallInt(i) => Ok(Value::Double(*i as f64 / state.count as f64)),
237 Value::Int(i) => Ok(Value::Double(*i as f64 / state.count as f64)),
238 Value::BigInt(i) => Ok(Value::Double(*i as f64 / state.count as f64)),
239 Value::Float(f) => Ok(Value::Double(*f as f64 / state.count as f64)),
240 Value::Double(f) => Ok(Value::Double(*f / state.count as f64)),
241 _ => Ok(Value::Double(0.0)),
242 }
243 } else {
244 Ok(Value::Double(0.0))
245 }
246 }
247 AggregateFunction::Collect => Ok(Value::list(List::from(state.values.clone()))),
248 AggregateFunction::CollectSet => Ok(Value::set(
249 state
250 .values
251 .iter()
252 .cloned()
253 .collect::<std::collections::HashSet<_>>(),
254 )),
255 AggregateFunction::Percentile => state.calculate_percentile(50.0),
256 AggregateFunction::PercentileCont => state.calculate_percentile(50.0),
257 AggregateFunction::Std => state.calculate_std(),
258 AggregateFunction::StddevPop => state.calculate_stddev_pop(),
259 AggregateFunction::StddevSamp => state.calculate_stddev_samp(),
260 AggregateFunction::Product => state.calculate_product(),
261 AggregateFunction::Variance => state.calculate_variance(),
262 AggregateFunction::Median => state.calculate_median(),
263 AggregateFunction::Mode => state.calculate_mode(),
264 AggregateFunction::BitAnd => state.calculate_bit_and(),
265 AggregateFunction::BitOr => state.calculate_bit_or(),
266 AggregateFunction::BoolAnd => state.calculate_bool_and(),
267 AggregateFunction::BoolOr => state.calculate_bool_or(),
268 AggregateFunction::GroupConcat | AggregateFunction::GroupConcatWithOrder => {
269 state.calculate_group_concat()
270 }
271 AggregateFunction::VecSum => Ok(state.vec_sum.clone()),
272 AggregateFunction::VecAvg => {
273 if state.count > 0 {
274 Ok(state.vec_avg.clone())
275 } else {
276 Ok(Value::Null(linkrs_core::value::NullType::NaN))
277 }
278 }
279 }
280 }
281}
282
283#[derive(Debug, Clone)]
285pub struct AggregateState {
286 pub count: i64,
287 pub sum: Value,
288 pub min: Option<Value>,
289 pub max: Option<Value>,
290 pub values: Vec<Value>,
291 pub distinct_values: std::collections::HashSet<String>,
292 pub percentile_values: Vec<f64>,
293 pub std_values: Vec<f64>,
294 pub variance_values: Vec<f64>,
295 pub median_values: Vec<f64>,
296 pub mode_values: Vec<Value>,
297 pub bit_and_value: Option<i64>,
298 pub bit_or_value: Option<i64>,
299 pub bool_and_value: Option<bool>,
300 pub bool_or_value: Option<bool>,
301 pub group_concat_values: Vec<Value>,
302 pub vec_sum: Value,
304 pub vec_avg: Value,
306}
307
308impl Default for AggregateState {
309 fn default() -> Self {
310 Self::new()
311 }
312}
313
314impl AggregateState {
315 pub fn new() -> Self {
316 Self {
317 count: 0,
318 sum: Value::Int(0),
319 min: None,
320 max: None,
321 values: Vec::new(),
322 distinct_values: std::collections::HashSet::new(),
323 percentile_values: Vec::new(),
324 std_values: Vec::new(),
325 variance_values: Vec::new(),
326 median_values: Vec::new(),
327 mode_values: Vec::new(),
328 bit_and_value: None,
329 bit_or_value: None,
330 bool_and_value: None,
331 bool_or_value: None,
332 group_concat_values: Vec::new(),
333 vec_sum: Value::Null(linkrs_core::value::NullType::NaN),
334 vec_avg: Value::Null(linkrs_core::value::NullType::NaN),
335 }
336 }
337
338 pub fn reset(&mut self) {
339 self.count = 0;
340 self.sum = Value::Int(0);
341 self.min = None;
342 self.max = None;
343 self.values.clear();
344 self.distinct_values.clear();
345 self.percentile_values.clear();
346 self.std_values.clear();
347 self.variance_values.clear();
348 self.median_values.clear();
349 self.mode_values.clear();
350 self.bit_and_value = None;
351 self.bit_or_value = None;
352 self.bool_and_value = None;
353 self.bool_or_value = None;
354 self.group_concat_values.clear();
355 self.vec_sum = Value::Null(linkrs_core::value::NullType::NaN);
356 self.vec_avg = Value::Null(linkrs_core::value::NullType::NaN);
357 }
358
359 pub fn update(&mut self, function: &AggregateFunction, value: &Value, distinct: bool) {
361 let value_str = format!("{}", value);
362
363 if distinct && self.distinct_values.contains(&value_str) {
365 return;
366 }
367
368 if distinct {
370 self.distinct_values.insert(value_str);
371 }
372
373 self.count += 1;
374 self.values.push(value.clone());
375
376 match function {
378 AggregateFunction::Percentile | AggregateFunction::PercentileCont => {
379 match value {
381 Value::SmallInt(v) => self.percentile_values.push(*v as f64),
382 Value::Int(v) => self.percentile_values.push(*v as f64),
383 Value::BigInt(v) => self.percentile_values.push(*v as f64),
384 Value::Float(v) => self.percentile_values.push(*v as f64),
385 Value::Double(v) => self.percentile_values.push(*v),
386 _ => {}
387 }
388 }
389 AggregateFunction::Std
390 | AggregateFunction::StddevPop
391 | AggregateFunction::StddevSamp
392 | AggregateFunction::Variance => {
393 match value {
395 Value::SmallInt(v) => self.std_values.push(*v as f64),
396 Value::Int(v) => self.std_values.push(*v as f64),
397 Value::BigInt(v) => self.std_values.push(*v as f64),
398 Value::Float(v) => self.std_values.push(*v as f64),
399 Value::Double(v) => self.std_values.push(*v),
400 _ => {}
401 }
402 }
403 AggregateFunction::Median => {
404 match value {
406 Value::SmallInt(v) => self.median_values.push(*v as f64),
407 Value::Int(v) => self.median_values.push(*v as f64),
408 Value::BigInt(v) => self.median_values.push(*v as f64),
409 Value::Float(v) => self.median_values.push(*v as f64),
410 Value::Double(v) => self.median_values.push(*v),
411 _ => {}
412 }
413 }
414 AggregateFunction::Mode => {
415 self.mode_values.push(value.clone());
416 }
417 AggregateFunction::BitAnd => {
418 if let Value::BigInt(v) = value {
420 if let Some(current) = self.bit_and_value {
421 self.bit_and_value = Some(current & v);
422 } else {
423 self.bit_and_value = Some(*v);
424 }
425 }
426 }
427 AggregateFunction::BitOr => {
428 if let Value::BigInt(v) = value {
430 if let Some(current) = self.bit_or_value {
431 self.bit_or_value = Some(current | v);
432 } else {
433 self.bit_or_value = Some(*v);
434 }
435 }
436 }
437 AggregateFunction::BoolAnd => {
438 if let Value::Bool(b) = value {
439 if let Some(current) = self.bool_and_value {
440 self.bool_and_value = Some(current && *b);
441 } else {
442 self.bool_and_value = Some(*b);
443 }
444 }
445 }
446 AggregateFunction::BoolOr => {
447 if let Value::Bool(b) = value {
448 if let Some(current) = self.bool_or_value {
449 self.bool_or_value = Some(current || *b);
450 } else {
451 self.bool_or_value = Some(*b);
452 }
453 }
454 }
455 AggregateFunction::GroupConcat | AggregateFunction::GroupConcatWithOrder => {
456 self.group_concat_values.push(value.clone());
458 }
459 AggregateFunction::VecSum => {
460 if matches!(value, Value::Vector(_)) {
462 if self.vec_sum.is_null() {
463 self.vec_sum = value.clone();
464 } else if let (Value::Vector(sum_vec), Value::Vector(input_vec)) =
465 (&mut self.vec_sum, value)
466 {
467 let sum_data = sum_vec.to_dense();
468 let input_data = input_vec.to_dense();
469
470 if sum_data.len() == input_data.len() {
471 let new_data: Vec<f32> = sum_data
472 .iter()
473 .zip(input_data.iter())
474 .map(|(&a, &b)| a + b)
475 .collect();
476 self.vec_sum = Value::vector(new_data);
477 }
478 }
479 }
480 }
481 AggregateFunction::VecAvg => {
482 if matches!(value, Value::Vector(_)) {
484 if self.vec_avg.is_null() {
485 self.vec_avg = value.clone();
486 } else if let (Value::Vector(avg_vec), Value::Vector(input_vec)) =
487 (&mut self.vec_avg, value)
488 {
489 let avg_data = avg_vec.to_dense();
490 let input_data = input_vec.to_dense();
491
492 if avg_data.len() == input_data.len() {
493 let new_avg: Vec<f32> = avg_data
495 .iter()
496 .zip(input_data.iter())
497 .map(|(&avg, &input)| avg + (input - avg) / self.count as f32)
498 .collect();
499 self.vec_avg = Value::vector(new_avg);
500 }
501 }
502 }
503 }
504 AggregateFunction::Product => {
505 if !value.is_null() && !value.is_empty() {
507 if self.sum == Value::Int(0) {
508 self.sum = value.clone();
509 } else {
510 self.sum = match (&self.sum, value) {
511 (Value::SmallInt(a), Value::SmallInt(b)) => Value::SmallInt(a * b),
512 (Value::SmallInt(a), Value::Int(b)) => Value::Int(*a as i32 * b),
513 (Value::Int(a), Value::Int(b)) => Value::Int(a * b),
514 (Value::Int(a), Value::SmallInt(b)) => Value::Int(a * *b as i32),
515 (Value::BigInt(a), Value::BigInt(b)) => Value::BigInt(a * b),
516 (Value::Float(a), Value::Float(b)) => Value::Float(a * b),
517 (Value::Double(a), Value::Double(b)) => Value::Double(a * b),
518 _ => Value::Null(NullType::BadData),
519 };
520 }
521 }
522 }
523 _ => {
524 if self.min.as_ref().is_none_or(|min_val| value < min_val) {
527 self.min = Some(value.clone());
528 }
529
530 if self.max.as_ref().is_none_or(|max_val| value > max_val) {
532 self.max = Some(value.clone());
533 }
534
535 match (&mut self.sum, value) {
537 (Value::SmallInt(ref mut sum_int), Value::SmallInt(val_int)) => {
538 *sum_int += *val_int;
539 }
540 (Value::Int(ref mut sum_int), Value::Int(val_int)) => {
541 *sum_int += *val_int;
542 }
543 (Value::BigInt(ref mut sum_int), Value::BigInt(val_int)) => {
544 *sum_int += *val_int;
545 }
546 (Value::Float(ref mut sum_float), Value::Float(val_float)) => {
547 *sum_float += *val_float;
548 }
549 (Value::Double(ref mut sum_float), Value::Double(val_float)) => {
550 *sum_float += *val_float;
551 }
552 (Value::SmallInt(ref mut sum_int), Value::Int(val_int)) => {
553 self.sum = Value::Int(*sum_int as i32 + *val_int);
554 }
555 (Value::Int(ref mut sum_int), Value::SmallInt(val_int)) => {
556 *sum_int += *val_int as i32;
557 }
558 (Value::Int(ref mut sum_int), Value::BigInt(val_int)) => {
559 self.sum = Value::BigInt(*sum_int as i64 + *val_int);
560 }
561 (Value::BigInt(ref mut sum_int), Value::Int(val_int)) => {
562 *sum_int += *val_int as i64;
563 }
564 (Value::Float(ref mut sum_float), Value::Double(val_float)) => {
565 self.sum = Value::Double(*sum_float as f64 + *val_float);
566 }
567 (Value::Double(ref mut sum_float), Value::Float(val_float)) => {
568 *sum_float += *val_float as f64;
569 }
570 _ => {}
571 }
572 }
573 }
574 }
575
576 pub fn calculate_percentile(&self, percentile: f64) -> Result<Value, ExpressionError> {
578 if self.percentile_values.is_empty() {
579 return Ok(Value::Null(linkrs_core::value::NullType::Null));
580 }
581
582 if !(0.0..=100.0).contains(&percentile) {
583 return Err(ExpressionError::function_error(
584 "Percentile must be between 0 and 100".to_string(),
585 ));
586 }
587
588 let mut sorted_values = self.percentile_values.clone();
589 sorted_values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
590
591 let index = (percentile / 100.0) * (sorted_values.len() - 1) as f64;
592 let lower_index = index.floor() as usize;
593 let upper_index = index.ceil() as usize;
594
595 if lower_index == upper_index {
596 Ok(Value::Double(sorted_values[lower_index]))
597 } else {
598 let lower_value = sorted_values[lower_index];
599 let upper_value = sorted_values[upper_index];
600 let weight = index - lower_index as f64;
601 let interpolated = lower_value + weight * (upper_value - lower_value);
602 Ok(Value::Double(interpolated))
603 }
604 }
605
606 pub fn calculate_std(&self) -> Result<Value, ExpressionError> {
608 if self.std_values.is_empty() {
609 return Ok(Value::Null(linkrs_core::value::NullType::Null));
610 }
611
612 let n = self.std_values.len() as f64;
613 let mean: f64 = self.std_values.iter().sum::<f64>() / n;
614 let variance: f64 = self
615 .std_values
616 .iter()
617 .map(|value| (value - mean).powi(2))
618 .sum::<f64>()
619 / n;
620 let std_dev = variance.sqrt();
621
622 Ok(Value::Double(std_dev))
623 }
624
625 pub fn calculate_bit_and(&self) -> Result<Value, ExpressionError> {
627 if let Some(value) = self.bit_and_value {
628 Ok(Value::BigInt(value))
629 } else {
630 Ok(Value::Null(linkrs_core::value::NullType::Null))
631 }
632 }
633
634 pub fn calculate_bit_or(&self) -> Result<Value, ExpressionError> {
636 if let Some(value) = self.bit_or_value {
637 Ok(Value::BigInt(value))
638 } else {
639 Ok(Value::Null(linkrs_core::value::NullType::Null))
640 }
641 }
642
643 pub fn calculate_group_concat(&self) -> Result<Value, ExpressionError> {
645 if self.group_concat_values.is_empty() {
646 return Ok(Value::string(String::new()));
647 }
648
649 let result: Vec<String> = self
650 .group_concat_values
651 .iter()
652 .map(|v| format!("{}", v))
653 .collect();
654 Ok(Value::string(result.join(",")))
655 }
656
657 pub fn calculate_variance(&self) -> Result<Value, ExpressionError> {
659 if self.std_values.is_empty() {
660 return Ok(Value::Null(linkrs_core::value::NullType::Null));
661 }
662
663 let n = self.std_values.len() as f64;
664 let mean: f64 = self.std_values.iter().sum::<f64>() / n;
665 let variance: f64 = self
666 .std_values
667 .iter()
668 .map(|value| (value - mean).powi(2))
669 .sum::<f64>()
670 / n;
671
672 Ok(Value::Double(variance))
673 }
674
675 pub fn calculate_median(&self) -> Result<Value, ExpressionError> {
677 if self.median_values.is_empty() {
678 return Ok(Value::Null(linkrs_core::value::NullType::Null));
679 }
680
681 let mut sorted_values = self.median_values.clone();
682 sorted_values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
683
684 let len = sorted_values.len();
685 if len.is_multiple_of(2) {
686 let mid = len / 2;
687 Ok(Value::Double(
688 (sorted_values[mid - 1] + sorted_values[mid]) / 2.0,
689 ))
690 } else {
691 Ok(Value::Double(sorted_values[len / 2]))
692 }
693 }
694
695 pub fn calculate_mode(&self) -> Result<Value, ExpressionError> {
697 if self.mode_values.is_empty() {
698 return Ok(Value::Null(linkrs_core::value::NullType::Null));
699 }
700
701 let mut frequency_map = std::collections::HashMap::new();
702 for value in &self.mode_values {
703 let key = format!("{}", value);
704 *frequency_map.entry(key).or_insert(0usize) += 1;
705 }
706
707 let mode = frequency_map
708 .into_iter()
709 .max_by_key(|(_, count)| *count)
710 .map(|(key, _)| key);
711
712 match mode {
713 Some(mode_str) => {
714 if let Ok(int_val) = mode_str.parse::<i32>() {
715 Ok(Value::Int(int_val))
716 } else if let Ok(float_val) = mode_str.parse::<f64>() {
717 Ok(Value::Double(float_val))
718 } else if mode_str == "true" {
719 Ok(Value::Bool(true))
720 } else if mode_str == "false" {
721 Ok(Value::Bool(false))
722 } else {
723 Ok(Value::string(mode_str))
724 }
725 }
726 None => Ok(Value::Null(linkrs_core::value::NullType::Null)),
727 }
728 }
729
730 pub fn calculate_bool_and(&self) -> Result<Value, ExpressionError> {
732 if let Some(value) = self.bool_and_value {
733 Ok(Value::Bool(value))
734 } else {
735 Ok(Value::Null(linkrs_core::value::NullType::Null))
736 }
737 }
738
739 pub fn calculate_bool_or(&self) -> Result<Value, ExpressionError> {
741 if let Some(value) = self.bool_or_value {
742 Ok(Value::Bool(value))
743 } else {
744 Ok(Value::Null(linkrs_core::value::NullType::Null))
745 }
746 }
747
748 pub fn calculate_stddev_pop(&self) -> Result<Value, ExpressionError> {
750 if self.std_values.is_empty() {
751 return Ok(Value::Null(linkrs_core::value::NullType::Null));
752 }
753 let n = self.std_values.len() as f64;
754 let mean: f64 = self.std_values.iter().sum::<f64>() / n;
755 let variance: f64 = self
756 .std_values
757 .iter()
758 .map(|value| (value - mean).powi(2))
759 .sum::<f64>()
760 / n;
761 Ok(Value::Double(variance.sqrt()))
762 }
763
764 pub fn calculate_stddev_samp(&self) -> Result<Value, ExpressionError> {
766 let n = self.std_values.len() as f64;
767 if n < 2.0 {
768 return Ok(Value::Null(linkrs_core::value::NullType::Null));
769 }
770 let mean: f64 = self.std_values.iter().sum::<f64>() / n;
771 let variance: f64 = self
772 .std_values
773 .iter()
774 .map(|value| (value - mean).powi(2))
775 .sum::<f64>()
776 / (n - 1.0);
777 Ok(Value::Double(variance.sqrt()))
778 }
779
780 pub fn calculate_product(&self) -> Result<Value, ExpressionError> {
782 Ok(self.sum.clone())
783 }
784}
785
786#[cfg(test)]
787mod tests {
788 use super::*;
789
790 #[test]
791 fn test_unified_aggregate_function() {
792 let func = aggregate_from_str("COUNT").expect("from_str should succeed");
794 assert!(matches!(func, AggregateFunction::Count));
795
796 let func = aggregate_from_str("SUM").expect("from_str should succeed");
797 assert!(matches!(func, AggregateFunction::Sum));
798
799 let sum_func = aggregate_from_str_with_args("SUM", &["field".to_string()])
800 .expect("from_str_with_args should succeed");
801 assert!(sum_func.is_numeric());
802 assert!(!sum_func.is_collection());
803
804 let collect_func = aggregate_from_str_with_args("COLLECT", &["field".to_string()])
805 .expect("from_str_with_args should succeed");
806 assert!(!collect_func.is_numeric());
807 assert!(collect_func.is_collection());
808 }
809}