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

gluesql / gluesql / 16858447755

10 Aug 2025 06:52AM UTC coverage: 97.975% (-0.006%) from 97.981%
16858447755

push

github

web-flow
Evaluate expressions to NULL when any operand is NULL (#1685)

This change refactors SQL expression evaluation logic to handle NULL values more explicitly, especially for equality, BETWEEN, IN, and logical operations. It introduces new tests for NULL semantics, BETWEEN, and IN list expressions, and adds utility methods to the evaluator. The test suite is expanded to cover these cases.

23 of 23 new or added lines in 4 files covered. (100.0%)

3 existing lines in 3 files now uncovered.

39958 of 40784 relevant lines covered (97.97%)

63821.02 hits per line

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

99.84
/core/src/data/value/binary_op/integer/macros.rs
1
macro_rules! impl_interval_method {
2
    (checked_mul, $lhs_variant: ident, $op: ident, $lhs: ident, $rhs: ident) => {
3
        return Ok(Value::Interval($lhs * $rhs))
4
    };
5
    ($other: ident, $lhs_variant: ident, $op: ident, $lhs: ident, $rhs: ident) => {
6
        return Err(ValueError::NonNumericMathOperation {
7
            lhs: $lhs_variant($lhs),
8
            operator: $op,
9
            rhs: Value::Interval($rhs),
10
        }
11
        .into())
12
    };
13
}
14

15
macro_rules! impl_method {
16
    ($lhs_variant: ident, $lhs_primitive: ident, $lhs: ident, $method: ident, $op: ident, $rhs: ident) => {{
17
        match *$rhs {
18
            I8(rhs) => $lhs
19
                .$method($lhs_primitive::try_from($rhs)?)
20
                .ok_or_else(|| {
100✔
21
                    ValueError::BinaryOperationOverflow {
100✔
22
                        lhs: $lhs_variant($lhs),
100✔
23
                        rhs: I8(rhs),
100✔
24
                        operator: $op,
100✔
25
                    }
100✔
26
                    .into()
100✔
27
                }),
100✔
28
            I16(rhs) => $lhs
29
                .$method($lhs_primitive::try_from($rhs)?)
30
                .ok_or_else(|| {
100✔
31
                    ValueError::BinaryOperationOverflow {
100✔
32
                        lhs: $lhs_variant($lhs),
100✔
33
                        rhs: I16(rhs),
100✔
34
                        operator: $op,
100✔
35
                    }
100✔
36
                    .into()
100✔
37
                }),
100✔
38
            I32(rhs) => $lhs
39
                .$method($lhs_primitive::try_from($rhs)?)
40
                .ok_or_else(|| {
100✔
41
                    ValueError::BinaryOperationOverflow {
100✔
42
                        lhs: $lhs_variant($lhs),
100✔
43
                        rhs: I32(rhs),
100✔
44
                        operator: $op,
100✔
45
                    }
100✔
46
                    .into()
100✔
47
                }),
100✔
48
            I64(rhs) => $lhs
49
                .$method($lhs_primitive::try_from($rhs)?)
50
                .ok_or_else(|| {
100✔
51
                    ValueError::BinaryOperationOverflow {
100✔
52
                        lhs: $lhs_variant($lhs),
100✔
53
                        rhs: I64(rhs),
100✔
54
                        operator: $op,
100✔
55
                    }
100✔
56
                    .into()
100✔
57
                }),
100✔
58
            I128(rhs) => $lhs
59
                .$method($lhs_primitive::try_from($rhs)?)
60
                .ok_or_else(|| {
100✔
61
                    ValueError::BinaryOperationOverflow {
100✔
62
                        lhs: $lhs_variant($lhs),
100✔
63
                        rhs: I128(rhs),
100✔
64
                        operator: $op,
100✔
65
                    }
100✔
66
                    .into()
100✔
67
                }),
100✔
68
            U8(rhs) => $lhs
69
                .$method($lhs_primitive::try_from($rhs)?)
70
                .ok_or_else(|| {
100✔
71
                    ValueError::BinaryOperationOverflow {
100✔
72
                        lhs: $lhs_variant($lhs),
100✔
73
                        rhs: U8(rhs),
100✔
74
                        operator: $op,
100✔
75
                    }
100✔
76
                    .into()
100✔
77
                }),
100✔
78
            U16(rhs) => $lhs
79
                .$method($lhs_primitive::try_from($rhs)?)
80
                .ok_or_else(|| {
100✔
81
                    ValueError::BinaryOperationOverflow {
100✔
82
                        lhs: $lhs_variant($lhs),
100✔
83
                        rhs: U16(rhs),
100✔
84
                        operator: $op,
100✔
85
                    }
100✔
86
                    .into()
100✔
87
                }),
100✔
88
            U32(rhs) => $lhs
89
                .$method($lhs_primitive::try_from($rhs)?)
90
                .ok_or_else(|| {
100✔
91
                    ValueError::BinaryOperationOverflow {
100✔
92
                        lhs: $lhs_variant($lhs),
100✔
93
                        rhs: U32(rhs),
100✔
94
                        operator: $op,
100✔
95
                    }
100✔
96
                    .into()
100✔
97
                }),
100✔
98
            U64(rhs) => $lhs
99
                .$method($lhs_primitive::try_from($rhs)?)
100
                .ok_or_else(|| {
100✔
101
                    ValueError::BinaryOperationOverflow {
100✔
102
                        lhs: $lhs_variant($lhs),
100✔
103
                        rhs: U64(rhs),
100✔
104
                        operator: $op,
100✔
105
                    }
100✔
106
                    .into()
100✔
107
                }),
100✔
108
            U128(rhs) => $lhs
109
                .$method($lhs_primitive::try_from($rhs)?)
110
                .ok_or_else(|| {
100✔
111
                    ValueError::BinaryOperationOverflow {
100✔
112
                        lhs: $lhs_variant($lhs),
100✔
113
                        rhs: U128(rhs),
100✔
114
                        operator: $op,
100✔
115
                    }
100✔
116
                    .into()
100✔
117
                }),
100✔
118
            F32(rhs) => $lhs
119
                .$method($lhs_primitive::try_from($rhs)?)
120
                .ok_or_else(|| {
100✔
121
                    ValueError::BinaryOperationOverflow {
100✔
122
                        lhs: $lhs_variant($lhs),
100✔
123
                        rhs: F32(rhs),
100✔
124
                        operator: $op,
100✔
125
                    }
100✔
126
                    .into()
100✔
127
                }),
100✔
128
            F64(rhs) => $lhs
129
                .$method($lhs_primitive::try_from($rhs)?)
130
                .ok_or_else(|| {
100✔
131
                    ValueError::BinaryOperationOverflow {
100✔
132
                        lhs: $lhs_variant($lhs),
100✔
133
                        rhs: F64(rhs),
100✔
134
                        operator: $op,
100✔
135
                    }
100✔
136
                    .into()
100✔
137
                }),
100✔
138
            Decimal(rhs) => $lhs
139
                .$method($lhs_primitive::try_from($rhs)?)
140
                .ok_or_else(|| {
100✔
141
                    ValueError::BinaryOperationOverflow {
100✔
142
                        lhs: $lhs_variant($lhs),
100✔
143
                        rhs: Decimal(rhs),
100✔
144
                        operator: $op,
100✔
145
                    }
100✔
146
                    .into()
100✔
147
                }),
100✔
148
            Null => return Ok(Null),
149
            Interval(rhs) => {
150
                super::macros::impl_interval_method!($method, $lhs_variant, $op, $lhs, rhs);
151
            }
152
            _ => Err(ValueError::NonNumericMathOperation {
153
                lhs: $lhs_variant($lhs),
154
                operator: $op,
155
                rhs: $rhs.clone(),
156
            }
157
            .into()),
158
        }
159
        .map($lhs_variant)
160
    }};
161
}
162

163
macro_rules! impl_try_binary_op {
164
    ($variant: ident, $primitive: ident) => {
165
        use $crate::{
166
            data::value::{
167
                TryBinaryOperator,
168
                Value::*,
169
                error::{NumericBinaryOperator::*, ValueError},
170
            },
171
            result::Result,
172
        };
173

174
        impl TryBinaryOperator for $primitive {
175
            type Rhs = Value;
176

177
            fn try_add(&self, rhs: &Self::Rhs) -> Result<Value> {
207,502✔
178
                let lhs = *self;
207,502✔
179
                super::macros::impl_method!($variant, $primitive, lhs, checked_add, Add, rhs)
207,502✔
180
            }
207,502✔
181

182
            fn try_subtract(&self, rhs: &Self::Rhs) -> Result<Value> {
59,386✔
183
                let lhs = *self;
59,386✔
184
                super::macros::impl_method!($variant, $primitive, lhs, checked_sub, Subtract, rhs)
59,386✔
185
            }
59,386✔
186

187
            fn try_multiply(&self, rhs: &Self::Rhs) -> Result<Value> {
89,815✔
188
                let lhs = *self;
89,815✔
189
                super::macros::impl_method!($variant, $primitive, lhs, checked_mul, Multiply, rhs)
89,815✔
190
            }
89,815✔
191

192
            fn try_divide(&self, rhs: &Self::Rhs) -> Result<Value> {
48,424✔
193
                let lhs = *self;
48,424✔
194
                super::macros::impl_method!($variant, $primitive, lhs, checked_div, Divide, rhs)
48,424✔
195
            }
48,424✔
196

197
            fn try_modulo(&self, rhs: &Self::Rhs) -> Result<Value> {
62,246✔
198
                let lhs = *self;
62,246✔
199
                super::macros::impl_method!($variant, $primitive, lhs, checked_rem, Modulo, rhs)
62,246✔
200
            }
62,246✔
201
        }
202
    };
203
}
204

205
#[cfg(test)]
206
macro_rules! generate_binary_op_tests {
207
    ($variant: ident, $primitive: ident) => {
208
        mod try_binary_op_tests {
209
            use {
210
                rust_decimal::prelude::Decimal,
211
                $crate::data::{
212
                    NumericBinaryOperator::{self, *},
213
                    ValueError,
214
                    value::{
215
                        TryBinaryOperator,
216
                        Value::{self, *},
217
                    },
218
                },
219
            };
220

221
            fn overflow_err(
1,300✔
222
                lhs: Value,
1,300✔
223
                rhs: Value,
1,300✔
224
                op: NumericBinaryOperator,
1,300✔
225
            ) -> Result<Value, $crate::result::Error> {
1,300✔
226
                Err(ValueError::BinaryOperationOverflow {
1,300✔
227
                    lhs,
1,300✔
228
                    rhs,
1,300✔
229
                    operator: op,
1,300✔
230
                }
1,300✔
231
                .into())
1,300✔
232
            }
1,300✔
233

234
            #[test]
235
            fn add_overflow() {
20✔
236
                assert_eq!(
20✔
237
                    $primitive::MAX.try_add(&Decimal(Decimal::from(1))),
20✔
238
                    overflow_err($variant($primitive::MAX), Decimal(Decimal::from(1)), Add)
20✔
239
                );
20✔
240
                assert_eq!(
20✔
241
                    $primitive::MAX.try_add(&F32(1.0_f32)),
20✔
242
                    overflow_err($variant($primitive::MAX), F32(1.0_f32), Add)
20✔
243
                );
20✔
244
                assert_eq!(
20✔
245
                    $primitive::MAX.try_add(&F64(1.0)),
20✔
246
                    overflow_err($variant($primitive::MAX), F64(1.0), Add)
20✔
247
                );
20✔
248
                assert_eq!(
20✔
249
                    $primitive::MAX.try_add(&I8(1)),
20✔
250
                    overflow_err($variant($primitive::MAX), I8(1), Add)
20✔
251
                );
20✔
252
                assert_eq!(
20✔
253
                    $primitive::MAX.try_add(&I16(1)),
20✔
254
                    overflow_err($variant($primitive::MAX), I16(1), Add)
20✔
255
                );
20✔
256
                assert_eq!(
20✔
257
                    $primitive::MAX.try_add(&I32(1)),
20✔
258
                    overflow_err($variant($primitive::MAX), I32(1), Add)
20✔
259
                );
20✔
260
                assert_eq!(
20✔
261
                    $primitive::MAX.try_add(&I64(1)),
20✔
262
                    overflow_err($variant($primitive::MAX), I64(1), Add)
20✔
263
                );
20✔
264
                assert_eq!(
20✔
265
                    $primitive::MAX.try_add(&I128(1)),
20✔
266
                    overflow_err($variant($primitive::MAX), I128(1), Add)
20✔
267
                );
20✔
268
                assert_eq!(
20✔
269
                    $primitive::MAX.try_add(&U8(1)),
20✔
270
                    overflow_err($variant($primitive::MAX), U8(1), Add)
20✔
271
                );
20✔
272
                assert_eq!(
20✔
273
                    $primitive::MAX.try_add(&U16(1)),
20✔
274
                    overflow_err($variant($primitive::MAX), U16(1), Add)
20✔
275
                );
20✔
276
                assert_eq!(
20✔
277
                    $primitive::MAX.try_add(&U32(1)),
20✔
278
                    overflow_err($variant($primitive::MAX), U32(1), Add)
20✔
279
                );
20✔
280
                assert_eq!(
20✔
281
                    $primitive::MAX.try_add(&U64(1)),
20✔
282
                    overflow_err($variant($primitive::MAX), U64(1), Add)
20✔
283
                );
20✔
284
                assert_eq!(
20✔
285
                    $primitive::MAX.try_add(&U128(1)),
20✔
286
                    overflow_err($variant($primitive::MAX), U128(1), Add)
20✔
287
                );
20✔
288
            }
20✔
289

290
            #[test]
291
            fn sub_overflow() {
20✔
292
                assert_eq!(
20✔
293
                    $primitive::MIN.try_subtract(&Decimal(Decimal::from(1))),
20✔
294
                    overflow_err(
20✔
295
                        $variant($primitive::MIN),
20✔
296
                        Decimal(Decimal::from(1)),
20✔
297
                        Subtract
20✔
298
                    )
20✔
299
                );
20✔
300
                assert_eq!(
20✔
301
                    $primitive::MIN.try_subtract(&F32(1.0_f32)),
20✔
302
                    overflow_err($variant($primitive::MIN), F32(1.0_f32), Subtract)
20✔
303
                );
20✔
304
                assert_eq!(
20✔
305
                    $primitive::MIN.try_subtract(&F64(1.0)),
20✔
306
                    overflow_err($variant($primitive::MIN), F64(1.0), Subtract)
20✔
307
                );
20✔
308
                assert_eq!(
20✔
309
                    $primitive::MIN.try_subtract(&I8(1)),
20✔
310
                    overflow_err($variant($primitive::MIN), I8(1), Subtract)
20✔
311
                );
20✔
312
                assert_eq!(
20✔
313
                    $primitive::MIN.try_subtract(&I16(1)),
20✔
314
                    overflow_err($variant($primitive::MIN), I16(1), Subtract)
20✔
315
                );
20✔
316
                assert_eq!(
20✔
317
                    $primitive::MIN.try_subtract(&I32(1)),
20✔
318
                    overflow_err($variant($primitive::MIN), I32(1), Subtract)
20✔
319
                );
20✔
320
                assert_eq!(
20✔
321
                    $primitive::MIN.try_subtract(&I64(1)),
20✔
322
                    overflow_err($variant($primitive::MIN), I64(1), Subtract)
20✔
323
                );
20✔
324
                assert_eq!(
20✔
325
                    $primitive::MIN.try_subtract(&I128(1)),
20✔
326
                    overflow_err($variant($primitive::MIN), I128(1), Subtract)
20✔
327
                );
20✔
328
                assert_eq!(
20✔
329
                    $primitive::MIN.try_subtract(&U8(1)),
20✔
330
                    overflow_err($variant($primitive::MIN), U8(1), Subtract)
20✔
331
                );
20✔
332
                assert_eq!(
20✔
333
                    $primitive::MIN.try_subtract(&U16(1)),
20✔
334
                    overflow_err($variant($primitive::MIN), U16(1), Subtract)
20✔
335
                );
20✔
336
                assert_eq!(
20✔
337
                    $primitive::MIN.try_subtract(&U32(1)),
20✔
338
                    overflow_err($variant($primitive::MIN), U32(1), Subtract)
20✔
339
                );
20✔
340
                assert_eq!(
20✔
341
                    $primitive::MIN.try_subtract(&U64(1)),
20✔
342
                    overflow_err($variant($primitive::MIN), U64(1), Subtract)
20✔
343
                );
20✔
344
                assert_eq!(
20✔
345
                    $primitive::MIN.try_subtract(&U128(1)),
20✔
346
                    overflow_err($variant($primitive::MIN), U128(1), Subtract)
20✔
347
                );
20✔
348
            }
20✔
349

350
            #[test]
351
            fn mul_overflow() {
20✔
352
                assert_eq!(
20✔
353
                    $primitive::MAX.try_multiply(&Decimal(Decimal::from(2))),
20✔
354
                    overflow_err(
20✔
355
                        $variant($primitive::MAX),
20✔
356
                        Decimal(Decimal::from(2)),
20✔
357
                        Multiply
20✔
358
                    )
20✔
359
                );
20✔
360
                assert_eq!(
20✔
361
                    $primitive::MAX.try_multiply(&F32(2.0_f32)),
20✔
362
                    overflow_err($variant($primitive::MAX), F32(2.0_f32), Multiply)
20✔
363
                );
20✔
364
                assert_eq!(
20✔
365
                    $primitive::MAX.try_multiply(&F64(2.0)),
20✔
366
                    overflow_err($variant($primitive::MAX), F64(2.0), Multiply)
20✔
367
                );
20✔
368
                assert_eq!(
20✔
369
                    $primitive::MAX.try_multiply(&I8(2)),
20✔
370
                    overflow_err($variant($primitive::MAX), I8(2), Multiply)
20✔
371
                );
20✔
372
                assert_eq!(
20✔
373
                    $primitive::MAX.try_multiply(&I16(2)),
20✔
374
                    overflow_err($variant($primitive::MAX), I16(2), Multiply)
20✔
375
                );
20✔
376
                assert_eq!(
20✔
377
                    $primitive::MAX.try_multiply(&I32(2)),
20✔
378
                    overflow_err($variant($primitive::MAX), I32(2), Multiply)
20✔
379
                );
20✔
380
                assert_eq!(
20✔
381
                    $primitive::MAX.try_multiply(&I64(2)),
20✔
382
                    overflow_err($variant($primitive::MAX), I64(2), Multiply)
20✔
383
                );
20✔
384
                assert_eq!(
20✔
385
                    $primitive::MAX.try_multiply(&I128(2)),
20✔
386
                    overflow_err($variant($primitive::MAX), I128(2), Multiply)
20✔
387
                );
20✔
388
                assert_eq!(
20✔
389
                    $primitive::MAX.try_multiply(&U8(2)),
20✔
390
                    overflow_err($variant($primitive::MAX), U8(2), Multiply)
20✔
391
                );
20✔
392
                assert_eq!(
20✔
393
                    $primitive::MAX.try_multiply(&U16(2)),
20✔
394
                    overflow_err($variant($primitive::MAX), U16(2), Multiply)
20✔
395
                );
20✔
396
                assert_eq!(
20✔
397
                    $primitive::MAX.try_multiply(&U32(2)),
20✔
398
                    overflow_err($variant($primitive::MAX), U32(2), Multiply)
20✔
399
                );
20✔
400
                assert_eq!(
20✔
401
                    $primitive::MAX.try_multiply(&U64(2)),
20✔
402
                    overflow_err($variant($primitive::MAX), U64(2), Multiply)
20✔
403
                );
20✔
404
                assert_eq!(
20✔
405
                    $primitive::MAX.try_multiply(&U128(2)),
20✔
406
                    overflow_err($variant($primitive::MAX), U128(2), Multiply)
20✔
407
                );
20✔
408
            }
20✔
409

410
            #[test]
411
            fn div_overflow() {
20✔
412
                assert_eq!(
20✔
413
                    $primitive::MAX.try_divide(&Decimal(Decimal::from(0))),
20✔
414
                    overflow_err($variant($primitive::MAX), Decimal(Decimal::from(0)), Divide)
20✔
415
                );
20✔
416
                assert_eq!(
20✔
417
                    $primitive::MAX.try_divide(&F32(0.0_f32)),
20✔
418
                    overflow_err($variant($primitive::MAX), F32(0.0_f32), Divide)
20✔
419
                );
20✔
420
                assert_eq!(
20✔
421
                    $primitive::MAX.try_divide(&F64(0.0)),
20✔
422
                    overflow_err($variant($primitive::MAX), F64(0.0), Divide)
20✔
423
                );
20✔
424
                assert_eq!(
20✔
425
                    $primitive::MAX.try_divide(&I8(0)),
20✔
426
                    overflow_err($variant($primitive::MAX), I8(0), Divide)
20✔
427
                );
20✔
428
                assert_eq!(
20✔
429
                    $primitive::MAX.try_divide(&I16(0)),
20✔
430
                    overflow_err($variant($primitive::MAX), I16(0), Divide)
20✔
431
                );
20✔
432
                assert_eq!(
20✔
433
                    $primitive::MAX.try_divide(&I32(0)),
20✔
434
                    overflow_err($variant($primitive::MAX), I32(0), Divide)
20✔
435
                );
20✔
436
                assert_eq!(
20✔
437
                    $primitive::MAX.try_divide(&I64(0)),
20✔
438
                    overflow_err($variant($primitive::MAX), I64(0), Divide)
20✔
439
                );
20✔
440
                assert_eq!(
20✔
441
                    $primitive::MAX.try_divide(&I128(0)),
20✔
442
                    overflow_err($variant($primitive::MAX), I128(0), Divide)
20✔
443
                );
20✔
444
                assert_eq!(
20✔
445
                    $primitive::MAX.try_divide(&U8(0)),
20✔
446
                    overflow_err($variant($primitive::MAX), U8(0), Divide)
20✔
447
                );
20✔
448
                assert_eq!(
20✔
449
                    $primitive::MAX.try_divide(&U16(0)),
20✔
450
                    overflow_err($variant($primitive::MAX), U16(0), Divide)
20✔
451
                );
20✔
452
                assert_eq!(
20✔
453
                    $primitive::MAX.try_divide(&U32(0)),
20✔
454
                    overflow_err($variant($primitive::MAX), U32(0), Divide)
20✔
455
                );
20✔
456
                assert_eq!(
20✔
457
                    $primitive::MAX.try_divide(&U64(0)),
20✔
458
                    overflow_err($variant($primitive::MAX), U64(0), Divide)
20✔
459
                );
20✔
460
                assert_eq!(
20✔
461
                    $primitive::MAX.try_divide(&U128(0)),
20✔
462
                    overflow_err($variant($primitive::MAX), U128(0), Divide)
20✔
463
                );
20✔
464
            }
20✔
465

466
            #[test]
467
            fn mod_overflow() {
20✔
468
                assert_eq!(
20✔
469
                    $primitive::MAX.try_modulo(&Decimal(Decimal::from(0))),
20✔
470
                    overflow_err($variant($primitive::MAX), Decimal(Decimal::from(0)), Modulo)
20✔
471
                );
20✔
472
                assert_eq!(
20✔
473
                    $primitive::MAX.try_modulo(&F32(0.0_f32)),
20✔
474
                    overflow_err($variant($primitive::MAX), F32(0.0_f32), Modulo)
20✔
475
                );
20✔
476
                assert_eq!(
20✔
477
                    $primitive::MAX.try_modulo(&F64(0.0)),
20✔
478
                    overflow_err($variant($primitive::MAX), F64(0.0), Modulo)
20✔
479
                );
20✔
480
                assert_eq!(
20✔
481
                    $primitive::MAX.try_modulo(&I8(0)),
20✔
482
                    overflow_err($variant($primitive::MAX), I8(0), Modulo)
20✔
483
                );
20✔
484
                assert_eq!(
20✔
485
                    $primitive::MAX.try_modulo(&I16(0)),
20✔
486
                    overflow_err($variant($primitive::MAX), I16(0), Modulo)
20✔
487
                );
20✔
488
                assert_eq!(
20✔
489
                    $primitive::MAX.try_modulo(&I32(0)),
20✔
490
                    overflow_err($variant($primitive::MAX), I32(0), Modulo)
20✔
491
                );
20✔
492
                assert_eq!(
20✔
493
                    $primitive::MAX.try_modulo(&I64(0)),
20✔
494
                    overflow_err($variant($primitive::MAX), I64(0), Modulo)
20✔
495
                );
20✔
496
                assert_eq!(
20✔
497
                    $primitive::MAX.try_modulo(&I128(0)),
20✔
498
                    overflow_err($variant($primitive::MAX), I128(0), Modulo)
20✔
499
                );
20✔
500
                assert_eq!(
20✔
501
                    $primitive::MAX.try_modulo(&U8(0)),
20✔
502
                    overflow_err($variant($primitive::MAX), U8(0), Modulo)
20✔
503
                );
20✔
504
                assert_eq!(
20✔
505
                    $primitive::MAX.try_modulo(&U16(0)),
20✔
506
                    overflow_err($variant($primitive::MAX), U16(0), Modulo)
20✔
507
                );
20✔
508
                assert_eq!(
20✔
509
                    $primitive::MAX.try_modulo(&U32(0)),
20✔
510
                    overflow_err($variant($primitive::MAX), U32(0), Modulo)
20✔
511
                );
20✔
512
                assert_eq!(
20✔
513
                    $primitive::MAX.try_modulo(&U64(0)),
20✔
514
                    overflow_err($variant($primitive::MAX), U64(0), Modulo)
20✔
515
                );
20✔
516
                assert_eq!(
20✔
517
                    $primitive::MAX.try_modulo(&U128(0)),
20✔
518
                    overflow_err($variant($primitive::MAX), U128(0), Modulo)
20✔
519
                );
20✔
520
            }
20✔
521

522
            #[test]
523
            fn try_add() {
20✔
524
                let base: $primitive = 1;
20✔
525

20✔
526
                assert_eq!(base.try_add(&Decimal(Decimal::ONE)), Ok($variant(2)));
20✔
527
                assert_eq!(base.try_add(&F32(1.0_f32)), Ok($variant(2)));
20✔
528
                assert_eq!(base.try_add(&F64(1.0)), Ok($variant(2)));
20✔
529
                assert_eq!(base.try_add(&I8(1)), Ok($variant(2)));
20✔
530
                assert_eq!(base.try_add(&I16(1)), Ok($variant(2)));
20✔
531
                assert_eq!(base.try_add(&I32(1)), Ok($variant(2)));
20✔
532
                assert_eq!(base.try_add(&I64(1)), Ok($variant(2)));
20✔
533
                assert_eq!(base.try_add(&I128(1)), Ok($variant(2)));
20✔
534
                assert_eq!(base.try_add(&U8(1)), Ok($variant(2)));
20✔
535
                assert_eq!(base.try_add(&U16(1)), Ok($variant(2)));
20✔
536
                assert_eq!(base.try_add(&U32(1)), Ok($variant(2)));
20✔
537
                assert_eq!(base.try_add(&U64(1)), Ok($variant(2)));
20✔
538
                assert_eq!(base.try_add(&U128(1)), Ok($variant(2)));
20✔
539

540
                assert_eq!(
20✔
541
                    base.try_add(&Bool(true)),
20✔
542
                    Err(ValueError::NonNumericMathOperation {
20✔
543
                        lhs: $variant(base),
20✔
544
                        operator: NumericBinaryOperator::Add,
20✔
545
                        rhs: Bool(true)
20✔
546
                    }
20✔
547
                    .into())
20✔
548
                );
20✔
549
            }
20✔
550

551
            #[test]
552
            fn try_subtract() {
20✔
553
                let base: $primitive = 1;
20✔
554

20✔
555
                assert_eq!(base.try_subtract(&Decimal(Decimal::ONE)), Ok($variant(0)));
20✔
556
                assert_eq!(base.try_subtract(&F32(1.0_f32)), Ok($variant(0)));
20✔
557
                assert_eq!(base.try_subtract(&F64(1.0)), Ok($variant(0)));
20✔
558
                assert_eq!(base.try_subtract(&I8(1)), Ok($variant(0)));
20✔
559
                assert_eq!(base.try_subtract(&I16(1)), Ok($variant(0)));
20✔
560
                assert_eq!(base.try_subtract(&I32(1)), Ok($variant(0)));
20✔
561
                assert_eq!(base.try_subtract(&I64(1)), Ok($variant(0)));
20✔
562
                assert_eq!(base.try_subtract(&I128(1)), Ok($variant(0)));
20✔
563
                assert_eq!(base.try_subtract(&U8(1)), Ok($variant(0)));
20✔
564
                assert_eq!(base.try_subtract(&U16(1)), Ok($variant(0)));
20✔
565
                assert_eq!(base.try_subtract(&U32(1)), Ok($variant(0)));
20✔
566
                assert_eq!(base.try_subtract(&U64(1)), Ok($variant(0)));
20✔
567
                assert_eq!(base.try_subtract(&U128(1)), Ok($variant(0)));
20✔
568

569
                assert_eq!(
20✔
570
                    base.try_subtract(&Bool(true)),
20✔
571
                    Err(ValueError::NonNumericMathOperation {
20✔
572
                        lhs: $variant(base),
20✔
573
                        operator: NumericBinaryOperator::Subtract,
20✔
574
                        rhs: Bool(true)
20✔
575
                    }
20✔
576
                    .into())
20✔
577
                );
20✔
578
            }
20✔
579

580
            #[test]
581
            fn try_multiply() {
20✔
582
                let base: $primitive = 3;
20✔
583

20✔
584
                assert_eq!(base.try_multiply(&Decimal(Decimal::TWO)), Ok($variant(6)));
20✔
585
                assert_eq!(base.try_multiply(&F32(2.0_f32)), Ok($variant(6)));
20✔
586
                assert_eq!(base.try_multiply(&F64(2.0)), Ok($variant(6)));
20✔
587
                assert_eq!(base.try_multiply(&I8(2)), Ok($variant(6)));
20✔
588
                assert_eq!(base.try_multiply(&I16(2)), Ok($variant(6)));
20✔
589
                assert_eq!(base.try_multiply(&I32(2)), Ok($variant(6)));
20✔
590
                assert_eq!(base.try_multiply(&I64(2)), Ok($variant(6)));
20✔
591
                assert_eq!(base.try_multiply(&I128(2)), Ok($variant(6)));
20✔
592
                assert_eq!(base.try_multiply(&U8(2)), Ok($variant(6)));
20✔
593
                assert_eq!(base.try_multiply(&U16(2)), Ok($variant(6)));
20✔
594
                assert_eq!(base.try_multiply(&U32(2)), Ok($variant(6)));
20✔
595
                assert_eq!(base.try_multiply(&U64(2)), Ok($variant(6)));
20✔
596
                assert_eq!(base.try_multiply(&U128(2)), Ok($variant(6)));
20✔
597

598
                assert_eq!(
20✔
599
                    base.try_multiply(&Bool(true)),
20✔
600
                    Err(ValueError::NonNumericMathOperation {
20✔
601
                        lhs: $variant(base),
20✔
602
                        operator: NumericBinaryOperator::Multiply,
20✔
603
                        rhs: Bool(true)
20✔
604
                    }
20✔
605
                    .into())
20✔
606
                );
20✔
607
            }
20✔
608

609
            #[test]
610
            fn try_divide() {
20✔
611
                let base: $primitive = 6;
20✔
612

20✔
613
                assert_eq!(base.try_divide(&Decimal(Decimal::TWO)), Ok($variant(3)));
20✔
614
                assert_eq!(base.try_divide(&F32(2.0_f32)), Ok($variant(3)));
20✔
615
                assert_eq!(base.try_divide(&F64(2.0)), Ok($variant(3)));
20✔
616
                assert_eq!(base.try_divide(&I8(2)), Ok($variant(3)));
20✔
617
                assert_eq!(base.try_divide(&I16(2)), Ok($variant(3)));
20✔
618
                assert_eq!(base.try_divide(&I32(2)), Ok($variant(3)));
20✔
619
                assert_eq!(base.try_divide(&I64(2)), Ok($variant(3)));
20✔
620
                assert_eq!(base.try_divide(&I128(2)), Ok($variant(3)));
20✔
621
                assert_eq!(base.try_divide(&U8(2)), Ok($variant(3)));
20✔
622
                assert_eq!(base.try_divide(&U16(2)), Ok($variant(3)));
20✔
623
                assert_eq!(base.try_divide(&U32(2)), Ok($variant(3)));
20✔
624
                assert_eq!(base.try_divide(&U64(2)), Ok($variant(3)));
20✔
625
                assert_eq!(base.try_divide(&U128(2)), Ok($variant(3)));
20✔
626

627
                assert_eq!(
20✔
628
                    base.try_divide(&Bool(true)),
20✔
629
                    Err(ValueError::NonNumericMathOperation {
20✔
630
                        lhs: $variant(base),
20✔
631
                        operator: NumericBinaryOperator::Divide,
20✔
632
                        rhs: Bool(true)
20✔
633
                    }
20✔
634
                    .into())
20✔
635
                );
20✔
636
            }
20✔
637

638
            #[test]
639
            fn try_modulo() {
20✔
640
                let base: $primitive = 9;
20✔
641

20✔
642
                assert_eq!(base.try_modulo(&Decimal(Decimal::ONE)), Ok($variant(0)));
20✔
643
                assert_eq!(base.try_modulo(&F32(1.0_f32)), Ok($variant(0)));
20✔
644
                assert_eq!(base.try_modulo(&F64(1.0)), Ok($variant(0)));
20✔
645
                assert_eq!(base.try_modulo(&I8(1)), Ok($variant(0)));
20✔
646
                assert_eq!(base.try_modulo(&I16(1)), Ok($variant(0)));
20✔
647
                assert_eq!(base.try_modulo(&I32(1)), Ok($variant(0)));
20✔
648
                assert_eq!(base.try_modulo(&I64(1)), Ok($variant(0)));
20✔
649
                assert_eq!(base.try_modulo(&I128(1)), Ok($variant(0)));
20✔
650
                assert_eq!(base.try_modulo(&U8(1)), Ok($variant(0)));
20✔
651
                assert_eq!(base.try_modulo(&U16(1)), Ok($variant(0)));
20✔
652
                assert_eq!(base.try_modulo(&U32(1)), Ok($variant(0)));
20✔
653
                assert_eq!(base.try_modulo(&U64(1)), Ok($variant(0)));
20✔
654
                assert_eq!(base.try_modulo(&U128(1)), Ok($variant(0)));
20✔
655

656
                assert_eq!(
20✔
657
                    base.try_modulo(&Bool(true)),
20✔
658
                    Err(ValueError::NonNumericMathOperation {
20✔
659
                        lhs: $variant(base),
20✔
660
                        operator: NumericBinaryOperator::Modulo,
20✔
661
                        rhs: Bool(true)
20✔
662
                    }
20✔
663
                    .into())
20✔
664
                );
20✔
665
            }
20✔
666
        }
667
    };
668
}
669

670
macro_rules! impl_partial_cmp_ord_method {
671
    ($primitive: ident) => {
672
        impl PartialEq<Value> for $primitive {
673
            fn eq(&self, other: &Value) -> bool {
1,373,325✔
674
                if matches!(other, Value::Bool(_)) {
1,373,325✔
675
                    return false;
20✔
676
                }
1,373,305✔
677

1,373,305✔
678
                let lhs = *self;
1,373,305✔
679
                let rhs = match $primitive::try_from(other) {
1,373,305✔
680
                    Ok(rhs) => rhs,
1,373,305✔
UNCOV
681
                    Err(_) => return false,
×
682
                };
683

684
                lhs == rhs
1,373,305✔
685
            }
1,373,325✔
686
        }
687

688
        impl PartialOrd<Value> for $primitive {
689
            fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
153,936✔
690
                if matches!(other, Value::Bool(_)) {
153,936✔
691
                    return None;
20✔
692
                }
153,916✔
693

153,916✔
694
                let lhs = self;
153,916✔
695
                let rhs = match $primitive::try_from(other) {
153,916✔
696
                    Ok(rhs) => rhs,
147,952✔
697
                    Err(_) => return None,
5,964✔
698
                };
699

700
                lhs.partial_cmp(&rhs)
147,952✔
701
            }
153,936✔
702
        }
703
    };
704
}
705

