Skip to content

Commit e42c0ae

Browse files
committed
refactor(nodedb-query): split expr.rs and scan_filter into focused modules
Move the monolithic `expr.rs` into an `expr/` directory (eval, codec, binary, types submodules) so each concern lives in its own file. Extract `FilterOp` and the `ScanFilter`/`CompareValue` types from `scan_filter/mod.rs` into `op.rs` and `types.rs` respectively, leaving `mod.rs` as pure re-exports. Add `like` and `parse` as explicit submodule declarations now that the types they depend on are in separate files. `msgpack_scan/filter.rs` updated to import from the new paths.
1 parent 1ce86d0 commit e42c0ae

12 files changed

Lines changed: 1032 additions & 1005 deletions

File tree

nodedb-query/src/expr.rs

Lines changed: 0 additions & 625 deletions
This file was deleted.

nodedb-query/src/expr/binary.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! Binary-operator evaluation on `Value` operands.
2+
3+
use nodedb_types::Value;
4+
5+
use crate::value_ops::{
6+
coerced_eq, compare_values, is_truthy, to_value_number, value_to_display_string, value_to_f64,
7+
};
8+
9+
use super::types::BinaryOp;
10+
11+
pub(super) fn eval_binary_op(left: &Value, op: BinaryOp, right: &Value) -> Value {
12+
match op {
13+
BinaryOp::Add => match (value_to_f64(left, true), value_to_f64(right, true)) {
14+
(Some(a), Some(b)) => to_value_number(a + b),
15+
_ => Value::Null,
16+
},
17+
BinaryOp::Sub => match (value_to_f64(left, true), value_to_f64(right, true)) {
18+
(Some(a), Some(b)) => to_value_number(a - b),
19+
_ => Value::Null,
20+
},
21+
BinaryOp::Mul => match (value_to_f64(left, true), value_to_f64(right, true)) {
22+
(Some(a), Some(b)) => to_value_number(a * b),
23+
_ => Value::Null,
24+
},
25+
BinaryOp::Div => match (value_to_f64(left, true), value_to_f64(right, true)) {
26+
(Some(a), Some(b)) => {
27+
if b == 0.0 {
28+
Value::Null
29+
} else {
30+
to_value_number(a / b)
31+
}
32+
}
33+
_ => Value::Null,
34+
},
35+
BinaryOp::Mod => match (value_to_f64(left, true), value_to_f64(right, true)) {
36+
(Some(a), Some(b)) => {
37+
if b == 0.0 {
38+
Value::Null
39+
} else {
40+
to_value_number(a % b)
41+
}
42+
}
43+
_ => Value::Null,
44+
},
45+
BinaryOp::Concat => {
46+
let ls = value_to_display_string(left);
47+
let rs = value_to_display_string(right);
48+
Value::String(format!("{ls}{rs}"))
49+
}
50+
BinaryOp::Eq => Value::Bool(coerced_eq(left, right)),
51+
BinaryOp::NotEq => Value::Bool(!coerced_eq(left, right)),
52+
BinaryOp::Gt => Value::Bool(compare_values(left, right) == std::cmp::Ordering::Greater),
53+
BinaryOp::GtEq => {
54+
let c = compare_values(left, right);
55+
Value::Bool(c == std::cmp::Ordering::Greater || c == std::cmp::Ordering::Equal)
56+
}
57+
BinaryOp::Lt => Value::Bool(compare_values(left, right) == std::cmp::Ordering::Less),
58+
BinaryOp::LtEq => {
59+
let c = compare_values(left, right);
60+
Value::Bool(c == std::cmp::Ordering::Less || c == std::cmp::Ordering::Equal)
61+
}
62+
BinaryOp::And => Value::Bool(is_truthy(left) && is_truthy(right)),
63+
BinaryOp::Or => Value::Bool(is_truthy(left) || is_truthy(right)),
64+
}
65+
}

