• 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

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

4
use std::fmt::{Debug, Display};
5

6
use vortex_array::compute::{BetweenOptions, StrictComparison, between as between_compute};
7
use vortex_array::{ArrayRef, DeserializeMetadata, ProstMetadata};
8
use vortex_dtype::DType;
9
use vortex_dtype::DType::Bool;
10
use vortex_error::{VortexResult, vortex_bail};
11
use vortex_proto::expr as pb;
12

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

17
vtable!(Between);
18

19
#[allow(clippy::derived_hash_with_manual_eq)]
20
#[derive(Clone, Debug, Hash)]
21
pub struct BetweenExpr {
22
    arr: ExprRef,
23
    lower: ExprRef,
24
    upper: ExprRef,
25
    options: BetweenOptions,
26
}
27

28
impl PartialEq for BetweenExpr {
29
    fn eq(&self, other: &Self) -> bool {
889✔
30
        self.arr.eq(&other.arr)
889✔
31
            && self.lower.eq(&other.lower)
889✔
32
            && self.upper.eq(&other.upper)
889✔
33
            && self.options == other.options
889✔
34
    }
889✔
35
}
36

37
pub struct BetweenExprEncoding;
38

39
impl VTable for BetweenVTable {
40
    type Expr = BetweenExpr;
41
    type Encoding = BetweenExprEncoding;
42
    type Metadata = ProstMetadata<pb::BetweenOpts>;
43

44
    fn id(_encoding: &Self::Encoding) -> ExprId {
124✔
45
        ExprId::new_ref("between")
124✔
46
    }
124✔
47

48
    fn encoding(_expr: &Self::Expr) -> ExprEncodingRef {
1✔
49
        ExprEncodingRef::new_ref(BetweenExprEncoding.as_ref())
1✔
50
    }
1✔
51

52
    fn metadata(expr: &Self::Expr) -> Option<Self::Metadata> {
1✔
53
        Some(ProstMetadata(pb::BetweenOpts {
1✔
54
            lower_strict: expr.options.lower_strict == StrictComparison::Strict,
1✔
55
            upper_strict: expr.options.upper_strict == StrictComparison::Strict,
1✔
56
        }))
1✔
57
    }
1✔
58

59
    fn children(expr: &Self::Expr) -> Vec<&ExprRef> {
4,807✔
60
        vec![&expr.arr, &expr.lower, &expr.upper]
4,807✔
61
    }
4,807✔
62

63
    fn with_children(expr: &Self::Expr, children: Vec<ExprRef>) -> VortexResult<Self::Expr> {
126✔
64
        Ok(BetweenExpr::new(
126✔
65
            children[0].clone(),
126✔
66
            children[1].clone(),
126✔
67
            children[2].clone(),
126✔
68
            expr.options.clone(),
126✔
69
        ))
126✔
70
    }
126✔
71

72
    fn build(
1✔
73
        _encoding: &Self::Encoding,
1✔
74
        metadata: &<Self::Metadata as DeserializeMetadata>::Output,
1✔
75
        children: Vec<ExprRef>,
1✔
76
    ) -> VortexResult<Self::Expr> {
1✔
77
        Ok(BetweenExpr::new(
1✔
78
            children[0].clone(),
1✔
79
            children[1].clone(),
1✔
80
            children[2].clone(),
1✔
81
            BetweenOptions {
1✔
82
                lower_strict: if metadata.lower_strict {
1✔
83
                    StrictComparison::Strict
1✔
84
                } else {
UNCOV
85
                    StrictComparison::NonStrict
×
86
                },
87
                upper_strict: if metadata.upper_strict {
1✔
88
                    StrictComparison::Strict
1✔
89
                } else {
UNCOV
90
                    StrictComparison::NonStrict
×
91
                },
92
            },
93
        ))
94
    }
1✔
95

96
    fn evaluate(expr: &Self::Expr, scope: &Scope) -> VortexResult<ArrayRef> {
166✔
97
        let arr_val = expr.arr.unchecked_evaluate(scope)?;
166✔
98
        let lower_arr_val = expr.lower.unchecked_evaluate(scope)?;
166✔
99
        let upper_arr_val = expr.upper.unchecked_evaluate(scope)?;
166✔
100

101
        between_compute(&arr_val, &lower_arr_val, &upper_arr_val, &expr.options)
166✔
102
    }
166✔
103

104
    fn return_dtype(expr: &Self::Expr, scope: &DType) -> VortexResult<DType> {
250✔
105
        let arr_dt = expr.arr.return_dtype(scope)?;
250✔
106
        let lower_dt = expr.lower.return_dtype(scope)?;
250✔
107
        let upper_dt = expr.upper.return_dtype(scope)?;
250✔
108

109
        if !arr_dt.eq_ignore_nullability(&lower_dt) {
250✔
UNCOV
110
            vortex_bail!(
×
111
                "Array dtype {} does not match lower dtype {}",
×
112
                arr_dt,
×
113
                lower_dt
×
114
            );
×
115
        }
250✔
116
        if !arr_dt.eq_ignore_nullability(&upper_dt) {
250✔
UNCOV
117
            vortex_bail!(
×
118
                "Array dtype {} does not match upper dtype {}",
×
119
                arr_dt,
×
120
                upper_dt
×
121
            );
×
122
        }
250✔
123

250✔
124
        Ok(Bool(
250✔
125
            arr_dt.nullability() | lower_dt.nullability() | upper_dt.nullability(),
250✔
126
        ))
250✔
127
    }
250✔
128
}
129

130
impl BetweenExpr {
131
    pub fn new(arr: ExprRef, lower: ExprRef, upper: ExprRef, options: BetweenOptions) -> Self {
398✔
132
        Self {
398✔
133
            arr,
398✔
134
            lower,
398✔
135
            upper,
398✔
136
            options,
398✔
137
        }
398✔
138
    }
398✔
139

140
    pub fn new_expr(
42✔
141
        arr: ExprRef,
42✔
142
        lower: ExprRef,
42✔
143
        upper: ExprRef,
42✔
144
        options: BetweenOptions,
42✔
145
    ) -> ExprRef {
42✔
146
        Self::new(arr, lower, upper, options).into_expr()
42✔
147
    }
42✔
148

UNCOV
149
    pub fn to_binary_expr(&self) -> ExprRef {
×
150
        let lhs = BinaryExpr::new(
×
151
            self.lower.clone(),
×
152
            self.options.lower_strict.to_operator().into(),
×
153
            self.arr.clone(),
×
154
        );
×
155
        let rhs = BinaryExpr::new(
×
156
            self.arr.clone(),
×
157
            self.options.upper_strict.to_operator().into(),
×
158
            self.upper.clone(),
×
159
        );
×
160
        BinaryExpr::new(lhs.into_expr(), crate::Operator::And, rhs.into_expr()).into_expr()
×
161
    }
×
162
}
163

164
impl Display for BetweenExpr {
UNCOV
165
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
166
        write!(
×
167
            f,
×
168
            "({} {} {} {} {})",
×
169
            self.lower,
×
170
            self.options.lower_strict.to_operator(),
×
171
            self.arr,
×
172
            self.options.upper_strict.to_operator(),
×
173
            self.upper
×
174
        )
×
175
    }
×
176
}
177

178
impl AnalysisExpr for BetweenExpr {}
179

180
pub fn between(arr: ExprRef, lower: ExprRef, upper: ExprRef, options: BetweenOptions) -> ExprRef {
7✔
181
    BetweenExpr::new(arr, lower, upper, options).into_expr()
7✔
182
}
7✔
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