2019-03-10 19:58:20 +08:00
|
|
|
use fallible_iterator::FallibleIterator;
|
|
|
|
use fallible_streaming_iterator::FallibleStreamingIterator;
|
2020-04-07 05:43:06 +08:00
|
|
|
use std::convert;
|
2017-03-09 05:57:43 +08:00
|
|
|
|
2019-03-10 19:58:20 +08:00
|
|
|
use super::{Error, Result, Statement};
|
2018-10-31 03:11:35 +08:00
|
|
|
use crate::types::{FromSql, FromSqlError, ValueRef};
|
2017-03-09 05:57:43 +08:00
|
|
|
|
|
|
|
/// An handle for the resulting rows of a query.
|
2020-09-02 14:15:25 +08:00
|
|
|
#[must_use = "Rows is lazy and will do nothing unless consumed"]
|
2017-03-09 05:57:43 +08:00
|
|
|
pub struct Rows<'stmt> {
|
2019-03-20 03:33:36 +08:00
|
|
|
pub(crate) stmt: Option<&'stmt Statement<'stmt>>,
|
2019-02-03 21:01:42 +08:00
|
|
|
row: Option<Row<'stmt>>,
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'stmt> Rows<'stmt> {
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2017-03-09 05:57:43 +08:00
|
|
|
fn reset(&mut self) {
|
|
|
|
if let Some(stmt) = self.stmt.take() {
|
|
|
|
stmt.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 18:12:14 +08:00
|
|
|
/// Attempt to get the next row from the query. Returns `Ok(Some(Row))` if
|
|
|
|
/// there is another row, `Err(...)` if there was an error
|
|
|
|
/// getting the next row, and `Ok(None)` if all rows have been retrieved.
|
2017-03-09 05:57:43 +08:00
|
|
|
///
|
|
|
|
/// ## 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`.
|
2019-03-10 18:12:14 +08:00
|
|
|
/// This is a fallible "streaming iterator". For a more natural interface,
|
2023-09-03 16:46:12 +08:00
|
|
|
/// consider using [`query_map`](Statement::query_map) or
|
|
|
|
/// [`query_and_then`](Statement::query_and_then) instead, which
|
2018-08-17 00:29:46 +08:00
|
|
|
/// return types that implement `Iterator`.
|
2018-12-07 02:00:55 +08:00
|
|
|
#[allow(clippy::should_implement_trait)] // cannot implement Iterator
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-03-10 18:12:14 +08:00
|
|
|
pub fn next(&mut self) -> Result<Option<&Row<'stmt>>> {
|
|
|
|
self.advance()?;
|
|
|
|
Ok((*self).get())
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
2019-03-10 19:58:20 +08:00
|
|
|
|
2020-05-17 17:21:10 +08:00
|
|
|
/// Map over this `Rows`, converting it to a [`Map`], which
|
|
|
|
/// implements `FallibleIterator`.
|
2020-05-25 02:42:54 +08:00
|
|
|
/// ```rust,no_run
|
|
|
|
/// use fallible_iterator::FallibleIterator;
|
2020-11-03 17:32:46 +08:00
|
|
|
/// # use rusqlite::{Result, Statement};
|
2020-05-25 02:42:54 +08:00
|
|
|
/// fn query(stmt: &mut Statement) -> Result<Vec<i64>> {
|
2020-11-03 17:32:46 +08:00
|
|
|
/// let rows = stmt.query([])?;
|
2020-05-25 02:42:54 +08:00
|
|
|
/// rows.map(|r| r.get(0)).collect()
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
// FIXME Hide FallibleStreamingIterator::map
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-03-10 19:58:20 +08:00
|
|
|
pub fn map<F, B>(self, f: F) -> Map<'stmt, F>
|
|
|
|
where
|
|
|
|
F: FnMut(&Row<'_>) -> Result<B>,
|
|
|
|
{
|
2019-03-22 02:13:55 +08:00
|
|
|
Map { rows: self, f }
|
2019-03-10 19:58:20 +08:00
|
|
|
}
|
2020-04-07 04:01:39 +08:00
|
|
|
|
|
|
|
/// Map over this `Rows`, converting it to a [`MappedRows`], which
|
|
|
|
/// implements `Iterator`.
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2020-04-07 04:01:39 +08:00
|
|
|
pub fn mapped<F, B>(self, f: F) -> MappedRows<'stmt, F>
|
|
|
|
where
|
|
|
|
F: FnMut(&Row<'_>) -> Result<B>,
|
|
|
|
{
|
|
|
|
MappedRows { rows: self, map: f }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Map over this `Rows` with a fallible function, converting it to a
|
|
|
|
/// [`AndThenRows`], which implements `Iterator` (instead of
|
|
|
|
/// `FallibleStreamingIterator`).
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2020-04-07 04:01:39 +08:00
|
|
|
pub fn and_then<F, T, E>(self, f: F) -> AndThenRows<'stmt, F>
|
|
|
|
where
|
2020-04-07 05:43:06 +08:00
|
|
|
F: FnMut(&Row<'_>) -> Result<T, E>,
|
2020-04-07 04:01:39 +08:00
|
|
|
{
|
|
|
|
AndThenRows { rows: self, map: f }
|
|
|
|
}
|
2021-05-26 20:51:28 +08:00
|
|
|
|
|
|
|
/// Give access to the underlying statement
|
2022-01-06 02:40:31 +08:00
|
|
|
#[must_use]
|
2021-05-26 20:51:28 +08:00
|
|
|
pub fn as_ref(&self) -> Option<&Statement<'stmt>> {
|
|
|
|
self.stmt
|
|
|
|
}
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
2018-08-01 04:17:17 +08:00
|
|
|
impl<'stmt> Rows<'stmt> {
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2018-08-01 04:17:17 +08:00
|
|
|
pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Rows<'stmt> {
|
2019-02-03 21:01:42 +08:00
|
|
|
Rows {
|
|
|
|
stmt: Some(stmt),
|
|
|
|
row: None,
|
|
|
|
}
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-02-03 21:01:42 +08:00
|
|
|
pub(crate) fn get_expected_row(&mut self) -> Result<&Row<'stmt>> {
|
|
|
|
match self.next()? {
|
|
|
|
Some(row) => Ok(row),
|
2017-03-09 05:57:43 +08:00
|
|
|
None => Err(Error::QueryReturnedNoRows),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-03 18:02:38 +08:00
|
|
|
impl Drop for Rows<'_> {
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2017-03-09 05:57:43 +08:00
|
|
|
fn drop(&mut self) {
|
|
|
|
self.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-08 01:39:53 +08:00
|
|
|
/// `F` is used to transform the _streaming_ iterator into a _fallible_
|
|
|
|
/// iterator.
|
2020-09-02 14:15:25 +08:00
|
|
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
2019-03-10 19:58:20 +08:00
|
|
|
pub struct Map<'stmt, F> {
|
|
|
|
rows: Rows<'stmt>,
|
|
|
|
f: F,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F, B> FallibleIterator for Map<'_, F>
|
|
|
|
where
|
|
|
|
F: FnMut(&Row<'_>) -> Result<B>,
|
|
|
|
{
|
|
|
|
type Error = Error;
|
|
|
|
type Item = B;
|
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-03-10 19:58:20 +08:00
|
|
|
fn next(&mut self) -> Result<Option<B>> {
|
|
|
|
match self.rows.next()? {
|
|
|
|
Some(v) => Ok(Some((self.f)(v)?)),
|
|
|
|
None => Ok(None),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-09 05:57:43 +08:00
|
|
|
/// An iterator over the mapped resulting rows of a query.
|
2020-06-03 01:05:09 +08:00
|
|
|
///
|
2021-05-08 01:39:53 +08:00
|
|
|
/// `F` is used to transform the _streaming_ iterator into a _standard_
|
|
|
|
/// iterator.
|
2020-09-02 14:15:25 +08:00
|
|
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
2017-03-09 05:57:43 +08:00
|
|
|
pub struct MappedRows<'stmt, F> {
|
|
|
|
rows: Rows<'stmt>,
|
|
|
|
map: F,
|
|
|
|
}
|
|
|
|
|
2019-02-03 18:02:38 +08:00
|
|
|
impl<T, F> Iterator for MappedRows<'_, F>
|
2018-08-11 18:48:21 +08:00
|
|
|
where
|
2019-03-10 18:12:14 +08:00
|
|
|
F: FnMut(&Row<'_>) -> Result<T>,
|
2017-03-09 05:57:43 +08:00
|
|
|
{
|
|
|
|
type Item = Result<T>;
|
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2017-03-09 05:57:43 +08:00
|
|
|
fn next(&mut self) -> Option<Result<T>> {
|
|
|
|
let map = &mut self.map;
|
2017-04-08 01:43:24 +08:00
|
|
|
self.rows
|
|
|
|
.next()
|
2019-02-03 21:01:42 +08:00
|
|
|
.transpose()
|
2021-10-02 02:09:48 +08:00
|
|
|
.map(|row_result| row_result.and_then(map))
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over the mapped resulting rows of a query, with an Error type
|
|
|
|
/// unifying with Error.
|
2020-09-02 14:15:25 +08:00
|
|
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
2017-03-09 05:57:43 +08:00
|
|
|
pub struct AndThenRows<'stmt, F> {
|
|
|
|
rows: Rows<'stmt>,
|
|
|
|
map: F,
|
|
|
|
}
|
|
|
|
|
2019-02-03 18:02:38 +08:00
|
|
|
impl<T, E, F> Iterator for AndThenRows<'_, F>
|
2018-08-11 18:48:21 +08:00
|
|
|
where
|
2022-05-29 19:33:51 +08:00
|
|
|
E: From<Error>,
|
2020-04-07 05:43:06 +08:00
|
|
|
F: FnMut(&Row<'_>) -> Result<T, E>,
|
2017-03-09 05:57:43 +08:00
|
|
|
{
|
2020-04-07 05:43:06 +08:00
|
|
|
type Item = Result<T, E>;
|
2017-03-09 05:57:43 +08:00
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2017-03-09 05:57:43 +08:00
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
let map = &mut self.map;
|
2017-04-08 01:43:24 +08:00
|
|
|
self.rows
|
|
|
|
.next()
|
2019-02-03 21:01:42 +08:00
|
|
|
.transpose()
|
2021-10-02 02:09:48 +08:00
|
|
|
.map(|row_result| row_result.map_err(E::from).and_then(map))
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-25 02:42:54 +08:00
|
|
|
/// `FallibleStreamingIterator` differs from the standard library's `Iterator`
|
|
|
|
/// in two ways:
|
2022-01-06 02:19:13 +08:00
|
|
|
/// * each call to `next` (`sqlite3_step`) can fail.
|
2020-05-25 02:42:54 +08:00
|
|
|
/// * returned `Row` is valid until `next` is called again or `Statement` is
|
|
|
|
/// reset or finalized.
|
|
|
|
///
|
|
|
|
/// While these iterators cannot be used with Rust `for` loops, `while let`
|
|
|
|
/// loops offer a similar level of ergonomics:
|
|
|
|
/// ```rust,no_run
|
2020-11-03 17:32:46 +08:00
|
|
|
/// # use rusqlite::{Result, Statement};
|
2020-05-25 02:42:54 +08:00
|
|
|
/// fn query(stmt: &mut Statement) -> Result<()> {
|
2020-11-03 17:32:46 +08:00
|
|
|
/// let mut rows = stmt.query([])?;
|
2020-05-25 02:42:54 +08:00
|
|
|
/// while let Some(row) = rows.next()? {
|
|
|
|
/// // scan columns value
|
|
|
|
/// }
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2019-02-03 21:01:42 +08:00
|
|
|
impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
|
|
|
|
type Error = Error;
|
|
|
|
type Item = Row<'stmt>;
|
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-02-03 21:01:42 +08:00
|
|
|
fn advance(&mut self) -> Result<()> {
|
2022-01-06 02:59:54 +08:00
|
|
|
if let Some(stmt) = self.stmt {
|
|
|
|
match stmt.step() {
|
2019-02-03 21:01:42 +08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2022-01-06 02:59:54 +08:00
|
|
|
} else {
|
|
|
|
self.row = None;
|
|
|
|
Ok(())
|
2019-02-03 21:01:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-04 11:10:23 +08:00
|
|
|
#[inline]
|
2019-02-03 21:01:42 +08:00
|
|
|
fn get(&self) -> Option<&Row<'stmt>> {
|
|
|
|
self.row.as_ref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-09 05:57:43 +08:00
|
|
|
/// A single result row of a query.
|
2019-02-03 21:01:42 +08:00
|
|
|
pub struct Row<'stmt> {
|
2019-03-20 03:33:36 +08:00
|
|
|
pub(crate) stmt: &'stmt Statement<'stmt>,
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
2019-02-03 21:01:42 +08:00
|
|
|
impl<'stmt> Row<'stmt> {
|
2017-03-09 05:57:43 +08:00
|
|
|
/// Get the value of a particular column of the result row.
|
|
|
|
///
|
2023-09-03 16:46:12 +08:00
|
|
|
/// # Panics
|
2017-03-09 05:57:43 +08:00
|
|
|
///
|
2020-12-23 04:34:30 +08:00
|
|
|
/// Panics if calling [`row.get(idx)`](Row::get) would return an error,
|
2018-08-17 00:29:46 +08:00
|
|
|
/// including:
|
2017-03-09 05:57:43 +08:00
|
|
|
///
|
2019-02-22 03:48:09 +08:00
|
|
|
/// * If the underlying SQLite column type is not a valid type as a source
|
|
|
|
/// for `T`
|
2019-02-02 22:18:11 +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
|
2023-04-14 00:56:27 +08:00
|
|
|
#[track_caller]
|
2019-02-22 03:48:09 +08:00
|
|
|
pub fn get_unwrap<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
|
|
|
|
self.get(idx).unwrap()
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// 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.
|
2017-03-09 05:57:43 +08:00
|
|
|
///
|
2018-08-17 00:29:46 +08:00
|
|
|
/// Returns an `Error::InvalidColumnName` if `idx` is not a valid column
|
|
|
|
/// name for this row.
|
Add a feature for storing i128 as blobs.
This is behind the `i128_blob` feature.
Blobs are stored as 16 byte big-endian values, with their most significant bit
flipped. This is so that sorting, comparison, etc all work properly, even with
negative numbers. This also allows the representation to be stable across
different computers.
It's possible that the `FromSql` implementation should handle the case that the
real value is stored in an integer. I didn't do this, but would be willing to
make the change. I don't think we should store them this way though, since I
don't think users would be able to sort/compare them sanely.
Support for `u128` is not implemented, as comparison with i128 values would work
strangely. This also is consistent with `u64` not being allowed, not that I
think that would be reason enough on it's own.
The `byteorder` crate is used if this feature is flipped, as it's quite small
and implements things more or less optimally. If/when `i128::{to,from}_be_bytes`
gets stabilized (https://github.com/rust-lang/rust/issues/52963), we should
probably use that instead.
2018-10-09 03:04:07 +08:00
|
|
|
///
|
|
|
|
/// 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.
|
2023-04-14 00:56:27 +08:00
|
|
|
#[track_caller]
|
2019-02-22 03:48:09 +08:00
|
|
|
pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
|
2018-10-31 03:11:35 +08:00
|
|
|
let idx = idx.idx(self.stmt)?;
|
2017-03-09 05:57:43 +08:00
|
|
|
let value = self.stmt.value_ref(idx);
|
|
|
|
FromSql::column_result(value).map_err(|err| match err {
|
2019-08-31 18:17:48 +08:00
|
|
|
FromSqlError::InvalidType => Error::InvalidColumnType(
|
|
|
|
idx,
|
|
|
|
self.stmt.column_name_unwrap(idx).into(),
|
|
|
|
value.data_type(),
|
|
|
|
),
|
2018-08-11 18:48:21 +08:00
|
|
|
FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
|
|
|
|
FromSqlError::Other(err) => {
|
2022-01-03 04:41:50 +08:00
|
|
|
Error::FromSqlConversionFailure(idx, value.data_type(), err)
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
2022-01-03 04:41:50 +08:00
|
|
|
FromSqlError::InvalidBlobSize { .. } => {
|
|
|
|
Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
|
2022-01-02 16:57:06 +08:00
|
|
|
}
|
2018-08-11 18:48:21 +08:00
|
|
|
})
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
2018-10-19 02:59:30 +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
|
2020-12-23 04:34:30 +08:00
|
|
|
/// served by [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
|
2018-10-19 02:59:30 +08:00
|
|
|
///
|
|
|
|
/// ## 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.
|
2020-12-23 04:34:30 +08:00
|
|
|
pub fn get_ref<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'_>> {
|
2018-10-19 02:59:30 +08:00
|
|
|
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
|
2020-12-23 04:34:30 +08:00
|
|
|
/// [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
|
2018-10-19 02:59:30 +08:00
|
|
|
///
|
2023-09-03 16:46:12 +08:00
|
|
|
/// # Panics
|
2018-10-19 02:59:30 +08:00
|
|
|
///
|
2021-04-03 17:03:50 +08:00
|
|
|
/// Panics if calling [`row.get_ref(idx)`](Row::get_ref) would return an
|
|
|
|
/// error, including:
|
2018-10-19 02:59:30 +08:00
|
|
|
///
|
2019-02-02 22:18:11 +08:00
|
|
|
/// * If `idx` is outside the range of columns in the returned query.
|
|
|
|
/// * If `idx` is not a valid column name for this row.
|
2023-04-14 00:56:27 +08:00
|
|
|
#[track_caller]
|
2020-12-23 04:34:30 +08:00
|
|
|
pub fn get_ref_unwrap<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
|
|
|
|
self.get_ref(idx).unwrap()
|
|
|
|
}
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
2021-05-26 20:51:28 +08:00
|
|
|
impl<'stmt> AsRef<Statement<'stmt>> for Row<'stmt> {
|
|
|
|
fn as_ref(&self) -> &Statement<'stmt> {
|
|
|
|
self.stmt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-09 17:43:02 +08:00
|
|
|
/// Debug `Row` like an ordered `Map<Result<&str>, Result<(Type, ValueRef)>>`
|
|
|
|
/// with column name as key except that for `Type::Blob` only its size is
|
|
|
|
/// printed (not its content).
|
|
|
|
impl<'stmt> std::fmt::Debug for Row<'stmt> {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
let mut dm = f.debug_map();
|
|
|
|
for c in 0..self.stmt.column_count() {
|
|
|
|
let name = self.stmt.column_name(c);
|
|
|
|
dm.key(&name);
|
|
|
|
let value = self.get_ref(c);
|
|
|
|
match value {
|
|
|
|
Ok(value) => {
|
|
|
|
let dt = value.data_type();
|
|
|
|
match value {
|
|
|
|
ValueRef::Null => {
|
|
|
|
dm.value(&(dt, ()));
|
|
|
|
}
|
|
|
|
ValueRef::Integer(i) => {
|
|
|
|
dm.value(&(dt, i));
|
|
|
|
}
|
|
|
|
ValueRef::Real(f) => {
|
|
|
|
dm.value(&(dt, f));
|
|
|
|
}
|
|
|
|
ValueRef::Text(s) => {
|
|
|
|
dm.value(&(dt, String::from_utf8_lossy(s)));
|
|
|
|
}
|
|
|
|
ValueRef::Blob(b) => {
|
|
|
|
dm.value(&(dt, b.len()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(ref _err) => {
|
|
|
|
dm.value(&value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dm.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 11:28:50 +08:00
|
|
|
mod sealed {
|
|
|
|
/// This trait exists just to ensure that the only impls of `trait Params`
|
|
|
|
/// that are allowed are ones in this crate.
|
|
|
|
pub trait Sealed {}
|
|
|
|
impl Sealed for usize {}
|
|
|
|
impl Sealed for &str {}
|
|
|
|
}
|
|
|
|
|
2017-03-09 05:57:43 +08:00
|
|
|
/// A trait implemented by types that can index into columns of a row.
|
2020-11-03 11:28:50 +08:00
|
|
|
///
|
|
|
|
/// It is only implemented for `usize` and `&str`.
|
|
|
|
pub trait RowIndex: sealed::Sealed {
|
2017-03-09 05:57:43 +08:00
|
|
|
/// Returns the index of the appropriate column, or `None` if no such
|
|
|
|
/// column exists.
|
2018-12-08 04:57:04 +08:00
|
|
|
fn idx(&self, stmt: &Statement<'_>) -> Result<usize>;
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
|
2018-05-24 03:04:13 +08:00
|
|
|
impl RowIndex for usize {
|
2017-03-09 05:57:43 +08:00
|
|
|
#[inline]
|
2018-12-08 04:57:04 +08:00
|
|
|
fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
|
2018-05-24 03:04:13 +08:00
|
|
|
if *self >= stmt.column_count() {
|
2017-03-09 05:57:43 +08:00
|
|
|
Err(Error::InvalidColumnIndex(*self))
|
|
|
|
} else {
|
|
|
|
Ok(*self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-03 18:02:38 +08:00
|
|
|
impl RowIndex for &'_ str {
|
2017-03-09 05:57:43 +08:00
|
|
|
#[inline]
|
2018-12-08 04:57:04 +08:00
|
|
|
fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
|
2022-07-31 13:00:37 +08:00
|
|
|
stmt.column_index(self)
|
2017-03-09 05:57:43 +08:00
|
|
|
}
|
|
|
|
}
|
2020-05-13 17:47:29 +08:00
|
|
|
|
|
|
|
macro_rules! tuple_try_from_row {
|
|
|
|
($($field:ident),*) => {
|
2020-05-17 12:37:25 +08:00
|
|
|
impl<'a, $($field,)*> convert::TryFrom<&'a Row<'a>> for ($($field,)*) where $($field: FromSql,)* {
|
2020-05-13 17:47:29 +08:00
|
|
|
type Error = crate::Error;
|
|
|
|
|
|
|
|
// we end with index += 1, which rustc warns about
|
|
|
|
// unused_variables and unused_mut are allowed for ()
|
|
|
|
#[allow(unused_assignments, unused_variables, unused_mut)]
|
2020-05-17 12:37:25 +08:00
|
|
|
fn try_from(row: &'a Row<'a>) -> Result<Self> {
|
2020-05-13 17:47:29 +08:00
|
|
|
let mut index = 0;
|
|
|
|
$(
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
let $field = row.get::<_, $field>(index)?;
|
|
|
|
index += 1;
|
|
|
|
)*
|
|
|
|
Ok(($($field,)*))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! tuples_try_from_row {
|
|
|
|
() => {
|
|
|
|
// not very useful, but maybe some other macro users will find this helpful
|
|
|
|
tuple_try_from_row!();
|
|
|
|
};
|
|
|
|
($first:ident $(, $remaining:ident)*) => {
|
|
|
|
tuple_try_from_row!($first $(, $remaining)*);
|
|
|
|
tuples_try_from_row!($($remaining),*);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
tuples_try_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-05-17 12:37:25 +08:00
|
|
|
#![allow(clippy::redundant_closure)] // false positives due to lifetime issues; clippy issue #5594
|
2020-11-06 05:14:00 +08:00
|
|
|
use crate::{Connection, Result};
|
2020-05-17 12:37:25 +08:00
|
|
|
|
2020-05-13 17:47:29 +08:00
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_try_from_row_for_tuple_1() -> Result<()> {
|
|
|
|
use crate::ToSql;
|
2020-05-13 17:47:29 +08:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
2020-11-06 05:14:00 +08:00
|
|
|
let conn = Connection::open_in_memory()?;
|
2020-05-13 17:47:29 +08:00
|
|
|
conn.execute(
|
|
|
|
"CREATE TABLE test (a INTEGER)",
|
2020-11-03 15:34:08 +08:00
|
|
|
crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
|
2020-11-06 05:14:00 +08:00
|
|
|
)?;
|
|
|
|
conn.execute("INSERT INTO test VALUES (42)", [])?;
|
|
|
|
let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
|
2020-05-13 17:47:29 +08:00
|
|
|
assert_eq!(val, (42,));
|
2020-11-03 15:34:08 +08:00
|
|
|
let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
|
2022-07-31 13:00:37 +08:00
|
|
|
fail.unwrap_err();
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2020-05-13 17:47:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_try_from_row_for_tuple_2() -> Result<()> {
|
2020-05-13 17:47:29 +08:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
2020-11-06 05:14:00 +08:00
|
|
|
let conn = Connection::open_in_memory()?;
|
|
|
|
conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
|
|
|
|
conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
|
|
|
|
let val = conn.query_row("SELECT a, b FROM test", [], |row| {
|
|
|
|
<(u32, u32)>::try_from(row)
|
|
|
|
})?;
|
2020-05-13 17:47:29 +08:00
|
|
|
assert_eq!(val, (42, 47));
|
2020-11-03 15:34:08 +08:00
|
|
|
let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
|
|
|
|
<(u32, u32, u32)>::try_from(row)
|
|
|
|
});
|
2022-07-31 13:00:37 +08:00
|
|
|
fail.unwrap_err();
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2020-05-13 17:47:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-11-06 05:14:00 +08:00
|
|
|
fn test_try_from_row_for_tuple_16() -> Result<()> {
|
2020-05-13 17:47:29 +08:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
|
|
|
let create_table = "CREATE TABLE test (
|
|
|
|
a INTEGER,
|
|
|
|
b INTEGER,
|
|
|
|
c INTEGER,
|
|
|
|
d INTEGER,
|
|
|
|
e INTEGER,
|
|
|
|
f INTEGER,
|
|
|
|
g INTEGER,
|
|
|
|
h INTEGER,
|
|
|
|
i INTEGER,
|
|
|
|
j INTEGER,
|
|
|
|
k INTEGER,
|
|
|
|
l INTEGER,
|
|
|
|
m INTEGER,
|
|
|
|
n INTEGER,
|
|
|
|
o INTEGER,
|
|
|
|
p INTEGER
|
|
|
|
)";
|
|
|
|
|
|
|
|
let insert_values = "INSERT INTO test VALUES (
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
3,
|
|
|
|
4,
|
|
|
|
5,
|
|
|
|
6,
|
|
|
|
7,
|
|
|
|
8,
|
|
|
|
9,
|
|
|
|
10,
|
|
|
|
11,
|
|
|
|
12,
|
|
|
|
13,
|
|
|
|
14,
|
|
|
|
15
|
|
|
|
)";
|
|
|
|
|
|
|
|
type BigTuple = (
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
u32,
|
|
|
|
);
|
|
|
|
|
2020-11-06 05:14:00 +08:00
|
|
|
let conn = Connection::open_in_memory()?;
|
|
|
|
conn.execute(create_table, [])?;
|
|
|
|
conn.execute(insert_values, [])?;
|
|
|
|
let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
|
2020-05-13 17:47:29 +08:00
|
|
|
// Debug is not implemented for tuples of 16
|
|
|
|
assert_eq!(val.0, 0);
|
|
|
|
assert_eq!(val.1, 1);
|
|
|
|
assert_eq!(val.2, 2);
|
|
|
|
assert_eq!(val.3, 3);
|
|
|
|
assert_eq!(val.4, 4);
|
|
|
|
assert_eq!(val.5, 5);
|
|
|
|
assert_eq!(val.6, 6);
|
|
|
|
assert_eq!(val.7, 7);
|
|
|
|
assert_eq!(val.8, 8);
|
|
|
|
assert_eq!(val.9, 9);
|
|
|
|
assert_eq!(val.10, 10);
|
|
|
|
assert_eq!(val.11, 11);
|
|
|
|
assert_eq!(val.12, 12);
|
|
|
|
assert_eq!(val.13, 13);
|
|
|
|
assert_eq!(val.14, 14);
|
|
|
|
assert_eq!(val.15, 15);
|
|
|
|
|
|
|
|
// We don't test one bigger because it's unimplemented
|
2020-11-06 05:14:00 +08:00
|
|
|
Ok(())
|
2020-05-13 17:47:29 +08:00
|
|
|
}
|
|
|
|
}
|