| 151 | } |
| 152 | |
| 153 | fn fold_binary(l: SqlValue, op: BinaryOp, r: SqlValue) -> Option<SqlValue> { |
| 154 | Some(match (l, op, r) { |
| 155 | // Int × Int arithmetic. |
| 156 | (SqlValue::Int(a), BinaryOp::Add, SqlValue::Int(b)) => SqlValue::Int(a.checked_add(b)?), |
| 157 | (SqlValue::Int(a), BinaryOp::Sub, SqlValue::Int(b)) => SqlValue::Int(a.checked_sub(b)?), |
| 158 | (SqlValue::Int(a), BinaryOp::Mul, SqlValue::Int(b)) => SqlValue::Int(a.checked_mul(b)?), |
| 159 | // Float × Float arithmetic. |
| 160 | (SqlValue::Float(a), BinaryOp::Add, SqlValue::Float(b)) => SqlValue::Float(a + b), |
| 161 | (SqlValue::Float(a), BinaryOp::Sub, SqlValue::Float(b)) => SqlValue::Float(a - b), |
| 162 | (SqlValue::Float(a), BinaryOp::Mul, SqlValue::Float(b)) => SqlValue::Float(a * b), |
| 163 | // Decimal × Decimal arithmetic. |
| 164 | (SqlValue::Decimal(a), BinaryOp::Add, SqlValue::Decimal(b)) => { |
| 165 | SqlValue::Decimal(a.checked_add(b)?) |
| 166 | } |
| 167 | (SqlValue::Decimal(a), BinaryOp::Sub, SqlValue::Decimal(b)) => { |
| 168 | SqlValue::Decimal(a.checked_sub(b)?) |
| 169 | } |
| 170 | (SqlValue::Decimal(a), BinaryOp::Mul, SqlValue::Decimal(b)) => { |
| 171 | SqlValue::Decimal(a.checked_mul(b)?) |
| 172 | } |
| 173 | (SqlValue::Decimal(a), BinaryOp::Div, SqlValue::Decimal(b)) => { |
| 174 | SqlValue::Decimal(a.checked_div(b)?) |
| 175 | } |
| 176 | // Decimal × Int widening (Int promotes to Decimal). |
| 177 | (SqlValue::Decimal(a), BinaryOp::Add, SqlValue::Int(b)) => { |
| 178 | SqlValue::Decimal(a.checked_add(rust_decimal::Decimal::from(b))?) |
| 179 | } |
| 180 | (SqlValue::Int(a), BinaryOp::Add, SqlValue::Decimal(b)) => { |
| 181 | SqlValue::Decimal(rust_decimal::Decimal::from(a).checked_add(b)?) |
| 182 | } |
| 183 | (SqlValue::Decimal(a), BinaryOp::Sub, SqlValue::Int(b)) => { |
| 184 | SqlValue::Decimal(a.checked_sub(rust_decimal::Decimal::from(b))?) |
| 185 | } |
| 186 | (SqlValue::Int(a), BinaryOp::Sub, SqlValue::Decimal(b)) => { |
| 187 | SqlValue::Decimal(rust_decimal::Decimal::from(a).checked_sub(b)?) |
| 188 | } |
| 189 | (SqlValue::Decimal(a), BinaryOp::Mul, SqlValue::Int(b)) => { |
| 190 | SqlValue::Decimal(a.checked_mul(rust_decimal::Decimal::from(b))?) |
| 191 | } |
| 192 | (SqlValue::Int(a), BinaryOp::Mul, SqlValue::Decimal(b)) => { |
| 193 | SqlValue::Decimal(rust_decimal::Decimal::from(a).checked_mul(b)?) |
| 194 | } |
| 195 | (SqlValue::Decimal(a), BinaryOp::Div, SqlValue::Int(b)) => { |
| 196 | SqlValue::Decimal(a.checked_div(rust_decimal::Decimal::from(b))?) |
| 197 | } |
| 198 | (SqlValue::Int(a), BinaryOp::Div, SqlValue::Decimal(b)) => { |
| 199 | SqlValue::Decimal(rust_decimal::Decimal::from(a).checked_div(b)?) |
| 200 | } |
| 201 | // String concat. |
| 202 | (SqlValue::String(a), BinaryOp::Concat, SqlValue::String(b)) => { |
| 203 | SqlValue::String(format!("{a}{b}")) |
| 204 | } |
| 205 | _ => return None, |
| 206 | }) |
| 207 | } |
| 208 | |
| 209 | /// Fold a function call by recursively folding its arguments, dispatching |
| 210 | /// through the shared scalar evaluator, and converting the result back to |