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

vortex-data / vortex / 16204612549

10 Jul 2025 07:50PM UTC coverage: 81.152% (+2.9%) from 78.263%
16204612549

Pull #3825

github

web-flow
Merge d0d2717da into be9c2fd3e
Pull Request #3825: feat: Add optimize ArrayOp with VBView implementation

178 of 211 new or added lines in 4 files covered. (84.36%)

330 existing lines in 34 files now uncovered.

45433 of 55985 relevant lines covered (81.15%)

145951.87 hits per line

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

68.91
/vortex-expr/src/exprs/like.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::{LikeOptions, like};
8
use vortex_array::{ArrayRef, DeserializeMetadata, ProstMetadata};
9
use vortex_dtype::DType;
10
use vortex_error::{VortexResult, vortex_bail};
11
use vortex_proto::expr as pb;
12

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

15
vtable!(Like);
16

17
#[allow(clippy::derived_hash_with_manual_eq)]
18
#[derive(Clone, Debug, Hash)]
19
pub struct LikeExpr {
20
    child: ExprRef,
21
    pattern: ExprRef,
22
    negated: bool,
23
    case_insensitive: bool,
24
}
25

26
impl PartialEq for LikeExpr {
27
    fn eq(&self, other: &Self) -> bool {
266✔
28
        self.child.eq(&other.child)
266✔
29
            && self.pattern.eq(&other.pattern)
266✔
30
            && self.negated == other.negated
266✔
31
            && self.case_insensitive == other.case_insensitive
266✔
32
    }
266✔
33
}
34

35
pub struct LikeExprEncoding;
36

37
impl VTable for LikeVTable {
38
    type Expr = LikeExpr;
39
    type Encoding = LikeExprEncoding;
40
    type Metadata = ProstMetadata<pb::LikeOpts>;
41

42
    fn id(_encoding: &Self::Encoding) -> ExprId {
123✔
43
        ExprId::new_ref("like")
123✔
44
    }
123✔
45

UNCOV
46
    fn encoding(_expr: &Self::Expr) -> ExprEncodingRef {
×
UNCOV
47
        ExprEncodingRef::new_ref(LikeExprEncoding.as_ref())
×
48
    }
×
49

50
    fn metadata(expr: &Self::Expr) -> Option<Self::Metadata> {
×
UNCOV
51
        Some(ProstMetadata(pb::LikeOpts {
×
52
            negated: expr.negated,
×
53
            case_insensitive: expr.case_insensitive,
×
54
        }))
×
55
    }
×
56

57
    fn children(expr: &Self::Expr) -> Vec<&ExprRef> {
2,142✔
58
        vec![&expr.child, &expr.pattern]
2,142✔
59
    }
2,142✔
60

61
    fn with_children(expr: &Self::Expr, children: Vec<ExprRef>) -> VortexResult<Self::Expr> {
102✔
62
        Ok(LikeExpr::new(
102✔
63
            children[0].clone(),
102✔
64
            children[1].clone(),
102✔
65
            expr.negated,
102✔
66
            expr.case_insensitive,
102✔
67
        ))
102✔
68
    }
102✔
69

UNCOV
70
    fn build(
×
UNCOV
71
        _encoding: &Self::Encoding,
×
72
        metadata: &<Self::Metadata as DeserializeMetadata>::Output,
×
73
        children: Vec<ExprRef>,
×
74
    ) -> VortexResult<Self::Expr> {
×
75
        if children.len() != 2 {
×
76
            vortex_bail!(
×
77
                "Like expression must have exactly 2 children, got {}",
×
78
                children.len()
×
79
            );
×
80
        }
×
81

×
82
        Ok(LikeExpr::new(
×
83
            children[0].clone(),
×
84
            children[1].clone(),
×
85
            metadata.negated,
×
86
            metadata.case_insensitive,
×
87
        ))
×
88
    }
×
89

90
    fn evaluate(expr: &Self::Expr, scope: &Scope) -> VortexResult<ArrayRef> {
76✔
91
        let child = expr.child().unchecked_evaluate(scope)?;
76✔
92
        let pattern = expr.pattern().unchecked_evaluate(scope)?;
76✔
93
        like(
76✔
94
            &child,
76✔
95
            &pattern,
76✔
96
            LikeOptions {
76✔
97
                negated: expr.negated,
76✔
98
                case_insensitive: expr.case_insensitive,
76✔
99
            },
76✔
100
        )
76✔
101
    }
76✔
102

103
    fn return_dtype(expr: &Self::Expr, scope: &DType) -> VortexResult<DType> {
145✔
104
        let input = expr.child().return_dtype(scope)?;
145✔
105
        let pattern = expr.pattern().return_dtype(scope)?;
145✔
106
        Ok(DType::Bool(
107
            (input.is_nullable() || pattern.is_nullable()).into(),
145✔
108
        ))
109
    }
145✔
110
}
111

