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 #[expect(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>) -> Self {
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 #[expect(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 Row<'_> {
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 std::fmt::Debug for Row<'_> {
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).expect("valid column index");
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 #[expect(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 use crate::{Connection, Result};
467
468 #[test]
469 fn test_try_from_row_for_tuple_1() -> Result<()> {
470 use crate::ToSql;
471 use std::convert::TryFrom;
472
473 let conn = Connection::open_in_memory()?;
474 conn.execute(
475 "CREATE TABLE test (a INTEGER)",
476 crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
477 )?;
478 conn.execute("INSERT INTO test VALUES (42)", [])?;
479 let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
480 assert_eq!(val, (42,));
481 let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
482 fail.unwrap_err();
483 Ok(())
484 }
485
486 #[test]
487 fn test_try_from_row_for_tuple_2() -> Result<()> {
488 use std::convert::TryFrom;
489
490 let conn = Connection::open_in_memory()?;
491 conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
492 conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
493 let val = conn.query_row("SELECT a, b FROM test", [], |row| {
494 <(u32, u32)>::try_from(row)
495 })?;
496 assert_eq!(val, (42, 47));
497 let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
498 <(u32, u32, u32)>::try_from(row)
499 });
500 fail.unwrap_err();
501 Ok(())
502 }
503
504 #[test]
505 fn test_try_from_row_for_tuple_16() -> Result<()> {
506 use std::convert::TryFrom;
507
508 let create_table = "CREATE TABLE test (
509 a INTEGER,
510 b INTEGER,
511 c INTEGER,
512 d INTEGER,
513 e INTEGER,
514 f INTEGER,
515 g INTEGER,
516 h INTEGER,
517 i INTEGER,
518 j INTEGER,
519 k INTEGER,
520 l INTEGER,
521 m INTEGER,
522 n INTEGER,
523 o INTEGER,
524 p INTEGER
525 )";
526
527 let insert_values = "INSERT INTO test VALUES (
528 0,
529 1,
530 2,
531 3,
532 4,
533 5,
534 6,
535 7,
536 8,
537 9,
538 10,
539 11,
540 12,
541 13,
542 14,
543 15
544 )";
545
546 type BigTuple = (
547 u32,
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 );
564
565 let conn = Connection::open_in_memory()?;
566 conn.execute(create_table, [])?;
567 conn.execute(insert_values, [])?;
568 let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
569 assert_eq!(val.0, 0);
571 assert_eq!(val.1, 1);
572 assert_eq!(val.2, 2);
573 assert_eq!(val.3, 3);
574 assert_eq!(val.4, 4);
575 assert_eq!(val.5, 5);
576 assert_eq!(val.6, 6);
577 assert_eq!(val.7, 7);
578 assert_eq!(val.8, 8);
579 assert_eq!(val.9, 9);
580 assert_eq!(val.10, 10);
581 assert_eq!(val.11, 11);
582 assert_eq!(val.12, 12);
583 assert_eq!(val.13, 13);
584 assert_eq!(val.14, 14);
585 assert_eq!(val.15, 15);
586
587 Ok(())
589 }
590
591 #[test]
592 #[cfg(feature = "bundled")]
593 fn pathological_case() -> Result<()> {
594 let conn = Connection::open_in_memory()?;
595 conn.execute_batch(
596 "CREATE TABLE foo(x);
597 CREATE TRIGGER oops BEFORE INSERT ON foo BEGIN SELECT RAISE(FAIL, 'Boom'); END;",
598 )?;
599 let mut stmt = conn.prepare("INSERT INTO foo VALUES (0) RETURNING rowid;")?;
600 {
601 let iterator_count = stmt.query_map([], |_| Ok(()))?.count();
602 assert_eq!(1, iterator_count); use fallible_streaming_iterator::FallibleStreamingIterator;
604 let fallible_iterator_count = stmt.query([])?.count().unwrap_or(0);
605 assert_eq!(0, fallible_iterator_count);
606 }
607 {
608 let iterator_last = stmt.query_map([], |_| Ok(()))?.last();
609 assert!(iterator_last.is_some()); use fallible_iterator::FallibleIterator;
611 let fallible_iterator_last = stmt.query([])?.map(|_| Ok(())).last();
612 assert!(fallible_iterator_last.is_err());
613 }
614 Ok(())
615 }
616
617 #[test]
618 fn as_ref() -> Result<()> {
619 let conn = Connection::open_in_memory()?;
620 let mut stmt = conn.prepare("SELECT 'Lisa' as name, 1 as id")?;
621 let rows = stmt.query([])?;
622 assert_eq!(rows.as_ref().unwrap().column_count(), 2);
623 Ok(())
624 }
625
626 #[test]
627 fn debug() -> Result<()> {
628 let conn = Connection::open_in_memory()?;
629 let mut stmt = conn.prepare(
630 "SELECT 'Lisa' as name, 1 as id, 3.14 as pi, X'53514C697465' as blob, NULL as void",
631 )?;
632 let mut rows = stmt.query([])?;
633 let row = rows.next()?.unwrap();
634 let s = format!("{row:?}");
635 assert_eq!(
636 s,
637 r#"{"name": (Text, "Lisa"), "id": (Integer, 1), "pi": (Real, 3.14), "blob": (Blob, 6), "void": (Null, ())}"#
638 );
639 Ok(())
640 }
641}