remove the DB type parameter from HasCursor and push to an associated type; remove Cursor::first

This commit is contained in:
Ryan Leckey 2020-02-29 12:17:36 -08:00
parent d981262e7e
commit 72b60e8a7d
9 changed files with 38 additions and 127 deletions

View File

@ -16,32 +16,28 @@ use crate::{Connect, Pool, Row};
/// Initially the `Cursor` is positioned before the first row. The `next` method moves the cursor
/// to the next row, and because it returns `None` when there are no more rows, it can be used
/// in a `while` loop to iterate through all returned rows.
pub trait Cursor<'c, 'q, DB>
pub trait Cursor<'c, 'q>
where
Self: Send,
DB: Database,
// `.await`-ing a cursor will return the affected rows from the query
Self: Future<Output = crate::Result<u64>>,
{
type Database: Database;
#[doc(hidden)]
fn from_pool<E>(pool: &Pool<DB::Connection>, query: E) -> Self
fn from_pool<E>(pool: &Pool<<Self::Database as Database>::Connection>, query: E) -> Self
where
Self: Sized,
E: Execute<'q, DB>;
E: Execute<'q, Self::Database>;
#[doc(hidden)]
fn from_connection<E, C>(conn: C, query: E) -> Self
where
Self: Sized,
DB::Connection: Connect,
C: Into<MaybeOwnedConnection<'c, DB::Connection>>,
E: Execute<'q, DB>;
#[doc(hidden)]
fn first(self) -> BoxFuture<'c, crate::Result<Option<<DB as HasRow<'c>>::Row>>>
where
'q: 'c;
<Self::Database as Database>::Connection: Connect,
C: Into<MaybeOwnedConnection<'c, <Self::Database as Database>::Connection>>,
E: Execute<'q, Self::Database>;
/// Fetch the next row in the result. Returns `None` if there are no more rows.
fn next(&mut self) -> BoxFuture<crate::Result<Option<<DB as HasRow>::Row>>>;
fn next(&mut self) -> BoxFuture<crate::Result<Option<<Self::Database as HasRow>::Row>>>;
}

View File

@ -15,7 +15,7 @@ where
Self: Sized + 'static,
Self: for<'a> HasRow<'a, Database = Self>,
Self: for<'a> HasRawValue<'a>,
Self: for<'c, 'q> HasCursor<'c, 'q, Self>,
Self: for<'c, 'q> HasCursor<'c, 'q, Database = Self>,
{
/// The concrete `Connection` implementation for this database.
type Connection: Connection<Database = Self>;
@ -34,11 +34,10 @@ pub trait HasRawValue<'a> {
type RawValue;
}
pub trait HasCursor<'c, 'q, DB>
where
DB: Database,
{
type Cursor: Cursor<'c, 'q, DB>;
pub trait HasCursor<'c, 'q> {
type Database: Database;
type Cursor: Cursor<'c, 'q, Database = Self::Database>;
}
pub trait HasRow<'a> {

View File

@ -22,18 +22,12 @@ where
type Database: Database;
/// Executes a query that may or may not return a result set.
fn execute<'q, E>(
self,
query: E,
) -> <Self::Database as HasCursor<'c, 'q, Self::Database>>::Cursor
fn execute<'q, E>(self, query: E) -> <Self::Database as HasCursor<'c, 'q>>::Cursor
where
E: Execute<'q, Self::Database>;
#[doc(hidden)]
fn execute_by_ref<'b, E>(
&mut self,
query: E,
) -> <Self::Database as HasCursor<'_, 'b, Self::Database>>::Cursor
fn execute_by_ref<'b, E>(&mut self, query: E) -> <Self::Database as HasCursor<'_, 'b>>::Cursor
where
E: Execute<'b, Self::Database>;
}

View File

