1use crate::{
4 error::{err_column_null, err_type_conv},
5 FbError, SqlType,
6};
7
8pub use SqlType::*;
9
10pub struct Row {
12 pub cols: Vec<Column>,
13}
14
15impl Row {
16 pub fn get<T>(&self, idx: usize) -> Result<T, FbError>
18 where
19 Column: ColumnToVal<T>,
20 {
21 if let Some(col) = self.cols.get(idx) {
22 col.clone().to_val()
23 } else {
24 Err("This index doesn't exists".into())
25 }
26 }
27
28 pub fn get_all<T>(self) -> Result<T, FbError>
30 where
31 T: FromRow,
32 {
33 <T as FromRow>::try_from(self.cols)
34 }
35}
36
37#[derive(Debug, Clone)]
38pub struct Column {
39 pub value: SqlType,
40 pub name: String,
41}
42
43impl Column {
44 pub fn new(name: String, value: SqlType) -> Self {
45 Column { name, value }
46 }
47}
48
49#[allow(clippy::wrong_self_convention)]
50pub trait ColumnToVal<T> {
52 fn to_val(self) -> Result<T, FbError>
53 where
54 Self: std::marker::Sized;
55}
56
57impl ColumnToVal<String> for Column {
58 fn to_val(self) -> Result<String, FbError> {
59 match self.value {
60 Text(t) => Ok(t),
61
62 Integer(i) => Ok(i.to_string()),
63
64 Floating(f) => Ok(f.to_string()),
65
66 Timestamp(ts) => Ok(ts.to_string()),
67
68 Binary(_) => Err("This is a binary column. You cannot use string to access".into()),
69
70 Boolean(bo) => Ok(bo.to_string()),
71
72 Null => Err(err_column_null("String")),
73 }
74 }
75}
76
77impl ColumnToVal<i64> for Column {
78 fn to_val(self) -> Result<i64, FbError> {
79 match self.value {
80 Integer(i) => Ok(i),
81
82 Null => Err(err_column_null("i64")),
83
84 col => err_type_conv(col, "i64"),
85 }
86 }
87}
88
89impl ColumnToVal<i32> for Column {
90 fn to_val(self) -> Result<i32, FbError> {
91 ColumnToVal::<i64>::to_val(self).map(|i| i as i32)
92 }
93}
94
95impl ColumnToVal<i16> for Column {
96 fn to_val(self) -> Result<i16, FbError> {
97 ColumnToVal::<i64>::to_val(self).map(|i| i as i16)
98 }
99}
100
101impl ColumnToVal<f64> for Column {
102 fn to_val(self) -> Result<f64, FbError> {
103 match self.value {
104 Floating(f) => Ok(f),
105
106 Null => Err(err_column_null("f64")),
107
108 col => err_type_conv(col, "f64"),
109 }
110 }
111}
112
113impl ColumnToVal<f32> for Column {
114 fn to_val(self) -> Result<f32, FbError> {
115 ColumnToVal::<f64>::to_val(self).map(|i| i as f32)
116 }
117}
118
119impl ColumnToVal<Vec<u8>> for Column {
120 fn to_val(self) -> Result<Vec<u8>, FbError> {
121 match self.value {
122 Binary(b) => Ok(b),
123
124 Null => Err(err_column_null("Vec<u8>")),
125
126 col => err_type_conv(col, "Vec<u8>"),
127 }
128 }
129}
130
131impl ColumnToVal<bool> for Column {
132 fn to_val(self) -> Result<bool, FbError> {
133 match self.value {
134 Boolean(bo) => Ok(bo),
135
136 Null => Err(err_column_null("bool")),
137
138 col => err_type_conv(col, "bool"),
139 }
140 }
141}
142
143impl<T> ColumnToVal<Option<T>> for Column
145where
146 Column: ColumnToVal<T>,
147{
148 fn to_val(self) -> Result<Option<T>, FbError> {
149 if self.value.is_null() {
150 return Ok(None);
151 }
152
153 Ok(Some(self.to_val()?))
154 }
155}
156
157pub trait FromRow {
159 fn try_from(row: Vec<Column>) -> Result<Self, FbError>
160 where
161 Self: std::marker::Sized;
162}
163
164impl FromRow for Row {
167 fn try_from(row: Vec<Column>) -> Result<Self, FbError>
168 where
169 Self: Sized,
170 {
171 Ok(Row { cols: row })
172 }
173}
174
175impl FromRow for () {
177 fn try_from(_row: Vec<Column>) -> Result<Self, FbError>
178 where
179 Self: Sized,
180 {
181 Ok(())
182 }
183}
184
185macro_rules! impl_from_row {
187 ($($t: ident),+) => {
188 impl<'a, $($t),+> FromRow for ($($t,)+)
189 where
190 $( Column: ColumnToVal<$t>, )+
191 {
192 fn try_from(row: Vec<Column>) -> Result<Self, FbError> {
193 let len = row.len();
194 let mut iter = row.into_iter();
195
196 Ok(( $(
197 ColumnToVal::<$t>::to_val(
198 iter
199 .next()
200 .ok_or_else(|| {
201 FbError::Other(
202 format!("The sql returned less columns than the {} expected", len),
203 )
204 })?
205 )?,
206 )+ ))
207 }
208 }
209 };
210}
211
212macro_rules! impls_from_row {
214 ($t: ident) => {
215 impl_from_row!($t);
216 };
217
218 ($t: ident, $($ts: ident),+ ) => {
219 impls_from_row!($($ts),+);
220
221 impl_from_row!($t, $($ts),+);
222 };
223}
224
225impls_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);