Skip to main content

pg/
row.rs

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}