1use base64::prelude::*;
2use rusqlite::{Statement, types};
3use std::fmt::Debug;
4use std::ops::Index;
5use std::str::FromStr;
6use std::sync::Arc;
7use thiserror::Error;
8
9#[derive(Debug, Copy, Clone)]
10pub enum ValueType {
11 Integer = 1,
12 Real,
13 Text,
14 Blob,
15 Null,
16}
17
18impl FromStr for ValueType {
19 type Err = ();
20
21 fn from_str(s: &str) -> std::result::Result<ValueType, Self::Err> {
22 match s {
23 "TEXT" => Ok(ValueType::Text),
24 "INTEGER" => Ok(ValueType::Integer),
25 "BLOB" => Ok(ValueType::Blob),
26 "NULL" => Ok(ValueType::Null),
27 "REAL" => Ok(ValueType::Real),
28 _ => Err(()),
29 }
30 }
31}
32
33#[derive(Debug, Clone)]
34pub struct Column {
35 name: String,
36 decl_type: Option<ValueType>,
37}
38
39#[derive(Debug)]
40pub struct Rows(pub(crate) Vec<Row>, pub(crate) Arc<Vec<Column>>);
41
42pub(crate) fn columns(stmt: &Statement<'_>) -> Vec<Column> {
43 return stmt
44 .columns()
45 .into_iter()
46 .map(|c| Column {
47 name: c.name().to_string(),
48 decl_type: c.decl_type().and_then(|s| ValueType::from_str(s).ok()),
49 })
50 .collect();
51}
52
53impl Rows {
54 pub fn from_rows(mut rows: rusqlite::Rows) -> rusqlite::Result<Self> {
55 let columns: Arc<Vec<Column>> = Arc::new(rows.as_ref().map_or(vec![], columns));
56
57 let mut result = vec![];
58 while let Some(row) = rows.next()? {
59 result.push(Row::from_row(row, Some(columns.clone()))?);
60 }
61
62 return Ok(Self(result, columns));
63 }
64
65 pub fn len(&self) -> usize {
66 return self.0.len();
67 }
68
69 pub fn is_empty(&self) -> bool {
70 return self.0.is_empty();
71 }
72
73 pub fn iter(&self) -> std::slice::Iter<'_, Row> {
74 return self.0.iter();
75 }
76
77 pub fn get(&self, idx: usize) -> Option<&Row> {
78 return self.0.get(idx);
79 }
80
81 pub fn last(&self) -> Option<&Row> {
82 return self.0.last();
83 }
84
85 pub fn column_count(&self) -> usize {
86 return self.1.len();
87 }
88
89 pub fn column_names(&self) -> Vec<&str> {
90 return self.1.iter().map(|s| s.name.as_str()).collect();
91 }
92
93 pub fn column_name(&self, idx: usize) -> Option<&str> {
94 return self.1.get(idx).map(|c| c.name.as_str());
95 }
96
97 pub fn column_type(&self, idx: usize) -> std::result::Result<ValueType, rusqlite::Error> {
98 if let Some(c) = self.1.get(idx) {
99 return c.decl_type.ok_or_else(|| {
100 rusqlite::Error::InvalidColumnType(
101 idx,
102 self.column_name(idx).unwrap_or("?").to_string(),
103 types::Type::Null,
104 )
105 });
106 }
107
108 return Err(rusqlite::Error::InvalidColumnType(
109 idx,
110 self.column_name(idx).unwrap_or("?").to_string(),
111 types::Type::Null,
112 ));
113 }
114}
115
116impl Index<usize> for Rows {
117 type Output = Row;
118
119 fn index(&self, idx: usize) -> &Self::Output {
120 return &self.0[idx];
121 }
122}
123
124impl IntoIterator for Rows {
125 type Item = Row;
126 type IntoIter = std::vec::IntoIter<Self::Item>;
127
128 fn into_iter(self) -> Self::IntoIter {
129 return self.0.into_iter();
130 }
131}
132
133#[derive(Debug)]
134pub struct Row(Vec<types::Value>, Arc<Vec<Column>>);
135
136impl Row {
137 pub fn from_row(row: &rusqlite::Row, cols: Option<Arc<Vec<Column>>>) -> rusqlite::Result<Self> {
138 let columns = cols.unwrap_or_else(|| Arc::new(columns(row.as_ref())));
139
140 let values = (0..columns.len())
141 .map(|idx| Ok(row.get_ref(idx)?.into()))
142 .collect::<Result<Vec<types::Value>, rusqlite::Error>>()?;
143
144 return Ok(Self(values, columns));
145 }
146
147 pub fn split_off(&mut self, at: usize) -> Row {
148 let split_values = self.0.split_off(at);
149 let mut columns = (*self.1).clone();
150 let split_columns = columns.split_off(at);
151 self.1 = Arc::new(columns);
152 return Row(split_values, Arc::new(split_columns));
153 }
154
155 pub fn get<T>(&self, idx: usize) -> types::FromSqlResult<T>
156 where
157 T: types::FromSql,
158 {
159 let Some(value) = self.0.get(idx) else {
160 return Err(types::FromSqlError::OutOfRange(idx as i64));
161 };
162 return T::column_result(value.into());
163 }
164
165 pub fn get_value(&self, idx: usize) -> Option<&types::Value> {
166 return self.0.get(idx);
167 }
168
169 pub fn len(&self) -> usize {
170 assert_eq!(self.1.len(), self.0.len());
171 return self.0.len();
172 }
173
174 pub fn is_empty(&self) -> bool {
175 return self.0.is_empty();
176 }
177
178 pub fn last(&self) -> Option<&types::Value> {
179 return self.0.last();
180 }
181
182 pub fn column_count(&self) -> usize {
183 assert_eq!(self.1.len(), self.0.len());
184 return self.1.len();
185 }
186
187 pub fn column_names(&self) -> Vec<&str> {
188 return self.1.iter().map(|s| s.name.as_str()).collect();
189 }
190
191 pub fn column_name(&self, idx: usize) -> Option<&str> {
192 return self.1.get(idx).map(|c| c.name.as_str());
193 }
194}
195
196impl Index<usize> for Row {
197 type Output = types::Value;
198
199 fn index(&self, idx: usize) -> &Self::Output {
200 return &self.0[idx];
201 }
202}
203
204#[derive(Debug, Error)]
205pub enum JsonError {
206 #[error("Float not finite")]
207 Finite,
208 #[error("Value not found")]
209 ValueNotFound,
210}
211
212pub fn value_to_json(value: &types::Value) -> Result<serde_json::Value, JsonError> {
213 return Ok(match value {
214 types::Value::Null => serde_json::Value::Null,
215 types::Value::Real(real) => {
216 let Some(number) = serde_json::Number::from_f64(*real) else {
217 return Err(JsonError::Finite);
218 };
219 serde_json::Value::Number(number)
220 }
221 types::Value::Integer(integer) => serde_json::Value::Number(serde_json::Number::from(*integer)),
222 types::Value::Blob(blob) => serde_json::Value::String(BASE64_URL_SAFE.encode(blob)),
223 types::Value::Text(text) => serde_json::Value::String(text.clone()),
224 });
225}
226
227pub fn row_to_json_array(row: &Row) -> Result<Vec<serde_json::Value>, JsonError> {
228 let cols = row.column_count();
229 let mut json_row = Vec::<serde_json::Value>::with_capacity(cols);
230
231 for i in 0..cols {
232 let value = row.get_value(i).ok_or(JsonError::ValueNotFound)?;
233 json_row.push(value_to_json(value)?);
234 }
235
236 return Ok(json_row);
237}
238
239pub fn rows_to_json_arrays(rows: &Rows) -> Result<Vec<Vec<serde_json::Value>>, JsonError> {
240 return rows.iter().map(row_to_json_array).collect();
241}