fix: dx changes

This commit is contained in:
Orion Kindel 2023-07-06 22:29:28 -05:00
parent 790af54a0f
commit 6c6a266c14
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
6 changed files with 212 additions and 136 deletions

View File

@ -848,9 +848,7 @@ pub trait ToSql: fmt::Debug {
/// The return value indicates if this value should be represented as /// The return value indicates if this value should be represented as
/// `NULL`. If this is the case, implementations **must not** write /// `NULL`. If this is the case, implementations **must not** write
/// anything to `out`. /// anything to `out`.
fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>;
where
Self: Sized;
/// Determines if a value of this type can be converted to the specified /// Determines if a value of this type can be converted to the specified
/// Postgres `Type`. /// Postgres `Type`.

View File

@ -1,29 +1,29 @@
#![allow(missing_docs)]
use tokio_postgres::Column;
use tokio_postgres::row::RowIndex;
use tokio_postgres::types::FromSql;
use crate::types::{BorrowToSql, ToSql, Type}; use crate::types::{BorrowToSql, ToSql, Type};
use crate::{ use crate::{
Client, CopyInWriter, CopyOutReader, Error, Row, RowIter, SimpleQueryMessage, Statement, Client, CopyInWriter, CopyOutReader, Error, Row, RowIter, SimpleQueryMessage, Statement,
ToStatement, Transaction, ToStatement, Transaction
}; };
mod private { macro_rules! common {
pub trait Sealed {} ($transaction:ty, $err:ty) => {
}
/// A trait allowing abstraction over connections and transactions.
///
/// This trait is "sealed", and cannot be implemented outside of this crate.
pub trait GenericClient: private::Sealed {
/// Like `Client::execute`. /// Like `Client::execute`.
fn execute<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<u64, Error> fn execute<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<u64, $err>
where where
T: ?Sized + ToStatement; T: ?Sized + ToStatement;
/// Like `Client::query`. /// Like `Client::query`.
fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>, Error> fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Self::Row>, $err>
where where
T: ?Sized + ToStatement; T: ?Sized + ToStatement;
/// Like `Client::query_one`. /// Like `Client::query_one`.
fn query_one<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Row, Error> fn query_one<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Self::Row, $err>
where where
T: ?Sized + ToStatement; T: ?Sized + ToStatement;
@ -32,12 +32,12 @@ pub trait GenericClient: private::Sealed {
&mut self, &mut self,
query: &T, query: &T,
params: &[&(dyn ToSql + Sync)], params: &[&(dyn ToSql + Sync)],
) -> Result<Option<Row>, Error> ) -> Result<Option<Self::Row>, $err>
where where
T: ?Sized + ToStatement; T: ?Sized + ToStatement;
/// Like `Client::query_raw`. /// Like `Client::query_raw`.
fn query_raw<T, P, I>(&mut self, query: &T, params: I) -> Result<RowIter<'_>, Error> fn query_raw<T, P, I>(&mut self, query: &T, params: I) -> Result<RowIter<'_>, $err>
where where
T: ?Sized + ToStatement, T: ?Sized + ToStatement,
P: BorrowToSql, P: BorrowToSql,
@ -45,34 +45,74 @@ pub trait GenericClient: private::Sealed {
I::IntoIter: ExactSizeIterator; I::IntoIter: ExactSizeIterator;
/// Like `Client::prepare`. /// Like `Client::prepare`.
fn prepare(&mut self, query: &str) -> Result<Statement, Error>; fn prepare(&mut self, query: &str) -> Result<Statement, $err>;
/// Like `Client::prepare_typed`. /// Like `Client::prepare_typed`.
fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result<Statement, Error>; fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result<Statement, $err>;
/// Like `Client::copy_in`. /// Like `Client::copy_in`.
fn copy_in<T>(&mut self, query: &T) -> Result<CopyInWriter<'_>, Error> fn copy_in<T>(&mut self, query: &T) -> Result<CopyInWriter<'_>, $err>
where where
T: ?Sized + ToStatement; T: ?Sized + ToStatement;
/// Like `Client::copy_out`. /// Like `Client::copy_out`.
fn copy_out<T>(&mut self, query: &T) -> Result<CopyOutReader<'_>, Error> fn copy_out<T>(&mut self, query: &T) -> Result<CopyOutReader<'_>, $err>
where where
T: ?Sized + ToStatement; T: ?Sized + ToStatement;
/// Like `Client::simple_query`. /// Like `Client::simple_query`.
fn simple_query(&mut self, query: &str) -> Result<Vec<SimpleQueryMessage>, Error>; fn simple_query(&mut self, query: &str) -> Result<Vec<SimpleQueryMessage>, $err>;
/// Like `Client::batch_execute`. /// Like `Client::batch_execute`.
fn batch_execute(&mut self, query: &str) -> Result<(), Error>; fn batch_execute(&mut self, query: &str) -> Result<(), $err>;
/// Like `Client::transaction`. /// Like `Client::transaction`.
fn transaction(&mut self) -> Result<Transaction<'_>, Error>; fn transaction(&mut self) -> Result<$transaction, $err>;
};
} }
impl private::Sealed for Client {} pub trait GenericRow {
type Error: core::fmt::Debug;
fn columns(&self) -> &[Column];
fn len(&self) -> usize;
fn get<'a, I, T>(&'a self, idx: I) -> T
where
I: RowIndex + core::fmt::Display,
T: FromSql<'a>;
fn try_get<'a, I, T>(&'a self, idx: I) -> Result<T, Self::Error>
where
I: RowIndex + core::fmt::Display,
T: FromSql<'a>;
}
pub trait GenericTransaction<'a> where Self: Sized {
type Error: core::fmt::Debug;
type NestedTransaction<'b> where Self: 'b;
type Row: GenericRow<Error = Self::Error>;
fn commit(self) -> Result<(), Self::Error>;
fn rollback(self) -> Result<(), Self::Error>;
common!(Self::NestedTransaction<'_>, Self::Error);
}
/// A trait allowing abstraction over connections and transactions.
pub trait GenericClient {
type Error: core::fmt::Debug;
type Transaction<'a>: GenericTransaction<'a> where Self: 'a;
type Row: GenericRow<Error = Self::Error>;
common!(Self::Transaction<'_>, Self::Error);
}
impl GenericClient for Client { impl GenericClient for Client {
type Error = Error;
type Transaction<'a> = Transaction<'a>;
type Row = Row;
fn execute<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<u64, Error> fn execute<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<u64, Error>
where where
T: ?Sized + ToStatement, T: ?Sized + ToStatement,
@ -80,14 +120,14 @@ impl GenericClient for Client {
self.execute(query, params) self.execute(query, params)
} }
fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>, Error> fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Self::Row>, Error>
where where
T: ?Sized + ToStatement, T: ?Sized + ToStatement,
{ {
self.query(query, params) self.query(query, params)
} }
fn query_one<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Row, Error> fn query_one<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Self::Row, Error>
where where
T: ?Sized + ToStatement, T: ?Sized + ToStatement,
{ {
@ -98,7 +138,7 @@ impl GenericClient for Client {
&mut self, &mut self,
query: &T, query: &T,
params: &[&(dyn ToSql + Sync)], params: &[&(dyn ToSql + Sync)],
) -> Result<Option<Row>, Error> ) -> Result<Option<Self::Row>, Error>
where where
T: ?Sized + ToStatement, T: ?Sized + ToStatement,
{ {
@ -145,87 +185,131 @@ impl GenericClient for Client {
self.batch_execute(query) self.batch_execute(query)
} }
fn transaction(&mut self) -> Result<Transaction<'_>, Error> { fn transaction(&mut self) -> Result<Self::Transaction<'_>, Error> {
self.transaction() self.transaction()
} }
} }
impl private::Sealed for Transaction<'_> {} macro_rules! transaction_common {
($transaction:ty) => {
fn execute<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<u64, Error>
where
T: ?Sized + ToStatement,
{
self.execute(query, params)
}
fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Self::Row>, Error>
where
T: ?Sized + ToStatement,
{
self.query(query, params)
}
fn query_one<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Self::Row, Error>
where
T: ?Sized + ToStatement,
{
self.query_one(query, params)
}
fn query_opt<T>(
&mut self,
query: &T,
params: &[&(dyn ToSql + Sync)],
) -> Result<Option<Self::Row>, Error>
where
T: ?Sized + ToStatement,
{
self.query_opt(query, params)
}
fn query_raw<T, P, I>(&mut self, query: &T, params: I) -> Result<RowIter<'_>, Error>
where
T: ?Sized + ToStatement,
P: BorrowToSql,
I: IntoIterator<Item = P>,
I::IntoIter: ExactSizeIterator,
{
self.query_raw(query, params)
}
fn prepare(&mut self, query: &str) -> Result<Statement, Error> {
self.prepare(query)
}
fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result<Statement, Error> {
self.prepare_typed(query, types)
}
fn copy_in<T>(&mut self, query: &T) -> Result<CopyInWriter<'_>, Error>
where
T: ?Sized + ToStatement,
{
self.copy_in(query)
}
fn copy_out<T>(&mut self, query: &T) -> Result<CopyOutReader<'_>, Error>
where
T: ?Sized + ToStatement,
{
self.copy_out(query)
}
fn simple_query(&mut self, query: &str) -> Result<Vec<SimpleQueryMessage>, Error> {
self.simple_query(query)
}
fn batch_execute(&mut self, query: &str) -> Result<(), Error> {
self.batch_execute(query)
}
fn transaction(&mut self) -> Result<$transaction, Error> {
self.transaction()
}
};
}
impl<'a> GenericTransaction<'a> for Transaction<'a> {
type Error = Error;
type NestedTransaction<'b> = Transaction<'b> where Self: 'b;
type Row = Row;
fn commit(self) -> Result<(), Error> {Transaction::commit(self)}
fn rollback(self) -> Result<(), Error> {Transaction::rollback(self)}
transaction_common!(Self::NestedTransaction<'_>);
}
impl GenericClient for Transaction<'_> { impl GenericClient for Transaction<'_> {
fn execute<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<u64, Error> type Error = Error;
type Transaction<'a> = Transaction<'a> where Self: 'a;
type Row = Row;
transaction_common!(Self::Transaction<'_>);
}
impl GenericRow for Row {
type Error = Error;
fn columns(&self) -> &[Column] {
self.columns()
}
fn len(&self) -> usize {
self.len()
}
fn get<'a, I, T>(&'a self, idx: I) -> T
where where
T: ?Sized + ToStatement, I: RowIndex + core::fmt::Display,
{ T: FromSql<'a> {
self.execute(query, params) self.get(idx)
} }
fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>, Error> fn try_get<'a, I, T>(&'a self, idx: I) -> Result<T, Error>
where where
T: ?Sized + ToStatement, I: RowIndex + core::fmt::Display,
{ T: FromSql<'a> {
self.query(query, params) self.try_get(idx)
}
fn query_one<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Row, Error>
where
T: ?Sized + ToStatement,
{
self.query_one(query, params)
}
fn query_opt<T>(
&mut self,
query: &T,
params: &[&(dyn ToSql + Sync)],
) -> Result<Option<Row>, Error>
where
T: ?Sized + ToStatement,
{
self.query_opt(query, params)
}
fn query_raw<T, P, I>(&mut self, query: &T, params: I) -> Result<RowIter<'_>, Error>
where
T: ?Sized + ToStatement,
P: BorrowToSql,
I: IntoIterator<Item = P>,
I::IntoIter: ExactSizeIterator,
{
self.query_raw(query, params)
}
fn prepare(&mut self, query: &str) -> Result<Statement, Error> {
self.prepare(query)
}
fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result<Statement, Error> {
self.prepare_typed(query, types)
}
fn copy_in<T>(&mut self, query: &T) -> Result<CopyInWriter<'_>, Error>
where
T: ?Sized + ToStatement,
{
self.copy_in(query)
}
fn copy_out<T>(&mut self, query: &T) -> Result<CopyOutReader<'_>, Error>
where
T: ?Sized + ToStatement,
{
self.copy_out(query)
}
fn simple_query(&mut self, query: &str) -> Result<Vec<SimpleQueryMessage>, Error> {
self.simple_query(query)
}
fn batch_execute(&mut self, query: &str) -> Result<(), Error> {
self.batch_execute(query)
}
fn transaction(&mut self) -> Result<Transaction<'_>, Error> {
self.transaction()
} }
} }