706
#[cfg(test)]
707
macro_rules! generate_cmp_ord_tests {
708
    ($primitive: ident) => {
709
        mod cmp_ord_tests {
710
            use {
711
                rust_decimal::prelude::Decimal, std::cmp::Ordering, $crate::data::value::Value::*,
712
            };
713

714
            #[test]
715
            fn eq() {
20✔
716
                let base: $primitive = 1;
20✔
717

20✔
718
                assert_eq!(base, Decimal(Decimal::ONE));
20✔
719
                assert_eq!(base, F32(1.0_f32));
20✔
720
                assert_eq!(base, F64(1.0));
20✔
721
                assert_eq!(base, I8(1));
20✔
722
                assert_eq!(base, I16(1));
20✔
723
                assert_eq!(base, I32(1));
20✔
724
                assert_eq!(base, I64(1));
20✔
725
                assert_eq!(base, I128(1));
20✔
726
                assert_eq!(base, U8(1));
20✔
727
                assert_eq!(base, U16(1));
20✔
728
                assert_eq!(base, U32(1));
20✔
729
                assert_eq!(base, U64(1));
20✔
730
                assert_eq!(base, U128(1));
20✔
731

732
                assert_ne!(base, Bool(true));
20✔
733
            }
20✔
734

735
            #[test]
736
            fn partial_cmp() {
20✔
737
                let base: $primitive = 1;
20✔
738

20✔
739
                assert_eq!(
20✔
740
                    base.partial_cmp(&Decimal(Decimal::ZERO)),
20✔
741
                    Some(Ordering::Greater)
20✔
742
                );
20✔
743
                assert_eq!(base.partial_cmp(&F32(0.0_f32)), Some(Ordering::Greater));
20✔
744
                assert_eq!(base.partial_cmp(&F64(0.0)), Some(Ordering::Greater));
20✔
745
                assert_eq!(base.partial_cmp(&I8(0)), Some(Ordering::Greater));
20✔
746
                assert_eq!(base.partial_cmp(&I16(0)), Some(Ordering::Greater));
20✔
747
                assert_eq!(base.partial_cmp(&I32(0)), Some(Ordering::Greater));
20✔
748
                assert_eq!(base.partial_cmp(&I64(0)), Some(Ordering::Greater));
20✔
749
                assert_eq!(base.partial_cmp(&I128(0)), Some(Ordering::Greater));
20✔
750
                assert_eq!(base.partial_cmp(&U8(0)), Some(Ordering::Greater));
20✔
751
                assert_eq!(base.partial_cmp(&U16(0)), Some(Ordering::Greater));
20✔
752
                assert_eq!(base.partial_cmp(&U32(0)), Some(Ordering::Greater));
20✔
753
                assert_eq!(base.partial_cmp(&U64(0)), Some(Ordering::Greater));
20✔
754
                assert_eq!(base.partial_cmp(&U128(0)), Some(Ordering::Greater));
20✔
755

756
                assert_eq!(
20✔
757
                    base.partial_cmp(&Decimal(Decimal::ONE)),
20✔
758
                    Some(Ordering::Equal)
20✔
759
                );
20✔
760
                assert_eq!(base.partial_cmp(&F32(1.0_f32)), Some(Ordering::Equal));
20✔
761
                assert_eq!(base.partial_cmp(&F64(1.0)), Some(Ordering::Equal));
20✔
762
                assert_eq!(base.partial_cmp(&I8(1)), Some(Ordering::Equal));
20✔
763
                assert_eq!(base.partial_cmp(&I16(1)), Some(Ordering::Equal));
20✔
764
                assert_eq!(base.partial_cmp(&I32(1)), Some(Ordering::Equal));
20✔
765
                assert_eq!(base.partial_cmp(&I64(1)), Some(Ordering::Equal));
20✔
766
                assert_eq!(base.partial_cmp(&I128(1)), Some(Ordering::Equal));
20✔
767
                assert_eq!(base.partial_cmp(&U8(1)), Some(Ordering::Equal));
20✔
768
                assert_eq!(base.partial_cmp(&U16(1)), Some(Ordering::Equal));
20✔
769
                assert_eq!(base.partial_cmp(&U32(1)), Some(Ordering::Equal));
20✔
770
                assert_eq!(base.partial_cmp(&U64(1)), Some(Ordering::Equal));
20✔
771
                assert_eq!(base.partial_cmp(&U128(1)), Some(Ordering::Equal));
20✔
772

773
                assert_eq!(
20✔
774
                    base.partial_cmp(&Decimal(Decimal::TWO)),
20✔
775
                    Some(Ordering::Less)
20✔
776
                );
20✔
777
                assert_eq!(base.partial_cmp(&F32(2.0_f32)), Some(Ordering::Less));
20✔
778
                assert_eq!(base.partial_cmp(&F64(2.0)), Some(Ordering::Less));
20✔
779
                assert_eq!(base.partial_cmp(&I8(2)), Some(Ordering::Less));
20✔
780
                assert_eq!(base.partial_cmp(&I16(2)), Some(Ordering::Less));
20✔
781
                assert_eq!(base.partial_cmp(&I32(2)), Some(Ordering::Less));
20✔
782
                assert_eq!(base.partial_cmp(&I64(2)), Some(Ordering::Less));
20✔
783
                assert_eq!(base.partial_cmp(&I128(2)), Some(Ordering::Less));
20✔
784
                assert_eq!(base.partial_cmp(&U8(2)), Some(Ordering::Less));
20✔
785
                assert_eq!(base.partial_cmp(&U16(2)), Some(Ordering::Less));
20✔
786
                assert_eq!(base.partial_cmp(&U32(2)), Some(Ordering::Less));
20✔
787
                assert_eq!(base.partial_cmp(&U64(2)), Some(Ordering::Less));
20✔
788
                assert_eq!(base.partial_cmp(&U128(2)), Some(Ordering::Less));
20✔
789

790
                assert_eq!(base.partial_cmp(&Bool(true)), None);
20✔
791
            }
20✔
792
        }
793
    };
794
}
795

796
#[cfg(test)]
797
pub(crate) use {generate_binary_op_tests, generate_cmp_ord_tests};
798
pub(crate) use {
799
    impl_interval_method, impl_method, impl_partial_cmp_ord_method, impl_try_binary_op,
800
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc