mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-27 03:51:38 +08:00
224 lines
7.1 KiB
Rust
224 lines
7.1 KiB
Rust
use std::{convert, result};
|
|
use std::marker::PhantomData;
|
|
|
|
use super::{Statement, Error, Result};
|
|
use types::{FromSql, FromSqlError};
|
|
use statement::StatementCrateImpl;
|
|
|
|
/// An handle for the resulting rows of a query.
|
|
pub struct Rows<'stmt> {
|
|
stmt: Option<&'stmt Statement<'stmt>>,
|
|
}
|
|
|
|
impl<'stmt> Rows<'stmt> {
|
|
fn reset(&mut self) {
|
|
if let Some(stmt) = self.stmt.take() {
|
|
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`.
|
|
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: stmt,
|
|
phantom: PhantomData,
|
|
}))
|
|
}
|
|
Ok(false) => {
|
|
self.reset();
|
|
None
|
|
}
|
|
Err(err) => {
|
|
self.reset();
|
|
Some(Err(err))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TODO: This trait lets us have "pub(crate)" visibility on some methods. Remove this
|
|
// once pub(crate) is stable.
|
|
pub trait RowsCrateImpl<'stmt> {
|
|
fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt>;
|
|
fn get_expected_row<'a>(&'a mut self) -> Result<Row<'a, 'stmt>>;
|
|
}
|
|
|
|
impl<'stmt> RowsCrateImpl<'stmt> for Rows<'stmt> {
|
|
fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
|
|
Rows { stmt: Some(stmt) }
|
|
}
|
|
|
|
fn get_expected_row<'a>(&'a mut self) -> Result<Row<'a, 'stmt>> {
|
|
match self.next() {
|
|
Some(row) => row,
|
|
None => Err(Error::QueryReturnedNoRows),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'stmt> Drop for Rows<'stmt> {
|
|
fn drop(&mut self) {
|
|
self.reset();
|
|
}
|
|
}
|
|
|
|
/// An iterator over the mapped resulting rows of a query.
|
|
pub struct MappedRows<'stmt, F> {
|
|
rows: Rows<'stmt>,
|
|
map: F,
|
|
}
|
|
|
|
// TODO: This trait lets us have "pub(crate)" visibility on some methods. Remove this
|
|
// once pub(crate) is stable.
|
|
pub trait MappedRowsCrateImpl<'stmt, T, F> {
|
|
fn new(rows: Rows<'stmt>, f: F) -> MappedRows<'stmt, F>;
|
|
}
|
|
|
|
impl<'stmt, T, F> MappedRowsCrateImpl<'stmt, T, F> for MappedRows<'stmt, F>
|
|
where F: FnMut(&Row) -> T
|
|
{
|
|
fn new(rows: Rows<'stmt>, f: F) -> MappedRows<'stmt, F> {
|
|
MappedRows { rows: rows, map: f }
|
|
}
|
|
}
|
|
|
|
impl<'conn, T, F> Iterator for MappedRows<'conn, F>
|
|
where F: FnMut(&Row) -> T
|
|
{
|
|
type Item = Result<T>;
|
|
|
|
fn next(&mut self) -> Option<Result<T>> {
|
|
let map = &mut self.map;
|
|
self.rows
|
|
.next()
|
|
.map(|row_result| row_result.map(|row| (map)(&row)))
|
|
}
|
|
}
|
|
|
|
/// An iterator over the mapped resulting rows of a query, with an Error type
|
|
/// unifying with Error.
|
|
pub struct AndThenRows<'stmt, F> {
|
|
rows: Rows<'stmt>,
|
|
map: F,
|
|
}
|
|
|
|
// TODO: This trait lets us have "pub(crate)" visibility on some methods. Remove this
|
|
// once pub(crate) is stable.
|
|
pub trait AndThenRowsCrateImpl<'stmt, T, E, F> {
|
|
fn new(rows: Rows<'stmt>, f: F) -> AndThenRows<'stmt, F>;
|
|
}
|
|
|
|
impl<'stmt, T, E, F> AndThenRowsCrateImpl<'stmt, T, E, F> for AndThenRows<'stmt, F>
|
|
where F: FnMut(&Row) -> result::Result<T, E>
|
|
{
|
|
fn new(rows: Rows<'stmt>, f: F) -> AndThenRows<'stmt, F> {
|
|
AndThenRows { rows: rows, map: f }
|
|
}
|
|
}
|
|
|
|
impl<'stmt, T, E, F> Iterator for AndThenRows<'stmt, F>
|
|
where E: convert::From<Error>,
|
|
F: FnMut(&Row) -> result::Result<T, E>
|
|
{
|
|
type Item = result::Result<T, E>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let map = &mut self.map;
|
|
self.rows
|
|
.next()
|
|
.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> {
|
|
stmt: &'stmt Statement<'stmt>,
|
|
phantom: PhantomData<&'a ()>,
|
|
}
|
|
|
|
impl<'a, 'stmt> Row<'a, 'stmt> {
|
|
/// Get the value of a particular column of the result row.
|
|
///
|
|
/// ## Failure
|
|
///
|
|
/// Panics if calling `row.get_checked(idx)` would return an error, including:
|
|
///
|
|
/// * If the underlying SQLite column type is not a valid type as a source for `T`
|
|
/// * If the underlying SQLite integral value is outside the range representable by `T`
|
|
/// * If `idx` is outside the range of columns in the returned query
|
|
pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
|
|
self.get_checked(idx).unwrap()
|
|
}
|
|
|
|
/// Get the value of a particular column of the result row.
|
|
///
|
|
/// ## Failure
|
|
///
|
|
/// Returns an `Error::InvalidColumnType` if the underlying SQLite column
|
|
/// type is not a valid type as a source for `T`.
|
|
///
|
|
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid column range
|
|
/// for this row.
|
|
///
|
|
/// Returns an `Error::InvalidColumnName` if `idx` is not a valid column name
|
|
/// for this row.
|
|
pub fn get_checked<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
|
|
let idx = try!(idx.idx(self.stmt));
|
|
let value = self.stmt.value_ref(idx);
|
|
FromSql::column_result(value).map_err(|err| match err {
|
|
FromSqlError::InvalidType => {
|
|
Error::InvalidColumnType(idx,
|
|
value.data_type())
|
|
}
|
|
FromSqlError::OutOfRange(i) => {
|
|
Error::IntegralValueOutOfRange(idx, i)
|
|
}
|
|
FromSqlError::Other(err) => {
|
|
Error::FromSqlConversionFailure(idx as usize, value.data_type(), err)
|
|
}
|
|
})
|
|
}
|
|
|
|
/// Return the number of columns in the current row.
|
|
pub fn column_count(&self) -> i32 {
|
|
self.stmt.column_count()
|
|
}
|
|
}
|
|
|
|
/// A trait implemented by types that can index into columns of a row.
|
|
pub trait RowIndex {
|
|
/// Returns the index of the appropriate column, or `None` if no such
|
|
/// column exists.
|
|
fn idx(&self, stmt: &Statement) -> Result<i32>;
|
|
}
|
|
|
|
impl RowIndex for i32 {
|
|
#[inline]
|
|
fn idx(&self, stmt: &Statement) -> Result<i32> {
|
|
if *self < 0 || *self >= stmt.column_count() {
|
|
Err(Error::InvalidColumnIndex(*self))
|
|
} else {
|
|
Ok(*self)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> RowIndex for &'a str {
|
|
#[inline]
|
|
fn idx(&self, stmt: &Statement) -> Result<i32> {
|
|
stmt.column_index(*self)
|
|
}
|
|
}
|