• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16277982668

14 Jul 2025 09:12PM UTC coverage: 81.564% (+0.4%) from 81.147%
16277982668

Pull #3852

github

web-flow
Merge e78f6e62e into b0be264bf
Pull Request #3852: feat: call optimize in compressor

3 of 3 new or added lines in 1 file covered. (100.0%)

381 existing lines in 36 files now uncovered.

46289 of 56752 relevant lines covered (81.56%)

157514.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.29
/vortex-expr/src/exprs/is_null.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use std::fmt::Display;
5
use std::ops::Not;
6

7
use vortex_array::arrays::{BoolArray, ConstantArray};
8
use vortex_array::{Array, ArrayRef, DeserializeMetadata, EmptyMetadata, IntoArray};
9
use vortex_dtype::{DType, Nullability};
10
use vortex_error::{VortexResult, vortex_bail};
11
use vortex_mask::Mask;
12

13
use crate::{AnalysisExpr, ExprEncodingRef, ExprId, ExprRef, IntoExpr, Scope, VTable, vtable};
14

15
vtable!(IsNull);
16

17
#[allow(clippy::derived_hash_with_manual_eq)]
18
#[derive(Clone, Debug, Hash)]
19
pub struct IsNullExpr {
20
    child: ExprRef,
21
}
22

23
impl PartialEq for IsNullExpr {
24
    fn eq(&self, other: &Self) -> bool {
×
25
        self.child.eq(&other.child)
×
26
    }
×
27
}
28

29
pub struct IsNullExprEncoding;
30

31
impl VTable for IsNullVTable {
32
    type Expr = IsNullExpr;
33
    type Encoding = IsNullExprEncoding;
34
    type Metadata = EmptyMetadata;
35

36
    fn id(_encoding: &Self::Encoding) -> ExprId {
×
37
        ExprId::new_ref("is_null")
×
38
    }
×
39

40
    fn encoding(_expr: &Self::Expr) -> ExprEncodingRef {
×
41
        ExprEncodingRef::new_ref(IsNullExprEncoding.as_ref())
×
42
    }
×
43

44
    fn metadata(_expr: &Self::Expr) -> Option<Self::Metadata> {
×
45
        Some(EmptyMetadata)
×
46
    }
×
47

48
    fn children(expr: &Self::Expr) -> Vec<&ExprRef> {
1✔
49
        vec![&expr.child]
1✔
50
    }
1✔
51

52
    fn with_children(_expr: &Self::Expr, children: Vec<ExprRef>) -> VortexResult<Self::Expr> {
1✔
53
        Ok(IsNullExpr::new(children[0].clone()))
1✔
54
    }
1✔
55

56
    fn build(
×
57
        _encoding: &Self::Encoding,
×
58
        _metadata: &<Self::Metadata as DeserializeMetadata>::Output,
×
59
        children: Vec<ExprRef>,
×
60
    ) -> VortexResult<Self::Expr> {
×
61
        if children.len() != 1 {
×
62
            vortex_bail!("IsNull expects exactly one child, got {}", children.len());
×
63
        }
×
64
        Ok(IsNullExpr::new(children[0].clone()))
×
65
    }
×
66

67
    fn evaluate(expr: &Self::Expr, scope: &Scope) -> VortexResult<ArrayRef> {
24✔
68
        let array = expr.child.unchecked_evaluate(scope)?;
24✔
69
        match array.validity_mask()? {
24✔
70
            Mask::AllTrue(len) => Ok(ConstantArray::new(false, len).into_array()),
1✔
71
            Mask::AllFalse(len) => Ok(ConstantArray::new(true, len).into_array()),
1✔
72
            Mask::Values(mask) => Ok(BoolArray::from(mask.boolean_buffer().not()).into_array()),
22✔
73
        }
74
    }
24✔
75

76
    fn return_dtype(_expr: &Self::Expr, _scope: &DType) -> VortexResult<DType> {
25✔
77
        Ok(DType::Bool(Nullability::NonNullable))
25✔
78
    }
25✔
79
}
80

81
impl IsNullExpr {
82
    pub fn new(child: ExprRef) -> Self {
27✔
83
        Self { child }
27✔
84
    }
27✔
85

UNCOV
86
    pub fn new_expr(child: ExprRef) -> ExprRef {
×
UNCOV
87
        Self::new(child).into_expr()
×
88
    }
×
89
}
90

91
impl Display for IsNullExpr {
UNCOV
92
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
UNCOV
93
        write!(f, "is_null({})", self.child)
×
UNCOV
94
    }
×
95
}
96

97
impl AnalysisExpr for IsNullExpr {}
98

