sqlx_core/
row.rs

1use crate::column::ColumnIndex;
2use crate::database::Database;
3use crate::decode::Decode;
4use crate::error::{mismatched_types, Error};
5
6use crate::type_info::TypeInfo;
7use crate::types::Type;
8use crate::value::ValueRef;
9
10/// Represents a single row from the database.
11///
12/// [`FromRow`]: crate::row::FromRow
13/// [`Query::fetch`]: crate::query::Query::fetch
14pub trait Row: Unpin + Send + Sync + 'static {
15    type Database: Database<Row = Self>;
16
17    /// Returns `true` if this row has no columns.
18    #[inline]
19    fn is_empty(&self) -> bool {
20        self.len() == 0
21    }
22
23    /// Returns the number of columns in this row.
24    #[inline]
25    fn len(&self) -> usize {
26        self.columns().len()
27    }
28
29    /// Gets the column information at `index`.
30    ///
31    /// A string index can be used to access a column by name and a `usize` index
32    /// can be used to access a column by position.
33    ///
34    /// # Panics
35    ///
36    /// Panics if `index` is out of bounds.
37    /// See [`try_column`](Self::try_column) for a non-panicking version.
38    fn column<I>(&self, index: I) -> &<Self::Database as Database>::Column
39    where
40        I: ColumnIndex<Self>,
41    {
42        self.try_column(index).unwrap()
43    }
44
45    /// Gets the column information at `index` or a `ColumnIndexOutOfBounds` error if out of bounds.
46    fn try_column<I>(&self, index: I) -> Result<&<Self::Database as Database>::Column, Error>
47    where
48        I: ColumnIndex<Self>,
49    {
50        Ok(&self.columns()[index.index(self)?])
51    }
52
53    /// Gets all columns in this statement.
54    fn columns(&self) -> &[<Self::Database as Database>::Column];
55
56    /// Index into the database row and decode a single value.
57    ///
58    /// A string index can be used to access a column by name and a `usize` index
59    /// can be used to access a column by position.
60    ///
61    /// # Panics
62    ///
63    /// Panics if the column does not exist or its value cannot be decoded into the requested type.
64    /// See [`try_get`](Self::try_get) for a non-panicking version.
65    ///
66    #[inline]
67    fn get<'r, T, I>(&'r self, index: I) -> T
68    where
69        I: ColumnIndex<Self>,
70        T: Decode<'r, Self::Database> + Type<Self::Database>,
71    {
72        self.try_get::<T, I>(index).unwrap()
73    }
74
75    /// Index into the database row and decode a single value.
76    ///
77    /// Unlike [`get`](Self::get), this method does not check that the type
78    /// being returned from the database is compatible with the Rust type and blindly tries
79    /// to decode the value.
80    ///
81    /// # Panics
82    ///
83    /// Panics if the column does not exist or its value cannot be decoded into the requested type.
84    /// See [`try_get_unchecked`](Self::try_get_unchecked) for a non-panicking version.
85    ///
86    #[inline]
87    fn get_unchecked<'r, T, I>(&'r self, index: I) -> T
88    where
89        I: ColumnIndex<Self>,
90        T: Decode<'r, Self::Database>,
91    {
92        self.try_get_unchecked::<T, I>(index).unwrap()
93    }
94
95    /// Index into the database row and decode a single value.
96    ///
97    /// A string index can be used to access a column by name and a `usize` index
98    /// can be used to access a column by position.
99    ///
100    /// # Errors
101    ///
102    ///  * [`ColumnNotFound`] if the column by the given name was not found.
103    ///  * [`ColumnIndexOutOfBounds`] if the `usize` index was greater than the number of columns in the row.
104    ///  * [`ColumnDecode`] if the value could not be decoded into the requested type.
105    ///
106    /// [`ColumnDecode`]: Error::ColumnDecode
107    /// [`ColumnNotFound`]: Error::ColumnNotFound
108    /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds
109    ///
110    fn try_get<'r, T, I>(&'r self, index: I) -> Result<T, Error>
111    where
112        I: ColumnIndex<Self>,
113        T: Decode<'r, Self::Database> + Type<Self::Database>,
114    {
115        let value = self.try_get_raw(&index)?;
116
117        if !value.is_null() {
118            let ty = value.type_info();
119
120            if !ty.is_null() && !T::compatible(&ty) {
121                return Err(Error::ColumnDecode {
122                    index: format!("{index:?}"),
123                    source: mismatched_types::<Self::Database, T>(&ty),
124                });
125            }
126        }
127
128        T::decode(value).map_err(|source| Error::ColumnDecode {
129            index: format!("{index:?}"),
130            source,
131        })
132    }
133
134    /// Index into the database row and decode a single value.
135    ///
136    /// Unlike [`try_get`](Self::try_get), this method does not check that the type
137    /// being returned from the database is compatible with the Rust type and blindly tries
138    /// to decode the value.
139    ///
140    /// # Errors
141    ///
142    ///  * [`ColumnNotFound`] if the column by the given name was not found.
143    ///  * [`ColumnIndexOutOfBounds`] if the `usize` index was greater than the number of columns in the row.
144    ///  * [`ColumnDecode`] if the value could not be decoded into the requested type.
145    ///
146    /// [`ColumnDecode`]: Error::ColumnDecode
147    /// [`ColumnNotFound`]: Error::ColumnNotFound
148    /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds
149    ///
150    #[inline]
151    fn try_get_unchecked<'r, T, I>(&'r self, index: I) -> Result<T, Error>
152    where
153        I: ColumnIndex<Self>,
154        T: Decode<'r, Self::Database>,
155    {
156        let value = self.try_get_raw(&index)?;
157
158        T::decode(value).map_err(|source| Error::ColumnDecode {
159            index: format!("{index:?}"),
160            source,
161        })
162    }
163
164    /// Index into the database row and decode a single value.
165    ///
166    /// # Errors
167    ///
168    ///  * [`ColumnNotFound`] if the column by the given name was not found.
169    ///  * [`ColumnIndexOutOfBounds`] if the `usize` index was greater than the number of columns in the row.
170    ///
171    /// [`ColumnNotFound`]: Error::ColumnNotFound
172    /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds
173    ///
174    fn try_get_raw<I>(&self, index: I) -> Result<<Self::Database as Database>::ValueRef<'_>, Error>
175    where
176        I: ColumnIndex<Self>;
177}