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    /// Get the raw bytes for the column at the given index.
188    fn col_buffer(&self, idx: usize) -> Option<&[u8]> {
189        let range = self.ranges[idx].to_owned()?;
190        Some(&self.body.buffer()[range])
191    }
192}
193
194impl AsName for SimpleColumn {
195    fn as_name(&self) -> &str {
196        self.name()
197    }
198}
199
200/// A row of data returned from the database by a simple query.
201#[derive(Debug)]
202pub struct SimpleQueryRow {
203    columns: Arc<[SimpleColumn]>,
204    body: DataRowBody,
205    ranges: Vec<Option<Range<usize>>>,
206}
207
208impl SimpleQueryRow {
209    #[allow(clippy::new_ret_no_self)]
210    pub(crate) fn new(
211        columns: Arc<[SimpleColumn]>,
212        body: DataRowBody,
213    ) -> Result<SimpleQueryRow, Error> {
214        let ranges = body.ranges().collect().map_err(Error::parse)?;
215        Ok(SimpleQueryRow {
216            columns,
217            body,
218            ranges,
219        })
220    }
221
222    /// Returns information about the columns of data in the row.
223    pub fn columns(&self) -> &[SimpleColumn] {
224        &self.columns
225    }
226
227    /// Determines if the row contains no values.
228    pub fn is_empty(&self) -> bool {
229        self.len() == 0
230    }
231
232    /// Returns the number of values in the row.
233    pub fn len(&self) -> usize {
234        self.columns.len()
235    }
236
237    /// Returns a value from the row.
238    ///
239    /// The value can be specified either by its numeric index in the row, or by its column name.
240    ///
241    /// # Panics
242    ///
243    /// Panics if the index is out of bounds or if the value cannot be converted to the specified type.
244    #[track_caller]
245    pub fn get<I>(&self, idx: I) -> Option<&str>
246    where
247        I: RowIndex + fmt::Display,
248    {
249        match self.get_inner(&idx) {
250            Ok(ok) => ok,
251            Err(err) => panic!("error retrieving column {}: {}", idx, err),
252        }
253    }
254
255    /// Like `SimpleQueryRow::get`, but returns a `Result` rather than panicking.
256    pub fn try_get<I>(&self, idx: I) -> Result<Option<&str>, Error>
257    where
258        I: RowIndex + fmt::Display,
259    {
260        self.get_inner(&idx)
261    }
262
263    fn get_inner<I>(&self, idx: &I) -> Result<Option<&str>, Error>
264    where
265        I: RowIndex + fmt::Display,
266    {
267        let idx = match idx.__idx(&self.columns) {
268            Some(idx) => idx,
269            None => return Err(Error::column(idx.to_string())),
270        };
271
272        let buf = self.ranges[idx].clone().map(|r| &self.body.buffer()[r]);
273        FromSql::from_sql_nullable(&Type::TEXT, buf).map_err(|e| Error::from_sql(e, idx))
274    }
275}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy