1use fallible_iterator::FallibleIterator;
2use fallible_streaming_iterator::FallibleStreamingIterator;
3use std::convert;
4
5use super::{Error, Result, Statement};
6use crate::types::{FromSql, FromSqlError, ValueRef};
7
8#[must_use = "Rows is lazy and will do nothing unless consumed"]
10pub struct Rows<'stmt> {
11 pub(crate) stmt: Option<&'stmt Statement<'stmt>>,
12 row: Option<Row<'stmt>>,
13}
14
15impl<'stmt> Rows<'stmt> {
16 #[inline]
17 fn reset(&mut self) -> Result<()> {
18 if let Some(stmt) = self.stmt.take() {
19 stmt.reset()
20 } else {
21 Ok(())
22 }
23 }
24
25 #[allow(clippy::should_implement_trait)] #[inline]
39 pub fn next(&mut self) -> Result<Option<&Row<'stmt>>> {
40 self.advance()?;
41 Ok((*self).get())
42 }
43
44 #[inline]
56 pub fn map<F, B>(self, f: F) -> Map<'stmt, F>
57 where
58 F: FnMut(&Row<'_>) -> Result<B>,
59 {
60 Map { rows: self, f }
61 }
62
63 #[inline]
66 pub fn mapped<F, B>(self, f: F) -> MappedRows<'stmt, F>
67 where
68 F: FnMut(&Row<'_>) -> Result<B>,
69 {
70 MappedRows { rows: self, map: f }
71 }
72
73 #[inline]
77 pub fn and_then<F, T, E>(self, f: F) -> AndThenRows<'stmt, F>
78 where
79 F: FnMut(&Row<'_>) -> Result<T, E>,
80 {
81 AndThenRows { rows: self, map: f }
82 }
83
84 #[must_use]
86 pub fn as_ref(&self) -> Option<&Statement<'stmt>> {
87 self.stmt
88 }
89}
90
91impl<'stmt> Rows<'stmt> {
92 #[inline]
93 pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
94 Rows {
95 stmt: Some(stmt),
96 row: None,
97 }
98 }
99
100 #[inline]
101 pub(crate) fn get_expected_row(&mut self) -> Result<&Row<'stmt>> {
102 match self.next()? {
103 Some(row) => Ok(row),
104 None => Err(Error::QueryReturnedNoRows),
105 }
106 }
107}
108
109impl Drop for Rows<'_> {
110 #[allow(unused_must_use)]
111 #[inline]
112 fn drop(&mut self) {
113 self.reset();
114 }
115}
116
117#[must_use = "iterators are lazy and do nothing unless consumed"]
120pub struct Map<'stmt, F> {
121 rows: Rows<'stmt>,
122 f: F,
123}
124
125impl<F, B> FallibleIterator for Map<'_, F>
126where
127 F: FnMut(&Row<'_>) -> Result<B>,
128{
129 type Error = Error;
130 type Item = B;
131
132 #[inline]
133 fn next(&mut self) -> Result<Option<B>> {
134 match self.rows.next()? {
135 Some(v) => Ok(Some((self.f)(v)?)),
136 None => Ok(None),
137 }
138 }
139}
140
141#[must_use = "iterators are lazy and do nothing unless consumed"]
146pub struct MappedRows<'stmt, F> {
147 rows: Rows<'stmt>,
148 map: F,
149}
150
151impl<T, F> Iterator for MappedRows<'_, F>
152where
153 F: FnMut(&Row<'_>) -> Result<T>,
154{
155 type Item = Result<T>;
156
157 #[inline]
158 fn next(&mut self) -> Option<Result<T>> {
159 let map = &mut self.map;
160 self.rows
161 .next()
162 .transpose()
163 .map(|row_result| row_result.and_then(map))
164 }
165}
166
167#[must_use = "iterators are lazy and do nothing unless consumed"]
170pub struct AndThenRows<'stmt, F> {
171 rows: Rows<'stmt>,
172 map: F,
173}
174
175impl<T, E, F> Iterator for AndThenRows<'_, F>
176where
177 E: From<Error>,
178 F: FnMut(&Row<'_>) -> Result<T, E>,
179{
180 type Item = Result<T, E>;
181
182 #[inline]
183 fn next(&mut self) -> Option<Self::Item> {
184 let map = &mut self.map;
185 self.rows
186 .next()
187 .transpose()
188 .map(|row_result| row_result.map_err(E::from).and_then(map))
189 }
190}
191
192impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
211 type Error = Error;
212 type Item = Row<'stmt>;
213
214 #[inline]
215 fn advance(&mut self) -> Result<()> {
216 if let Some(stmt) = self.stmt {
217 match stmt.step() {
218 Ok(true) => {
219 self.row = Some(Row { stmt });
220 Ok(())
221 }
222 Ok(false) => {
223 let r = self.reset();
224 self.row = None;
225 r
226 }
227 Err(e) => {
228 let _ = self.reset(); self.row = None;
230 Err(e)
231 }
232 }
233 } else {
234 self.row = None;
235 Ok(())
236 }
237 }
238
239 #[inline]
240 fn get(&self) -> Option<&Row<'stmt>> {
241 self.row.as_ref()
242 }
243}
244
245pub struct Row<'stmt> {
247 pub(crate) stmt: &'stmt Statement<'stmt>,
248}
249
250impl<'stmt> Row<'stmt> {
251 #[track_caller]
264 pub fn get_unwrap<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
265 self.get(idx).unwrap()
266 }
267
268 #[track_caller]
285 pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
286 let idx = idx.idx(self.stmt)?;
287 let value = self.stmt.value_ref(idx);
288 FromSql::column_result(value).map_err(|err| match err {
289 FromSqlError::InvalidType => Error::InvalidColumnType(
290 idx,
291 self.stmt.column_name_unwrap(idx).into(),
292 value.data_type(),
293 ),
294 FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
295 FromSqlError::Other(err) => {
296 Error::FromSqlConversionFailure(idx, value.data_type(), err)
297 }
298 FromSqlError::InvalidBlobSize { .. } => {
299 Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
300 }
301 })
302 }
303
304 pub fn get_ref<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'_>> {
320 let idx = idx.idx(self.stmt)?;
321 let val_ref = self.stmt.value_ref(idx);
325 Ok(val_ref)
326 }
327
328 #[track_caller]
344 pub fn get_ref_unwrap<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
345 self.get_ref(idx).unwrap()
346 }
347}
348
349impl<'stmt> AsRef<Statement<'stmt>> for Row<'stmt> {
350 fn as_ref(&self) -> &Statement<'stmt> {
351 self.stmt
352 }
353}
354
355impl<'stmt> std::fmt::Debug for Row<'stmt> {
359 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360 let mut dm = f.debug_map();
361 for c in 0..self.stmt.column_count() {
362 let name = self.stmt.column_name(c);
363 dm.key(&name);
364 let value = self.get_ref(c);
365 match value {
366 Ok(value) => {
367 let dt = value.data_type();
368 match value {
369 ValueRef::Null => {
370 dm.value(&(dt, ()));
371 }
372 ValueRef::Integer(i) => {
373 dm.value(&(dt, i));
374 }
375 ValueRef::Real(f) => {
376 dm.value(&(dt, f));
377 }
378 ValueRef::Text(s) => {
379 dm.value(&(dt, String::from_utf8_lossy(s)));
380 }
381 ValueRef::Blob(b) => {
382 dm.value(&(dt, b.len()));
383 }
384 }
385 }
386 Err(ref _err) => {
387 dm.value(&value);
388 }
389 }
390 }
391 dm.finish()
392 }
393}
394
395mod sealed {
396 pub trait Sealed {}
399 impl Sealed for usize {}
400 impl Sealed for &str {}
401}
402
403pub trait RowIndex: sealed::Sealed {
407 fn idx(&self, stmt: &Statement<'_>) -> Result<usize>;
410}
411
412impl RowIndex for usize {
413 #[inline]
414 fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
415 if *self >= stmt.column_count() {
416 Err(Error::InvalidColumnIndex(*self))
417 } else {
418 Ok(*self)
419 }
420 }
421}
422
423impl RowIndex for &'_ str {
424 #[inline]
425 fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
426 stmt.column_index(self)
427 }
428}
429
430macro_rules! tuple_try_from_row {
431 ($($field:ident),*) => {
432 impl<'a, $($field,)*> convert::TryFrom<&'a Row<'a>> for ($($field,)*) where $($field: FromSql,)* {
433 type Error = crate::Error;
434
435 #[allow(unused_assignments, unused_variables, unused_mut)]
438 fn try_from(row: &'a Row<'a>) -> Result<Self> {
439 let mut index = 0;
440 $(
441 #[allow(non_snake_case)]
442 let $field = row.get::<_, $field>(index)?;
443 index += 1;
444 )*
445 Ok(($($field,)*))
446 }
447 }
448 }
449}
450
451macro_rules! tuples_try_from_row {
452 () => {
453 tuple_try_from_row!();
455 };
456 ($first:ident $(, $remaining:ident)*) => {
457 tuple_try_from_row!($first $(, $remaining)*);
458 tuples_try_from_row!($($remaining),*);
459 };
460}
461
462tuples_try_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
463
464#[cfg(test)]
465mod tests {
466 #![allow(clippy::redundant_closure)] use crate::{Connection, Result};
468
469 #[test]
470 fn test_try_from_row_for_tuple_1() -> Result<()> {
471 use crate::ToSql;
472 use std::convert::TryFrom;
473
474 let conn = Connection::open_in_memory()?;
475 conn.execute(
476 "CREATE TABLE test (a INTEGER)",
477 crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
478 )?;
479 conn.execute("INSERT INTO test VALUES (42)", [])?;
480 let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
481 assert_eq!(val, (42,));
482 let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
483 fail.unwrap_err();
484 Ok(())
485 }
486
487 #[test]
488 fn test_try_from_row_for_tuple_2() -> Result<()> {
489 use std::convert::TryFrom;
490
491 let conn = Connection::open_in_memory()?;
492 conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
493 conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
494 let val = conn.query_row("SELECT a, b FROM test", [], |row| {
495 <(u32, u32)>::try_from(row)
496 })?;
497 assert_eq!(val, (42, 47));
498 let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
499 <(u32, u32, u32)>::try_from(row)
500 });
501 fail.unwrap_err();
502 Ok(())
503 }
504
505 #[test]
506 fn test_try_from_row_for_tuple_16() -> Result<()> {
507 use std::convert::TryFrom;
508
509 let create_table = "CREATE TABLE test (
510 a INTEGER,
511 b INTEGER,
512 c INTEGER,
513 d INTEGER,
514 e INTEGER,
515 f INTEGER,
516 g INTEGER,
517 h INTEGER,
518 i INTEGER,
519 j INTEGER,
520 k INTEGER,
521 l INTEGER,
522 m INTEGER,
523 n INTEGER,
524 o INTEGER,
525 p INTEGER
526 )";
527
528 let insert_values = "INSERT INTO test VALUES (
529 0,
530 1,
531 2,
532 3,
533 4,
534 5,
535 6,
536 7,
537 8,
538 9,
539 10,
540 11,
541 12,
542 13,
543 14,
544 15
545 )";
546
547 type BigTuple = (
548 u32,
549 u32,
550 u32,
551 u32,
552 u32,
553 u32,
554 u32,
555 u32,
556 u32,
557 u32,
558 u32,
559 u32,
560 u32,
561 u32,
562 u32,
563 u32,
564 );
565
566 let conn = Connection::open_in_memory()?;
567 conn.execute(create_table, [])?;
568 conn.execute(insert_values, [])?;
569 let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
570 assert_eq!(val.0, 0);
572 assert_eq!(val.1, 1);
573 assert_eq!(val.2, 2);
574 assert_eq!(val.3, 3);
575 assert_eq!(val.4, 4);
576 assert_eq!(val.5, 5);
577 assert_eq!(val.6, 6);
578 assert_eq!(val.7, 7);
579 assert_eq!(val.8, 8);
580 assert_eq!(val.9, 9);
581 assert_eq!(val.10, 10);
582 assert_eq!(val.11, 11);
583 assert_eq!(val.12, 12);
584 assert_eq!(val.13, 13);
585 assert_eq!(val.14, 14);
586 assert_eq!(val.15, 15);
587
588 Ok(())
590 }
591
592 #[test]
593 #[cfg(feature = "bundled")]
594 fn pathological_case() -> Result<()> {
595 let conn = Connection::open_in_memory()?;
596 conn.execute_batch(
597 "CREATE TABLE foo(x);
598 CREATE TRIGGER oops BEFORE INSERT ON foo BEGIN SELECT RAISE(FAIL, 'Boom'); END;",
599 )?;
600 let mut stmt = conn.prepare("INSERT INTO foo VALUES (0) RETURNING rowid;")?;
601 {
602 let iterator_count = stmt.query_map([], |_| Ok(()))?.count();
603 assert_eq!(1, iterator_count); use fallible_streaming_iterator::FallibleStreamingIterator;
605 let fallible_iterator_count = stmt.query([])?.count().unwrap_or(0);
606 assert_eq!(0, fallible_iterator_count);
607 }
608 {
609 let iterator_last = stmt.query_map([], |_| Ok(()))?.last();
610 assert!(iterator_last.is_some()); use fallible_iterator::FallibleIterator;
612 let fallible_iterator_last = stmt.query([])?.map(|_| Ok(())).last();
613 assert!(fallible_iterator_last.is_err());
614 }
615 Ok(())
616 }
617}