1use rusqlite::{types, Statement};
2use std::fmt::Debug;
3use std::ops::Index;
4use std::str::FromStr;
5use std::sync::Arc;
6
7#[derive(Debug, Copy, Clone)]
8pub enum ValueType {
9 Integer = 1,
10 Real,
11 Text,
12 Blob,
13 Null,
14}
15
16impl FromStr for ValueType {
17 type Err = ();
18
19 fn from_str(s: &str) -> std::result::Result<ValueType, Self::Err> {
20 match s {
21 "TEXT" => Ok(ValueType::Text),
22 "INTEGER" => Ok(ValueType::Integer),
23 "BLOB" => Ok(ValueType::Blob),
24 "NULL" => Ok(ValueType::Null),
25 "REAL" => Ok(ValueType::Real),
26 _ => Err(()),
27 }
28 }
29}
30
31#[allow(unused)]
32#[derive(Debug)]
33pub struct Column {
34 name: String,
35 decl_type: Option<ValueType>,
36}
37
38#[derive(Debug)]
39pub struct Rows(pub(crate) Vec<Row>, pub(crate) Arc<Vec<Column>>);
40
41pub(crate) fn columns(stmt: &Statement<'_>) -> Vec<Column> {
42 return stmt
43 .columns()
44 .into_iter()
45 .map(|c| Column {
46 name: c.name().to_string(),
47 decl_type: c.decl_type().and_then(|s| ValueType::from_str(s).ok()),
48 })
49 .collect();
50}
51
52impl Rows {
53 pub fn from_rows(mut rows: rusqlite::Rows) -> rusqlite::Result<Self> {
54 let columns: Arc<Vec<Column>> = Arc::new(rows.as_ref().map_or(vec![], columns));
55
56 let mut result = vec![];
57 while let Some(row) = rows.next()? {
58 result.push(Row::from_row(row, Some(columns.clone()))?);
59 }
60
61 return Ok(Self(result, columns));
62 }
63
64 pub fn len(&self) -> usize {
65 return self.0.len();
66 }
67
68 pub fn is_empty(&self) -> bool {
69 return self.0.is_empty();
70 }
71
72 pub fn iter(&self) -> std::slice::Iter<'_, Row> {
73 return self.0.iter();
74 }
75
76 pub fn get(&self, idx: usize) -> Option<&Row> {
77 return self.0.get(idx);
78 }
79
80 pub fn last(&self) -> Option<&Row> {
81 return self.0.last();
82 }
83
84 pub fn column_count(&self) -> usize {
85 return self.1.len();
86 }
87
88 pub fn column_names(&self) -> Vec<&str> {
89 return self.1.iter().map(|s| s.name.as_str()).collect();
90 }
91
92 pub fn column_name(&self, idx: usize) -> Option<&str> {
93 return self.1.get(idx).map(|c| c.name.as_str());
94 }
95
96 pub fn column_type(&self, idx: usize) -> std::result::Result<ValueType, rusqlite::Error> {
97 if let Some(c) = self.1.get(idx) {
98 return c.decl_type.ok_or_else(|| {
99 rusqlite::Error::InvalidColumnType(
100 idx,
101 self.column_name(idx).unwrap_or("?").to_string(),
102 types::Type::Null,
103 )
104 });
105 }
106
107 return Err(rusqlite::Error::InvalidColumnType(
108 idx,
109 self.column_name(idx).unwrap_or("?").to_string(),
110 types::Type::Null,
111 ));
112 }
113}
114
115impl Index<usize> for Rows {
116 type Output = Row;
117
118 fn index(&self, idx: usize) -> &Self::Output {
119 return &self.0[idx];
120 }
121}
122
123#[derive(Debug)]
124pub struct Row(Vec<types::Value>, Arc<Vec<Column>>);
125
126impl Row {
127 pub fn from_row(row: &rusqlite::Row, cols: Option<Arc<Vec<Column>>>) -> rusqlite::Result<Self> {
128 let columns = cols.unwrap_or_else(|| Arc::new(columns(row.as_ref())));
129
130 let count = columns.len();
131 let mut values = Vec::<types::Value>::with_capacity(count);
132 for idx in 0..count {
133 values.push(row.get_ref(idx)?.into());
134 }
135
136 return Ok(Self(values, columns));
137 }
138
139 pub fn get<T>(&self, idx: usize) -> types::FromSqlResult<T>
140 where
141 T: types::FromSql,
142 {
143 let Some(value) = self.0.get(idx) else {
144 return Err(types::FromSqlError::OutOfRange(idx as i64));
145 };
146 return T::column_result(value.into());
147 }
148
149 pub fn get_value(&self, idx: usize) -> Option<&types::Value> {
150 return self.0.get(idx);
151 }
152
153 pub fn len(&self) -> usize {
154 assert_eq!(self.1.len(), self.0.len());
155 return self.0.len();
156 }
157
158 pub fn is_empty(&self) -> bool {
159 return self.0.is_empty();
160 }
161
162 pub fn column_count(&self) -> usize {
163 assert_eq!(self.1.len(), self.0.len());
164 return self.1.len();
165 }
166
167 pub fn column_names(&self) -> Vec<&str> {
168 return self.1.iter().map(|s| s.name.as_str()).collect();
169 }
170
171 pub fn column_name(&self, idx: usize) -> Option<&str> {
172 return self.1.get(idx).map(|c| c.name.as_str());
173 }
174}
175
176impl Index<usize> for Row {
177 type Output = types::Value;
178
179 fn index(&self, idx: usize) -> &Self::Output {
180 return &self.0[idx];
181 }
182}