sqlx_core_oldapi/
row.rs

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