1use crate::row::sealed::{AsName, Sealed};
4use crate::simple_query::SimpleColumn;
5use crate::statement::Column;
6use crate::types::{FromSql, Type, WrongType};
7use crate::{Error, Statement};
8use fallible_iterator::FallibleIterator;
9use postgres_protocol::message::backend::DataRowBody;
10use std::fmt;
11use std::io;
12use std::ops::Range;
13use std::str;
14use std::sync::Arc;
15
16mod sealed {
17 pub trait Sealed {}
18
19 pub trait AsName {
20 fn as_name(&self) -> &str;
21 }
22}
23
24impl AsName for Column {
25 fn as_name(&self) -> &str {
26 self.name()
27 }
28}
29
30impl AsName for String {
31 fn as_name(&self) -> &str {
32 self
33 }
34}
35
36pub trait RowIndex: Sealed {
40 #[doc(hidden)]
41 fn __idx<T>(&self, columns: &[T]) -> Option<usize>
42 where
43 T: AsName;
44}
45
46impl Sealed for usize {}
47
48impl RowIndex for usize {
49 #[inline]
50 fn __idx<T>(&self, columns: &[T]) -> Option<usize>
51 where
52 T: AsName,
53 {
54 if *self >= columns.len() {
55 None
56 } else {
57 Some(*self)
58 }
59 }
60}
61
62impl Sealed for str {}
63
64impl RowIndex for str {
65 #[inline]
66 fn __idx<T>(&self, columns: &[T]) -> Option<usize>
67 where
68 T: AsName,
69 {
70 if let Some(idx) = columns.iter().position(|d| d.as_name() == self) {
71 return Some(idx);
72 };
73
74 columns
78 .iter()
79 .position(|d| d.as_name().eq_ignore_ascii_case(self))
80 }
81}
82
83impl<T> Sealed for &T where T: ?Sized + Sealed {}
84
85impl<T> RowIndex for &T
86where
87 T: ?Sized + RowIndex,
88{
89 #[inline]
90 fn __idx<U>(&self, columns: &[U]) -> Option<usize>
91 where
92 U: AsName,
93 {
94 T::__idx(*self, columns)
95 }
96}
97
98#[derive(Clone)]
100pub struct Row {
101 statement: Statement,
102 body: DataRowBody,
103 ranges: Vec<Option<Range<usize>>>,
104}
105
106impl fmt::Debug for Row {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 f.debug_struct("Row")
109 .field("columns", &self.columns())
110 .finish()
111 }
112}
113
114impl Row {
115 pub(crate) fn new(statement: Statement, body: DataRowBody) -> Result<Row, Error> {
116 let ranges = body.ranges().collect().map_err(Error::parse)?;
117 let row = Row {
118 statement,
119 body,
120 ranges,
121 };
122 if row.ranges.len() != row.statement.columns().len() {
126 return Err(Error::parse(io::Error::new(
127 io::ErrorKind::InvalidData,
128 "DataRow field count does not match the number of columns",
129 )));
130 }
131 Ok(row)
132 }
133
134 pub fn columns(&self) -> &[Column] {
136 self.statement.columns()
137 }
138
139 pub fn is_empty(&self) -> bool {
141 self.len() == 0
142 }
143
144 pub fn len(&self) -> usize {
146 self.columns().len()
147 }
148
149 #[track_caller]
157 pub fn get<'a, I, T>(&'a self, idx: I) -> T
158 where
159 I: RowIndex + fmt::Display,
160 T: FromSql<'a>,
161 {
162 match self.get_inner(&idx) {
163 Ok(ok) => ok,
164 Err(err) => panic!("error retrieving column {}: {}", idx, err),
165 }
166 }
167
168 pub fn try_get<'a, I, T>(&'a self, idx: I) -> Result<T, Error>
170 where
171 I: RowIndex + fmt::Display,
172 T: FromSql<'a>,
173 {
174 self.get_inner(&idx)
175 }
176
177 fn get_inner<'a, I, T>(&'a self, idx: &I) -> Result<T, Error>
178 where
179 I: RowIndex + fmt::Display,
180 T: FromSql<'a>,
181 {
182 let idx = match idx.__idx(self.columns()) {
183 Some(idx) => idx,
184 None => return Err(Error::column(idx.to_string())),
185 };
186
187 let ty = self.columns()[idx].type_();
188 if !T::accepts(ty) {
189 return Err(Error::from_sql(
190 Box::new(WrongType::new::<T>(ty.clone())),
191 idx,
192 ));
193 }
194
195 FromSql::from_sql_nullable(ty, self.col_buffer(idx)).map_err(|e| Error::from_sql(e, idx))
196 }
197
198 pub fn raw_size_bytes(&self) -> usize {
200 self.body.buffer_bytes().len()
201 }
202
203 fn col_buffer(&self, idx: usize) -> Option<&[u8]> {
205 let range = self.ranges[idx].to_owned()?;
206 Some(&self.body.buffer()[range])
207 }
208}
209
210impl AsName for SimpleColumn {
211 fn as_name(&self) -> &str {
212 self.name()
213 }
214}
215
216#[derive(Debug)]
218pub struct SimpleQueryRow {
219 columns: Arc<[SimpleColumn]>,
220 body: DataRowBody,
221 ranges: Vec<Option<Range<usize>>>,
222}
223
224impl SimpleQueryRow {
225 #[allow(clippy::new_ret_no_self)]
226 pub(crate) fn new(
227 columns: Arc<[SimpleColumn]>,
228 body: DataRowBody,
229 ) -> Result<SimpleQueryRow, Error> {
230 let ranges = body.ranges().collect().map_err(Error::parse)?;
231 let row = SimpleQueryRow {
232 columns,
233 body,
234 ranges,
235 };
236 if row.ranges.len() != row.columns.len() {
240 return Err(Error::parse(io::Error::new(
241 io::ErrorKind::InvalidData,
242 "DataRow field count does not match the number of columns",
243 )));
244 }
245 Ok(row)
246 }
247
248 pub fn columns(&self) -> &[SimpleColumn] {
250 &self.columns
251 }
252
253 pub fn is_empty(&self) -> bool {
255 self.len() == 0
256 }
257
258 pub fn len(&self) -> usize {
260 self.columns.len()
261 }
262
263 #[track_caller]
271 pub fn get<I>(&self, idx: I) -> Option<&str>
272 where
273 I: RowIndex + fmt::Display,
274 {
275 match self.get_inner(&idx) {
276 Ok(ok) => ok,
277 Err(err) => panic!("error retrieving column {}: {}", idx, err),
278 }
279 }
280
281 pub fn try_get<I>(&self, idx: I) -> Result<Option<&str>, Error>
283 where
284 I: RowIndex + fmt::Display,
285 {
286 self.get_inner(&idx)
287 }
288
289 fn get_inner<I>(&self, idx: &I) -> Result<Option<&str>, Error>
290 where
291 I: RowIndex + fmt::Display,
292 {
293 let idx = match idx.__idx(&self.columns) {
294 Some(idx) => idx,
295 None => return Err(Error::column(idx.to_string())),
296 };
297
298 let buf = self.ranges[idx].clone().map(|r| &self.body.buffer()[r]);
299 FromSql::from_sql_nullable(&Type::TEXT, buf).map_err(|e| Error::from_sql(e, idx))
300 }
301}
302
303#[cfg(test)]
304mod test {
305 use bytes::BytesMut;
306 use postgres_protocol::message::backend::{DataRowBody, Message};
307
308 use super::*;
309
310 fn data_row(field_count: u16, fields: &[&[u8]]) -> DataRowBody {
311 let mut body = BytesMut::new();
312 body.extend_from_slice(&field_count.to_be_bytes());
313 for field in fields {
314 body.extend_from_slice(&(field.len() as i32).to_be_bytes());
315 body.extend_from_slice(field);
316 }
317
318 let mut buf = BytesMut::new();
319 buf.extend_from_slice(b"D");
320 buf.extend_from_slice(&(body.len() as i32 + 4).to_be_bytes());
321 buf.extend_from_slice(&body);
322
323 match Message::parse(&mut buf).unwrap().unwrap() {
324 Message::DataRow(body) => body,
325 _ => unreachable!("expected DataRow"),
326 }
327 }
328
329 fn column(name: &str) -> Column {
330 Column {
331 name: name.to_string(),
332 table_oid: None,
333 column_id: None,
334 type_modifier: 0,
335 r#type: Type::TEXT,
336 }
337 }
338
339 #[test]
340 fn fewer_data_row_fields_than_columns_is_rejected() {
341 let body = data_row(1, &[b""]);
344 let statement = Statement::unnamed(vec![], vec![column("a"), column("b")]);
345 assert!(Row::new(statement, body).is_err());
346 }
347
348 #[test]
349 fn matching_data_row_field_count_is_accepted() {
350 let body = data_row(2, &[b"x", b"y"]);
351 let statement = Statement::unnamed(vec![], vec![column("a"), column("b")]);
352 assert!(Row::new(statement, body).is_ok());
353 }
354}