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

vortex-data / vortex / 16139349253

08 Jul 2025 09:26AM UTC coverage: 78.057% (-0.2%) from 78.253%
16139349253

push

github

web-flow
VortexExpr VTables (#3713)

Adds the same vtable machinery as arrays and layouts already use. It
uses the "Encoding" naming scheme from arrays and layouts. I don't
particularly like it, but it's consistent. Open to renames later.

Further, adds an expression registry to the Vortex session that will be
used for deserialization.

Expressions only decide their "options" serialization. So in theory, can
support many container formats, not just proto, provided each expression
can deserialize their own options format.

---------

Signed-off-by: Nicholas Gates <nick@nickgates.com>

800 of 1190 new or added lines in 38 files covered. (67.23%)

40 existing lines in 13 files now uncovered.

44100 of 56497 relevant lines covered (78.06%)

54989.55 hits per line

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

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

4
use core::fmt;
5
use std::fmt::{Display, Formatter};
6

7
use vortex_array::compute;
8
use vortex_error::VortexError;
9
use vortex_proto::expr::binary_opts::BinaryOp;
10

11
/// Equalities, inequalities, and boolean operations over possibly null values.
12
///
13
/// For the equalities and inequalities, if either side is null, the result is null. The Boolean
14
/// operators obey [Kleene (three-valued) logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics).
15
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
16
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17
pub enum Operator {
18
    // comparison
19
    Eq,
20
    NotEq,
21
    Gt,
22
    Gte,
23
    Lt,
24
    Lte,
25
    // boolean algebra
26
    And,
27
    Or,
28
    // arithmetic
29
    /// The sum of the arguments.
30
    ///
31
    /// Errs at runtime if the sum would overflow or underflow.
32
    ///
33
    /// The result is null at any index that either input is null.
34
    Add,
35
}
36

37
impl From<Operator> for i32 {
38
    fn from(value: Operator) -> Self {
3✔
39
        let op: BinaryOp = value.into();
3✔
40
        op.into()
3✔
41
    }
3✔
42
}
43

44
impl From<Operator> for BinaryOp {
45
    fn from(value: Operator) -> Self {
3✔
46
        match value {
3✔
47
            Operator::Eq => BinaryOp::Eq,
1✔
NEW
48
            Operator::NotEq => BinaryOp::NotEq,
×
NEW
49
            Operator::Gt => BinaryOp::Gt,
×
NEW
50
            Operator::Gte => BinaryOp::Gte,
×
NEW
51
            Operator::Lt => BinaryOp::Lt,
×
NEW
52
            Operator::Lte => BinaryOp::Lte,
×
53
            Operator::And => BinaryOp::And,
1✔
54
            Operator::Or => BinaryOp::Or,
1✔
NEW
55
            Operator::Add => BinaryOp::Add,
×
56
        }
57
    }
3✔
58
}
59

60
impl TryFrom<i32> for Operator {
61
    type Error = VortexError;
62

NEW
63
    fn try_from(value: i32) -> Result<Self, Self::Error> {
×
NEW
64
        Ok(BinaryOp::try_from(value)?.into())
×
UNCOV
65
    }
×
66
}
67

68
impl From<BinaryOp> for Operator {
69
    fn from(value: BinaryOp) -> Self {
3✔
70
        match value {
3✔
71
            BinaryOp::Eq => Operator::Eq,
1✔
NEW
72
            BinaryOp::NotEq => Operator::NotEq,
×
NEW
73
            BinaryOp::Gt => Operator::Gt,
×
NEW
74
            BinaryOp::Gte => Operator::Gte,
×
NEW
75
            BinaryOp::Lt => Operator::Lt,
×
NEW
76
            BinaryOp::Lte => Operator::Lte,
×
77
            BinaryOp::And => Operator::And,
1✔
78
            BinaryOp::Or => Operator::Or,
1✔
NEW
79
            BinaryOp::Add => Operator::Add,
×
80
        }
81
    }
3✔
82
}
83

84
impl Display for Operator {
85
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
11✔
86
        let display = match &self {
11✔
87
            Operator::Eq => "=",
1✔
88
            Operator::NotEq => "!=",
2✔
89
            Operator::Gt => ">",
1✔
90
            Operator::Gte => ">=",
1✔
91
            Operator::Lt => "<",
2✔
92
            Operator::Lte => "<=",
1✔
93
            Operator::And => "and",
1✔
94
            Operator::Or => "or",
2✔
95
            Operator::Add => "+w",
×
96
        };
97
        Display::fmt(display, f)
11✔
98
    }
11✔
99
}
100

101
impl Operator {
102
    pub fn inverse(self) -> Option<Self> {
×
103
        match self {
×
104
            Operator::Eq => Some(Operator::NotEq),
×
105
            Operator::NotEq => Some(Operator::Eq),
×
106
            Operator::Gt => Some(Operator::Lte),
×
107
            Operator::Gte => Some(Operator::Lt),
×
108
            Operator::Lt => Some(Operator::Gte),
×
109
            Operator::Lte => Some(Operator::Gt),
×
110
            Operator::And | Operator::Or | Operator::Add => None,
×
111
        }
112
    }
×
113

114
    pub fn logical_inverse(self) -> Option<Self> {
×
115
        match self {
×
116
            Operator::And => Some(Operator::Or),
×
117
            Operator::Or => Some(Operator::And),
×
118
            _ => None,
×
119
        }
120
    }
×
121

122
    /// Change the sides of the operator, where changing lhs and rhs won't change the result of the operation
123
    pub fn swap(self) -> Self {
34✔
124
        match self {
34✔
125
            Operator::Eq => Operator::Eq,
×
126
            Operator::NotEq => Operator::NotEq,
×
127
            Operator::Gt => Operator::Lt,
24✔
128
            Operator::Gte => Operator::Lte,
7✔
129
            Operator::Lt => Operator::Gt,
3✔
130
            Operator::Lte => Operator::Gte,
×
131
            Operator::And => Operator::And,
×
132
            Operator::Or => Operator::Or,
×
133
            Operator::Add => Operator::Add,
×
134
        }
135
    }
34✔
136

137
    pub fn maybe_cmp_operator(self) -> Option<compute::Operator> {
×
138
        match self {
×
139
            Operator::Eq => Some(compute::Operator::Eq),
×
140
            Operator::NotEq => Some(compute::Operator::NotEq),
×
141
            Operator::Lt => Some(compute::Operator::Lt),
×
142
            Operator::Lte => Some(compute::Operator::Lte),
×
143
            Operator::Gt => Some(compute::Operator::Gt),
×
144
            Operator::Gte => Some(compute::Operator::Gte),
×
145
            _ => None,
×
146
        }
147
    }
×
148
}
149

150
impl From<compute::Operator> for Operator {
151
    fn from(cmp_operator: compute::Operator) -> Self {
×
152
        match cmp_operator {
×
153
            compute::Operator::Eq => Operator::Eq,
×
154
            compute::Operator::NotEq => Operator::NotEq,
×
155
            compute::Operator::Gt => Operator::Gt,
×
156
            compute::Operator::Gte => Operator::Gte,
×
157
            compute::Operator::Lt => Operator::Lt,
×
158
            compute::Operator::Lte => Operator::Lte,
×
159
        }
160
    }
×
161
}
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