mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-22 16:29:20 +08:00
Merge pull request #249 from jgallagher/reorganize-extract-row
Reorganize: Extract Row/Rows and helper types into their own mod file.
This commit is contained in:
commit
ccf1f61127
18
src/cache.rs
18
src/cache.rs
@ -176,16 +176,14 @@ mod test {
|
|||||||
{
|
{
|
||||||
let mut stmt = db.prepare_cached(sql).unwrap();
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
assert_eq!(0,
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
|
|
||||||
}
|
}
|
||||||
assert_eq!(1, cache.len());
|
assert_eq!(1, cache.len());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut stmt = db.prepare_cached(sql).unwrap();
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
assert_eq!(0,
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
|
|
||||||
}
|
}
|
||||||
assert_eq!(1, cache.len());
|
assert_eq!(1, cache.len());
|
||||||
|
|
||||||
@ -203,8 +201,7 @@ mod test {
|
|||||||
{
|
{
|
||||||
let mut stmt = db.prepare_cached(sql).unwrap();
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
assert_eq!(0,
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
|
|
||||||
}
|
}
|
||||||
assert_eq!(1, cache.len());
|
assert_eq!(1, cache.len());
|
||||||
|
|
||||||
@ -214,8 +211,7 @@ mod test {
|
|||||||
{
|
{
|
||||||
let mut stmt = db.prepare_cached(sql).unwrap();
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
assert_eq!(0,
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
|
|
||||||
}
|
}
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
|
|
||||||
@ -223,8 +219,7 @@ mod test {
|
|||||||
{
|
{
|
||||||
let mut stmt = db.prepare_cached(sql).unwrap();
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
assert_eq!(0,
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
|
|
||||||
}
|
}
|
||||||
assert_eq!(1, cache.len());
|
assert_eq!(1, cache.len());
|
||||||
}
|
}
|
||||||
@ -238,8 +233,7 @@ mod test {
|
|||||||
{
|
{
|
||||||
let mut stmt = db.prepare_cached(sql).unwrap();
|
let mut stmt = db.prepare_cached(sql).unwrap();
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
assert_eq!(0,
|
assert_eq!(0, stmt.query_row(&[], |r| r.get::<i32, i64>(0)).unwrap());
|
||||||
stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
|
|
||||||
stmt.discard();
|
stmt.discard();
|
||||||
}
|
}
|
||||||
assert_eq!(0, cache.len());
|
assert_eq!(0, cache.len());
|
||||||
|
177
src/lib.rs
177
src/lib.rs
@ -62,7 +62,6 @@ extern crate lazy_static;
|
|||||||
|
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::convert;
|
use std::convert;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -75,7 +74,7 @@ use std::sync::{Once, ONCE_INIT};
|
|||||||
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
||||||
use std::os::raw::{c_int, c_char};
|
use std::os::raw::{c_int, c_char};
|
||||||
|
|
||||||
use types::{ToSql, FromSql, FromSqlError, ValueRef};
|
use types::{ToSql, ValueRef};
|
||||||
use error::{error_from_sqlite_code, error_from_handle};
|
use error::{error_from_sqlite_code, error_from_handle};
|
||||||
use raw_statement::RawStatement;
|
use raw_statement::RawStatement;
|
||||||
use cache::StatementCache;
|
use cache::StatementCache;
|
||||||
@ -83,6 +82,9 @@ use cache::StatementCache;
|
|||||||
pub use statement::Statement;
|
pub use statement::Statement;
|
||||||
use statement::StatementCrateImpl;
|
use statement::StatementCrateImpl;
|
||||||
|
|
||||||
|
pub use row::{Row, Rows, MappedRows, AndThenRows};
|
||||||
|
use row::RowsCrateImpl;
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub use transaction::{SqliteTransaction, SqliteTransactionBehavior};
|
pub use transaction::{SqliteTransaction, SqliteTransactionBehavior};
|
||||||
pub use transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
|
pub use transaction::{DropBehavior, Savepoint, Transaction, TransactionBehavior};
|
||||||
@ -105,6 +107,7 @@ mod transaction;
|
|||||||
mod cache;
|
mod cache;
|
||||||
mod error;
|
mod error;
|
||||||
mod raw_statement;
|
mod raw_statement;
|
||||||
|
mod row;
|
||||||
mod statement;
|
mod statement;
|
||||||
#[cfg(feature = "load_extension")]
|
#[cfg(feature = "load_extension")]
|
||||||
mod load_extension_guard;
|
mod load_extension_guard;
|
||||||
@ -865,185 +868,15 @@ impl Drop for InnerConnection {
|
|||||||
#[deprecated(since = "0.6.0", note = "Use Statement instead")]
|
#[deprecated(since = "0.6.0", note = "Use Statement instead")]
|
||||||
pub type SqliteStatement<'conn> = Statement<'conn>;
|
pub type SqliteStatement<'conn> = Statement<'conn>;
|
||||||
|
|
||||||
/// An iterator over the mapped resulting rows of a query.
|
|
||||||
pub struct MappedRows<'stmt, F> {
|
|
||||||
rows: Rows<'stmt>,
|
|
||||||
map: F,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'stmt, T, F> Iterator for MappedRows<'stmt, 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Old name for `Rows`. `SqliteRows` is deprecated.
|
/// Old name for `Rows`. `SqliteRows` is deprecated.
|
||||||
#[deprecated(since = "0.6.0", note = "Use Rows instead")]
|
#[deprecated(since = "0.6.0", note = "Use Rows instead")]
|
||||||
pub type SqliteRows<'stmt> = Rows<'stmt>;
|
pub type SqliteRows<'stmt> = Rows<'stmt>;
|
||||||
|
|
||||||
/// An handle for the resulting rows of a query.
|
|
||||||
pub struct Rows<'stmt> {
|
|
||||||
stmt: Option<&'stmt Statement<'stmt>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(should_implement_trait)]
|
|
||||||
impl<'stmt> 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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'stmt> Drop for Rows<'stmt> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Old name for `Row`. `SqliteRow` is deprecated.
|
/// Old name for `Row`. `SqliteRow` is deprecated.
|
||||||
#[deprecated(since = "0.6.0", note = "Use Row instead")]
|
#[deprecated(since = "0.6.0", note = "Use Row instead")]
|
||||||
pub type SqliteRow<'a, 'stmt> = Row<'a, 'stmt>;
|
pub type SqliteRow<'a, 'stmt> = Row<'a, 'stmt>;
|
||||||
|
|
||||||
/// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
222
src/row.rs
Normal file
222
src/row.rs
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ use super::ffi;
|
|||||||
use super::{Connection, RawStatement, Result, Error, ValueRef, Row, Rows, AndThenRows, MappedRows};
|
use super::{Connection, RawStatement, Result, Error, ValueRef, Row, Rows, AndThenRows, MappedRows};
|
||||||
use super::str_to_cstring;
|
use super::str_to_cstring;
|
||||||
use types::{ToSql, ToSqlOutput};
|
use types::{ToSql, ToSqlOutput};
|
||||||
|
use row::{RowsCrateImpl, MappedRowsCrateImpl, AndThenRowsCrateImpl};
|
||||||
|
|
||||||
/// A prepared statement.
|
/// A prepared statement.
|
||||||
pub struct Statement<'conn> {
|
pub struct Statement<'conn> {
|
||||||
@ -211,12 +212,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
pub fn query_map<'a, T, F>(&'a mut self, params: &[&ToSql], f: F) -> Result<MappedRows<'a, F>>
|
pub fn query_map<'a, T, F>(&'a mut self, params: &[&ToSql], f: F) -> Result<MappedRows<'a, F>>
|
||||||
where F: FnMut(&Row) -> T
|
where F: FnMut(&Row) -> T
|
||||||
{
|
{
|
||||||
let row_iter = try!(self.query(params));
|
let rows = self.query(params)?;
|
||||||
|
Ok(MappedRows::new(rows, f))
|
||||||
Ok(MappedRows {
|
|
||||||
rows: row_iter,
|
|
||||||
map: f,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the prepared statement with named parameter(s), returning an iterator over the
|
/// Execute the prepared statement with named parameter(s), returning an iterator over the
|
||||||
@ -251,11 +248,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
-> Result<MappedRows<'a, F>>
|
-> Result<MappedRows<'a, F>>
|
||||||
where F: FnMut(&Row) -> T
|
where F: FnMut(&Row) -> T
|
||||||
{
|
{
|
||||||
let rows = try!(self.query_named(params));
|
let rows = self.query_named(params)?;
|
||||||
Ok(MappedRows {
|
Ok(MappedRows::new(rows, f))
|
||||||
rows: rows,
|
|
||||||
map: f,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the prepared statement and maps a function over the resulting
|
/// Executes the prepared statement and maps a function over the resulting
|
||||||
@ -272,12 +266,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
where E: convert::From<Error>,
|
where E: convert::From<Error>,
|
||||||
F: FnMut(&Row) -> result::Result<T, E>
|
F: FnMut(&Row) -> result::Result<T, E>
|
||||||
{
|
{
|
||||||
let row_iter = try!(self.query(params));
|
let rows = self.query(params)?;
|
||||||
|
Ok(AndThenRows::new(rows, f))
|
||||||
Ok(AndThenRows {
|
|
||||||
rows: row_iter,
|
|
||||||
map: f,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the prepared statement with named parameter(s), returning an iterator over the
|
/// Execute the prepared statement with named parameter(s), returning an iterator over the
|
||||||
@ -322,11 +312,8 @@ impl<'conn> Statement<'conn> {
|
|||||||
where E: convert::From<Error>,
|
where E: convert::From<Error>,
|
||||||
F: FnMut(&Row) -> result::Result<T, E>
|
F: FnMut(&Row) -> result::Result<T, E>
|
||||||
{
|
{
|
||||||
let rows = try!(self.query_named(params));
|
let rows = self.query_named(params)?;
|
||||||
Ok(AndThenRows {
|
Ok(AndThenRows::new(rows, f))
|
||||||
rows: rows,
|
|
||||||
map: f,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if a query in the SQL statement it executes returns one or more rows
|
/// Return `true` if a query in the SQL statement it executes returns one or more rows
|
||||||
|
Loading…
Reference in New Issue
Block a user