row: RowIndex -> ColumnIndex and de-duplicate logic with macros

This commit is contained in:
Ryan Leckey 2020-02-27 01:59:37 -08:00 committed by Ryan Leckey
parent 0cb7bd1185
commit d981262e7e
5 changed files with 77 additions and 78 deletions

View file

@ -23,9 +23,6 @@ where
// `.await`-ing a cursor will return the affected rows from the query
Self: Future<Output = crate::Result<u64>>,
{
// Construct the [Cursor] from a [Pool]
// Meant for internal use only
// TODO: Anyone have any better ideas on how to instantiate cursors generically from a pool?
#[doc(hidden)]
fn from_pool<E>(pool: &Pool<DB::Connection>, query: E) -> Self
where
@ -37,8 +34,6 @@ where
where
Self: Sized,
DB::Connection: Connect,
// MaybeOwnedConnection<'c, DB::Connection>:
// Connect<Database = DB>,
C: Into<MaybeOwnedConnection<'c, DB::Connection>>,
E: Execute<'q, DB>;

View file

@ -26,9 +26,15 @@ pub enum Error {
/// More than one row was returned by a query that expected to return exactly one row.
FoundMoreThanOne,
/// Column was not found in Row during [Row::try_get].
/// Column was not found by name in a Row (during [Row::try_get]).
ColumnNotFound(Box<str>),
/// Column index was out of bounds (e.g., asking for column 4 in a 2-column row).
ColumnIndexOutOfBounds {
index: usize,
len: usize,
},
/// Unexpected or invalid data was encountered. This would indicate that we received
/// data that we were not expecting or it was in a format we did not understand. This
/// generally means either there is a programming error in a SQLx driver or
@ -89,6 +95,12 @@ impl Display for Error {
write!(f, "no column found with the name {:?}", name)
}
Error::ColumnIndexOutOfBounds { index, len } => write!(
f,
"column index out of bounds: there are {} columns but the index is {}",
len, index
),
Error::FoundMoreThanOne => {
f.write_str("found more than one row when we expected exactly one")
}

View file

@ -27,13 +27,9 @@ impl DataRow {
}
impl DataRow {
pub(crate) fn read<'a>(
connection: &mut PgConnection,
// buffer: &'a [u8],
// values: &'a mut Vec<Option<Range<u32>>>,
) -> crate::Result<Self> {
pub(crate) fn read(connection: &mut PgConnection) -> crate::Result<Self> {
let buffer = connection.stream.buffer();
let values = &mut connection.data_row_values_buf;
let values = &mut connection.current_row_values;
values.clear();
@ -64,22 +60,3 @@ impl DataRow {
Ok(Self { len })
}
}
#[cfg(test)]
mod tests {
use super::{DataRow, Decode};
const DATA_ROW: &[u8] = b"\0\x03\0\0\0\x011\0\0\0\x012\0\0\0\x013";
#[test]
fn it_reads_data_row() {
let mut values = Vec::new();
let m = DataRow::read(DATA_ROW, &mut values).unwrap();
assert_eq!(m.len, 3);
assert_eq!(m.get(DATA_ROW, &values, 0), Some(&b"1"[..]));
assert_eq!(m.get(DATA_ROW, &values, 1), Some(&b"2"[..]));
assert_eq!(m.get(DATA_ROW, &values, 2), Some(&b"3"[..]));
}
}

View file

@ -6,7 +6,7 @@ use crate::decode::Decode;
use crate::pool::PoolConnection;
use crate::postgres::protocol::DataRow;
use crate::postgres::{PgConnection, Postgres};
use crate::row::{Row, RowIndex};
use crate::row::{ColumnIndex, Row};
use crate::types::Type;
pub struct PgRow<'c> {
@ -24,46 +24,16 @@ impl<'c> Row<'c> for PgRow<'c> {
fn try_get_raw<'i, I>(&'c self, index: I) -> crate::Result<Option<&'c [u8]>>
where
I: RowIndex<'c, Self> + 'i,
I: ColumnIndex<'c, Self> + 'i,
{
index.try_get_raw(self)
}
}
impl<'c> RowIndex<'c, PgRow<'c>> for usize {
fn try_get_raw(self, row: &'c PgRow<'c>) -> crate::Result<Option<&'c [u8]>> {
Ok(row.data.get(
row.connection.stream.buffer(),
&row.connection.data_row_values_buf,
self,
Ok(self.data.get(
self.connection.stream.buffer(),
&self.connection.current_row_values,
index.try_resolve(self)?,
))
}
}
impl<'c> RowIndex<'c, PgRow<'c>> for &'_ str {
fn try_get_raw(self, row: &'c PgRow<'c>) -> crate::Result<Option<&'c [u8]>> {
let index = row
.columns
.get(self)
.ok_or_else(|| crate::Error::ColumnNotFound((*self).into()))?;
Ok(row.data.get(
row.connection.stream.buffer(),
&row.connection.data_row_values_buf,
*index,
))
}
}
// TODO: impl_from_row_for_row!(PgRow);
impl<O: Unpin, F> crate::query::MapRow<Postgres> for F
where
F: for<'c> FnMut(PgRow<'c>) -> crate::Result<O>,
{
type Mapped = O;
fn map_row(&mut self, row: PgRow) -> crate::Result<O> {
(self)(row)
}
}
impl_map_row_for_row!(Postgres, PgRow);
impl_column_index_for_row!(PgRow);
impl_from_row_for_row!(PgRow);

