Line data Source code
1 : //! Rows.
2 :
3 : use crate::row::sealed::{AsName, Sealed};
4 : use crate::simple_query::SimpleColumn;
5 : use crate::statement::Column;
6 : use crate::types::{FromSql, Type, WrongType};
7 : use crate::{Error, Statement};
8 : use fallible_iterator::FallibleIterator;
9 : use postgres_protocol2::message::backend::DataRowBody;
10 : use postgres_types2::{Format, WrongFormat};
11 : use std::fmt;
12 : use std::ops::Range;
13 : use std::str;
14 : use std::sync::Arc;
15 :
16 : mod sealed {
17 : pub trait Sealed {}
18 :
19 : pub trait AsName {
20 : fn as_name(&self) -> &str;
21 : }
22 : }
23 :
24 : impl AsName for Column {
25 0 : fn as_name(&self) -> &str {
26 0 : self.name()
27 0 : }
28 : }
29 :
30 : impl AsName for String {
31 0 : fn as_name(&self) -> &str {
32 0 : self
33 0 : }
34 : }
35 :
36 : /// A trait implemented by types that can index into columns of a row.
37 : ///
38 : /// This cannot be implemented outside of this crate.
39 : pub trait RowIndex: Sealed {
40 : #[doc(hidden)]
41 : fn __idx<T>(&self, columns: &[T]) -> Option<usize>
42 : where
43 : T: AsName;
44 : }
45 :
46 : impl Sealed for usize {}
47 :
48 : impl RowIndex for usize {
49 : #[inline]
50 0 : fn __idx<T>(&self, columns: &[T]) -> Option<usize>
51 0 : where
52 0 : T: AsName,
53 0 : {
54 0 : if *self >= columns.len() {
55 0 : None
56 : } else {
57 0 : Some(*self)
58 : }
59 0 : }
60 : }
61 :
62 : impl Sealed for str {}
63 :
64 : impl RowIndex for str {
65 : #[inline]
66 0 : fn __idx<T>(&self, columns: &[T]) -> Option<usize>
67 0 : where
68 0 : T: AsName,
69 0 : {
70 0 : if let Some(idx) = columns.iter().position(|d| d.as_name() == self) {
71 0 : return Some(idx);
72 0 : };
73 0 :
74 0 : // FIXME ASCII-only case insensitivity isn't really the right thing to
75 0 : // do. Postgres itself uses a dubious wrapper around tolower and JDBC
76 0 : // uses the US locale.
77 0 : columns
78 0 : .iter()
79 0 : .position(|d| d.as_name().eq_ignore_ascii_case(self))
80 0 : }
81 : }
82 :
83 : impl<T> Sealed for &T where T: ?Sized + Sealed {}
84 :
85 : impl<T> RowIndex for &T
86 : where
87 : T: ?Sized + RowIndex,
88 : {
89 : #[inline]
90 0 : fn __idx<U>(&self, columns: &[U]) -> Option<usize>
91 0 : where
92 0 : U: AsName,
93 0 : {
94 0 : T::__idx(*self, columns)
95 0 : }
96 : }
97 :
98 : /// A row of data returned from the database by a query.
99 : pub struct Row {
100 : statement: Statement,
101 : output_format: Format,
102 : body: DataRowBody,
103 : ranges: Vec<Option<Range<usize>>>,
104 : }
105 :
106 : impl fmt::Debug for Row {
107 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 0 : f.debug_struct("Row")
109 0 : .field("columns", &self.columns())
110 0 : .finish()
111 0 : }
112 : }
113 :
114 : impl Row {
115 0 : pub(crate) fn new(
116 0 : statement: Statement,
117 0 : body: DataRowBody,
118 0 : output_format: Format,
119 0 : ) -> Result<Row, Error> {
120 0 : let ranges = body.ranges().collect().map_err(Error::parse)?;
121 0 : Ok(Row {
122 0 : statement,
123 0 : body,
124 0 : ranges,
125 0 : output_format,
126 0 : })
127 0 : }
128 :
129 : /// Returns information about the columns of data in the row.
130 0 : pub fn columns(&self) -> &[Column] {
131 0 : self.statement.columns()
132 0 : }
133 :
134 : /// Determines if the row contains no values.
135 0 : pub fn is_empty(&self) -> bool {
136 0 : self.len() == 0
137 0 : }
138 :
139 : /// Returns the number of values in the row.
140 0 : pub fn len(&self) -> usize {
141 0 : self.columns().len()
142 0 : }
143 :
144 : /// Deserializes a value from the row.
145 : ///
146 : /// The value can be specified either by its numeric index in the row, or by its column name.
147 : ///
148 : /// # Panics
149 : ///
150 : /// Panics if the index is out of bounds or if the value cannot be converted to the specified type.
151 0 : pub fn get<'a, I, T>(&'a self, idx: I) -> T
152 0 : where
153 0 : I: RowIndex + fmt::Display,
154 0 : T: FromSql<'a>,
155 0 : {
156 0 : match self.get_inner(&idx) {
157 0 : Ok(ok) => ok,
158 0 : Err(err) => panic!("error retrieving column {}: {}", idx, err),
159 : }
160 0 : }
161 :
162 : /// Like `Row::get`, but returns a `Result` rather than panicking.
163 0 : pub fn try_get<'a, I, T>(&'a self, idx: I) -> Result<T, Error>
164 0 : where
165 0 : I: RowIndex + fmt::Display,
166 0 : T: FromSql<'a>,
167 0 : {
168 0 : self.get_inner(&idx)
169 0 : }
170 :
171 0 : fn get_inner<'a, I, T>(&'a self, idx: &I) -> Result<T, Error>
172 0 : where
173 0 : I: RowIndex + fmt::Display,
174 0 : T: FromSql<'a>,
175 0 : {
176 0 : let idx = match idx.__idx(self.columns()) {
177 0 : Some(idx) => idx,
178 0 : None => return Err(Error::column(idx.to_string())),
179 : };
180 :
181 0 : let ty = self.columns()[idx].type_();
182 0 : if !T::accepts(ty) {
183 0 : return Err(Error::from_sql(
184 0 : Box::new(WrongType::new::<T>(ty.clone())),
185 0 : idx,
186 0 : ));
187 0 : }
188 0 :
189 0 : FromSql::from_sql_nullable(ty, self.col_buffer(idx)).map_err(|e| Error::from_sql(e, idx))
190 0 : }
191 :
192 : /// Get the raw bytes for the column at the given index.
193 0 : fn col_buffer(&self, idx: usize) -> Option<&[u8]> {
194 0 : let range = self.ranges.get(idx)?.to_owned()?;
195 0 : Some(&self.body.buffer()[range])
196 0 : }
197 :
198 : /// Interpret the column at the given index as text
199 : ///
200 : /// Useful when using query_raw_txt() which sets text transfer mode
201 0 : pub fn as_text(&self, idx: usize) -> Result<Option<&str>, Error> {
202 0 : if self.output_format == Format::Text {
203 0 : match self.col_buffer(idx) {
204 0 : Some(raw) => {
205 0 : FromSql::from_sql(&Type::TEXT, raw).map_err(|e| Error::from_sql(e, idx))
206 : }
207 0 : None => Ok(None),
208 : }
209 : } else {
210 0 : Err(Error::from_sql(Box::new(WrongFormat {}), idx))
211 : }
212 0 : }
213 :
214 : /// Row byte size
215 0 : pub fn body_len(&self) -> usize {
216 0 : self.body.buffer().len()
217 0 : }
218 : }
219 :
220 : impl AsName for SimpleColumn {
221 0 : fn as_name(&self) -> &str {
222 0 : self.name()
223 0 : }
224 : }
225 :
226 : /// A row of data returned from the database by a simple query.
227 : #[derive(Debug)]
228 : pub struct SimpleQueryRow {
229 : columns: Arc<[SimpleColumn]>,
230 : body: DataRowBody,
231 : ranges: Vec<Option<Range<usize>>>,
232 : }
233 :
234 : impl SimpleQueryRow {
235 : #[allow(clippy::new_ret_no_self)]
236 0 : pub(crate) fn new(
237 0 : columns: Arc<[SimpleColumn]>,
238 0 : body: DataRowBody,
239 0 : ) -> Result<SimpleQueryRow, Error> {
240 0 : let ranges = body.ranges().collect().map_err(Error::parse)?;
241 0 : Ok(SimpleQueryRow {
242 0 : columns,
243 0 : body,
244 0 : ranges,
245 0 : })
246 0 : }
247 :
248 : /// Returns information about the columns of data in the row.
249 0 : pub fn columns(&self) -> &[SimpleColumn] {
250 0 : &self.columns
251 0 : }
252 :
253 : /// Determines if the row contains no values.
254 0 : pub fn is_empty(&self) -> bool {
255 0 : self.len() == 0
256 0 : }
257 :
258 : /// Returns the number of values in the row.
259 0 : pub fn len(&self) -> usize {
260 0 : self.columns.len()
261 0 : }
262 :
263 : /// Returns a value from the row.
264 : ///
265 : /// The value can be specified either by its numeric index in the row, or by its column name.
266 : ///
267 : /// # Panics
268 : ///
269 : /// Panics if the index is out of bounds or if the value cannot be converted to the specified type.
270 0 : pub fn get<I>(&self, idx: I) -> Option<&str>
271 0 : where
272 0 : I: RowIndex + fmt::Display,
273 0 : {
274 0 : match self.get_inner(&idx) {
275 0 : Ok(ok) => ok,
276 0 : Err(err) => panic!("error retrieving column {}: {}", idx, err),
277 : }
278 0 : }
279 :
280 : /// Like `SimpleQueryRow::get`, but returns a `Result` rather than panicking.
281 0 : pub fn try_get<I>(&self, idx: I) -> Result<Option<&str>, Error>
282 0 : where
283 0 : I: RowIndex + fmt::Display,
284 0 : {
285 0 : self.get_inner(&idx)
286 0 : }
287 :
288 0 : fn get_inner<I>(&self, idx: &I) -> Result<Option<&str>, Error>
289 0 : where
290 0 : I: RowIndex + fmt::Display,
291 0 : {
292 0 : let idx = match idx.__idx(&self.columns) {
293 0 : Some(idx) => idx,
294 0 : None => return Err(Error::column(idx.to_string())),
295 : };
296 :
297 0 : let buf = self.ranges[idx].clone().map(|r| &self.body.buffer()[r]);
298 0 : FromSql::from_sql_nullable(&Type::TEXT, buf).map_err(|e| Error::from_sql(e, idx))
299 0 : }
300 : }
|