• 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-array/src/stats/bound.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use std::cmp::Ordering;
5

6
use vortex_error::{VortexError, VortexResult};
7

8
use crate::partial_ord::{partial_max, partial_min};
9
use crate::stats::Precision::{Exact, Inexact};
10
use crate::stats::{Precision, StatBound};
11

12
/// Interpret the value as a lower bound.
13
/// These form a partial order over successively more precise bounds
14
#[derive(Debug, Clone, PartialEq, Eq)]
15
pub struct LowerBound<T>(pub(crate) Precision<T>);
16

17
impl<T> LowerBound<T> {
UNCOV
18
    pub(crate) fn min_value(self) -> T {
×
UNCOV
19
        self.0.into_inner()
×
UNCOV
20
    }
×
21
}
22

23
impl<T> LowerBound<T> {
24
    pub fn is_exact(&self) -> bool {
×
25
        self.0.is_exact()
×
26
    }
×
27
}
28

29
/// The result of the fallible intersection of two bound, defined to avoid `Option`
30
/// `IntersectionResult` mixup.
31
#[derive(Debug, Clone, PartialEq, Eq)]
32
pub enum IntersectionResult<T> {
33
    /// An intersection result was found
34
    Value(T),
35
    /// Values has no intersection.
36
    None,
37
}
38

39
impl<T> IntersectionResult<T> {
UNCOV
40
    pub fn ok_or_else<F>(self, err: F) -> VortexResult<T>
×
UNCOV
41
    where
×
UNCOV
42
        F: FnOnce() -> VortexError,
×
43
    {
UNCOV
44
        match self {
×
UNCOV
45
            IntersectionResult::Value(v) => Ok(v),
×
UNCOV
46
            IntersectionResult::None => Err(err()),
×
47
        }
UNCOV
48
    }
×
49
}
50

51
impl<T: PartialOrd + Clone> StatBound<T> for LowerBound<T> {
UNCOV
52
    fn lift(value: Precision<T>) -> Self {
×
UNCOV
53
        Self(value)
×
UNCOV
54
    }
×
55

UNCOV
56
    fn union(&self, other: &Self) -> Option<LowerBound<T>> {
×
UNCOV
57
        Some(LowerBound(match (&self.0, &other.0) {
×
UNCOV
58
            (Exact(lhs), Exact(rhs)) => Exact(partial_min(lhs, rhs)?.clone()),
×
59
            (Inexact(lhs), Inexact(rhs)) => Inexact(partial_min(lhs, rhs)?.clone()),
×
UNCOV
60
            (Inexact(lhs), Exact(rhs)) => {
×
UNCOV
61
                if rhs <= lhs {
×
UNCOV
62
                    Exact(rhs.clone())
×
63
                } else {
UNCOV
64
                    Inexact(lhs.clone())
×
65
                }
66
            }
UNCOV
67
            (Exact(lhs), Inexact(rhs)) => {
×
UNCOV
68
                if rhs >= lhs {
×
UNCOV
69
                    Exact(lhs.clone())
×
70
                } else {
71
                    Inexact(rhs.clone())
×
72
                }
73
            }
74
        }))
UNCOV
75
    }
×
76

77
    // The join of the smallest intersection of both bounds, this can fail.
UNCOV
78
    fn intersection(&self, other: &Self) -> Option<IntersectionResult<LowerBound<T>>> {
×
UNCOV
79
        Some(match (&self.0, &other.0) {
×
80
            (Exact(lhs), Exact(rhs)) => {
×
81
                if lhs == rhs {
×
82
                    IntersectionResult::Value(LowerBound(Exact(lhs.clone())))
×
83
                } else {
84
                    // The two intervals do not overlap
85
                    IntersectionResult::None
×
86
                }
87
            }
88
            (Inexact(lhs), Inexact(rhs)) => {
×
89
                IntersectionResult::Value(LowerBound(Inexact(partial_max(lhs, rhs)?.clone())))
×
90
            }
91
            (Inexact(lhs), Exact(rhs)) => {
×
92
                if rhs >= lhs {
×
93
                    IntersectionResult::Value(LowerBound(Exact(rhs.clone())))
×
94
                } else {
95
                    // The two intervals do not overlap
96
                    IntersectionResult::None
×
97
                }
98
            }
UNCOV
99
            (Exact(lhs), Inexact(rhs)) => {
×
UNCOV
100
                if rhs <= lhs {
×
UNCOV
101
                    IntersectionResult::Value(LowerBound(Exact(lhs.clone())))
×
102
                } else {
103
                    // The two intervals do not overlap
UNCOV
104
                    IntersectionResult::None
×
105
                }
106
            }
107
        })
UNCOV
108
    }
×
109

110
    fn to_exact(&self) -> Option<&T> {
×
111
        self.0.to_exact()
×
112
    }
×
113

UNCOV
114
    fn into_value(self) -> Precision<T> {
×
UNCOV
115
        self.0
×
UNCOV
116
    }
×
117
}
118

