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

vortex-data / vortex / 16935267080

13 Aug 2025 11:00AM UTC coverage: 24.312% (-63.3%) from 87.658%
16935267080

Pull #4226

github

web-flow
Merge 81b48c7fb into baa6ea202
Pull Request #4226: Support converting TimestampTZ to and from duckdb

0 of 2 new or added lines in 1 file covered. (0.0%)

20666 existing lines in 469 files now uncovered.

8726 of 35892 relevant lines covered (24.31%)

147.74 hits per line

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

0.0
/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, Eq)]
19
pub struct LikeExpr {
20
    child: ExprRef,
21
    pattern: ExprRef,
22
    negated: bool,
23
    case_insensitive: bool,
24
}
25

26
impl PartialEq for LikeExpr {
UNCOV
27
    fn eq(&self, other: &Self) -> bool {
×
UNCOV
28
        self.child.eq(&other.child)
×
UNCOV
29
            && self.pattern.eq(&other.pattern)
×
UNCOV
30
            && self.negated == other.negated
×
UNCOV
31
            && self.case_insensitive == other.case_insensitive
×
UNCOV
32
    }
×
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

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

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

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

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

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

70
    fn build(
×
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

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

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

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

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

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

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

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

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

148
impl Display for LikeExpr {
149
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
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() {
166
        let not_expr = not(root());
167
        let bools = BoolArray::from_iter([false, true, false, false, true, true]);
168
        assert_eq!(
169
            not_expr
170
                .evaluate(&Scope::new(bools.to_array()))
171
                .unwrap()
172
                .to_bool()
173
                .unwrap()
174
                .boolean_buffer()
175
                .iter()
176
                .collect::<Vec<_>>(),
177
            vec![true, false, true, true, false, false]
178
        );
179
    }
180

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