1use std::{collections::HashMap, sync::Arc};
2
3use serde_json::Value;
4
5use crate::{column::Column, from_row::FromRow, IntoTypedError};
6
7#[derive(Debug)]
8pub struct Row {
9 values: Box<[Value]>,
10 columns: Arc<Vec<Column>>,
11 column_names: Arc<HashMap<String, usize>>,
12}
13
14impl Row {
15 #[must_use]
16 pub fn new(
17 columns: &Arc<Vec<Column>>,
18 column_names: &Arc<HashMap<String, usize>>,
19 values: Box<[Value]>,
20 ) -> Row {
21 Row {
22 values,
23 columns: Arc::clone(columns),
24 column_names: Arc::clone(column_names),
25 }
26 }
27
28 #[must_use]
29 pub fn columns(&self) -> &Arc<Vec<Column>> {
30 &self.columns
31 }
32
33 #[must_use]
34 pub fn column_names(&self) -> &Arc<HashMap<String, usize>> {
35 &self.column_names
36 }
37
38 pub fn get<T: serde::de::DeserializeOwned>(&self, name: &str) -> Result<T, IntoTypedError> {
43 let index = self
44 .column_names
45 .get(name)
46 .ok_or(IntoTypedError::ColumnNotFound)?;
47
48 let value = self
49 .values
50 .get(*index)
51 .ok_or(IntoTypedError::ValueNotFound)?;
52
53 let value =
54 serde_json::from_value(value.clone()).map_err(IntoTypedError::ConversionError)?;
55
56 Ok(value)
57 }
58
59 pub fn get_opt<T: serde::de::DeserializeOwned>(
64 &self,
65 name: &str,
66 ) -> Result<Option<T>, IntoTypedError> {
67 let Some(index) = self.column_names.get(name) else {
68 return Ok(None);
69 };
70
71 let value = self
73 .values
74 .get(*index)
75 .ok_or(IntoTypedError::ValueNotFound)?;
76
77 if value == &Value::Null {
78 Ok(None)
79 } else {
80 let value =
81 serde_json::from_value(value.clone()).map_err(IntoTypedError::ConversionError)?;
82 Ok(Some(value))
83 }
84 }
85
86 pub fn get_by_index<T: serde::de::DeserializeOwned>(
91 &self,
92 index: usize,
93 ) -> Result<T, IntoTypedError> {
94 let value = self
95 .values
96 .get(index)
97 .ok_or(IntoTypedError::ValueNotFound)?;
98 let value =
99 serde_json::from_value(value.clone()).map_err(IntoTypedError::ConversionError)?;
100 Ok(value)
101 }
102
103 pub fn get_by_index_opt<T: serde::de::DeserializeOwned>(
108 &self,
109 index: usize,
110 ) -> Result<Option<T>, IntoTypedError> {
111 let Some(value) = self.values.get(index) else {
112 return Ok(None);
113 };
114
115 if value == &Value::Null {
116 Ok(None)
117 } else {
118 let value =
119 serde_json::from_value(value.clone()).map_err(IntoTypedError::ConversionError)?;
120 Ok(Some(value))
121 }
122 }
123
124 #[must_use]
125 pub fn values(&self) -> &[Value] {
126 &self.values
127 }
128
129 #[must_use]
130 pub fn len(&self) -> usize {
131 self.values.len()
132 }
133
134 #[must_use]
135 pub fn is_empty(&self) -> bool {
136 self.values.is_empty()
137 }
138
139 pub fn into_typed<T>(self) -> Result<T, IntoTypedError>
144 where
145 T: FromRow,
146 {
147 T::from_row(self)
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 fn create_row() -> Row {
156 use serde_json::json;
157
158 let columns = Arc::new(vec![
159 Column::new("id".to_string(), 0usize, "integer".to_string()),
160 Column::new("name".to_string(), 1usize, "text".to_string()),
161 ]);
162
163 let column_names = Arc::new(
164 columns
165 .iter()
166 .enumerate()
167 .map(|(i, c)| (c.name().to_string(), i))
168 .collect::<HashMap<String, usize>>(),
169 );
170
171 let values = vec![json!(1), json!("test")].into_boxed_slice();
172
173 Row::new(&columns, &column_names, values)
174 }
175
176 #[test]
177 fn unit_row_get() {
178 let row = create_row();
179
180 assert_eq!(row.get::<i32>("id").unwrap(), 1);
181 assert_eq!(row.get::<String>("name").unwrap(), "test");
182 assert!(matches!(
183 row.get::<i32>("not_found").unwrap_err(),
184 IntoTypedError::ColumnNotFound
185 ));
186 }
187
188 #[test]
189 fn unit_row_get_opt() {
190 let row = create_row();
191
192 assert_eq!(row.get_opt::<i32>("id").unwrap(), Some(1));
193 assert_eq!(
194 row.get_opt::<String>("name").unwrap(),
195 Some("test".to_string())
196 );
197 assert_eq!(row.get_opt::<i32>("not_found").unwrap(), None);
198 }
199
200 #[test]
201 fn unit_row_get_by_index() {
202 let row = create_row();
203
204 assert_eq!(row.get_by_index::<i32>(0).unwrap(), 1);
205 assert_eq!(row.get_by_index::<String>(1).unwrap(), "test");
206 assert!(matches!(
207 row.get_by_index::<i32>(2).unwrap_err(),
208 IntoTypedError::ValueNotFound
209 ));
210 }
211
212 #[test]
213 fn unit_row_get_by_index_opt() {
214 let row = create_row();
215
216 assert_eq!(row.get_by_index_opt::<i32>(0).unwrap(), Some(1));
217 assert_eq!(
218 row.get_by_index_opt::<String>(1).unwrap(),
219 Some("test".to_string())
220 );
221 assert_eq!(row.get_by_index_opt::<i32>(2).unwrap(), None);
222 }
223
224 #[test]
225 fn unit_row_columns() {
226 let row = create_row();
227
228 assert_eq!(row.columns().len(), 2);
229 assert_eq!(row.columns()[0].name(), "id");
230 assert_eq!(row.columns()[1].name(), "name");
231 }
232
233 #[test]
234 fn unit_row_column_names() {
235 let row = create_row();
236
237 assert_eq!(row.column_names().len(), 2);
238 assert_eq!(row.column_names()["id"], 0);
239 assert_eq!(row.column_names()["name"], 1);
240 }
241
242 #[test]
243 fn unit_row_values() {
244 let row = create_row();
245
246 assert_eq!(row.values().len(), 2);
247 assert_eq!(row.values()[0], serde_json::json!(1));
248 assert_eq!(row.values()[1], serde_json::json!("test"));
249 }
250
251 #[test]
252 fn unit_row_len() {
253 let row = create_row();
254
255 assert_eq!(row.len(), 2);
256 }
257
258 #[test]
259 fn unit_row_is_empty() {
260 let row = create_row();
261
262 assert!(!row.is_empty());
263 }
264
265 #[test]
266 fn unit_row_into_typed_tuple() {
267 let row = create_row();
268
269 let (id, name) = row.into_typed::<(i32, String)>().unwrap();
270
271 assert_eq!(id, 1);
272 assert_eq!(name, "test");
273 }
274
275 #[test]
276 fn unit_row_into_typed_struct() {
277 struct Test {
278 id: i32,
279 name: String,
280 }
281
282 impl FromRow for Test {
283 fn from_row(row: Row) -> Result<Self, IntoTypedError> {
284 Ok(Test {
285 id: row.get("id")?,
286 name: row.get("name")?,
287 })
288 }
289 }
290
291 let row = create_row();
292
293 let test = row.into_typed::<Test>().unwrap();
294
295 assert_eq!(test.id, 1);
296 assert_eq!(test.name, "test");
297 }
298}