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::ops::Range;
12use std::str;
13use std::sync::Arc;
14
15mod sealed {
16 pub trait Sealed {}
17
18 pub trait AsName {
19 fn as_name(&self) -> &str;
20 }
21}
22
23impl AsName for Column {
24 fn as_name(&self) -> &str {
25 self.name()
26 }
27}
28
29impl AsName for String {
30 fn as_name(&self) -> &str {
31 self
32 }
33}
34
35pub trait RowIndex: Sealed {
39 #[doc(hidden)]
40 fn __idx<T>(&self, columns: &[T]) -> Option<usize>
41 where
42 T: AsName;
43}
44
45impl Sealed for usize {}
46
47impl RowIndex for usize {
48 #[inline]
49 fn __idx<T>(&self, columns: &[T]) -> Option<usize>
50 where
51 T: AsName,
52 {
53 if *self >= columns.len() {
54 None
55 } else {
56 Some(*self)
57 }
58 }
59}
60
61impl Sealed for str {}
62
63impl RowIndex for str {
64 #[inline]
65 fn __idx<T>(&self, columns: &[T]) -> Option<usize>
66 where
67 T: AsName,
68 {
69 if let Some(idx) = columns.iter().position(|d| d.as_name() == self) {
70 return Some(idx);
71 };
72
73 columns
77 .iter()
78 .position(|d| d.as_name().eq_ignore_ascii_case(self))
79 }
80}
81
82impl<T> Sealed for &T where T: ?Sized + Sealed {}
83
84impl<T> RowIndex for &T
85where
86 T: ?Sized + RowIndex,
87{
88 #[inline]
89 fn __idx<U>(&self, columns: &[U]) -> Option<usize>
90 where
91 U: AsName,
92 {
93 T::__idx(*self, columns)
94 }
95}
96
97#[derive(Clone)]
99pub struct Row {
100 statement: Statement,
101 body: DataRowBody,
102 ranges: Vec<Option<Range<usize>>>,
103}
104
105impl fmt::Debug for Row {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 f.debug_struct("Row")
108 .field("columns", &self.columns())
109 .finish()
110 }
111}
112
113impl Row {
114 pub(crate) fn new(statement: Statement, body: DataRowBody) -> Result<Row, Error> {
115 let ranges = body.ranges().collect().map_err(Error::parse)?;
116 Ok(Row {
117 statement,
118 body,
119 ranges,
120 })
121 }
122
123 pub fn columns(&self) -> &[Column] {
125 self.statement.columns()
126 }
127
128 pub fn is_empty(&self) -> bool {
130 self.len() == 0
131 }
132
133 pub fn len(&self) -> usize {
135 self.columns().len()
136 }
137
138 #[track_caller]
146 pub fn get<'a, I, T>(&'a self, idx: I) -> T
147 where
148 I: RowIndex + fmt::Display,
149 T: FromSql<'a>,
150 {
151 match self.get_inner(&idx) {
152 Ok(ok) => ok,
153 Err(err) => panic!("error retrieving column {}: {}", idx, err),
154 }
155 }
156
157 pub fn try_get<'a, I, T>(&'a self, idx: I) -> Result<T, Error>
159 where
160 I: RowIndex + fmt::Display,
161 T: FromSql<'a>,
162 {
163 self.get_inner(&idx)
164 }
165
166 fn get_inner<'a, I, T>(&'a self, idx: &I) -> Result<T, Error>
167 where
168 I: RowIndex + fmt::Display,
169 T: FromSql<'a>,
170 {
171 let idx = match idx.__idx(self.columns()) {
172 Some(idx) => idx,
173 None => return Err(Error::column(idx.to_string())),
174 };
175
176 let ty = self.columns()[idx].type_();
177 if !T::accepts(ty) {
178 return Err(Error::from_sql(
179 Box::new(WrongType::new::<T>(ty.clone())),
180 idx,
181 ));
182 }
183
184 FromSql::from_sql_nullable(ty, self.col_buffer(idx)).map_err(|e| Error::from_sql(e, idx))
185 }
186
187 pub fn raw_size_bytes(&self) -> usize {
189 self.body.buffer_bytes().len()
190 }
191
192 fn col_buffer(&self, idx: usize) -> Option<&[u8]> {
194 let range = self.ranges[idx].to_owned()?;
195 Some(&self.body.buffer()[range])
196 }
197}
198
199impl AsName for SimpleColumn {
200 fn as_name(&self) -> &str {
201 self.name()
202 }
203}
204
205#[derive(Debug)]
207pub struct SimpleQueryRow {
208 columns: Arc<[SimpleColumn]>,
209 body: DataRowBody,
210 ranges: Vec<Option<Range<usize>>>,
211}
212
213impl SimpleQueryRow {
214 #[allow(clippy::new_ret_no_self)]
215 pub(crate) fn new(
216 columns: Arc<[SimpleColumn]>,
217 body: DataRowBody,
218 ) -> Result<SimpleQueryRow, Error> {
219 let ranges = body.ranges().collect().map_err(Error::parse)?;
220 Ok(SimpleQueryRow {
221 columns,
222 body,
223 ranges,
224 })
225 }
226
227 pub fn columns(&self) -> &[SimpleColumn] {
229 &self.columns
230 }
231
232 pub fn is_empty(&self) -> bool {
234 self.len() == 0
235 }
236
237 pub fn len(&self) -> usize {
239 self.columns.len()
240 }
241
242 #[track_caller]
250 pub fn get<I>(&self, idx: I) -> Option<&str>
251 where
252 I: RowIndex + fmt::Display,
253 {
254 match self.get_inner(&idx) {
255 Ok(ok) => ok,
256 Err(err) => panic!("error retrieving column {}: {}", idx, err),
257 }
258 }
259
260 pub fn try_get<I>(&self, idx: I) -> Result<Option<&str>, Error>
262 where
263 I: RowIndex + fmt::Display,
264 {
265 self.get_inner(&idx)
266 }
267
268 fn get_inner<I>(&self, idx: &I) -> Result<Option<&str>, Error>
269 where
270 I: RowIndex + fmt::Display,
271 {
272 let idx = match idx.__idx(&self.columns) {
273 Some(idx) => idx,
274 None => return Err(Error::column(idx.to_string())),
275 };
276
277 let buf = self.ranges[idx].clone().map(|r| &self.body.buffer()[r]);
278 FromSql::from_sql_nullable(&Type::TEXT, buf).map_err(|e| Error::from_sql(e, idx))
279 }
280}