@ -19,12 +19,12 @@ impl<'p, C, DB> Executor<'p> for &'p Pool<C>
where
C: Connect<Database = DB>,
DB: Database<Connection = C>,
DB: for<'c, 'q> HasCursor<'c, 'q, DB>,
DB: for<'c, 'q> HasCursor<'c, 'q, Database = DB>,
for<'con> &'con mut C: Executor<'con>,
{
type Database = DB;
fn execute<'q, E>(self, query: E) -> <Self::Database as HasCursor<'p, 'q, DB>>::Cursor
fn execute<'q, E>(self, query: E) -> <Self::Database as HasCursor<'p, 'q>>::Cursor
where
E: Execute<'q, DB>,
{
@ -36,7 +36,7 @@ where
fn execute_by_ref<'q, 'e, E>(
&'e mut self,
query: E,
) -> <Self::Database as HasCursor<'_, 'q, DB>>::Cursor
) -> <Self::Database as HasCursor<'_, 'q>>::Cursor
where
E: Execute<'q, DB>,
{
@ -48,12 +48,12 @@ impl<'c, C, DB> Executor<'c> for &'c mut PoolConnection<C>
where
C: Connect<Database = DB>,
DB: Database<Connection = C>,
DB: for<'c2, 'q> HasCursor<'c2, 'q, DB>,
DB: for<'c2, 'q> HasCursor<'c2, 'q, Database = DB>,
for<'con> &'con mut C: Executor<'con>,
{
type Database = C::Database;
fn execute<'q, E>(self, query: E) -> <Self::Database as HasCursor<'c, 'q, DB>>::Cursor
fn execute<'q, E>(self, query: E) -> <Self::Database as HasCursor<'c, 'q>>::Cursor
where
E: Execute<'q, Self::Database>,
{
@ -65,7 +65,7 @@ where
fn execute_by_ref<'q, 'e, E>(
&'e mut self,
query: E,
) -> <Self::Database as HasCursor<'_, 'q, DB>>::Cursor
) -> <Self::Database as HasCursor<'_, 'q>>::Cursor
where
E: Execute<'q, Self::Database>,
{
@ -77,11 +77,11 @@ impl<C, DB> Executor<'static> for PoolConnection<C>
where
C: Connect<Database = DB>,
DB: Database<Connection = C>,
DB: for<'c, 'q> HasCursor<'c, 'q, DB>,
DB: for<'c, 'q> HasCursor<'c, 'q, Database = DB>,
{
type Database = DB;
fn execute<'q, E>(self, query: E) -> <DB as HasCursor<'static, 'q, DB>>::Cursor
fn execute<'q, E>(self, query: E) -> <DB as HasCursor<'static, 'q>>::Cursor
where
E: Execute<'q, Self::Database>,
{
@ -90,7 +90,7 @@ where
#[doc(hidden)]
#[inline]
fn execute_by_ref<'q, 'e, E>(&'e mut self, query: E) -> <DB as HasCursor<'_, 'q, DB>>::Cursor
fn execute_by_ref<'q, 'e, E>(&'e mut self, query: E) -> <DB as HasCursor<'_, 'q>>::Cursor
where
E: Execute<'q, Self::Database>,
{

View File

@ -87,8 +87,9 @@ pub struct PgConnection {
pub(super) next_statement_id: u32,
pub(super) is_ready: bool,
// TODO: Think of a better way to do this, better name perhaps?
pub(super) data_row_values_buf: Vec<Option<Range<u32>>>,
// Work buffer for the value ranges of the current row
// This is used as the backing memory for each Row's value indexes
pub(super) current_row_values: Vec<Option<Range<u32>>>,
}
// https://www.postgresql.org/docs/12/protocol-flow.html#id-1.10.5.7.3
@ -234,7 +235,7 @@ impl PgConnection {
Ok(Self {
stream,
data_row_values_buf: Vec::new(),
current_row_values: Vec::with_capacity(10),
next_statement_id: 1,
is_ready: true,
})

View File

@ -32,7 +32,9 @@ pub struct PgCursor<'c, 'q> {
state: State<'c, 'q>,
}
impl<'c, 'q> Cursor<'c, 'q, Postgres> for PgCursor<'c, 'q> {
impl<'c, 'q> Cursor<'c, 'q> for PgCursor<'c, 'q> {
type Database = Postgres;
#[doc(hidden)]
fn from_pool<E>(pool: &Pool<PgConnection>, query: E) -> Self
where
@ -64,14 +66,6 @@ impl<'c, 'q> Cursor<'c, 'q, Postgres> for PgCursor<'c, 'q> {
}
}
#[doc(hidden)]
fn first(self) -> BoxFuture<'c, crate::Result<Option<PgRow<'c>>>>
where
'q: 'c,
{
Box::pin(first(self))
}
fn next(&mut self) -> BoxFuture<crate::Result<Option<PgRow<'_>>>> {
Box::pin(next(self))
}
@ -266,51 +260,3 @@ async fn next<'a, 'c: 'a, 'q: 'a>(
Ok(None)
}
async fn first<'c, 'q>(mut cursor: PgCursor<'c, 'q>) -> crate::Result<Option<PgRow<'c>>> {
let mut conn = cursor.source.resolve().await?;
match cursor.state {
State::Query(q, ref mut arguments) => {
// write out the query to the connection
write(&mut conn, q, arguments.take()).await?;
}
State::NextRow => {
// just grab the next row as the first
}
State::Resolve(_) | State::AffectedRows(_) => {
panic!("`PgCursor` must not be used after being polled");
}
}
loop {
match conn.stream.read().await? {
Message::ParseComplete | Message::BindComplete => {
// ignore x_complete messages
}
Message::CommandComplete => {
// no more rows
break;
}
Message::DataRow => {
let data = DataRow::read(&mut conn)?;
return Ok(Some(PgRow {
connection: conn,
columns: Arc::default(),
data,
}));
}
message => {
return Err(protocol_err!("first: unexpected message: {:?}", message).into());
}
}
}
Ok(None)
}

View File

@ -20,7 +20,9 @@ impl<'a> HasRow<'a> for Postgres {
type Row = super::PgRow<'a>;
}
impl<'s, 'q> HasCursor<'s, 'q, Postgres> for Postgres {
impl<'s, 'q> HasCursor<'s, 'q> for Postgres {
type Database = Postgres;
type Cursor = super::PgCursor<'s, 'q>;
}

View File

@ -121,36 +121,12 @@ where
executor.execute(self).await
}
pub fn fetch<'e, E>(self, executor: E) -> <DB as HasCursor<'e, 'q, DB>>::Cursor
pub fn fetch<'e, E>(self, executor: E) -> <DB as HasCursor<'e, 'q>>::Cursor
where
E: Executor<'e, Database = DB>,
{
executor.execute(self)
}
pub async fn fetch_optional<'e, E>(
self,
executor: E,
) -> crate::Result<Option<<DB as HasRow<'e>>::Row>>
where
E: Executor<'e, Database = DB>,
'q: 'e,
{
executor.execute(self).first().await
}
pub async fn fetch_one<'e, E>(self, executor: E) -> crate::Result<<DB as HasRow<'e>>::Row>
where
E: Executor<'e, Database = DB>,
'q: 'e,
{
self.fetch_optional(executor)
.and_then(|row| match row {
Some(row) => ready(Ok(row)),
None => ready(Err(crate::Error::NotFound)),
})
.await
}
}
impl<'q, DB, F> Map<'q, DB, F>

View File

@ -136,10 +136,7 @@ where
{
type Database = <T as Connection>::Database;
fn execute<'q, E>(
self,
query: E,
) -> <<T as Connection>::Database as HasCursor<'c, 'q, DB>>::Cursor
fn execute<'q, E>(self, query: E) -> <<T as Connection>::Database as HasCursor<'c, 'q>>::Cursor
where
E: Execute<'q, Self::Database>,
{
@ -150,7 +147,7 @@ where
fn execute_by_ref<'q, 'e, E>(
&'e mut self,
query: E,
) -> <Self::Database as HasCursor<'e, 'q, DB>>::Cursor
) -> <Self::Database as HasCursor<'e, 'q>>::Cursor
where
E: Execute<'q, Self::Database>,
{