119
impl<T: PartialOrd> PartialEq<T> for LowerBound<T> {
120
    fn eq(&self, other: &T) -> bool {
×
121
        match &self.0 {
×
122
            Exact(lhs) => lhs == other,
×
123
            _ => false,
×
124
        }
125
    }
×
126
}
127

128
// We can only compare exact values with values and Precision::inexact values can only be greater than a value
129
impl<T: PartialOrd> PartialOrd<T> for LowerBound<T> {
130
    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
×
131
        match &self.0 {
×
132
            Exact(lhs) => lhs.partial_cmp(other),
×
133
            Inexact(lhs) => lhs
×
134
                .partial_cmp(other)
×
135
                .and_then(|o| if o == Ordering::Less { None } else { Some(o) }),
×
136
        }
137
    }
×
138
}
139

140
/// Interpret the value as an upper bound, see `LowerBound` for more details.
141
#[derive(Debug, Clone, PartialEq, Eq)]
142
pub struct UpperBound<T>(pub(crate) Precision<T>);
143

144
impl<T> UpperBound<T> {
UNCOV
145
    pub(crate) fn max_value(self) -> T {
×
UNCOV
146
        self.0.into_inner()
×
UNCOV
147
    }
×
148
}
149

150
impl<T: PartialOrd + Clone> StatBound<T> for UpperBound<T> {
UNCOV
151
    fn lift(value: Precision<T>) -> Self {
×
UNCOV
152
        Self(value)
×
UNCOV
153
    }
×
154

155
    /// The meet or tightest covering bound
UNCOV
156
    fn union(&self, other: &Self) -> Option<UpperBound<T>> {
×
UNCOV
157
        Some(UpperBound(match (&self.0, &other.0) {
×
UNCOV
158
            (Exact(lhs), Exact(rhs)) => Exact(partial_max(lhs, rhs)?.clone()),
×
UNCOV
159
            (Inexact(lhs), Inexact(rhs)) => Inexact(partial_max(lhs, rhs)?.clone()),
×
UNCOV
160
            (Inexact(lhs), Exact(rhs)) => {
×
UNCOV
161
                if rhs >= lhs {
×
UNCOV
162
                    Exact(rhs.clone())
×
163
                } else {
164
                    Inexact(lhs.clone())
×
165
                }
166
            }
UNCOV
167
            (Exact(lhs), Inexact(rhs)) => {
×
UNCOV
168
                if rhs <= lhs {
×
169
                    Exact(lhs.clone())
×
170
                } else {
UNCOV
171
                    Inexact(rhs.clone())
×
172
                }
173
            }
174
        }))
UNCOV
175
    }
×
176

UNCOV
177
    fn intersection(&self, other: &Self) -> Option<IntersectionResult<UpperBound<T>>> {
×
UNCOV
178
        Some(match (&self.0, &other.0) {
×
179
            (Exact(lhs), Exact(rhs)) => {
×
180
                if lhs == rhs {
×
181
                    IntersectionResult::Value(UpperBound(Exact(lhs.clone())))
×
182
                } else {
183
                    // The two intervals do not overlap
184
                    IntersectionResult::None
×
185
                }
186
            }
187
            (Inexact(lhs), Inexact(rhs)) => {
×
188
                IntersectionResult::Value(UpperBound(Inexact(partial_min(lhs, rhs)?.clone())))
×
189
            }
UNCOV
190
            (Inexact(lhs), Exact(rhs)) => {
×
UNCOV
191
                if rhs <= lhs {
×
UNCOV
192
                    IntersectionResult::Value(UpperBound(Exact(rhs.clone())))
×
193
                } else {
194
                    // The two intervals do not overlap
195
                    IntersectionResult::None
×
196
                }
197
            }
UNCOV
198
            (Exact(lhs), Inexact(rhs)) => {
×
UNCOV
199
                if rhs >= lhs {
×
UNCOV
200
                    IntersectionResult::Value(UpperBound(Exact(lhs.clone())))
×
201
                } else {
202
                    // The two intervals do not overlap
UNCOV
203
                    IntersectionResult::None
×
204
                }
205
            }
206
        })
UNCOV
207
    }
×
208

209
    fn to_exact(&self) -> Option<&T> {
×
210
        self.0.to_exact()
×
211
    }
×
212

UNCOV
213
    fn into_value(self) -> Precision<T> {
×
UNCOV
214
        self.0
×
UNCOV
215
    }
×
216
}
217

