1use std::collections::HashMap;
2
3use crate::{
4 decode::FromSql,
5 error::{PgError, Result},
6 protocol::FieldDescription,
7};
8
9#[derive(Debug, Clone)]
10pub struct Row {
11 columns: Vec<FieldDescription>,
12 values: Vec<Option<Vec<u8>>>,
13 name_to_index: HashMap<String, usize>,
14}
15
16impl Row {
17 pub fn new(fields: &[FieldDescription], values: &[Option<Vec<u8>>]) -> Self {
18 let name_to_index = fields.iter().enumerate().map(|(i, f)| (f.name.clone(), i)).collect();
19
20 Row {
21 columns: fields.to_vec(),
22 values: values.to_vec(),
23 name_to_index,
24 }
25 }
26
27 pub fn len(&self) -> usize {
28 self.columns.len()
29 }
30
31 pub fn is_empty(&self) -> bool {
32 self.columns.is_empty()
33 }
34
35 pub fn columns(&self) -> &[FieldDescription] {
36 &self.columns
37 }
38
39 pub fn try_get<T: FromSql>(&self, name: &str) -> Result<T> {
40 let idx = self
41 .name_to_index
42 .get(name)
43 .ok_or_else(|| PgError::ColumnNotFound(name.to_string()))?;
44
45 let field = &self.columns[*idx];
46 let type_oid = field.type_oid;
47
48 match &self.values[*idx] {
49 None => T::from_sql(type_oid, &[]),
50 Some(data) => T::from_sql(type_oid, data),
51 }
52 }
53
54 pub fn try_get_by_index<T: FromSql>(&self, idx: usize) -> Result<T> {
55 if idx >= self.columns.len() {
56 return Err(PgError::ColumnNotFound(format!("column index {}", idx)));
57 }
58
59 let field = &self.columns[idx];
60 let type_oid = field.type_oid;
61
62 match &self.values[idx] {
63 None => T::from_sql(type_oid, &[]),
64 Some(data) => T::from_sql(type_oid, data),
65 }
66 }
67}