1use {
2 super::{Convert, Value, ValueError, ValueType},
3 crate::{Error, Result},
4 chrono::{NaiveDate, NaiveDateTime, NaiveTime, ParseError},
5 std::convert::TryInto,
6 thousands::Separable,
7};
8
9pub trait Cast<Output> {
10 fn cast(self) -> Result<Output>;
11}
12pub trait CastWithRules<Output> {
13 fn cast_with_rule(self, rule: Self) -> Result<Output>;
14}
15
16fn failed_cast(value: &Value, value_type: ValueType) -> Error {
17 Error::Value(ValueError::FailedCast(value.clone(), value_type))
18}
19fn unimplemented_cast(value: &Value, value_type: ValueType) -> Error {
20 Error::Value(ValueError::FailedCast(value.clone().into(), value_type))
21}
22
23impl Cast<bool> for Value {
25 fn cast(self) -> Result<bool> {
26 Ok(match self {
27 Value::Bool(value) => value,
28 Value::I64(value) => match value {
29 1 => true,
30 0 => false,
31 _ => return Err(failed_cast(&self, ValueType::Bool)),
32 },
33 Value::F64(value) => {
34 if value.eq(&1.0) {
35 true
36 } else if value.eq(&0.0) {
37 false
38 } else {
39 return Err(failed_cast(&self, ValueType::Bool));
40 }
41 }
42 Value::Str(value) => match value.to_lowercase().as_str() {
43 "true" => true,
44 "false" => false,
45 _ => return Err(failed_cast(&Value::Str(value), ValueType::Bool)),
46 },
47 Value::Null => return Err(failed_cast(&self, ValueType::Bool)),
48 _ => return Err(unimplemented_cast(&self, ValueType::Bool)),
49 })
50 }
51}
52
53impl Cast<u64> for Value {
54 fn cast(self) -> Result<u64> {
55 Ok(match self {
56 Value::Bool(value) => {
57 if value {
58 1
59 } else {
60 0
61 }
62 }
63 Value::U64(value) => value,
64 Value::I64(value) => value
65 .try_into()
66 .map_err(|_| failed_cast(&self, ValueType::U64))?,
67 Value::F64(value) => (value.trunc() as i64)
68 .try_into()
69 .map_err(|_| failed_cast(&self, ValueType::U64))?,
70 Value::Str(value) => lexical::parse(&value)
71 .map_err(|_| failed_cast(&Value::Str(value), ValueType::U64))?,
72 Value::Null => return Err(failed_cast(&self, ValueType::U64)),
73 _ => return Err(unimplemented_cast(&self, ValueType::U64)),
74 })
75 }
76}
77
78impl Cast<i64> for Value {
79 fn cast(self) -> Result<i64> {
80 Ok(match self {
81 Value::Bool(value) => {
82 if value {
83 1
84 } else {
85 0
86 }
87 }
88 Value::U64(value) => value
89 .try_into()
90 .map_err(|_| failed_cast(&self, ValueType::I64))?,
91 Value::I64(value) => value,
92 Value::F64(value) => value.trunc() as i64,
93 Value::Str(value) => lexical::parse(&value)
94 .map_err(|_| failed_cast(&Value::Str(value), ValueType::I64))?,
95 Value::Null => return Err(failed_cast(&self, ValueType::I64)),
96 _ => return Err(unimplemented_cast(&self, ValueType::I64)),
97 })
98 }
99}
100
101impl Cast<f64> for Value {
102 fn cast(self) -> Result<f64> {
103 Ok(match self {
104 Value::Bool(value) => {
105 if value {
106 1.0
107 } else {
108 0.0
109 }
110 }
111 Value::U64(value) => (value as f64).trunc(),
112 Value::I64(value) => (value as f64).trunc(),
113 Value::F64(value) => value,
114 Value::Str(value) => fast_float::parse(&value)
115 .map_err(|_| failed_cast(&Value::Str(value), ValueType::F64))?,
116 Value::Null => return Err(failed_cast(&self, ValueType::F64)),
117 _ => return Err(unimplemented_cast(&self, ValueType::F64)),
118 })
119 }
120}
121impl Cast<String> for Value {
122 fn cast(self) -> Result<String> {
123 Ok(match self {
124 Value::Bool(value) => (if value { "true" } else { "false" }).to_string(),
125 Value::U64(value) => lexical::to_string(value),
126 Value::I64(value) => lexical::to_string(value),
127 Value::F64(value) => lexical::to_string(value),
128 Value::Str(value) => value,
129 Value::Timestamp(value) => NaiveDateTime::from_timestamp(value, 0).to_string(),
130 Value::Null => String::from("NULL"),
131 _ => return Err(unimplemented_cast(&self, ValueType::Str)),
132 })
133 }
134}
135
136impl Cast<usize> for Value {
138 fn cast(self) -> Result<usize> {
139 let int: u64 = self.cast()?;
140 int.try_into()
141 .map_err(|_| ValueError::ImpossibleCast.into())
142 }
143}
144
145impl CastWithRules<bool> for Value {
147 fn cast_with_rule(self, rule: Self) -> Result<bool> {
148 match rule {
149 Value::I64(000) | Value::Bool(true) => self.cast(),
150 _ => Err(ValueError::InvalidConversionRule.into()),
151 }
152 }
153}
154impl CastWithRules<i64> for Value {
155 fn cast_with_rule(self, rule: Self) -> Result<i64> {
156 match rule {
157 Value::I64(000) | Value::Bool(true) => self.cast(),
158 _ => Err(ValueError::InvalidConversionRule.into()),
159 }
160 }
161}
162impl CastWithRules<f64> for Value {
163 fn cast_with_rule(self, rule: Self) -> Result<f64> {
164 match rule {
165 Value::I64(000) | Value::Bool(true) => self.cast(),
166 _ => Err(ValueError::InvalidConversionRule.into()),
167 }
168 }
169}
170impl CastWithRules<String> for Value {
171 fn cast_with_rule(self, rule: Self) -> Result<String> {
172 match rule {
173 Value::I64(000) | Value::Bool(true) => self.cast(),
174 Value::Str(specified) if specified == *"DATETIME" => {
175 Ok(NaiveDateTime::from_timestamp(self.convert()?, 0)
176 .format("%F %T")
177 .to_string())
178 }
179 Value::Str(specified) if specified == *"MONEY" => {
180 let value: f64 = self.convert()?;
181 let value = (value * 100.0).round() / 100.0;
182 let value = value.separate_with_commas();
183 Ok(format!("${}", value))
184 }
185 Value::Str(specified) if specified == *"SEPARATED" => {
186 let value: f64 = self.convert()?;
187 let value = (value * 100.0).round() / 100.0;
188 let value = value.separate_with_commas();
189 Ok(value)
190 }
191 Value::Str(format) if matches!(self, Value::I64(..)) => {
192 Ok(NaiveDateTime::from_timestamp(self.convert()?, 0)
194 .format(&format)
195 .to_string())
196 }
197 _ => Err(ValueError::InvalidConversionRule.into()),
198 }
199 }
200}
201
202fn parse_error_into(error: ParseError) -> Error {
205 ValueError::DateTimeParseError(format!("{:?}", error)).into()
206}
207impl Cast<NaiveDateTime> for Value {
208 fn cast(self) -> Result<NaiveDateTime> {
210 let timestamp: i64 = self.cast()?;
211 NaiveDateTime::from_timestamp_opt(timestamp, 0)
212 .ok_or_else(|| ValueError::ImpossibleCast.into())
213 }
214}
215#[allow(clippy::zero_prefixed_literal)]
216impl CastWithRules<NaiveDateTime> for Value {
217 fn cast_with_rule(self, rule: Self) -> Result<NaiveDateTime> {
218 fn for_format_datetime(string: Value, format: &str) -> Result<NaiveDateTime> {
219 let string: String = string.cast()?;
220 let string: &str = string.as_str();
221 NaiveDateTime::parse_from_str(string, format).map_err(parse_error_into)
222 }
223 fn for_format_date(string: Value, format: &str) -> Result<NaiveDateTime> {
224 let string: String = string.cast()?;
225 let string: &str = string.as_str();
226 Ok(NaiveDate::parse_from_str(string, format)
227 .map_err(parse_error_into)?
228 .and_hms(0, 0, 0))
229 }
230 fn for_format_time(string: Value, format: &str) -> Result<NaiveDateTime> {
231 let string: String = string.cast()?;
232 let string: &str = string.as_str();
233 Ok(NaiveDateTime::from_timestamp(0, 0)
234 .date()
235 .and_time(NaiveTime::parse_from_str(string, format).map_err(parse_error_into)?))
236 }
237 fn try_rules(try_value: &Value, rules: &[i64]) -> Result<NaiveDateTime> {
238 rules
239 .iter()
240 .find_map(|try_rule| try_value.clone().cast_with_rule((*try_rule).into()).ok())
241 .ok_or_else(|| ValueError::ParseError(try_value.clone(), "TIMESTAMP").into())
242 }
243 const TRY_RULES_TIMESTAMP: [i64; 1] = [000];
244 const TRY_RULES_DATETIME: [i64; 9] = [010, 011, 020, 021, 030, 031, 060, 062, 063];
245 const TRY_RULES_DATE: [i64; 6] = [022, 033, 032, 061, 064, 040]; const TRY_RULES_TIME: [i64; 2] = [100, 101];
247
248 match rule {
249 Value::Null => try_rules(&self, &TRY_RULES_TIMESTAMP)
250 .or_else(|_| try_rules(&self, &TRY_RULES_DATETIME))
251 .or_else(|_| try_rules(&self, &TRY_RULES_DATE))
252 .or_else(|_| try_rules(&self, &TRY_RULES_TIME)),
253 Value::Bool(true) => try_rules(&self, &TRY_RULES_TIMESTAMP),
254 Value::Str(custom) => match custom.as_str() {
255 "TIMESTAMP" => try_rules(&self, &TRY_RULES_TIMESTAMP),
256 "DATETIME" => try_rules(&self, &TRY_RULES_DATETIME),
257 "DATE" => try_rules(&self, &TRY_RULES_DATE),
258 "TIME" => try_rules(&self, &TRY_RULES_TIME),
259 custom_format => for_format_datetime(self.clone(), custom_format)
260 .or_else(|_| for_format_date(self.clone(), custom_format))
261 .or_else(|_| for_format_time(self, custom_format)),
262 },
263 Value::I64(000) => {
264 self.cast()
266 }
267 Value::I64(020) => for_format_datetime(self, "%F %T"),
270 Value::I64(021) => for_format_datetime(self, "%F %R"),
272 Value::I64(022) => for_format_date(self, "%F"),
274
275 Value::I64(030) => for_format_datetime(self, "%F %r"),
278 Value::I64(031) => for_format_datetime(self, "%I:%M %p"),
280 Value::I64(032) => for_format_date(self, "%v"),
282 Value::I64(033) => for_format_date(self, "%e-%b-%y"),
284
285 Value::I64(040) => for_format_date(self, "%Y%m%d"),
286
287 Value::I64(060) => for_format_datetime(self, "%d/%m/%Y %H:%M"),
290 Value::I64(061) => for_format_date(self, "%d/%m/%Y"),
291 Value::I64(062) => for_format_datetime(self, "%d/%m/%Y %H:%M:%S"),
292 Value::I64(063) => for_format_datetime(self, "%d%m%Y %H:%M:%S"),
293 Value::I64(064) => for_format_date(self, "%d%m%Y"),
294
295 Value::I64(100) => for_format_time(self, "%T"),
298 Value::I64(101) => for_format_time(self, "%R"),
300 _ => Err(ValueError::InvalidConversionRule.into()),
301 }
302 }
303}