112
impl LikeExpr {
113
    pub fn new(child: ExprRef, pattern: ExprRef, negated: bool, case_insensitive: bool) -> Self {
137✔
114
        Self {
137✔
115
            child,
137✔
116
            pattern,
137✔
117
            negated,
137✔
118
            case_insensitive,
137✔
119
        }
137✔
120
    }
137✔
121

122
    pub fn new_expr(
22✔
123
        child: ExprRef,
22✔
124
        pattern: ExprRef,
22✔
125
        negated: bool,
22✔
126
        case_insensitive: bool,
22✔
127
    ) -> ExprRef {
22✔
128
        Self::new(child, pattern, negated, case_insensitive).into_expr()
22✔
129
    }
22✔
130

131
    pub fn child(&self) -> &ExprRef {
221✔
132
        &self.child
221✔
133
    }
221✔
134

135
    pub fn pattern(&self) -> &ExprRef {
221✔
136
        &self.pattern
221✔
137
    }
221✔
138

UNCOV
139
    pub fn negated(&self) -> bool {
×
UNCOV
140
        self.negated
×
141
    }
×
142

143
    pub fn case_insensitive(&self) -> bool {
×
UNCOV
144
        self.case_insensitive
×
145
    }
×
146
}
147

148
impl Display for LikeExpr {
UNCOV
149
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
UNCOV
150
        write!(f, "{} LIKE {}", self.child(), self.pattern())
×
151
    }
×
152
}
153

154
impl AnalysisExpr for LikeExpr {}
155

156
#[cfg(test)]
157
mod tests {
158
    use vortex_array::ToCanonical;
159
    use vortex_array::arrays::BoolArray;
160
    use vortex_dtype::{DType, Nullability};
161

162
    use crate::{LikeExpr, Scope, lit, not, root};
163

164
    #[test]
165
    fn invert_booleans() {
1✔
166
        let not_expr = not(root());
1✔
167
        let bools = BoolArray::from_iter([false, true, false, false, true, true]);
1✔
168
        assert_eq!(
1✔
169
            not_expr
1✔
170
                .evaluate(&Scope::new(bools.to_array()))
1✔
171
                .unwrap()
1✔
172
                .to_bool()
1✔
173
                .unwrap()
1✔
174
                .boolean_buffer()
1✔
175
                .iter()
1✔
176
                .collect::<Vec<_>>(),
1✔
177
            vec![true, false, true, true, false, false]
1✔
178
        );
1✔
179
    }
1✔
180

181
    #[test]
182
    fn dtype() {
1✔
183
        let dtype = DType::Utf8(Nullability::NonNullable);
1✔
184
        let like_expr = LikeExpr::new(root(), lit("%test%"), false, false);
1✔
185
        assert_eq!(
1✔
186
            like_expr.return_dtype(&dtype).unwrap(),
1✔
187
            DType::Bool(Nullability::NonNullable)
1✔
188
        );
1✔
189
    }
1✔
190
}
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