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 : }
|