99
pub fn is_null(child: ExprRef) -> ExprRef {
26✔
100
    IsNullExpr::new(child).into_expr()
26✔
101
}
26✔
102

103
#[cfg(test)]
104
mod tests {
105
    use vortex_array::IntoArray;
106
    use vortex_array::arrays::{PrimitiveArray, StructArray};
107
    use vortex_dtype::{DType, Nullability};
108
    use vortex_scalar::Scalar;
109

110
    use crate::is_null::is_null;
111
    use crate::{Scope, get_item, root, test_harness};
112

113
    #[test]
114
    fn dtype() {
1✔
115
        let dtype = test_harness::struct_dtype();
1✔
116
        assert_eq!(
1✔
117
            is_null(root()).return_dtype(&dtype).unwrap(),
1✔
118
            DType::Bool(Nullability::NonNullable)
1✔
119
        );
1✔
120
    }
1✔
121

122
    #[test]
123
    fn replace_children() {
1✔
124
        let expr = is_null(root());
1✔
125
        let _ = expr.with_children(vec![root()]);
1✔
126
    }
1✔
127

128
    #[test]
129
    fn evaluate_mask() {
1✔
130
        let test_array =
1✔
131
            PrimitiveArray::from_option_iter(vec![Some(1), None, Some(2), None, Some(3)])
1✔
132
                .into_array();
1✔
133
        let expected = [false, true, false, true, false];
1✔
134

1✔
135
        let result = is_null(root())
1✔
136
            .evaluate(&Scope::new(test_array.clone()))
1✔
137
            .unwrap();
1✔
138

1✔
139
        assert_eq!(result.len(), test_array.len());
1✔
140
        assert_eq!(result.dtype(), &DType::Bool(Nullability::NonNullable));
1✔
141

142
        for (i, expected_value) in expected.iter().enumerate() {
5✔
143
            assert_eq!(
5✔
144
                result.scalar_at(i).unwrap(),
5✔
145
                Scalar::bool(*expected_value, Nullability::NonNullable)
5✔
146
            );
5✔
147
        }
148
    }
1✔
149

150
    #[test]
151
    fn evaluate_all_false() {
1✔
152
        let test_array = PrimitiveArray::from_iter(vec![1, 2, 3, 4, 5]).into_array();
1✔
153

1✔
154
        let result = is_null(root())
1✔
155
            .evaluate(&Scope::new(test_array.clone()))
1✔
156
            .unwrap();
1✔
157

1✔
158
        assert_eq!(result.len(), test_array.len());
1✔
159
        assert_eq!(
1✔
160
            result.as_constant().unwrap(),
1✔
161
            Scalar::bool(false, Nullability::NonNullable)
1✔
162
        );
1✔
163
    }
1✔
164

165
    #[test]
166
    fn evaluate_all_true() {
1✔
167
        let test_array =
1✔
168
            PrimitiveArray::from_option_iter(vec![None::<i32>, None, None, None, None])
1✔
169
                .into_array();
1✔
170

1✔
171
        let result = is_null(root())
1✔
172
            .evaluate(&Scope::new(test_array.clone()))
1✔
173
            .unwrap();
1✔
174

1✔
175
        assert_eq!(result.len(), test_array.len());
1✔
176
        assert_eq!(
1✔
177
            result.as_constant().unwrap(),
1✔
178
            Scalar::bool(true, Nullability::NonNullable)
1✔
179
        );
1✔
180
    }
1✔
181

182
    #[test]
183
    fn evaluate_struct() {
1✔
184
        let test_array = StructArray::from_fields(&[(
1✔
185
            "a",
1✔
186
            PrimitiveArray::from_option_iter(vec![Some(1), None, Some(2), None, Some(3)])
1✔
187
                .into_array(),
1✔
188
        )])
1✔
189
        .unwrap()
1✔
190
        .into_array();
1✔
191
        let expected = [false, true, false, true, false];
1✔
192

1✔
193
        let result = is_null(get_item("a", root()))
1✔
194
            .evaluate(&Scope::new(test_array.clone()))
1✔
195
            .unwrap();
1✔
196

1✔
197
        assert_eq!(result.len(), test_array.len());
1✔
198
        assert_eq!(result.dtype(), &DType::Bool(Nullability::NonNullable));
1✔
199

200
        for (i, expected_value) in expected.iter().enumerate() {
5✔
201
            assert_eq!(
5✔
202
                result.scalar_at(i).unwrap(),
5✔
203
                Scalar::bool(*expected_value, Nullability::NonNullable)
5✔
204
            );
5✔
205
        }
206
    }
1✔
207
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc