Skip to main content

nodedb_sql/resolver/expr/
value.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use sqlparser::ast::Value;
4
5use crate::error::{Result, SqlError};
6use crate::types::*;
7
8/// Convert a sqlparser `Value` to our `SqlValue`.
9///
10/// Number literal routing:
11/// - Pure integers → `SqlValue::Int`.
12/// - Numbers with `.`, `e`, or `E` → `SqlValue::Decimal` (exact arithmetic).
13/// - If decimal parse fails → fallback to `SqlValue::Float`, then `SqlValue::String`.
14pub fn convert_value(val: &Value) -> Result<SqlValue> {
15    match val {
16        Value::Number(n, _) => {
17            if let Ok(i) = n.parse::<i64>() {
18                Ok(SqlValue::Int(i))
19            } else if n.contains('.') || n.contains('e') || n.contains('E') {
20                // Fractional or scientific notation: prefer exact Decimal.
21                if let Ok(d) = rust_decimal::Decimal::from_str_exact(n) {
22                    Ok(SqlValue::Decimal(d))
23                } else if let Ok(f) = n.parse::<f64>() {
24                    Ok(SqlValue::Float(f))
25                } else {
26                    Ok(SqlValue::String(n.clone()))
27                }
28            } else if let Ok(f) = n.parse::<f64>() {
29                Ok(SqlValue::Float(f))
30            } else {
31                Ok(SqlValue::String(n.clone()))
32            }
33        }
34        Value::SingleQuotedString(s) => Ok(SqlValue::String(s.clone())),
35        Value::Boolean(b) => Ok(SqlValue::Bool(*b)),
36        Value::Null => Ok(SqlValue::Null),
37        _ => Err(SqlError::Unsupported {
38            detail: format!("value literal: {val}"),
39        }),
40    }
41}
42
43/// Parse an interval string to microseconds.
44///
45/// Delegates to `nodedb_types::kv_parsing::parse_interval_to_ms` (ms → μs)
46/// and `NdbDuration::parse` for compound shorthand forms.
47pub(super) fn parse_interval_to_micros(s: &str) -> Option<i64> {
48    let s = s.trim();
49    if s.is_empty() {
50        return None;
51    }
52
53    // Try NdbDuration::parse first (handles compound "1h30m", "500ms", "2d").
54    if let Some(dur) = nodedb_types::NdbDuration::parse(s) {
55        return Some(dur.micros);
56    }
57
58    // Delegate to shared interval parser (handles all forms including compound).
59    if let Ok(ms) = nodedb_types::kv_parsing::parse_interval_to_ms(s) {
60        return Some(ms as i64 * 1000); // ms → μs
61    }
62
63    None
64}