View File

@ -69,7 +69,7 @@
pub use fallible_iterator; pub use fallible_iterator;
pub use tokio_postgres::{ pub use tokio_postgres::{
error, row, tls, types, Column, IsolationLevel, Notification, Portal, SimpleQueryMessage, error, row, tls, types, Column, IsolationLevel, Notification, Portal, SimpleQueryMessage,
Socket, Statement, ToStatement, Socket, Statement, ToStatement, StatementOrString,
}; };
pub use crate::cancel_token::CancelToken; pub use crate::cancel_token::CancelToken;
@ -79,7 +79,7 @@ pub use crate::copy_in_writer::CopyInWriter;
pub use crate::copy_out_reader::CopyOutReader; pub use crate::copy_out_reader::CopyOutReader;
#[doc(no_inline)] #[doc(no_inline)]
pub use crate::error::Error; pub use crate::error::Error;
pub use crate::generic_client::GenericClient; pub use crate::generic_client::{GenericClient, GenericTransaction, GenericRow};
#[doc(inline)] #[doc(inline)]
pub use crate::notifications::Notifications; pub use crate::notifications::Notifications;
#[doc(no_inline)] #[doc(no_inline)]

View File

@ -138,7 +138,7 @@ pub use crate::statement::{Column, Statement};
#[cfg(feature = "runtime")] #[cfg(feature = "runtime")]
use crate::tls::MakeTlsConnect; use crate::tls::MakeTlsConnect;
pub use crate::tls::NoTls; pub use crate::tls::NoTls;
pub use crate::to_statement::ToStatement; pub use crate::to_statement::{ToStatement, StatementOrString};
pub use crate::transaction::Transaction; pub use crate::transaction::Transaction;
pub use crate::transaction_builder::{IsolationLevel, TransactionBuilder}; pub use crate::transaction_builder::{IsolationLevel, TransactionBuilder};
use crate::types::ToSql; use crate::types::ToSql;

