1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4pub enum Type {
5 Int,
6 Long,
7 Float,
8 Double,
9 Decimal,
10 Text,
11 Date,
12 Timestamp,
13 TimestampTZ,
14 Boolean,
15 Array,
16 Struct,
17 Geography,
18 Bytes,
19}
20
21pub trait TypeConversion {
22 fn convert_from_json(
23 value: &serde_json::Value,
24 column_type: &Type,
25 ) -> Result<Self, crate::error::FireboltError>
26 where
27 Self: Sized;
28}
29
30impl TypeConversion for i32 {
31 fn convert_from_json(
32 value: &serde_json::Value,
33 column_type: &Type,
34 ) -> Result<Self, crate::error::FireboltError> {
35 match column_type {
36 Type::Int => {
37 if value.is_null() {
38 return Err(crate::error::FireboltError::Serialization(
39 "Cannot convert null to non-nullable type".to_string(),
40 ));
41 }
42 value
43 .as_i64()
44 .and_then(|v| i32::try_from(v).ok())
45 .ok_or_else(|| {
46 crate::error::FireboltError::Serialization(
47 "Failed to convert to i32".to_string(),
48 )
49 })
50 }
51 _ => Err(crate::error::FireboltError::Serialization(format!(
52 "Cannot convert {column_type:?} to i32"
53 ))),
54 }
55 }
56}
57
58impl TypeConversion for Option<i32> {
59 fn convert_from_json(
60 value: &serde_json::Value,
61 column_type: &Type,
62 ) -> Result<Self, crate::error::FireboltError> {
63 if value.is_null() {
64 return Ok(None);
65 }
66 match column_type {
67 Type::Int => {
68 let val = value
69 .as_i64()
70 .and_then(|v| i32::try_from(v).ok())
71 .ok_or_else(|| {
72 crate::error::FireboltError::Serialization(
73 "Failed to convert to i32".to_string(),
74 )
75 })?;
76 Ok(Some(val))
77 }
78 _ => Err(crate::error::FireboltError::Serialization(format!(
79 "Cannot convert {column_type:?} to Option<i32>"
80 ))),
81 }
82 }
83}
84
85impl TypeConversion for num_bigint::BigInt {
86 fn convert_from_json(
87 value: &serde_json::Value,
88 column_type: &Type,
89 ) -> Result<Self, crate::error::FireboltError> {
90 match column_type {
91 Type::Long => {
92 if value.is_null() {
93 return Err(crate::error::FireboltError::Serialization(
94 "Cannot convert null to non-nullable type".to_string(),
95 ));
96 }
97 if let Some(v) = value.as_i64() {
98 Ok(num_bigint::BigInt::from(v))
99 } else if let Some(s) = value.as_str() {
100 s.parse().map_err(|_| {
101 crate::error::FireboltError::Serialization(
102 "Failed to parse BigInt from string".to_string(),
103 )
104 })
105 } else {
106 Err(crate::error::FireboltError::Serialization(
107 "Failed to convert to BigInt".to_string(),
108 ))
109 }
110 }
111 _ => Err(crate::error::FireboltError::Serialization(format!(
112 "Cannot convert {column_type:?} to BigInt"
113 ))),
114 }
115 }
116}
117
118impl TypeConversion for Option<num_bigint::BigInt> {
119 fn convert_from_json(
120 value: &serde_json::Value,
121 column_type: &Type,
122 ) -> Result<Self, crate::error::FireboltError> {
123 if value.is_null() {
124 return Ok(None);
125 }
126 match column_type {
127 Type::Long => {
128 let val = if let Some(v) = value.as_i64() {
129 num_bigint::BigInt::from(v)
130 } else if let Some(s) = value.as_str() {
131 s.parse().map_err(|_| {
132 crate::error::FireboltError::Serialization(
133 "Failed to parse BigInt from string".to_string(),
134 )
135 })?
136 } else {
137 return Err(crate::error::FireboltError::Serialization(
138 "Failed to convert to BigInt".to_string(),
139 ));
140 };
141 Ok(Some(val))
142 }
143 _ => Err(crate::error::FireboltError::Serialization(format!(
144 "Cannot convert {column_type:?} to Option<BigInt>"
145 ))),
146 }
147 }
148}
149
150impl TypeConversion for f32 {
151 fn convert_from_json(
152 value: &serde_json::Value,
153 column_type: &Type,
154 ) -> Result<Self, crate::error::FireboltError> {
155 match column_type {
156 Type::Float => {
157 if value.is_null() {
158 return Err(crate::error::FireboltError::Serialization(
159 "Cannot convert null to non-nullable type".to_string(),
160 ));
161 }
162 value.as_f64().map(|v| v as f32).ok_or_else(|| {
163 crate::error::FireboltError::Serialization(
164 "Failed to convert to f32".to_string(),
165 )
166 })
167 }
168 _ => Err(crate::error::FireboltError::Serialization(format!(
169 "Cannot convert {column_type:?} to f32"
170 ))),
171 }
172 }
173}
174
175impl TypeConversion for Option<f32> {
176 fn convert_from_json(
177 value: &serde_json::Value,
178 column_type: &Type,
179 ) -> Result<Self, crate::error::FireboltError> {
180 if value.is_null() {
181 return Ok(None);
182 }
183 match column_type {
184 Type::Float => {
185 let val = value.as_f64().map(|v| v as f32).ok_or_else(|| {
186 crate::error::FireboltError::Serialization(
187 "Failed to convert to f32".to_string(),
188 )
189 })?;
190 Ok(Some(val))
191 }
192 _ => Err(crate::error::FireboltError::Serialization(format!(
193 "Cannot convert {column_type:?} to Option<f32>"
194 ))),
195 }
196 }
197}
198
199impl TypeConversion for f64 {
200 fn convert_from_json(
201 value: &serde_json::Value,
202 column_type: &Type,
203 ) -> Result<Self, crate::error::FireboltError> {
204 match column_type {
205 Type::Double => {
206 if value.is_null() {
207 return Err(crate::error::FireboltError::Serialization(
208 "Cannot convert null to non-nullable type".to_string(),
209 ));
210 }
211 value.as_f64().ok_or_else(|| {
212 crate::error::FireboltError::Serialization(
213 "Failed to convert to f64".to_string(),
214 )
215 })
216 }
217 _ => Err(crate::error::FireboltError::Serialization(format!(
218 "Cannot convert {column_type:?} to f64"
219 ))),
220 }
221 }
222}
223
224impl TypeConversion for Option<f64> {
225 fn convert_from_json(
226 value: &serde_json::Value,
227 column_type: &Type,
228 ) -> Result<Self, crate::error::FireboltError> {
229 if value.is_null() {
230 return Ok(None);
231 }
232 match column_type {
233 Type::Double => {
234 let val = value.as_f64().ok_or_else(|| {
235 crate::error::FireboltError::Serialization(
236 "Failed to convert to f64".to_string(),
237 )
238 })?;
239 Ok(Some(val))
240 }
241 _ => Err(crate::error::FireboltError::Serialization(format!(
242 "Cannot convert {column_type:?} to Option<f64>"
243 ))),
244 }
245 }
246}
247
248impl TypeConversion for rust_decimal::Decimal {
249 fn convert_from_json(
250 value: &serde_json::Value,
251 column_type: &Type,
252 ) -> Result<Self, crate::error::FireboltError> {
253 match column_type {
254 Type::Decimal => {
255 if value.is_null() {
256 return Err(crate::error::FireboltError::Serialization(
257 "Cannot convert null to non-nullable type".to_string(),
258 ));
259 }
260 if let Some(s) = value.as_str() {
261 s.parse().map_err(|_| {
262 crate::error::FireboltError::Serialization(
263 "Failed to parse Decimal from string".to_string(),
264 )
265 })
266 } else if let Some(f) = value.as_f64() {
267 rust_decimal::Decimal::try_from(f).map_err(|_| {
268 crate::error::FireboltError::Serialization(
269 "Failed to convert f64 to Decimal".to_string(),
270 )
271 })
272 } else {
273 Err(crate::error::FireboltError::Serialization(
274 "Failed to convert to Decimal".to_string(),
275 ))
276 }
277 }
278 _ => Err(crate::error::FireboltError::Serialization(format!(
279 "Cannot convert {column_type:?} to Decimal"
280 ))),
281 }
282 }
283}
284
285impl TypeConversion for Option<rust_decimal::Decimal> {
286 fn convert_from_json(
287 value: &serde_json::Value,
288 column_type: &Type,
289 ) -> Result<Self, crate::error::FireboltError> {
290 if value.is_null() {
291 return Ok(None);
292 }
293 match column_type {
294 Type::Decimal => {
295 let val = if let Some(s) = value.as_str() {
296 s.parse().map_err(|_| {
297 crate::error::FireboltError::Serialization(
298 "Failed to parse Decimal from string".to_string(),
299 )
300 })?
301 } else if let Some(f) = value.as_f64() {
302 rust_decimal::Decimal::try_from(f).map_err(|_| {
303 crate::error::FireboltError::Serialization(
304 "Failed to convert f64 to Decimal".to_string(),
305 )
306 })?
307 } else {
308 return Err(crate::error::FireboltError::Serialization(
309 "Failed to convert to Decimal".to_string(),
310 ));
311 };
312 Ok(Some(val))
313 }
314 _ => Err(crate::error::FireboltError::Serialization(format!(
315 "Cannot convert {column_type:?} to Option<Decimal>"
316 ))),
317 }
318 }
319}
320
321impl TypeConversion for String {
322 fn convert_from_json(
323 value: &serde_json::Value,
324 column_type: &Type,
325 ) -> Result<Self, crate::error::FireboltError> {
326 match column_type {
327 Type::Text => {
328 if value.is_null() {
329 return Err(crate::error::FireboltError::Serialization(
330 "Cannot convert null to non-nullable type".to_string(),
331 ));
332 }
333 value.as_str().map(|s| s.to_string()).ok_or_else(|| {
334 crate::error::FireboltError::Serialization(
335 "Failed to convert to String".to_string(),
336 )
337 })
338 }
339 _ => Err(crate::error::FireboltError::Serialization(format!(
340 "Cannot convert {column_type:?} to String"
341 ))),
342 }
343 }
344}
345
346impl TypeConversion for Option<String> {
347 fn convert_from_json(
348 value: &serde_json::Value,
349 column_type: &Type,
350 ) -> Result<Self, crate::error::FireboltError> {
351 if value.is_null() {
352 return Ok(None);
353 }
354 match column_type {
355 Type::Text => {
356 let val = value.as_str().map(|s| s.to_string()).ok_or_else(|| {
357 crate::error::FireboltError::Serialization(
358 "Failed to convert to String".to_string(),
359 )
360 })?;
361 Ok(Some(val))
362 }
363 _ => Err(crate::error::FireboltError::Serialization(format!(
364 "Cannot convert {column_type:?} to Option<String>"
365 ))),
366 }
367 }
368}
369
370impl TypeConversion for bool {
371 fn convert_from_json(
372 value: &serde_json::Value,
373 column_type: &Type,
374 ) -> Result<Self, crate::error::FireboltError> {
375 match column_type {
376 Type::Boolean => {
377 if value.is_null() {
378 return Err(crate::error::FireboltError::Serialization(
379 "Cannot convert null to non-nullable type".to_string(),
380 ));
381 }
382 value.as_bool().ok_or_else(|| {
383 crate::error::FireboltError::Serialization(
384 "Failed to convert to bool".to_string(),
385 )
386 })
387 }
388 _ => Err(crate::error::FireboltError::Serialization(format!(
389 "Cannot convert {column_type:?} to bool"
390 ))),
391 }
392 }
393}
394
395impl TypeConversion for Option<bool> {
396 fn convert_from_json(
397 value: &serde_json::Value,
398 column_type: &Type,
399 ) -> Result<Self, crate::error::FireboltError> {
400 if value.is_null() {
401 return Ok(None);
402 }
403 match column_type {
404 Type::Boolean => {
405 let val = value.as_bool().ok_or_else(|| {
406 crate::error::FireboltError::Serialization(
407 "Failed to convert to bool".to_string(),
408 )
409 })?;
410 Ok(Some(val))
411 }
412 _ => Err(crate::error::FireboltError::Serialization(format!(
413 "Cannot convert {column_type:?} to Option<bool>"
414 ))),
415 }
416 }
417}
418
419impl TypeConversion for Vec<u8> {
420 fn convert_from_json(
421 value: &serde_json::Value,
422 column_type: &Type,
423 ) -> Result<Self, crate::error::FireboltError> {
424 match column_type {
425 Type::Bytes => {
426 if value.is_null() {
427 return Err(crate::error::FireboltError::Serialization(
428 "Cannot convert null to non-nullable type".to_string(),
429 ));
430 }
431 if let Some(s) = value.as_str() {
432 if let Some(stripped) = s.strip_prefix("\\x") {
433 hex::decode(stripped).map_err(|_| {
434 crate::error::FireboltError::Serialization(
435 "Failed to decode hex string".to_string(),
436 )
437 })
438 } else {
439 Ok(s.as_bytes().to_vec())
440 }
441 } else {
442 Err(crate::error::FireboltError::Serialization(
443 "Failed to convert to Vec<u8>".to_string(),
444 ))
445 }
446 }
447 _ => Err(crate::error::FireboltError::Serialization(format!(
448 "Cannot convert {column_type:?} to Vec<u8>"
449 ))),
450 }
451 }
452}
453
454impl TypeConversion for Option<Vec<u8>> {
455 fn convert_from_json(
456 value: &serde_json::Value,
457 column_type: &Type,
458 ) -> Result<Self, crate::error::FireboltError> {
459 if value.is_null() {
460 return Ok(None);
461 }
462 match column_type {
463 Type::Bytes => {
464 let val = if let Some(s) = value.as_str() {
465 if let Some(stripped) = s.strip_prefix("\\x") {
466 hex::decode(stripped).map_err(|_| {
467 crate::error::FireboltError::Serialization(
468 "Failed to decode hex string".to_string(),
469 )
470 })?
471 } else {
472 s.as_bytes().to_vec()
473 }
474 } else {
475 return Err(crate::error::FireboltError::Serialization(
476 "Failed to convert to Vec<u8>".to_string(),
477 ));
478 };
479 Ok(Some(val))
480 }
481 _ => Err(crate::error::FireboltError::Serialization(format!(
482 "Cannot convert {column_type:?} to Option<Vec<u8>>"
483 ))),
484 }
485 }
486}
487
488impl TypeConversion for serde_json::Value {
489 fn convert_from_json(
490 value: &serde_json::Value,
491 _column_type: &Type,
492 ) -> Result<Self, crate::error::FireboltError> {
493 Ok(value.clone())
494 }
495}
496
497#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
498pub struct Column {
499 pub name: String,
500 pub r#type: Type,
501 pub precision: Option<i32>,
502 pub scale: Option<i32>,
503 pub is_nullable: bool,
504}
505
506#[derive(Debug, Clone)]
507pub enum ColumnRef {
508 Index(usize),
509 Name(String),
510}
511
512impl From<usize> for ColumnRef {
513 fn from(index: usize) -> Self {
514 ColumnRef::Index(index)
515 }
516}
517
518impl From<String> for ColumnRef {
519 fn from(name: String) -> Self {
520 ColumnRef::Name(name)
521 }
522}
523
524impl From<&str> for ColumnRef {
525 fn from(name: &str) -> Self {
526 ColumnRef::Name(name.to_string())
527 }
528}