mirror of
https://github.com/launchbadge/sqlx
synced 2024-11-10 14:34:19 +00:00
row: RowIndex -> ColumnIndex and de-duplicate logic with macros
This commit is contained in:
parent
0cb7bd1185
commit
d981262e7e
5 changed files with 77 additions and 78 deletions
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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"[..]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue