rustbasic_core/sql/
row.rs1use 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}