1use std::sync::Arc;
4
5use crate::{
6 error::{err_column_null, err_type_conv},
7 FbError, SqlType,
8};
9
10pub use SqlType::*;
11
12pub struct Row {
14 pub cols: Vec<Column>,
15}
16
17impl Row {
18 pub fn get<T>(&self, idx: usize) -> Result<T, FbError>
20 where
21 Column: ColumnToVal<T>,
22 {
23 if let Some(col) = self.cols.get(idx) {
24 col.clone().to_val()
25 } else {
26 Err("This index doesn't exists".into())
27 }
28 }
29
30 pub fn get_all<T>(self) -> Result<T, FbError>
32 where
33 T: FromRow,
34 {
35 <T as FromRow>::try_from(self.cols)
36 }
37}
38
39#[derive(Debug, Clone)]
40pub struct Column {
41 pub value: SqlType,
42 pub raw_type: u32,
43 pub name: Arc<str>,
47}
48
49impl Column {
50 pub fn new(name: impl Into<Arc<str>>, raw_type: u32, value: SqlType) -> Self {
51 Column {
52 name: name.into(),
53 raw_type,
54 value,
55 }
56 }
57}
58
59#[allow(clippy::wrong_self_convention)]
60pub trait ColumnToVal<T> {
62 fn to_val(self) -> Result<T, FbError>
63 where
64 Self: std::marker::Sized;
65}
66
67impl ColumnToVal<String> for Column {
68 fn to_val(self) -> Result<String, FbError> {
69 match self.value {
70 Text(t) => Ok(t),
71
72 Integer(i) => Ok(i.to_string()),
73
74 Int128(i) => Ok(i.to_string()),
75
76 Floating(f) => Ok(f.to_string()),
77
78 Timestamp(ts) => Ok(ts.to_string()),
79
80 Binary(_) => Err("This is a binary column. You cannot use string to access".into()),
81
82 Boolean(bo) => Ok(bo.to_string()),
83
84 Null => Err(err_column_null("String")),
85 }
86 }
87}
88
89impl ColumnToVal<i128> for Column {
90 fn to_val(self) -> Result<i128, FbError> {
91 match self.value {
92 Integer(i) => Ok(i128::from(i)),
93
94 Int128(i) => Ok(i),
95
96 Null => Err(err_column_null("i128")),
97
98 col => err_type_conv(col, "i128"),
99 }
100 }
101}
102
103impl ColumnToVal<i64> for Column {
104 fn to_val(self) -> Result<i64, FbError> {
105 match self.value {
106 Integer(i) => Ok(i),
107
108 Null => Err(err_column_null("i64")),
109
110 col => err_type_conv(col, "i64"),
111 }
112 }
113}
114
115impl ColumnToVal<i32> for Column {
116 fn to_val(self) -> Result<i32, FbError> {
117 ColumnToVal::<i64>::to_val(self).map(|i| i as i32)
118 }
119}
120
121impl ColumnToVal<i16> for Column {
122 fn to_val(self) -> Result<i16, FbError> {
123 ColumnToVal::<i64>::to_val(self).map(|i| i as i16)
124 }
125}
126
127impl ColumnToVal<f64> for Column {
128 fn to_val(self) -> Result<f64, FbError> {
129 match self.value {
130 Floating(f) => Ok(f),
131
132 Null => Err(err_column_null("f64")),
133
134 col => err_type_conv(col, "f64"),
135 }
136 }
137}
138
139impl ColumnToVal<f32> for Column {
140 fn to_val(self) -> Result<f32, FbError> {
141 ColumnToVal::<f64>::to_val(self).map(|i| i as f32)
142 }
143}
144
145impl ColumnToVal<Vec<u8>> for Column {
146 fn to_val(self) -> Result<Vec<u8>, FbError> {
147 match self.value {
148 Binary(b) => Ok(b),
149
150 Null => Err(err_column_null("Vec<u8>")),
151
152 col => err_type_conv(col, "Vec<u8>"),
153 }
154 }
155}
156
157impl ColumnToVal<bool> for Column {
158 fn to_val(self) -> Result<bool, FbError> {
159 match self.value {
160 Boolean(bo) => Ok(bo),
161
162 Null => Err(err_column_null("bool")),
163
164 col => err_type_conv(col, "bool"),
165 }
166 }
167}
168
169impl<T> ColumnToVal<Option<T>> for Column
171where
172 Column: ColumnToVal<T>,
173{
174 fn to_val(self) -> Result<Option<T>, FbError> {
175 if self.value.is_null() {
176 return Ok(None);
177 }
178
179 Ok(Some(self.to_val()?))
180 }
181}
182
183pub trait FromRow {
185 fn try_from(row: Vec<Column>) -> Result<Self, FbError>
186 where
187 Self: std::marker::Sized;
188}
189
190impl FromRow for Row {
193 fn try_from(row: Vec<Column>) -> Result<Self, FbError>
194 where
195 Self: Sized,
196 {
197 Ok(Row { cols: row })
198 }
199}
200
201impl FromRow for () {
203 fn try_from(_row: Vec<Column>) -> Result<Self, FbError>
204 where
205 Self: Sized,
206 {
207 Ok(())
208 }
209}
210
211macro_rules! impl_from_row {
213 ($($t: ident),+) => {
214 impl<'a, $($t),+> FromRow for ($($t,)+)
215 where
216 $( Column: ColumnToVal<$t>, )+
217 {
218 fn try_from(row: Vec<Column>) -> Result<Self, FbError> {
219 let len = row.len();
220 let mut iter = row.into_iter();
221
222 Ok(( $(
223 ColumnToVal::<$t>::to_val(
224 iter
225 .next()
226 .ok_or_else(|| {
227 FbError::Other(
228 format!("The sql returned less columns than the {} expected", len),
229 )
230 })?
231 )?,
232 )+ ))
233 }
234 }
235 };
236}
237
238macro_rules! impls_from_row {
240 ($t: ident) => {
241 impl_from_row!($t);
242 };
243
244 ($t: ident, $($ts: ident),+ ) => {
245 impls_from_row!($($ts),+);
246
247 impl_from_row!($t, $($ts),+);
248 };
249}
250
251impls_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);