LCOV - code coverage report
Current view: top level - libs/proxy/tokio-postgres2/src - row.rs (source / functions) Coverage Total Hit
Test: 5fe7fa8d483b39476409aee736d6d5e32728bfac.info Lines: 0.0 % 158 0
Test Date: 2025-03-12 16:10:49 Functions: 0.0 % 39 0

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

Generated by: LCOV version 2.1-beta