rusqlite/src/row.rs

254 lines
8.0 KiB
Rust
Raw Normal View History

use std::marker::PhantomData;
2018-08-11 18:48:21 +08:00
use std::{convert, result};
2018-08-11 18:48:21 +08:00
use super::{Error, Result, Statement};
2018-10-31 03:11:35 +08:00
use crate::types::{FromSql, FromSqlError, ValueRef};
/// 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();
}
}
2018-08-17 00:29:46 +08:00
/// 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
///
2018-08-17 00:29:46 +08:00
/// 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`.
#[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))] // cannot implement Iterator
pub fn next<'a>(&'a mut self) -> Option<Result<Row<'a, 'stmt>>> {
2018-08-11 18:48:21 +08:00
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))
}
})
}
}
2018-08-01 04:17:17 +08:00
impl<'stmt> Rows<'stmt> {
pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
Rows { stmt: Some(stmt) }
}
2018-08-01 04:17:17 +08:00
pub(crate) 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,
}
2018-08-01 04:17:17 +08:00
impl<'stmt, T, F> MappedRows<'stmt, F>
2018-08-11 18:48:21 +08:00
where
F: FnMut(&Row) -> T,
{
2018-08-01 04:17:17 +08:00
pub(crate) fn new(rows: Rows<'stmt>, f: F) -> MappedRows<'stmt, F> {
2018-05-05 01:55:55 +08:00
MappedRows { rows, map: f }
}
}
impl<'conn, T, F> Iterator for MappedRows<'conn, F>
2018-08-11 18:48:21 +08:00
where
F: FnMut(&Row) -> T,
{
type Item = Result<T>;
fn next(&mut self) -> Option<Result<T>> {
let map = &mut self.map;
2017-04-08 01:43:24 +08:00
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,
}
2018-08-01 04:17:17 +08:00
impl<'stmt, T, E, F> AndThenRows<'stmt, F>
2018-08-11 18:48:21 +08:00
where
F: FnMut(&Row) -> result::Result<T, E>,
{
2018-08-01 04:17:17 +08:00
pub(crate) fn new(rows: Rows<'stmt>, f: F) -> AndThenRows<'stmt, F> {
2018-05-05 01:55:55 +08:00
AndThenRows { rows, map: f }
}
}
impl<'stmt, T, E, F> Iterator for AndThenRows<'stmt, F>
2018-08-11 18:48:21 +08:00
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;
2017-04-08 01:43:24 +08:00
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: 'a> {
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
///
2018-08-17 00:29:46 +08:00
/// Panics if calling `row.get_checked(idx)` would return an error,
/// including:
///
2018-08-17 00:29:46 +08:00
/// * If the underlying SQLite column type is not a valid type as a
/// source for `T`
2018-10-28 15:51:02 +08:00
/// * 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`.
///
2018-08-17 00:29:46 +08:00
/// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid
/// column range for this row.
///
2018-08-17 00:29:46 +08:00
/// Returns an `Error::InvalidColumnName` if `idx` is not a valid column
/// name for this row.
///
/// If the result type is i128 (which requires the `i128_blob` feature to be
/// enabled), and the underlying SQLite column is a blob whose size is not
/// 16 bytes, `Error::InvalidColumnType` will also be returned.
pub fn get_checked<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
2018-10-31 03:11:35 +08:00
let idx = idx.idx(self.stmt)?;
let value = self.stmt.value_ref(idx);
FromSql::column_result(value).map_err(|err| match err {
2018-08-11 18:48:21 +08:00
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)
}
#[cfg(feature = "i128_blob")]
2018-10-28 15:51:02 +08:00
FromSqlError::InvalidI128Size(_) => Error::InvalidColumnType(idx, value.data_type()),
2018-08-11 18:48:21 +08:00
})
}
/// Get the value of a particular column of the result row as a `ValueRef`,
/// allowing data to be read out of a row without copying.
///
/// This `ValueRef` is valid only as long as this Row, which is enforced by
/// it's lifetime. This means that while this method is completely safe,
/// it can be somewhat difficult to use, and most callers will be better
/// served by `get` or `get_checked`.
///
/// ## Failure
///
/// 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_raw_checked<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'a>> {
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
// the next call to sqlite3_step.
let val_ref = self.stmt.value_ref(idx);
Ok(val_ref)
}
/// Get the value of a particular column of the result row as a `ValueRef`,
/// allowing data to be read out of a row without copying.
///
/// This `ValueRef` is valid only as long as this Row, which is enforced by
/// it's lifetime. This means that while this method is completely safe,
/// it can be difficult to use, and most callers will be better served by
/// `get` or `get_checked`.
///
/// ## Failure
///
/// Panics if calling `row.get_raw_checked(idx)` would return an error,
/// including:
///
/// * 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> {
self.get_raw_checked(idx).unwrap()
}
/// Return the number of columns in the current row.
pub fn column_count(&self) -> usize {
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<usize>;
}
impl RowIndex for usize {
#[inline]
fn idx(&self, stmt: &Statement) -> Result<usize> {
if *self >= stmt.column_count() {
Err(Error::InvalidColumnIndex(*self))
} else {
Ok(*self)
}
}
}
impl<'a> RowIndex for &'a str {
#[inline]
fn idx(&self, stmt: &Statement) -> Result<usize> {
stmt.column_index(*self)
}
}