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

flowlight0 / simpledb-rs / #119

21 Jun 2025 09:50AM UTC coverage: 78.816% (-0.03%) from 78.843%
#119

push

web-flow
refactor: move Expression to separate module (#126)

28 of 70 new or added lines in 1 file covered. (40.0%)

1 existing line in 1 file now uncovered.

2943 of 3734 relevant lines covered (78.82%)

1.69 hits per line

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

40.0
/src/parser/expression.rs
1
use crate::{
2
    errors::TransactionError,
3
    record::{field::Value, schema::Schema},
4
    scan::{Scan, ScanControl},
5
};
6

7
#[derive(Debug, Clone, PartialEq, Eq)]
8
pub enum Expression {
9
    NullConstant,
10
    I32Constant(i32),
11
    StringConstant(String),
12
    Field(String),
13
    Add(Box<Expression>, Box<Expression>),
14
    Sub(Box<Expression>, Box<Expression>),
15
    Mul(Box<Expression>, Box<Expression>),
16
    Div(Box<Expression>, Box<Expression>),
17
}
18

19
impl Expression {
20
    /// Evaluates the expression against the given [`Scan`].
21
    ///
22
    /// The resulting [`Value`] is returned in a `Result` since accessing a
23
    /// field may fail if the underlying scan encounters an error.
24
    pub fn evaluate(&self, scan: &mut Scan) -> Result<Value, TransactionError> {
2✔
25
        match self {
2✔
NEW
26
            Expression::NullConstant => Ok(Value::Null),
×
27
            Expression::I32Constant(value) => Ok(Value::I32(*value)),
1✔
28
            Expression::StringConstant(value) => Ok(Value::String(value.clone())),
2✔
29
            Expression::Field(field_name) => {
2✔
30
                if scan.has_field(field_name) {
2✔
31
                    scan.get_value(field_name)
2✔
32
                } else {
NEW
33
                    panic!("Field {} not found", field_name)
×
34
                }
35
            }
36
            Expression::Add(lhs, rhs) => {
1✔
37
                let l = lhs.evaluate(scan)?;
2✔
38
                let r = rhs.evaluate(scan)?;
2✔
39
                match (l, r) {
2✔
40
                    (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a + b)),
1✔
NEW
41
                    (Value::Null, _) | (_, Value::Null) => Ok(Value::Null),
×
NEW
42
                    _ => panic!("Type mismatch in addition"),
×
43
                }
44
            }
45
            Expression::Sub(lhs, rhs) => {
1✔
46
                let l = lhs.evaluate(scan)?;
2✔
47
                let r = rhs.evaluate(scan)?;
2✔
48
                match (l, r) {
2✔
49
                    (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a - b)),
1✔
NEW
50
                    (Value::Null, _) | (_, Value::Null) => Ok(Value::Null),
×
NEW
51
                    _ => panic!("Type mismatch in subtraction"),
×
52
                }
53
            }
NEW
54
            Expression::Mul(lhs, rhs) => {
×
NEW
55
                let l = lhs.evaluate(scan)?;
×
NEW
56
                let r = rhs.evaluate(scan)?;
×
NEW
57
                match (l, r) {
×
NEW
58
                    (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a * b)),
×
NEW
59
                    (Value::Null, _) | (_, Value::Null) => Ok(Value::Null),
×
NEW
60
                    _ => panic!("Type mismatch in multiplication"),
×
61
                }
62
            }
NEW
63
            Expression::Div(lhs, rhs) => {
×
NEW
64
                let l = lhs.evaluate(scan)?;
×
NEW
65
                let r = rhs.evaluate(scan)?;
×
NEW
66
                match (l, r) {
×
NEW
67
                    (Value::I32(_), Value::I32(0)) => Ok(Value::Null),
×
NEW
68
                    (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a / b)),
×
NEW
69
                    (Value::Null, _) | (_, Value::Null) => Ok(Value::Null),
×
NEW
70
                    _ => panic!("Type mismatch in division"),
×
71
                }
72
            }
73
        }
74
    }
75

76
    pub(crate) fn try_get_field(&self) -> Option<&str> {
1✔
77
        match self {
1✔
78
            Expression::Field(field_name) => Some(field_name),
1✔
79
            _ => None,
1✔
80
        }
81
    }
82

83
    pub(crate) fn try_get_constant(&self) -> Option<Value> {
1✔
84
        match self {
1✔
NEW
85
            Expression::NullConstant => Some(Value::Null),
×
86
            Expression::I32Constant(value) => Some(Value::I32(*value)),
1✔
NEW
87
            Expression::StringConstant(value) => Some(Value::String(value.clone())),
×
NEW
88
            Expression::Add(lhs, rhs) => match (lhs.try_get_constant(), rhs.try_get_constant()) {
×
NEW
89
                (Some(Value::I32(a)), Some(Value::I32(b))) => Some(Value::I32(a + b)),
×
NEW
90
                (Some(Value::Null), _) | (_, Some(Value::Null)) => Some(Value::Null),
×
NEW
91
                _ => None,
×
92
            },
NEW
93
            Expression::Sub(lhs, rhs) => match (lhs.try_get_constant(), rhs.try_get_constant()) {
×
NEW
94
                (Some(Value::I32(a)), Some(Value::I32(b))) => Some(Value::I32(a - b)),
×
NEW
95
                (Some(Value::Null), _) | (_, Some(Value::Null)) => Some(Value::Null),
×
NEW
96
                _ => None,
×
97
            },
NEW
98
            Expression::Mul(lhs, rhs) => match (lhs.try_get_constant(), rhs.try_get_constant()) {
×
NEW
99
                (Some(Value::I32(a)), Some(Value::I32(b))) => Some(Value::I32(a * b)),
×
NEW
100
                (Some(Value::Null), _) | (_, Some(Value::Null)) => Some(Value::Null),
×
NEW
101
                _ => None,
×
102
            },
NEW
103
            Expression::Div(lhs, rhs) => match (lhs.try_get_constant(), rhs.try_get_constant()) {
×
NEW
104
                (Some(Value::I32(_)), Some(Value::I32(0))) => Some(Value::Null),
×
NEW
105
                (Some(Value::I32(a)), Some(Value::I32(b))) => Some(Value::I32(a / b)),
×
NEW
106
                (Some(Value::Null), _) | (_, Some(Value::Null)) => Some(Value::Null),
×
NEW
107
                _ => None,
×
108
            },
109
            _ => None,
1✔
110
        }
111
    }
112

113
    /// Returns `true` if the expression can be applied to the given schema.
114
    ///
115
    /// Field references must exist in the schema while constant expressions are
116
    /// always applicable.
117
    pub(crate) fn is_applied_to(&self, schema: &Schema) -> bool {
1✔
118
        match self {
1✔
119
            Expression::Field(field_name) => schema.has_field(field_name),
1✔
NEW
120
            Expression::Add(lhs, rhs)
×
121
            | Expression::Sub(lhs, rhs)
122
            | Expression::Mul(lhs, rhs)
123
            | Expression::Div(lhs, rhs) => lhs.is_applied_to(schema) && rhs.is_applied_to(schema),
NEW
124
            _ => true,
×
125
        }
126
    }
127
}
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