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

vortex-data / vortex / 16876672762

11 Aug 2025 09:53AM UTC coverage: 86.203% (-0.03%) from 86.228%
16876672762

push

github

web-flow
fix[scan]: don't convert filter to `cnf` just extract conjunct list (#4174)

This PR replaces cnf extract with and unpacking.
We could look later at either trying to cnf transform with a conversion
expression size cap?

---------

Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>

18 of 19 new or added lines in 3 files covered. (94.74%)

7 existing lines in 3 files now uncovered.

53394 of 61940 relevant lines covered (86.2%)

546700.74 hits per line

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

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

4
use std::fmt::Display;
5
use std::hash::Hash;
6

7
use vortex_array::compute::invert;
8
use vortex_array::{ArrayRef, DeserializeMetadata, EmptyMetadata};
9
use vortex_dtype::DType;
10
use vortex_error::{VortexResult, vortex_bail};
11

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

14
vtable!(Not);
15

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

22
impl PartialEq for NotExpr {
23
    fn eq(&self, other: &Self) -> bool {
2✔
24
        self.child.eq(&other.child)
2✔
25
    }
2✔
26
}
27

28
pub struct NotExprEncoding;
29

30
impl VTable for NotVTable {
31
    type Expr = NotExpr;
32
    type Encoding = NotExprEncoding;
33
    type Metadata = EmptyMetadata;
34

35
    fn id(_encoding: &Self::Encoding) -> ExprId {
169✔
36
        ExprId::new_ref("not")
169✔
37
    }
169✔
38

39
    fn encoding(_expr: &Self::Expr) -> ExprEncodingRef {
2✔
40
        ExprEncodingRef::new_ref(NotExprEncoding.as_ref())
2✔
41
    }
2✔
42

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

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

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

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

69
    fn evaluate(expr: &Self::Expr, scope: &Scope) -> VortexResult<ArrayRef> {
23✔
70
        let child_result = expr.child.unchecked_evaluate(scope)?;
23✔
71
        invert(&child_result)
23✔
72
    }
23✔
73

74
    fn return_dtype(expr: &Self::Expr, scope: &DType) -> VortexResult<DType> {
25✔
75
        let child = expr.child.return_dtype(scope)?;
25✔
76
        if !matches!(child, DType::Bool(_)) {
25✔
77
            vortex_bail!("Not expression expects a boolean child, got: {}", child);
×
78
        }
25✔
79
        Ok(child)
25✔
80
    }
25✔
81
}
82

83
impl NotExpr {
84
    pub fn new(child: ExprRef) -> Self {
32✔
85
        Self { child }
32✔
86
    }
32✔
87

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

UNCOV
92
    pub fn child(&self) -> &ExprRef {
×
UNCOV
93
        &self.child
×
UNCOV
94
    }
×
95
}
96

97
impl Display for NotExpr {
98
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5✔
99
        write!(f, "(!{})", self.child)
5✔
100
    }
5✔
101
}
102

103
impl AnalysisExpr for NotExpr {}
104

105
pub fn not(operand: ExprRef) -> ExprRef {
30✔
106
    NotExpr::new(operand).into_expr()
30✔
107
}
30✔
108

109
#[cfg(test)]
110
mod tests {
111
    use vortex_array::ToCanonical;
112
    use vortex_array::arrays::BoolArray;
113
    use vortex_dtype::{DType, Nullability};
114

115
    use crate::{Scope, col, get_item, not, root, test_harness};
116

117
    #[test]
118
    fn invert_booleans() {
1✔
119
        let not_expr = not(root());
1✔
120
        let bools = BoolArray::from_iter([false, true, false, false, true, true]);
1✔
121
        assert_eq!(
1✔
122
            not_expr
1✔
123
                .evaluate(&Scope::new(bools.to_array()))
1✔
124
                .unwrap()
1✔
125
                .to_bool()
1✔
126
                .unwrap()
1✔
127
                .boolean_buffer()
1✔
128
                .iter()
1✔
129
                .collect::<Vec<_>>(),
1✔
130
            vec![true, false, true, true, false, false]
1✔
131
        );
132
    }
1✔
133

134
    #[test]
135
    fn test_display_order_of_operations() {
1✔
136
        let a = not(get_item("a", root()));
1✔
137
        let b = get_item("a", not(root()));
1✔
138
        assert_ne!(a.to_string(), b.to_string());
1✔
139
        assert_eq!(a.to_string(), "(!$.a)");
1✔
140
        assert_eq!(b.to_string(), "(!$).a");
1✔
141
    }
1✔
142

143
    #[test]
144
    fn dtype() {
1✔
145
        let not_expr = not(root());
1✔
146
        let dtype = DType::Bool(Nullability::NonNullable);
1✔
147
        assert_eq!(
1✔
148
            not_expr.return_dtype(&dtype).unwrap(),
1✔
149
            DType::Bool(Nullability::NonNullable)
150
        );
151

152
        let dtype = test_harness::struct_dtype();
1✔
153
        assert_eq!(
1✔
154
            not(col("bool1")).return_dtype(&dtype).unwrap(),
1✔
155
            DType::Bool(Nullability::NonNullable)
156
        );
157
    }
1✔
158
}
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