ddb_core/functions/
conversion.rs1use super::Value;
3use crate::error::{DdbError, Result};
4
5pub fn cast(value: &Value, target_type: &str) -> Result<Value> {
7 match target_type.to_uppercase().as_str() {
8 "INTEGER" | "INT" | "BIGINT" => {
9 Ok(Value::Integer(value.as_i64()?))
10 }
11 "FLOAT" | "REAL" | "DOUBLE" | "DECIMAL" | "NUMERIC" => {
12 Ok(Value::Float(value.as_f64()?))
13 }
14 "VARCHAR" | "CHAR" | "TEXT" | "STRING" => {
15 Ok(Value::String(value.to_string()))
16 }
17 "BOOLEAN" | "BOOL" => {
18 let val = match value {
19 Value::Boolean(b) => *b,
20 Value::Integer(i) => *i != 0,
21 Value::Float(f) => *f != 0.0,
22 Value::String(s) => {
23 s.eq_ignore_ascii_case("true")
24 || s.eq_ignore_ascii_case("yes")
25 || s.eq_ignore_ascii_case("1")
26 }
27 Value::Null => false,
28 _ => return Err(DdbError::TypeError(format!("Cannot convert {:?} to boolean", value))),
29 };
30 Ok(Value::Boolean(val))
31 }
32 "DATE" => {
33 let s = value.to_string();
34 let date = chrono::NaiveDate::parse_from_str(&s, "%Y-%m-%d")
35 .map_err(|e| DdbError::TypeError(format!("Invalid date format: {}", e)))?;
36 Ok(Value::Date(date))
37 }
38 "DATETIME" | "TIMESTAMP" => {
39 let s = value.to_string();
40 let dt = chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S")
41 .or_else(|_| chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d"))
42 .map_err(|e| DdbError::TypeError(format!("Invalid datetime format: {}", e)))?;
43 Ok(Value::DateTime(dt))
44 }
45 _ => Err(DdbError::TypeError(format!("Unknown type: {}", target_type))),
46 }
47}
48
49pub fn convert(value: &Value, target_type: &str) -> Result<Value> {
51 cast(value, target_type)
52}
53
54pub fn atof(value: &Value) -> Result<Value> {
56 let s = value.to_string();
57 s.parse::<f64>()
58 .map(Value::Float)
59 .map_err(|_| DdbError::TypeError(format!("Cannot parse '{}' as float", s)))
60}
61
62pub fn atoi(value: &Value) -> Result<Value> {
64 let s = value.to_string();
65 s.parse::<i64>()
66 .map(Value::Integer)
67 .map_err(|_| DdbError::TypeError(format!("Cannot parse '{}' as integer", s)))
68}
69
70pub fn to_string(value: &Value) -> Result<Value> {
72 Ok(Value::String(value.to_string()))
73}
74
75pub fn to_number(value: &Value) -> Result<Value> {
77 let s = value.to_string();
78
79 if let Ok(i) = s.parse::<i64>() {
81 return Ok(Value::Integer(i));
82 }
83
84 if let Ok(f) = s.parse::<f64>() {
86 return Ok(Value::Float(f));
87 }
88
89 Err(DdbError::TypeError(format!("Cannot convert '{}' to number", s)))
90}
91
92pub fn hex(value: &Value) -> Result<Value> {
94 match value {
95 Value::Integer(i) => Ok(Value::String(format!("{:X}", i))),
96 _ => {
97 let i = value.as_i64()?;
98 Ok(Value::String(format!("{:X}", i)))
99 }
100 }
101}
102
103pub fn bin(value: &Value) -> Result<Value> {
105 match value {
106 Value::Integer(i) => Ok(Value::String(format!("{:b}", i))),
107 _ => {
108 let i = value.as_i64()?;
109 Ok(Value::String(format!("{:b}", i)))
110 }
111 }
112}
113
114pub fn oct(value: &Value) -> Result<Value> {
116 match value {
117 Value::Integer(i) => Ok(Value::String(format!("{:o}", i))),
118 _ => {
119 let i = value.as_i64()?;
120 Ok(Value::String(format!("{:o}", i)))
121 }
122 }
123}
124
125pub fn format(value: &Value, decimals: &Value) -> Result<Value> {
127 let num = value.as_f64()?;
128 let dec = decimals.as_i64()? as usize;
129
130 let formatted = format!("{:.width$}", num, width = dec);
131
132 let parts: Vec<&str> = formatted.split('.').collect();
134 let integer_part = parts[0];
135 let decimal_part = parts.get(1).unwrap_or(&"");
136
137 let mut result = String::new();
138 for (i, ch) in integer_part.chars().rev().enumerate() {
139 if i > 0 && i % 3 == 0 {
140 result.insert(0, ',');
141 }
142 result.insert(0, ch);
143 }
144
145 if !decimal_part.is_empty() {
146 result.push('.');
147 result.push_str(decimal_part);
148 }
149
150 Ok(Value::String(result))
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_cast() {
159 assert_eq!(
160 cast(&Value::from("123"), "INTEGER").unwrap(),
161 Value::Integer(123)
162 );
163 assert_eq!(
164 cast(&Value::Integer(42), "STRING").unwrap(),
165 Value::from("42")
166 );
167 }
168
169 #[test]
170 fn test_atof_atoi() {
171 assert_eq!(atof(&Value::from("3.14")).unwrap(), Value::Float(3.14));
172 assert_eq!(atoi(&Value::from("42")).unwrap(), Value::Integer(42));
173 }
174
175 #[test]
176 fn test_hex_bin_oct() {
177 assert_eq!(hex(&Value::Integer(255)).unwrap(), Value::from("FF"));
178 assert_eq!(bin(&Value::Integer(7)).unwrap(), Value::from("111"));
179 assert_eq!(oct(&Value::Integer(8)).unwrap(), Value::from("10"));
180 }
181
182 #[test]
183 fn test_to_number() {
184 assert_eq!(to_number(&Value::from("123")).unwrap(), Value::Integer(123));
185 assert_eq!(to_number(&Value::from("12.5")).unwrap(), Value::Float(12.5));
186 }
187}