View file

@ -4,11 +4,11 @@ use crate::database::Database;
use crate::decode::Decode;
use crate::types::Type;
pub trait RowIndex<'c, R: ?Sized>
pub trait ColumnIndex<'c, R: ?Sized>
where
R: Row<'c>,
{
fn try_get_raw(self, row: &'c R) -> crate::Result<Option<&'c [u8]>>;
fn try_resolve(self, row: &'c R) -> crate::Result<usize>;
}
/// Represents a single row of the result set.
@ -26,7 +26,7 @@ pub trait Row<'c>: Unpin + Send {
fn get<T, I>(&'c self, index: I) -> T
where
T: Type<Self::Database>,
I: RowIndex<'c, Self>,
I: ColumnIndex<'c, Self>,
T: Decode<Self::Database>,
{
// todo: use expect with a proper message
@ -36,7 +36,7 @@ pub trait Row<'c>: Unpin + Send {
fn try_get<T, I>(&'c self, index: I) -> crate::Result<T>
where
T: Type<Self::Database>,
I: RowIndex<'c, Self>,
I: ColumnIndex<'c, Self>,
T: Decode<Self::Database>,
{
Ok(Decode::decode_nullable(self.try_get_raw(index)?)?)
@ -44,7 +44,7 @@ pub trait Row<'c>: Unpin + Send {
fn try_get_raw<'i, I>(&'c self, index: I) -> crate::Result<Option<&'c [u8]>>
where
I: RowIndex<'c, Self> + 'i;
I: ColumnIndex<'c, Self> + 'i;
}
/// A **record** that can be built from a row returned from by the database.
@ -55,12 +55,57 @@ where
fn from_row(row: R) -> Self;
}
// Macros to help unify the internal implementations as a good chunk is very similar
#[allow(unused_macros)]
macro_rules! impl_map_row_for_row {
($DB:ident, $R:ident) => {
impl<O: Unpin, F> crate::query::MapRow<$DB> for F
where
F: for<'c> FnMut($R<'c>) -> crate::Result<O>,
{
type Mapped = O;
fn map_row(&mut self, row: $R) -> crate::Result<O> {
(self)(row)
}
}
};
}
#[allow(unused_macros)]
macro_rules! impl_column_index_for_row {
($R:ident) => {
impl<'c> crate::row::ColumnIndex<'c, $R<'c>> for usize {
fn try_resolve(self, row: &'c $R<'c>) -> crate::Result<usize> {
if self >= row.len() {
return Err(crate::Error::ColumnIndexOutOfBounds {
len: row.len(),
index: self,
});
}
Ok(self)
}
}
impl<'c> crate::row::ColumnIndex<'c, $R<'c>> for &'_ str {
fn try_resolve(self, row: &'c $R<'c>) -> crate::Result<usize> {
row.columns
.get(self)
.ok_or_else(|| crate::Error::ColumnNotFound((*self).into()))
.map(|&index| index)
}
}
};
}
#[allow(unused_macros)]
macro_rules! impl_from_row_for_row {
($R:ty) => {
impl crate::row::FromRow<$R> for $R {
($R:ident) => {
impl<'c> crate::row::FromRow<'c, $R<'c>> for $R<'c> {
#[inline]
fn from_row(row: $R) -> Self {
fn from_row(row: $R<'c>) -> Self {
row
}
}