vortex_array/arrays/decimal/compute/
min_max.rs

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