vortex_array/arrays/decimal/compute/
min_max.rs

1use itertools::Itertools;
2use vortex_dtype::DType;
3use vortex_error::VortexResult;
4use vortex_mask::Mask;
5use vortex_scalar::{
6    DecimalValue, NativeDecimalType, Scalar, ScalarValue, match_each_decimal_value_type,
7};
8
9use crate::arrays::{DecimalArray, DecimalVTable};
10use crate::compute::{MinMaxKernel, MinMaxKernelAdapter, MinMaxResult};
11use crate::register_kernel;
12
13impl MinMaxKernel for DecimalVTable {
14    fn min_max(&self, array: &DecimalArray) -> VortexResult<Option<MinMaxResult>> {
15        match_each_decimal_value_type!(array.values_type(), |T| {
16            compute_min_max_with_validity::<T>(array)
17        })
18    }
19}
20
21register_kernel!(MinMaxKernelAdapter(DecimalVTable).lift());
22
23#[inline]
24fn compute_min_max_with_validity<D>(array: &DecimalArray) -> VortexResult<Option<MinMaxResult>>
25where
26    D: Into<DecimalValue> + NativeDecimalType,
27{
28    Ok(match array.validity_mask()? {
29        Mask::AllTrue(_) => compute_min_max(array.buffer::<D>().iter(), array.dtype()),
30        Mask::AllFalse(_) => None,
31        Mask::Values(v) => compute_min_max(
32            array
33                .buffer::<D>()
34                .iter()
35                .zip(v.boolean_buffer().iter())
36                .filter_map(|(v, m)| m.then_some(v)),
37            array.dtype(),
38        ),
39    })
40}
41
42fn compute_min_max<'a, T>(iter: impl Iterator<Item = &'a T>, dtype: &DType) -> Option<MinMaxResult>
43where
44    T: Into<DecimalValue> + NativeDecimalType + Ord + Copy + 'a,
45{
46    match iter.minmax_by(|a, b| a.cmp(b)) {
47        itertools::MinMaxResult::NoElements => None,
48        itertools::MinMaxResult::OneElement(&x) => {
49            let scalar = Scalar::new(dtype.clone(), ScalarValue::from(x.into()));
50            Some(MinMaxResult {
51                min: scalar.clone(),
52                max: scalar,
53            })
54        }
55        itertools::MinMaxResult::MinMax(&min, &max) => Some(MinMaxResult {
56            min: Scalar::new(dtype.clone(), ScalarValue::from(min.into())),
57            max: Scalar::new(dtype.clone(), ScalarValue::from(max.into())),
58        }),
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use vortex_buffer::buffer;
65    use vortex_dtype::DecimalDType;
66    use vortex_scalar::{DecimalValue, Scalar, ScalarValue};
67
68    use crate::arrays::DecimalArray;
69    use crate::compute::{MinMaxResult, min_max};
70    use crate::validity::Validity;
71
72    #[test]
73    fn min_max_test() {
74        let decimal = DecimalArray::new(
75            buffer![100i32, 2000i32, 200i32],
76            DecimalDType::new(4, 2),
77            Validity::from_iter([true, false, true]),
78        );
79
80        let min_max = min_max(decimal.as_ref()).unwrap();
81
82        let expected = MinMaxResult {
83            min: Scalar::new(
84                decimal.dtype().clone(),
85                ScalarValue::from(DecimalValue::from(100i32)),
86            ),
87            max: Scalar::new(
88                decimal.dtype().clone(),
89                ScalarValue::from(DecimalValue::from(200i32)),
90            ),
91        };
92
93        assert_eq!(Some(expected), min_max)
94    }
95}