Skip to main content

rustbasic_core/sql/
row.rs

1use super::error::Error;
2
3pub trait Row {}
4pub trait Column {}
5pub trait TypeInfo {}
6
7#[derive(Debug, Clone)]
8pub enum DbValue {
9    Null,
10    Text(String),
11    Blob(Vec<u8>),
12    Integer(i64),
13    Real(f64),
14    Bool(bool),
15}
16
17#[derive(Debug, Clone)]
18pub struct AnyTypeInfo {
19    pub name: String,
20}
21
22impl TypeInfo for AnyTypeInfo {}
23
24impl AnyTypeInfo {
25    pub fn name(&self) -> &str {
26        &self.name
27    }
28}
29
30#[derive(Debug, Clone)]
31pub struct AnyColumn {
32    pub name: String,
33    pub type_info: AnyTypeInfo,
34}
35
36impl Column for AnyColumn {}
37
38impl AnyColumn {
39    pub fn name(&self) -> &str {
40        &self.name
41    }
42
43    pub fn type_info(&self) -> &AnyTypeInfo {
44        &self.type_info
45    }
46}
47
48#[derive(Debug, Clone)]
49pub struct AnyRow {
50    pub columns: Vec<AnyColumn>,
51    pub values: Vec<DbValue>,
52}
53
54impl Row for AnyRow {}
55
56impl AnyRow {
57    pub fn len(&self) -> usize {
58        self.values.len()
59    }
60
61    pub fn is_empty(&self) -> bool {
62        self.values.is_empty()
63    }
64
65    pub fn column(&self, index: usize) -> &AnyColumn {
66        &self.columns[index]
67    }
68
69    pub fn try_get<T, I>(&self, index: I) -> Result<T, Error>
70    where
71        T: for<'r> Decode<'r>,
72        I: RowIndex,
73    {
74        let idx = index.index(self)?;
75        let val = &self.values[idx];
76        T::decode(val)
77    }
78
79    pub fn get<T, I>(&self, index: I) -> T
80    where
81        T: for<'r> Decode<'r>,
82        I: RowIndex,
83    {
84        self.try_get(index).unwrap()
85    }
86}
87
88pub trait RowIndex {
89    fn index(&self, row: &AnyRow) -> Result<usize, Error>;
90}
91
92impl RowIndex for usize {
93    fn index(&self, row: &AnyRow) -> Result<usize, Error> {
94        if *self < row.len() {
95            Ok(*self)
96        } else {
97            Err(Error::ColumnIndexOutOfBounds {
98                len: row.len(),
99                index: *self,
100            })
101        }
102    }
103}
104
105impl RowIndex for &str {
106    fn index(&self, row: &AnyRow) -> Result<usize, Error> {
107        row.columns
108            .iter()
109            .position(|col| col.name == *self)
110            .ok_or_else(|| Error::ColumnNotFound((*self).to_string()))
111    }
112}
113
114impl RowIndex for String {
115    fn index(&self, row: &AnyRow) -> Result<usize, Error> {
116        row.columns
117            .iter()
118            .position(|col| col.name == *self)
119            .ok_or_else(|| Error::ColumnNotFound((*self).to_string()))
120    }
121}
122
123pub trait Decode<'r>: Sized {
124    fn decode(value: &'r DbValue) -> Result<Self, Error>;
125}
126
127impl<'r, T: Decode<'r>> Decode<'r> for Option<T> {
128    fn decode(value: &'r DbValue) -> Result<Self, Error> {
129        match value {
130            DbValue::Null => Ok(None),
131            other => T::decode(other).map(Some),
132        }
133    }
134}
135
136impl<'r> Decode<'r> for String {
137    fn decode(value: &'r DbValue) -> Result<Self, Error> {
138        match value {
139            DbValue::Text(s) => Ok(s.clone()),
140            DbValue::Integer(i) => Ok(i.to_string()),
141            DbValue::Real(f) => Ok(f.to_string()),
142            DbValue::Bool(b) => Ok(b.to_string()),
143            DbValue::Blob(b) => String::from_utf8(b.clone())
144                .map_err(|e| Error::DecodeError(e.to_string())),
145            DbValue::Null => Err(Error::DecodeError("Cannot decode NULL to String".into())),
146        }
147    }
148}
149
150impl<'r> Decode<'r> for i64 {
151    fn decode(value: &'r DbValue) -> Result<Self, Error> {
152        match value {
153            DbValue::Integer(i) => Ok(*i),
154            DbValue::Text(s) => s.parse::<i64>().map_err(|e| Error::DecodeError(e.to_string())),
155            DbValue::Bool(b) => Ok(if *b { 1 } else { 0 }),
156            DbValue::Real(f) => Ok(*f as i64),
157            _ => Err(Error::DecodeError("Cannot decode to i64".into())),
158        }
159    }
160}
161
162impl<'r> Decode<'r> for i32 {
163    fn decode(value: &'r DbValue) -> Result<Self, Error> {
164        match value {
165            DbValue::Integer(i) => Ok(*i as i32),
166            DbValue::Text(s) => s.parse::<i32>().map_err(|e| Error::DecodeError(e.to_string())),
167            DbValue::Bool(b) => Ok(if *b { 1 } else { 0 }),
168            DbValue::Real(f) => Ok(*f as i32),
169            _ => Err(Error::DecodeError("Cannot decode to i32".into())),
170        }
171    }
172}
173
174impl<'r> Decode<'r> for u64 {
175    fn decode(value: &'r DbValue) -> Result<Self, Error> {
176        match value {
177            DbValue::Integer(i) => Ok(*i as u64),
178            DbValue::Text(s) => s.parse::<u64>().map_err(|e| Error::DecodeError(e.to_string())),
179            DbValue::Bool(b) => Ok(if *b { 1 } else { 0 }),
180            DbValue::Real(f) => Ok(*f as u64),
181            _ => Err(Error::DecodeError("Cannot decode to u64".into())),
182        }
183    }
184}
185
186impl<'r> Decode<'r> for f64 {
187    fn decode(value: &'r DbValue) -> Result<Self, Error> {
188        match value {
189            DbValue::Real(f) => Ok(*f),
190            DbValue::Integer(i) => Ok(*i as f64),
191            DbValue::Text(s) => s.parse::<f64>().map_err(|e| Error::DecodeError(e.to_string())),
192            _ => Err(Error::DecodeError("Cannot decode to f64".into())),
193        }
194    }
195}
196
197impl<'r> Decode<'r> for bool {
198    fn decode(value: &'r DbValue) -> Result<Self, Error> {
199        match value {
200            DbValue::Bool(b) => Ok(*b),
201            DbValue::Integer(i) => Ok(*i != 0),
202            DbValue::Text(s) => {
203                let s_lower = s.to_lowercase();
204                if s_lower == "true" || s_lower == "1" || s_lower == "t" || s_lower == "y" || s_lower == "yes" {
205                    Ok(true)
206                } else if s_lower == "false" || s_lower == "0" || s_lower == "f" || s_lower == "n" || s_lower == "no" || s_lower.is_empty() {
207                    Ok(false)
208                } else {
209                    Err(Error::DecodeError(format!("Cannot decode '{}' to bool", s)))
210                }
211            }
212            _ => Err(Error::DecodeError("Cannot decode to bool".into())),
213        }
214    }
215}
216
217impl<'r> Decode<'r> for Vec<u8> {
218    fn decode(value: &'r DbValue) -> Result<Self, Error> {
219        match value {
220            DbValue::Blob(b) => Ok(b.clone()),
221            DbValue::Text(s) => Ok(s.as_bytes().to_vec()),
222            _ => Err(Error::DecodeError("Cannot decode to Vec<u8>".into())),
223        }
224    }
225}