nodedb-query/src/expr/codec.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
//! Manual zerompk wire format for [`SqlExpr`].
2+
//!
3+
//! Each variant encodes as an array `[tag_u8, field1, field2, ...]`. Tags
4+
//! are stable and MUST NOT be renumbered — they are on-wire values in
5+
//! physical-plan envelopes. `Value`, `BinaryOp`, and `CastType` implement
6+
//! zerompk natively so they nest transparently.
7+
//!
8+
//! Tags: Column=0, Literal=1, BinaryOp=2, Negate=3, Function=4, Cast=5,
9+
//! Case=6, Coalesce=7, NullIf=8, IsNull=9, OldColumn=10.
10+
11+
use nodedb_types::Value;
12+
13+
use super::types::{BinaryOp, CastType, SqlExpr};
14+
15+
impl zerompk::ToMessagePack for SqlExpr {
16+
fn write<W: zerompk::Write>(&self, writer: &mut W) -> zerompk::Result<()> {
17+
match self {
18+
SqlExpr::Column(s) => {
19+
writer.write_array_len(2)?;
20+
writer.write_u8(0)?;
21+
writer.write_string(s)
22+
}
23+
SqlExpr::Literal(v) => {
24+
writer.write_array_len(2)?;
25+
writer.write_u8(1)?;
26+
v.write(writer)
27+
}
28+
SqlExpr::BinaryOp { left, op, right } => {
29+
writer.write_array_len(4)?;
30+
writer.write_u8(2)?;
31+
left.write(writer)?;
32+
op.write(writer)?;
33+
right.write(writer)
34+
}
35+
SqlExpr::Negate(inner) => {
36+
writer.write_array_len(2)?;
37+
writer.write_u8(3)?;
38+
inner.write(writer)
39+
}
40+
SqlExpr::Function { name, args } => {
41+
writer.write_array_len(3)?;
42+
writer.write_u8(4)?;
43+
writer.write_string(name)?;
44+
args.write(writer)
45+
}
46+
SqlExpr::Cast { expr, to_type } => {
47+
writer.write_array_len(3)?;
48+
writer.write_u8(5)?;
49+
expr.write(writer)?;
50+
to_type.write(writer)
51+
}
52+
SqlExpr::Case {
53+
operand,
54+
when_thens,
55+
else_expr,
56+
} => {
57+
writer.write_array_len(4)?;
58+
writer.write_u8(6)?;
59+
operand.write(writer)?;
60+
writer.write_array_len(when_thens.len())?;
61+
for (cond, val) in when_thens {
62+
writer.write_array_len(2)?;
63+
cond.write(writer)?;
64+
val.write(writer)?;
65+
}
66+
else_expr.write(writer)
67+
}
68+
SqlExpr::Coalesce(exprs) => {
69+
writer.write_array_len(2)?;
70+
writer.write_u8(7)?;
71+
exprs.write(writer)
72+
}
73+
SqlExpr::NullIf(e1, e2) => {
74+
writer.write_array_len(3)?;
75+
writer.write_u8(8)?;
76+
e1.write(writer)?;
77+
e2.write(writer)
78+
}
79+
SqlExpr::IsNull { expr, negated } => {
80+
writer.write_array_len(3)?;
81+
writer.write_u8(9)?;
82+
expr.write(writer)?;
83+
writer.write_boolean(*negated)
84+
}
85+
SqlExpr::OldColumn(s) => {
86+
writer.write_array_len(2)?;
87+
writer.write_u8(10)?;
88+
writer.write_string(s)
89+
}
90+
}
91+
}
92+
}
93+
94+
impl<'a> zerompk::FromMessagePack<'a> for SqlExpr {
95+
fn read<R: zerompk::Read<'a>>(reader: &mut R) -> zerompk::Result<Self> {
96+
let len = reader.read_array_len()?;
97+
if len == 0 {
98+
return Err(zerompk::Error::ArrayLengthMismatch {
99+
expected: 1,
100+
actual: 0,
101+
});
102+
}
103+
let tag = reader.read_u8()?;
104+
match tag {
105+
0 => Ok(SqlExpr::Column(reader.read_string()?.into_owned())),
106+
1 => {
107+
let v = Value::read(reader)?;
108+
Ok(SqlExpr::Literal(v))
109+
}
110+
2 => {
111+
let left = SqlExpr::read(reader)?;
112+
let op = BinaryOp::read(reader)?;
113+
let right = SqlExpr::read(reader)?;
114+
Ok(SqlExpr::BinaryOp {
115+
left: Box::new(left),
116+
op,
117+
right: Box::new(right),
118+
})
119+
}
120+
3 => {
121+
let inner = SqlExpr::read(reader)?;
122+
Ok(SqlExpr::Negate(Box::new(inner)))
123+
}
124+
4 => {
125+
let name = reader.read_string()?.into_owned();
126+
let args = Vec::<SqlExpr>::read(reader)?;
127+
Ok(SqlExpr::Function { name, args })
128+
}
129+
5 => {
130+
let expr = SqlExpr::read(reader)?;
131+
let to_type = CastType::read(reader)?;
132+
Ok(SqlExpr::Cast {
133+
expr: Box::new(expr),
134+
to_type,
135+
})
136+
}
137+
6 => {
138+
let operand = Option::<Box<SqlExpr>>::read(reader)?;
139+
let wt_len = reader.read_array_len()?;
140+
let mut when_thens = Vec::with_capacity(wt_len);
141+
for _ in 0..wt_len {
142+
let pair_len = reader.read_array_len()?;
143+
if pair_len != 2 {
144+
return Err(zerompk::Error::ArrayLengthMismatch {
145+
expected: 2,
146+
actual: pair_len,
147+
});
148+
}
149+
let cond = SqlExpr::read(reader)?;
150+
let val = SqlExpr::read(reader)?;
151+
when_thens.push((cond, val));
152+
}
153+
let else_expr = Option::<Box<SqlExpr>>::read(reader)?;
154+
Ok(SqlExpr::Case {
155+
operand,
156+
when_thens,
157+
else_expr,
158+
})
159+
}
160+
7 => {
161+
let exprs = Vec::<SqlExpr>::read(reader)?;
162+
Ok(SqlExpr::Coalesce(exprs))
163+
}
164+
8 => {
165+
let e1 = SqlExpr::read(reader)?;
166+
let e2 = SqlExpr::read(reader)?;
167+
Ok(SqlExpr::NullIf(Box::new(e1), Box::new(e2)))
168+
}
169+
9 => {
170+
let expr = SqlExpr::read(reader)?;
171+
let negated = reader.read_boolean()?;
172+
Ok(SqlExpr::IsNull {
173+
expr: Box::new(expr),
174+
negated,
175+
})
176+
}
177+
10 => Ok(SqlExpr::OldColumn(reader.read_string()?.into_owned())),
178+
_ => Err(zerompk::Error::InvalidMarker(tag)),
179+
}
180+
}
181+
}

0 commit comments

Comments
 (0)