diff --git a/src/aggregation/metric/sum.rs b/src/aggregation/metric/sum.rs index 2487c4e9d..8e1dc0f5d 100644 --- a/src/aggregation/metric/sum.rs +++ b/src/aggregation/metric/sum.rs @@ -59,8 +59,54 @@ impl IntermediateSum { pub fn merge_fruits(&mut self, other: IntermediateSum) { self.stats.merge_fruits(other.stats); } - /// Computes the final minimum value. + /// Computes the final sum value. + /// + /// Returns `None` when no values were collected (all documents had + /// missing/NULL values for the field), matching the behavior of + /// `IntermediateMin`, `IntermediateMax`, and `IntermediateAvg`. pub fn finalize(&self) -> Option { - Some(self.stats.finalize().sum) + let stats = self.stats.finalize(); + if stats.count == 0 { + None + } else { + Some(stats.sum) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sum_finalize_returns_none_when_no_values() { + // Default IntermediateSum has count=0 — finalize should return None, + // matching MIN/MAX/AVG behavior for all-NULL groups. + let sum = IntermediateSum::default(); + assert_eq!(sum.finalize(), None); + } + + #[test] + fn test_sum_finalize_returns_value_when_has_values() { + let mut sum = IntermediateSum::default(); + // Merge in a result that has actual values + let stats = IntermediateStats { + count: 3, + sum: 42.0, + min: 10.0, + max: 20.0, + ..Default::default() + }; + let other = IntermediateSum::from_stats(stats); + sum.merge_fruits(other); + assert_eq!(sum.finalize(), Some(42.0)); + } + + #[test] + fn test_sum_merge_two_empty_still_none() { + let mut a = IntermediateSum::default(); + let b = IntermediateSum::default(); + a.merge_fruits(b); + assert_eq!(a.finalize(), None); } }