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}