View File

@ -71,7 +71,7 @@ pub struct Column {
} }
impl Column { impl Column {
pub(crate) fn new(name: String, type_: Type) -> Column { pub fn new(name: String, type_: Type) -> Column {
Column { name, type_ } Column { name, type_ }
} }

View File

@ -1,23 +1,26 @@
use crate::to_statement::private::{Sealed, ToStatementType}; #![allow(missing_docs)]
use crate::Statement; use crate::Statement;
use crate::{Client, Error};
mod private { pub enum StatementOrString<'a> {
use crate::{Client, Error, Statement}; Statement(&'a Statement),
Query(&'a str),
}
pub trait Sealed {} impl<'a> StatementOrString<'a> {
pub async fn into_statement(self, client: &Client) -> Result<Statement, Error> {
pub enum ToStatementType<'a> { match self {
Statement(&'a Statement), StatementOrString::Statement(s) => Ok(s.clone()),
Query(&'a str), StatementOrString::Query(s) => client.prepare(s).await,
}
} }
impl<'a> ToStatementType<'a> { pub fn unwrap_str(self) -> &'a str {
pub async fn into_statement(self, client: &Client) -> Result<Statement, Error> { match self {
match self { StatementOrString::Query(s) => s,
ToStatementType::Statement(s) => Ok(s.clone()), _ => panic!(),
ToStatementType::Query(s) => client.prepare(s).await, }
}
}
} }
} }
@ -25,33 +28,24 @@ mod private {
/// ///
/// Many methods are generic over this bound, so that they support both a raw query string as well as a statement which /// Many methods are generic over this bound, so that they support both a raw query string as well as a statement which
/// was prepared previously. /// was prepared previously.
/// pub trait ToStatement {
/// This trait is "sealed" and cannot be implemented by anything outside this crate. fn __convert(&self) -> StatementOrString<'_>;
pub trait ToStatement: Sealed {
#[doc(hidden)]
fn __convert(&self) -> ToStatementType<'_>;
} }
impl ToStatement for Statement { impl ToStatement for Statement {
fn __convert(&self) -> ToStatementType<'_> { fn __convert(&self) -> StatementOrString<'_> {
ToStatementType::Statement(self) StatementOrString::Statement(self)
} }
} }
impl Sealed for Statement {}
impl ToStatement for str { impl ToStatement for str {
fn __convert(&self) -> ToStatementType<'_> { fn __convert(&self) -> StatementOrString<'_> {
ToStatementType::Query(self) StatementOrString::Query(self)
} }
} }
impl Sealed for str {}
impl ToStatement for String { impl ToStatement for String {
fn __convert(&self) -> ToStatementType<'_> { fn __convert(&self) -> StatementOrString<'_> {
ToStatementType::Query(self) StatementOrString::Query(self)
} }
} }
impl Sealed for String {}