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}