Skip to content

Commit f4f6b41

Browse files
authored
Merge pull request sfackler#458 from sfackler/param-iter
Add methods that take iterators of parameters
2 parents effd4df + 8192c77 commit f4f6b41

File tree

5 files changed

+149
-28
lines changed

5 files changed

+149
-28
lines changed

tokio-postgres/src/lib.rs

+74
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,17 @@ impl Client {
197197
///
198198
/// Panics if the number of parameters provided does not match the number expected.
199199
pub fn execute(&mut self, statement: &Statement, params: &[&dyn ToSql]) -> impls::Execute {
200+
self.execute_iter(statement, params.iter().cloned())
201+
}
202+
203+
/// Like [`execute`], but takes an iterator of parameters rather than a slice.
204+
///
205+
/// [`execute`]: #method.execute
206+
pub fn execute_iter<'a, I>(&mut self, statement: &Statement, params: I) -> impls::Execute
207+
where
208+
I: IntoIterator<Item = &'a dyn ToSql>,
209+
I::IntoIter: ExactSizeIterator,
210+
{
200211
impls::Execute(self.0.execute(&statement.0, params))
201212
}
202213

@@ -206,6 +217,17 @@ impl Client {
206217
///
207218
/// Panics if the number of parameters provided does not match the number expected.
208219
pub fn query(&mut self, statement: &Statement, params: &[&dyn ToSql]) -> impls::Query {
220+
self.query_iter(statement, params.iter().cloned())
221+
}
222+
223+
/// Like [`query`], but takes an iterator of parameters rather than a slice.
224+
///
225+
/// [`query`]: #method.query
226+
pub fn query_iter<'a, I>(&mut self, statement: &Statement, params: I) -> impls::Query
227+
where
228+
I: IntoIterator<Item = &'a dyn ToSql>,
229+
I::IntoIter: ExactSizeIterator,
230+
{
209231
impls::Query(self.0.query(&statement.0, params))
210232
}
211233

@@ -214,10 +236,22 @@ impl Client {
214236
/// Portals only last for the duration of the transaction in which they are created - in particular, a portal
215237
/// created outside of a transaction is immediately destroyed. Portals can only be used on the connection that
216238
/// created them.
239+
///
217240
/// # Panics
218241
///
219242
/// Panics if the number of parameters provided does not match the number expected.
220243
pub fn bind(&mut self, statement: &Statement, params: &[&dyn ToSql]) -> impls::Bind {
244+
self.bind_iter(statement, params.iter().cloned())
245+
}
246+
247+
/// Like [`bind`], but takes an iterator of parameters rather than a slice.
248+
///
249+
/// [`bind`]: #method.bind
250+
pub fn bind_iter<'a, I>(&mut self, statement: &Statement, params: I) -> impls::Bind
251+
where
252+
I: IntoIterator<Item = &'a dyn ToSql>,
253+
I::IntoIter: ExactSizeIterator,
254+
{
221255
impls::Bind(self.0.bind(&statement.0, next_portal(), params))
222256
}
223257

@@ -233,6 +267,10 @@ impl Client {
233267
///
234268
/// The data in the provided stream is passed along to the server verbatim; it is the caller's responsibility to
235269
/// ensure it uses the proper format.
270+
///
271+
/// # Panics
272+
///
273+
/// Panics if the number of parameters provided does not match the number expected.
236274
pub fn copy_in<S>(
237275
&mut self,
238276
statement: &Statement,
@@ -245,12 +283,48 @@ impl Client {
245283
<S::Item as IntoBuf>::Buf: 'static + Send,
246284
// FIXME error type?
247285
S::Error: Into<Box<dyn StdError + Sync + Send>>,
286+
{
287+
self.copy_in_iter(statement, params.iter().cloned(), stream)
288+
}
289+
290+
/// Like [`copy_in`], except that it takes an iterator of parameters rather than a slice.
291+
///
292+
/// [`copy_in`]: #method.copy_in
293+
pub fn copy_in_iter<'a, I, S>(
294+
&mut self,
295+
statement: &Statement,
296+
params: I,
297+
stream: S,
298+
) -> impls::CopyIn<S>
299+
where
300+
I: IntoIterator<Item = &'a dyn ToSql>,
301+
I::IntoIter: ExactSizeIterator,
302+
S: Stream,
303+
S::Item: IntoBuf,
304+
<S::Item as IntoBuf>::Buf: 'static + Send,
305+
// FIXME error type?
306+
S::Error: Into<Box<dyn StdError + Sync + Send>>,
248307
{
249308
impls::CopyIn(self.0.copy_in(&statement.0, params, stream))
250309
}
251310

252311
/// Executes a `COPY TO STDOUT` statement, returning a stream of the resulting data.
312+
///
313+
/// # Panics
314+
///
315+
/// Panics if the number of parameters provided does not match the number expected.
253316
pub fn copy_out(&mut self, statement: &Statement, params: &[&dyn ToSql]) -> impls::CopyOut {
317+
self.copy_out_iter(statement, params.iter().cloned())
318+
}
319+
320+
/// Like [`copy_out`], except that it takes an iterator of parameters rather than a slice.
321+
///
322+
/// [`copy_out`]: #method.copy_out
323+
pub fn copy_out_iter<'a, I>(&mut self, statement: &Statement, params: I) -> impls::CopyOut
324+
where
325+
I: IntoIterator<Item = &'a dyn ToSql>,
326+
I::IntoIter: ExactSizeIterator,
327+
{
254328
impls::CopyOut(self.0.copy_out(&statement.0, params))
255329
}
256330

tokio-postgres/src/proto/client.rs

+40-17
Original file line numberDiff line numberDiff line change
@@ -165,23 +165,35 @@ impl Client {
165165
PrepareFuture::new(self.clone(), pending, name)
166166
}
167167

168-
pub fn execute(&self, statement: &Statement, params: &[&dyn ToSql]) -> ExecuteFuture {
168+
pub fn execute<'a, I>(&self, statement: &Statement, params: I) -> ExecuteFuture
169+
where
170+
I: IntoIterator<Item = &'a dyn ToSql>,
171+
I::IntoIter: ExactSizeIterator,
172+
{
169173
let pending = PendingRequest(
170174
self.excecute_message(statement, params)
171175
.map(|m| (RequestMessages::Single(m), self.0.idle.guard())),
172176
);
173177
ExecuteFuture::new(self.clone(), pending, statement.clone())
174178
}
175179

176-
pub fn query(&self, statement: &Statement, params: &[&dyn ToSql]) -> QueryStream<Statement> {
180+
pub fn query<'a, I>(&self, statement: &Statement, params: I) -> QueryStream<Statement>
181+
where
182+
I: IntoIterator<Item = &'a dyn ToSql>,
183+
I::IntoIter: ExactSizeIterator,
184+
{
177185
let pending = PendingRequest(
178186
self.excecute_message(statement, params)
179187
.map(|m| (RequestMessages::Single(m), self.0.idle.guard())),
180188
);
181189
QueryStream::new(self.clone(), pending, statement.clone())
182190
}
183191

184-
pub fn bind(&self, statement: &Statement, name: String, params: &[&dyn ToSql]) -> BindFuture {
192+
pub fn bind<'a, I>(&self, statement: &Statement, name: String, params: I) -> BindFuture
193+
where
194+
I: IntoIterator<Item = &'a dyn ToSql>,
195+
I::IntoIter: ExactSizeIterator,
196+
{
185197
let mut buf = self.bind_message(statement, &name, params);
186198
if let Ok(ref mut buf) = buf {
187199
frontend::sync(buf);
@@ -204,17 +216,14 @@ impl Client {
204216
QueryStream::new(self.clone(), pending, portal.clone())
205217
}
206218

207-
pub fn copy_in<S>(
208-
&self,
209-
statement: &Statement,
210-
params: &[&dyn ToSql],
211-
stream: S,
212-
) -> CopyInFuture<S>
219+
pub fn copy_in<'a, S, I>(&self, statement: &Statement, params: I, stream: S) -> CopyInFuture<S>
213220
where
214221
S: Stream,
215222
S::Item: IntoBuf,
216223
<S::Item as IntoBuf>::Buf: 'static + Send,
217224
S::Error: Into<Box<dyn StdError + Sync + Send>>,
225+
I: IntoIterator<Item = &'a dyn ToSql>,
226+
I::IntoIter: ExactSizeIterator,
218227
{
219228
let (mut sender, receiver) = mpsc::channel(1);
220229
let pending = PendingRequest(self.excecute_message(statement, params).map(|data| {
@@ -233,7 +242,11 @@ impl Client {
233242
CopyInFuture::new(self.clone(), pending, statement.clone(), stream, sender)
234243
}
235244

236-
pub fn copy_out(&self, statement: &Statement, params: &[&dyn ToSql]) -> CopyOutStream {
245+
pub fn copy_out<'a, I>(&self, statement: &Statement, params: I) -> CopyOutStream
246+
where
247+
I: IntoIterator<Item = &'a dyn ToSql>,
248+
I::IntoIter: ExactSizeIterator,
249+
{
237250
let pending = PendingRequest(
238251
self.excecute_message(statement, params)
239252
.map(|m| (RequestMessages::Single(m), self.0.idle.guard())),
@@ -289,12 +302,18 @@ impl Client {
289302
});
290303
}
291304

292-
fn bind_message(
305+
fn bind_message<'a, I>(
293306
&self,
294307
statement: &Statement,
295308
name: &str,
296-
params: &[&dyn ToSql],
297-
) -> Result<Vec<u8>, Error> {
309+
params: I,
310+
) -> Result<Vec<u8>, Error>
311+
where
312+
I: IntoIterator<Item = &'a dyn ToSql>,
313+
I::IntoIter: ExactSizeIterator,
314+
{
315+
let params = params.into_iter();
316+
298317
assert!(
299318
statement.params().len() == params.len(),
300319
"expected {} parameters but got {}",
@@ -308,7 +327,7 @@ impl Client {
308327
name,
309328
statement.name(),
310329
Some(1),
311-
params.iter().zip(statement.params()).enumerate(),
330+
params.zip(statement.params()).enumerate(),
312331
|(idx, (param, ty)), buf| match param.to_sql_checked(ty, buf) {
313332
Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
314333
Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
@@ -327,11 +346,15 @@ impl Client {
327346
}
328347
}
329348

330-
fn excecute_message(
349+
fn excecute_message<'a, I>(
331350
&self,
332351
statement: &Statement,
333-
params: &[&dyn ToSql],
334-
) -> Result<FrontendMessage, Error> {
352+
params: I,
353+
) -> Result<FrontendMessage, Error>
354+
where
355+
I: IntoIterator<Item = &'a dyn ToSql>,
356+
I::IntoIter: ExactSizeIterator,
357+
{
335358
let mut buf = self.bind_message(statement, "", params)?;
336359
frontend::execute("", 0, &mut buf).map_err(Error::parse)?;
337360
frontend::sync(&mut buf);

tokio-postgres/src/proto/typeinfo.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::proto::query::QueryStream;
1010
use crate::proto::statement::Statement;
1111
use crate::proto::typeinfo_composite::TypeinfoCompositeFuture;
1212
use crate::proto::typeinfo_enum::TypeinfoEnumFuture;
13-
use crate::types::{Kind, Oid, Type};
13+
use crate::types::{Kind, Oid, ToSql, Type};
1414

1515
const TYPEINFO_QUERY: &str = "
1616
SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, t.typbasetype, n.nspname, t.typrelid
@@ -114,7 +114,10 @@ impl PollTypeinfo for Typeinfo {
114114

115115
match state.client.typeinfo_query() {
116116
Some(statement) => transition!(QueryingTypeinfo {
117-
future: state.client.query(&statement, &[&state.oid]).collect(),
117+
future: state
118+
.client
119+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
120+
.collect(),
118121
oid: state.oid,
119122
client: state.client,
120123
}),
@@ -149,7 +152,10 @@ impl PollTypeinfo for Typeinfo {
149152
};
150153
let state = state.take();
151154

152-
let future = state.client.query(&statement, &[&state.oid]).collect();
155+
let future = state
156+
.client
157+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
158+
.collect();
153159
state.client.set_typeinfo_query(&statement);
154160
transition!(QueryingTypeinfo {
155161
future,
@@ -164,7 +170,10 @@ impl PollTypeinfo for Typeinfo {
164170
let statement = try_ready!(state.future.poll());
165171
let state = state.take();
166172

167-
let future = state.client.query(&statement, &[&state.oid]).collect();
173+
let future = state
174+
.client
175+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
176+
.collect();
168177
state.client.set_typeinfo_query(&statement);
169178
transition!(QueryingTypeinfo {
170179
future,

tokio-postgres/src/proto/typeinfo_composite.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::proto::prepare::PrepareFuture;
1111
use crate::proto::query::QueryStream;
1212
use crate::proto::statement::Statement;
1313
use crate::proto::typeinfo::TypeinfoFuture;
14-
use crate::types::{Field, Oid};
14+
use crate::types::{Field, Oid, ToSql};
1515

1616
const TYPEINFO_COMPOSITE_QUERY: &str = "
1717
SELECT attname, atttypid
@@ -59,7 +59,10 @@ impl PollTypeinfoComposite for TypeinfoComposite {
5959

6060
match state.client.typeinfo_composite_query() {
6161
Some(statement) => transition!(QueryingCompositeFields {
62-
future: state.client.query(&statement, &[&state.oid]).collect(),
62+
future: state
63+
.client
64+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
65+
.collect(),
6366
client: state.client,
6467
}),
6568
None => transition!(PreparingTypeinfoComposite {
@@ -82,7 +85,10 @@ impl PollTypeinfoComposite for TypeinfoComposite {
8285

8386
state.client.set_typeinfo_composite_query(&statement);
8487
transition!(QueryingCompositeFields {
85-
future: state.client.query(&statement, &[&state.oid]).collect(),
88+
future: state
89+
.client
90+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
91+
.collect(),
8692
client: state.client,
8793
})
8894
}

tokio-postgres/src/proto/typeinfo_enum.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::proto::client::Client;
88
use crate::proto::prepare::PrepareFuture;
99
use crate::proto::query::QueryStream;
1010
use crate::proto::statement::Statement;
11-
use crate::types::Oid;
11+
use crate::types::{Oid, ToSql};
1212

1313
const TYPEINFO_ENUM_QUERY: &str = "
1414
SELECT enumlabel
@@ -58,7 +58,10 @@ impl PollTypeinfoEnum for TypeinfoEnum {
5858

5959
match state.client.typeinfo_enum_query() {
6060
Some(statement) => transition!(QueryingEnumVariants {
61-
future: state.client.query(&statement, &[&state.oid]).collect(),
61+
future: state
62+
.client
63+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
64+
.collect(),
6265
client: state.client,
6366
}),
6467
None => transition!(PreparingTypeinfoEnum {
@@ -98,7 +101,10 @@ impl PollTypeinfoEnum for TypeinfoEnum {
98101

99102
state.client.set_typeinfo_enum_query(&statement);
100103
transition!(QueryingEnumVariants {
101-
future: state.client.query(&statement, &[&state.oid]).collect(),
104+
future: state
105+
.client
106+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
107+
.collect(),
102108
client: state.client,
103109
})
104110
}
@@ -111,7 +117,10 @@ impl PollTypeinfoEnum for TypeinfoEnum {
111117

112118
state.client.set_typeinfo_enum_query(&statement);
113119
transition!(QueryingEnumVariants {
114-
future: state.client.query(&statement, &[&state.oid]).collect(),
120+
future: state
121+
.client
122+
.query(&statement, [&state.oid as &dyn ToSql].iter().cloned())
123+
.collect(),
115124
client: state.client,
116125
})
117126
}

0 commit comments

Comments
 (0)