tokio_postgres/
row.rs

1//! Rows.
2
3use crate::row::sealed::{AsName, Sealed};
4use crate::simple_query::SimpleColumn;
5use crate::statement::Column;
6use crate::types::{FromSql, Type, WrongType};
7use crate::{Error, Statement};
8use fallible_iterator::FallibleIterator;
9use postgres_protocol::message::backend::DataRowBody;
10use std::fmt;
11use std::ops::Range;
12use std::str;
13use std::sync::Arc;
14
15mod sealed {
16    pub trait Sealed {}
17
18    pub trait AsName {
19        fn as_name(&self) -> &str;
20    }
21}
22
23impl AsName for Column {
24    fn as_name(&self) -> &str {
25        self.name()
26    }
27}
28
29impl AsName for String {
30    fn as_name(&self) -> &str {
31        self
32    }
33}
34
35/// A trait implemented by types that can index into columns of a row.
36///
37/// This cannot be implemented outside of this crate.
38pub trait RowIndex: Sealed {
39    #[doc(hidden)]
40    fn __idx<T>(&self, columns: &[T]) -> Option<usize>
41    where
42        T: AsName;
43}
44
45impl Sealed for usize {}
46
47impl RowIndex for usize {
48    #[inline]
49    fn __idx<T>(&self, columns: &[T]) -> Option<usize>
50    where
51        T: AsName,
52    {
53        if *self >= columns.len() {
54            None
55        } else {
56            Some(*self)
57        }
58    }
59}
60
61impl Sealed for str {}
62
63impl RowIndex for str {
64    #[inline]
65    fn __idx<T>(&self, columns: &[T]) -> Option<usize>
66    where
67        T: AsName,
68    {
69        if let Some(idx) = columns.iter().position(|d| d.as_name() == self) {
70            return Some(idx);
71        };
72
73        // FIXME ASCII-only case insensitivity isn't really the right thing to
74        // do. Postgres itself uses a dubious wrapper around tolower and JDBC
75        // uses the US locale.
76        columns
77            .iter()
78            .position(|d| d.as_name().eq_ignore_ascii_case(self))
79    }
80}
81
82impl<T> Sealed for &T where T: ?Sized + Sealed {}
83
84impl<T> RowIndex for &T
85where
86    T: ?Sized + RowIndex,
87{
88    #[inline]
89    fn __idx<U>(&self, columns: &[U]) -> Option<usize>
90    where
91        U: AsName,
92    {
93        T::__idx(*self, columns)
94    }
95}
96
97/// A row of data returned from the database by a query.
98#[derive(Clone)]
99pub struct Row {
100    statement: Statement,
101    body: DataRowBody,
102    ranges: Vec<Option<Range<usize>>>,
103}
104
105impl fmt::Debug for Row {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        f.debug_struct("Row")
108            .field("columns", &self.columns())
109            .finish()
110    }
111}
112
113impl Row {
114    pub(crate) fn new(statement: Statement, body: DataRowBody) -> Result<Row, Error> {
115        let ranges = body.ranges().collect().map_err(Error::parse)?;
116        Ok(Row {
117            statement,
118            body,
119            ranges,
120        })
121    }
122
123    /// Returns information about the columns of data in the row.
124    pub fn columns(&self) -> &[Column] {
125        self.statement.columns()
126    }
127
128    /// Determines if the row contains no values.
129    pub fn is_empty(&self) -> bool {
130        self.len() == 0
131    }
132
133    /// Returns the number of values in the row.
134    pub fn len(&self) -> usize {
135        self.columns().len()
136    }
137
138    /// Deserializes a value from the row.
139    ///
140    /// The value can be specified either by its numeric index in the row, or by its column name.
141    ///
142    /// # Panics
143    ///
144    /// Panics if the index is out of bounds or if the value cannot be converted to the specified type.
145    #[track_caller]
146    pub fn get<'a, I, T>(&'a self, idx: I) -> T
147    where
148        I: RowIndex + fmt::Display,
149        T: FromSql<'a>,
150    {
151        match self.get_inner(&idx) {
152            Ok(ok) => ok,
153            Err(err) => panic!("error retrieving column {}: {}", idx, err),
154        }
155    }
156
157    /// Like `Row::get`, but returns a `Result` rather than panicking.
158    pub fn try_get<'a, I, T>(&'a self, idx: I) -> Result<T, Error>
159    where
160        I: RowIndex + fmt::Display,
161        T: FromSql<'a>,
162    {
163        self.get_inner(&idx)
164    }
165
166    fn get_inner<'a, I, T>(&'a self, idx: &I) -> Result<T, Error>
167    where
168        I: RowIndex + fmt::Display,
169        T: FromSql<'a>,
170    {
171        let idx = match idx.__idx(self.columns()) {
172            Some(idx) => idx,
173            None => return Err(Error::column(idx.to_string())),
174        };
175
176        let ty = self.columns()[idx].type_();
177        if !T::accepts(ty) {
178            return Err(Error::from_sql(
179                Box::new(WrongType::new::<T>(ty.clone())),
180                idx,
181            ));
182        }
183
184        FromSql::from_sql_nullable(ty, self.col_buffer(idx)).map_err(|e| Error::from_sql(e, idx))
185    }
186
187    /// Returns the raw size of the row in bytes.
188    pub fn raw_size_bytes(&self) -> usize {
189        self.body.buffer_bytes().len()
190    }
191
192    /// Get the raw bytes for the column at the given index.
193    fn col_buffer(&self, idx: usize) -> Option<&[u8]> {
194        let range = self.ranges[idx].to_owned()?;
195        Some(&self.body.buffer()[range])
196    }
197}
198
199impl AsName for SimpleColumn {
200    fn as_name(&self) -> &str {
201        self.name()
202    }
203}
204
205/// A row of data returned from the database by a simple query.
206#[derive(Debug)]
207pub struct SimpleQueryRow {
208    columns: Arc<[SimpleColumn]>,
209    body: DataRowBody,
210    ranges: Vec<Option<Range<usize>>>,
211}
212
213impl SimpleQueryRow {
214    #[allow(clippy::new_ret_no_self)]
215    pub(crate) fn new(
216        columns: Arc<[SimpleColumn]>,
217        body: DataRowBody,
218    ) -> Result<SimpleQueryRow, Error> {
219        let ranges = body.ranges().collect().map_err(Error::parse)?;
220        Ok(SimpleQueryRow {
221            columns,
222            body,
223            ranges,
224        })
225    }
226
227    /// Returns information about the columns of data in the row.
228    pub fn columns(&self) -> &[SimpleColumn] {
229        &self.columns
230    }
231
232    /// Determines if the row contains no values.
233    pub fn is_empty(&self) -> bool {
234        self.len() == 0
235    }
236
237    /// Returns the number of values in the row.
238    pub fn len(&self) -> usize {
239        self.columns.len()
240    }
241
242    /// Returns a value from the row.
243    ///
244    /// The value can be specified either by its numeric index in the row, or by its column name.
245    ///
246    /// # Panics
247    ///
248    /// Panics if the index is out of bounds or if the value cannot be converted to the specified type.
249    #[track_caller]
250    pub fn get<I>(&self, idx: I) -> Option<&str>
251    where
252        I: RowIndex + fmt::Display,
253    {
254        match self.get_inner(&idx) {
255            Ok(ok) => ok,
256            Err(err) => panic!("error retrieving column {}: {}", idx, err),
257        }
258    }
259
260    /// Like `SimpleQueryRow::get`, but returns a `Result` rather than panicking.
261    pub fn try_get<I>(&self, idx: I) -> Result<Option<&str>, Error>
262    where
263        I: RowIndex + fmt::Display,
264    {
265        self.get_inner(&idx)
266    }
267
268    fn get_inner<I>(&self, idx: &I) -> Result<Option<&str>, Error>
269    where
270        I: RowIndex + fmt::Display,
271    {
272        let idx = match idx.__idx(&self.columns) {
273            Some(idx) => idx,
274            None => return Err(Error::column(idx.to_string())),
275        };
276
277        let buf = self.ranges[idx].clone().map(|r| &self.body.buffer()[r]);
278        FromSql::from_sql_nullable(&Type::TEXT, buf).map_err(|e| Error::from_sql(e, idx))
279    }
280}