218
impl<T: PartialOrd> PartialEq<T> for UpperBound<T> {
UNCOV
219
    fn eq(&self, other: &T) -> bool {
×
UNCOV
220
        match &self.0 {
×
UNCOV
221
            Exact(lhs) => lhs == other,
×
UNCOV
222
            _ => false,
×
223
        }
UNCOV
224
    }
×
225
}
226

227
// We can only compare exact values with values and Precision::inexact values can only be greater than a value
228
impl<T: PartialOrd> PartialOrd<T> for UpperBound<T> {
UNCOV
229
    fn partial_cmp(&self, other: &T) -> Option<Ordering> {
×
UNCOV
230
        match &self.0 {
×
UNCOV
231
            Exact(lhs) => lhs.partial_cmp(other),
×
UNCOV
232
            Inexact(lhs) => lhs.partial_cmp(other).and_then(|o| {
×
UNCOV
233
                if o == Ordering::Greater {
×
UNCOV
234
                    None
×
235
                } else {
UNCOV
236
                    Some(o)
×
237
                }
UNCOV
238
            }),
×
239
        }
UNCOV
240
    }
×
241
}
242

243
#[cfg(test)]
244
mod tests {
245
    use crate::stats::bound::IntersectionResult;
246
    use crate::stats::{LowerBound, Precision, StatBound, UpperBound};
247

248
    #[test]
249
    fn test_upper_bound_cmp() {
250
        let ub = UpperBound(Precision::exact(10i32));
251

252
        assert_eq!(ub, 10);
253
        assert!(ub > 9);
254
        assert!(ub <= 10);
255
        assert!(ub <= 10);
256

257
        let ub = UpperBound(Precision::inexact(10i32));
258

259
        assert_ne!(ub, 10);
260
        assert!(ub < 11);
261
        // We cannot say anything about a value in the bound.
262
        assert!(!(ub >= 9));
263
    }
264

265
    #[test]
266
    fn test_upper_bound_union() {
267
        let ub1: UpperBound<i32> = UpperBound(Precision::exact(10i32));
268
        let ub2 = UpperBound(Precision::exact(12i32));
269

270
        assert_eq!(Some(ub2.clone()), ub1.union(&ub2));
271

272
        let ub1: UpperBound<i32> = UpperBound(Precision::inexact(10i32));
273
        let ub2 = UpperBound(Precision::exact(12i32));
274

275
        assert_eq!(Some(ub2.clone()), ub1.union(&ub2));
276

277
        let ub1: UpperBound<i32> = UpperBound(Precision::exact(10i32));
278
        let ub2 = UpperBound(Precision::inexact(12i32));
279

280
        assert_eq!(Some(ub2.clone()), ub1.union(&ub2));
281

282
        let ub1: UpperBound<i32> = UpperBound(Precision::inexact(10i32));
283
        let ub2 = UpperBound(Precision::inexact(12i32));
284

285
        assert_eq!(Some(ub2.clone()), ub1.union(&ub2))
286
    }
287

288
    #[test]
289
    fn test_upper_bound_intersection() {
290
        let ub1: UpperBound<i32> = UpperBound(Precision::exact(10i32));
291
        let ub2 = UpperBound(Precision::inexact(12i32));
292

293
        assert_eq!(
294
            Some(IntersectionResult::Value(ub1.clone())),
295
            ub1.intersection(&ub2)
296
        );
297

298
        let ub1: UpperBound<i32> = UpperBound(Precision::exact(13i32));
299
        let ub2 = UpperBound(Precision::inexact(12i32));
300

301
        assert_eq!(Some(IntersectionResult::None), ub1.intersection(&ub2));
302
    }
303

304
    #[test]
305
    fn test_lower_bound_intersection() {
306
        let lb1: LowerBound<i32> = LowerBound(Precision::exact(12i32));
307
        let lb2 = LowerBound(Precision::inexact(10i32));
308

309
        assert_eq!(
310
            Some(IntersectionResult::Value(lb1.clone())),
311
            lb1.intersection(&lb2)
312
        );
313

314
        let lb1: LowerBound<i32> = LowerBound(Precision::exact(12i32));
315
        let lb2 = LowerBound(Precision::inexact(13i32));
316

317
        assert_eq!(Some(IntersectionResult::None), lb1.intersection(&lb2));
318
    }
319
}
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