use crate::relational::SqlValue;
use crate::sql::error::{Result, SqlError};
use rust_decimal::Decimal;
use sqlparser::ast::Value;
use std::str::FromStr;
pub fn literal_to_value(value: &Value) -> Result<SqlValue> {
let out = match value {
Value::Number(s, _) => parse_number(s)?,
Value::SingleQuotedString(s)
| Value::TripleSingleQuotedString(s)
| Value::TripleDoubleQuotedString(s)
| Value::EscapedStringLiteral(s)
| Value::UnicodeStringLiteral(s)
| Value::NationalStringLiteral(s)
| Value::SingleQuotedRawStringLiteral(s)
| Value::DoubleQuotedRawStringLiteral(s) => SqlValue::Text(s.clone()),
Value::DollarQuotedString(d) => SqlValue::Text(d.value.clone()),
Value::Boolean(b) => SqlValue::Bool(*b),
Value::Null => SqlValue::Null,
Value::HexStringLiteral(s) => {
SqlValue::Text(s.clone())
}
Value::Placeholder(p) => {
return Err(SqlError::Internal(format!(
"unbound parameter placeholder {p}"
)));
}
other => SqlValue::Text(other.to_string()),
};
Ok(out)
}
pub fn parse_number(s: &str) -> Result<SqlValue> {
let is_integral = !s.contains(['.', 'e', 'E']);
if is_integral {
if let Ok(i) = s.parse::<i32>() {
return Ok(SqlValue::Int4(i));
}
if let Ok(i) = s.parse::<i64>() {
return Ok(SqlValue::Int8(i));
}
}
if let Ok(d) = Decimal::from_str(s) {
return Ok(SqlValue::Numeric(d));
}
s.parse::<f64>()
.map(SqlValue::Float8)
.map_err(|_| SqlError::InvalidTextRepresentation {
ty: "numeric".into(),
value: s.to_string(),
})
}