mirror of
https://github.com/isar/rusqlite.git
synced 2025-09-16 04:32:19 +08:00
Make Rows
implement FallibleStreamingIterator
This commit is contained in:
101
src/row.rs
101
src/row.rs
@@ -1,12 +1,12 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::{convert, result};
|
||||
|
||||
use super::{Error, Result, Statement};
|
||||
use super::{Error, FallibleStreamingIterator, Result, Statement};
|
||||
use crate::types::{FromSql, FromSqlError, ValueRef};
|
||||
|
||||
/// An handle for the resulting rows of a query.
|
||||
pub struct Rows<'stmt> {
|
||||
stmt: Option<&'stmt Statement<'stmt>>,
|
||||
row: Option<Row<'stmt>>,
|
||||
}
|
||||
|
||||
impl<'stmt> Rows<'stmt> {
|
||||
@@ -15,45 +15,19 @@ impl<'stmt> Rows<'stmt> {
|
||||
stmt.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to get the next row from the query. Returns `Some(Ok(Row))` if
|
||||
/// there is another row, `Some(Err(...))` if there was an error
|
||||
/// getting the next row, and `None` if all rows have been retrieved.
|
||||
///
|
||||
/// ## Note
|
||||
///
|
||||
/// This interface is not compatible with Rust's `Iterator` trait, because
|
||||
/// the lifetime of the returned row is tied to the lifetime of `self`.
|
||||
/// This is a "streaming iterator". For a more natural interface,
|
||||
/// consider using `query_map` or `query_and_then` instead, which
|
||||
/// return types that implement `Iterator`.
|
||||
#[allow(clippy::should_implement_trait)] // cannot implement Iterator
|
||||
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
|
||||
self.stmt.and_then(|stmt| match stmt.step() {
|
||||
Ok(true) => Some(Ok(Row {
|
||||
stmt,
|
||||
phantom: PhantomData,
|
||||
})),
|
||||
Ok(false) => {
|
||||
self.reset();
|
||||
None
|
||||
}
|
||||
Err(err) => {
|
||||
self.reset();
|
||||
Some(Err(err))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'stmt> Rows<'stmt> {
|
||||
pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
|
||||
Rows { stmt: Some(stmt) }
|
||||
Rows {
|
||||
stmt: Some(stmt),
|
||||
row: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_expected_row<'a>(&'a mut self) -> Result<Row<'a, 'stmt>> {
|
||||
match self.next() {
|
||||
Some(row) => row,
|
||||
pub(crate) fn get_expected_row(&mut self) -> Result<&Row<'stmt>> {
|
||||
match self.next()? {
|
||||
Some(row) => Ok(row),
|
||||
None => Err(Error::QueryReturnedNoRows),
|
||||
}
|
||||
}
|
||||
@@ -73,7 +47,7 @@ pub struct MappedRows<'stmt, F> {
|
||||
|
||||
impl<'stmt, T, F> MappedRows<'stmt, F>
|
||||
where
|
||||
F: FnMut(&Row<'_, '_>) -> T,
|
||||
F: FnMut(&Row<'_>) -> T,
|
||||
{
|
||||
pub(crate) fn new(rows: Rows<'stmt>, f: F) -> MappedRows<'stmt, F> {
|
||||
MappedRows { rows, map: f }
|
||||
@@ -82,7 +56,7 @@ where
|
||||
|
||||
impl<T, F> Iterator for MappedRows<'_, F>
|
||||
where
|
||||
F: FnMut(&Row<'_, '_>) -> T,
|
||||
F: FnMut(&Row<'_>) -> T,
|
||||
{
|
||||
type Item = Result<T>;
|
||||
|
||||
@@ -90,6 +64,7 @@ where
|
||||
let map = &mut self.map;
|
||||
self.rows
|
||||
.next()
|
||||
.transpose()
|
||||
.map(|row_result| row_result.map(|row| (map)(&row)))
|
||||
}
|
||||
}
|
||||
@@ -103,7 +78,7 @@ pub struct AndThenRows<'stmt, F> {
|
||||
|
||||
impl<'stmt, T, E, F> AndThenRows<'stmt, F>
|
||||
where
|
||||
F: FnMut(&Row<'_, '_>) -> result::Result<T, E>,
|
||||
F: FnMut(&Row<'_>) -> result::Result<T, E>,
|
||||
{
|
||||
pub(crate) fn new(rows: Rows<'stmt>, f: F) -> AndThenRows<'stmt, F> {
|
||||
AndThenRows { rows, map: f }
|
||||
@@ -113,7 +88,7 @@ where
|
||||
impl<T, E, F> Iterator for AndThenRows<'_, F>
|
||||
where
|
||||
E: convert::From<Error>,
|
||||
F: FnMut(&Row<'_, '_>) -> result::Result<T, E>,
|
||||
F: FnMut(&Row<'_>) -> result::Result<T, E>,
|
||||
{
|
||||
type Item = result::Result<T, E>;
|
||||
|
||||
@@ -121,17 +96,51 @@ where
|
||||
let map = &mut self.map;
|
||||
self.rows
|
||||
.next()
|
||||
.transpose()
|
||||
.map(|row_result| row_result.map_err(E::from).and_then(|row| (map)(&row)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A single result row of a query.
|
||||
pub struct Row<'a, 'stmt: 'a> {
|
||||
stmt: &'stmt Statement<'stmt>,
|
||||
phantom: PhantomData<&'a ()>,
|
||||
impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
|
||||
type Error = Error;
|
||||
type Item = Row<'stmt>;
|
||||
|
||||
fn advance(&mut self) -> Result<()> {
|
||||
match self.stmt {
|
||||
Some(ref stmt) => match stmt.step() {
|
||||
Ok(true) => {
|
||||
self.row = Some(Row { stmt });
|
||||
Ok(())
|
||||
}
|
||||
Ok(false) => {
|
||||
self.reset();
|
||||
self.row = None;
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
self.reset();
|
||||
self.row = None;
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
self.row = None;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self) -> Option<&Row<'stmt>> {
|
||||
self.row.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'stmt> Row<'a, 'stmt> {
|
||||
/// A single result row of a query.
|
||||
pub struct Row<'stmt> {
|
||||
stmt: &'stmt Statement<'stmt>,
|
||||
}
|
||||
|
||||
impl<'stmt> Row<'stmt> {
|
||||
/// Get the value of a particular column of the result row.
|
||||
///
|
||||
/// ## Failure
|
||||
@@ -193,7 +202,7 @@ impl<'a, 'stmt> Row<'a, 'stmt> {
|
||||
///
|
||||
/// Returns an `Error::InvalidColumnName` if `idx` is not a valid column
|
||||
/// name for this row.
|
||||
pub fn get_raw_checked<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'a>> {
|
||||
pub fn get_raw_checked<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'_>> {
|
||||
let idx = idx.idx(self.stmt)?;
|
||||
// Narrowing from `ValueRef<'stmt>` (which `self.stmt.value_ref(idx)`
|
||||
// returns) to `ValueRef<'a>` is needed because it's only valid until
|
||||
@@ -217,7 +226,7 @@ impl<'a, 'stmt> Row<'a, 'stmt> {
|
||||
///
|
||||
/// * If `idx` is outside the range of columns in the returned query.
|
||||
/// * If `idx` is not a valid column name for this row.
|
||||
pub fn get_raw<I: RowIndex>(&self, idx: I) -> ValueRef<'a> {
|
||||
pub fn get_raw<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
|
||||
self.get_raw_checked(idx).unwrap()
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user