Skip to content

Commit 0eab5fa

Browse files
committed
make iterators from &dyn ToSql or T: ToSql work as parameters
1 parent 5e065c3 commit 0eab5fa

File tree

5 files changed

+60
-21
lines changed

5 files changed

+60
-21
lines changed

postgres-types/src/lib.rs

+18
Original file line numberDiff line numberDiff line change
@@ -951,3 +951,21 @@ fn downcast(len: usize) -> Result<i32, Box<dyn Error + Sync + Send>> {
951951
Ok(len as i32)
952952
}
953953
}
954+
955+
/// A helper trait to be able create a parameters iterator from `&dyn ToSql` or `T: ToSql`
956+
pub trait BorrowToSql {
957+
/// Get a reference to a `ToSql` trait object
958+
fn borrow_to_sql(&self) -> &dyn ToSql;
959+
}
960+
961+
impl BorrowToSql for &dyn ToSql {
962+
fn borrow_to_sql(&self) -> &dyn ToSql {
963+
*self
964+
}
965+
}
966+
967+
impl<T: ToSql> BorrowToSql for T {
968+
fn borrow_to_sql(&self) -> &dyn ToSql {
969+
self
970+
}
971+
}

tokio-postgres/src/binary_copy.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use byteorder::{BigEndian, ByteOrder};
66
use bytes::{Buf, BufMut, Bytes, BytesMut};
77
use futures::{ready, SinkExt, Stream};
88
use pin_project_lite::pin_project;
9+
use postgres_types::BorrowToSql;
910
use std::convert::TryFrom;
1011
use std::io;
1112
use std::io::Cursor;
@@ -58,9 +59,10 @@ impl BinaryCopyInWriter {
5859
/// # Panics
5960
///
6061
/// Panics if the number of values provided does not match the number expected.
61-
pub async fn write_raw<'a, I>(self: Pin<&mut Self>, values: I) -> Result<(), Error>
62+
pub async fn write_raw<P, I>(self: Pin<&mut Self>, values: I) -> Result<(), Error>
6263
where
63-
I: IntoIterator<Item = &'a dyn ToSql>,
64+
P: BorrowToSql,
65+
I: IntoIterator<Item = P>,
6466
I::IntoIter: ExactSizeIterator,
6567
{
6668
let mut this = self.project();
@@ -79,6 +81,7 @@ impl BinaryCopyInWriter {
7981
let idx = this.buf.len();
8082
this.buf.put_i32(0);
8183
let len = match value
84+
.borrow_to_sql()
8285
.to_sql_checked(type_, this.buf)
8386
.map_err(|e| Error::to_sql(e, i))?
8487
{

tokio-postgres/src/bind.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::client::InnerClient;
22
use crate::codec::FrontendMessage;
33
use crate::connection::RequestMessages;
4-
use crate::types::ToSql;
4+
use crate::types::BorrowToSql;
55
use crate::{query, Error, Portal, Statement};
66
use postgres_protocol::message::backend::Message;
77
use postgres_protocol::message::frontend;
@@ -10,13 +10,14 @@ use std::sync::Arc;
1010

1111
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
1212

13-
pub async fn bind<'a, I>(
13+
pub async fn bind<P, I>(
1414
client: &Arc<InnerClient>,
1515
statement: Statement,
1616
params: I,
1717
) -> Result<Portal, Error>
1818
where
19-
I: IntoIterator<Item = &'a dyn ToSql>,
19+
P: BorrowToSql,
20+
I: IntoIterator<Item = P>,
2021
I::IntoIter: ExactSizeIterator,
2122
{
2223
let name = format!("p{}", NEXT_ID.fetch_add(1, Ordering::SeqCst));

tokio-postgres/src/client.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use futures::channel::mpsc;
2020
use futures::{future, pin_mut, ready, StreamExt, TryStreamExt};
2121
use parking_lot::Mutex;
2222
use postgres_protocol::message::backend::Message;
23+
use postgres_types::BorrowToSql;
2324
use std::collections::HashMap;
2425
use std::fmt;
2526
use std::sync::Arc;
@@ -342,10 +343,11 @@ impl Client {
342343
/// # Ok(())
343344
/// # }
344345
/// ```
345-
pub async fn query_raw<'a, T, I>(&self, statement: &T, params: I) -> Result<RowStream, Error>
346+
pub async fn query_raw<T, P, I>(&self, statement: &T, params: I) -> Result<RowStream, Error>
346347
where
347348
T: ?Sized + ToStatement,
348-
I: IntoIterator<Item = &'a dyn ToSql>,
349+
P: BorrowToSql,
350+
I: IntoIterator<Item = P>,
349351
I::IntoIter: ExactSizeIterator,
350352
{
351353
let statement = statement.__convert().into_statement(self).await?;
@@ -391,10 +393,11 @@ impl Client {
391393
/// Panics if the number of parameters provided does not match the number expected.
392394
///
393395
/// [`execute`]: #method.execute
394-
pub async fn execute_raw<'a, T, I>(&self, statement: &T, params: I) -> Result<u64, Error>
396+
pub async fn execute_raw<T, P, I>(&self, statement: &T, params: I) -> Result<u64, Error>
395397
where
396398
T: ?Sized + ToStatement,
397-
I: IntoIterator<Item = &'a dyn ToSql>,
399+
P: BorrowToSql,
400+
I: IntoIterator<Item = P>,
398401
I::IntoIter: ExactSizeIterator,
399402
{
400403
let statement = statement.__convert().into_statement(self).await?;

tokio-postgres/src/query.rs

+26-12
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
11
use crate::client::{InnerClient, Responses};
22
use crate::codec::FrontendMessage;
33
use crate::connection::RequestMessages;
4-
use crate::types::{IsNull, ToSql};
4+
use crate::types::{BorrowToSql, IsNull};
55
use crate::{Error, Portal, Row, Statement};
66
use bytes::{Bytes, BytesMut};
77
use futures::{ready, Stream};
88
use log::{debug, log_enabled, Level};
99
use pin_project_lite::pin_project;
1010
use postgres_protocol::message::backend::Message;
1111
use postgres_protocol::message::frontend;
12+
use std::fmt;
1213
use std::marker::PhantomPinned;
1314
use std::pin::Pin;
1415
use std::task::{Context, Poll};
1516

16-
pub async fn query<'a, I>(
17+
struct BorrowToSqlParamsDebug<'a, T: BorrowToSql>(&'a [T]);
18+
impl<'a, T: BorrowToSql> std::fmt::Debug for BorrowToSqlParamsDebug<'a, T> {
19+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20+
f.debug_list()
21+
.entries(self.0.iter().map(|x| x.borrow_to_sql()))
22+
.finish()
23+
}
24+
}
25+
26+
pub async fn query<P, I>(
1727
client: &InnerClient,
1828
statement: Statement,
1929
params: I,
2030
) -> Result<RowStream, Error>
2131
where
22-
I: IntoIterator<Item = &'a dyn ToSql>,
32+
P: BorrowToSql,
33+
I: IntoIterator<Item = P>,
2334
I::IntoIter: ExactSizeIterator,
2435
{
2536
let buf = if log_enabled!(Level::Debug) {
2637
let params = params.into_iter().collect::<Vec<_>>();
2738
debug!(
2839
"executing statement {} with parameters: {:?}",
2940
statement.name(),
30-
params,
41+
BorrowToSqlParamsDebug(params.as_slice()),
3142
);
3243
encode(client, &statement, params)?
3344
} else {
@@ -61,21 +72,22 @@ pub async fn query_portal(
6172
})
6273
}
6374

64-
pub async fn execute<'a, I>(
75+
pub async fn execute<P, I>(
6576
client: &InnerClient,
6677
statement: Statement,
6778
params: I,
6879
) -> Result<u64, Error>
6980
where
70-
I: IntoIterator<Item = &'a dyn ToSql>,
81+
P: BorrowToSql,
82+
I: IntoIterator<Item = P>,
7183
I::IntoIter: ExactSizeIterator,
7284
{
7385
let buf = if log_enabled!(Level::Debug) {
7486
let params = params.into_iter().collect::<Vec<_>>();
7587
debug!(
7688
"executing statement {} with parameters: {:?}",
7789
statement.name(),
78-
params,
90+
BorrowToSqlParamsDebug(params.as_slice()),
7991
);
8092
encode(client, &statement, params)?
8193
} else {
@@ -114,9 +126,10 @@ async fn start(client: &InnerClient, buf: Bytes) -> Result<Responses, Error> {
114126
Ok(responses)
115127
}
116128

117-
pub fn encode<'a, I>(client: &InnerClient, statement: &Statement, params: I) -> Result<Bytes, Error>
129+
pub fn encode<P, I>(client: &InnerClient, statement: &Statement, params: I) -> Result<Bytes, Error>
118130
where
119-
I: IntoIterator<Item = &'a dyn ToSql>,
131+
P: BorrowToSql,
132+
I: IntoIterator<Item = P>,
120133
I::IntoIter: ExactSizeIterator,
121134
{
122135
client.with_buf(|buf| {
@@ -127,14 +140,15 @@ where
127140
})
128141
}
129142

130-
pub fn encode_bind<'a, I>(
143+
pub fn encode_bind<P, I>(
131144
statement: &Statement,
132145
params: I,
133146
portal: &str,
134147
buf: &mut BytesMut,
135148
) -> Result<(), Error>
136149
where
137-
I: IntoIterator<Item = &'a dyn ToSql>,
150+
P: BorrowToSql,
151+
I: IntoIterator<Item = P>,
138152
I::IntoIter: ExactSizeIterator,
139153
{
140154
let params = params.into_iter();
@@ -152,7 +166,7 @@ where
152166
statement.name(),
153167
Some(1),
154168
params.zip(statement.params()).enumerate(),
155-
|(idx, (param, ty)), buf| match param.to_sql_checked(ty, buf) {
169+
|(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) {
156170
Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
157171
Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
158172
Err(e) => {

0 commit comments

Comments
 (0)