Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9cc4285

Browse files
authored
Add execute_typed* and query_typed* methods
1 parent b7f2cf0 commit 9cc4285

8 files changed

Lines changed: 613 additions & 0 deletions

File tree

postgres/src/client.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,48 @@ impl Client {
8383
self.connection.block_on(self.client.execute(query, params))
8484
}
8585

86+
/// Executes a statement, returning the number of rows modified.
87+
///
88+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
89+
/// provided, 1-indexed.
90+
///
91+
///
92+
/// Compared to `execute`, this method allows performing queries without three round trips (for
93+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
94+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
95+
/// supported (such as Cloudflare Workers with Hyperdrive).
96+
///
97+
/// If the statement does not modify any rows (e.g. `SELECT`), 0 is returned.
98+
///
99+
///
100+
/// # Example
101+
///
102+
/// ```no_run
103+
/// use postgres::{Client, NoTls, types::Type};
104+
///
105+
/// # fn main() -> Result<(), postgres::Error> {
106+
/// let mut client = Client::connect("host=localhost user=postgres", NoTls)?;
107+
///
108+
/// let bar = 1i32;
109+
/// let baz = true;
110+
/// let rows_updated = client.execute_typed(
111+
/// "UPDATE foo SET bar = $1 WHERE baz = $2",
112+
/// &[(&bar, Type::INT4), (&baz, Type::BOOL)],
113+
/// )?;
114+
///
115+
/// println!("{} rows updated", rows_updated);
116+
/// # Ok(())
117+
/// # }
118+
/// ```
119+
pub fn execute_typed(
120+
&mut self,
121+
query: &str,
122+
params: &[(&(dyn ToSql + Sync), Type)],
123+
) -> Result<u64, Error> {
124+
self.connection
125+
.block_on(self.client.execute_typed(query, params))
126+
}
127+
86128
/// Executes a statement, returning the resulting rows.
87129
///
88130
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
@@ -275,6 +317,49 @@ impl Client {
275317
.block_on(self.client.query_typed(query, params))
276318
}
277319

320+
/// Like `query_one`, but requires the types of query parameters to be explicitly specified.
321+
///
322+
/// Compared to `query_one`, this method allows performing queries without three round trips (for
323+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
324+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
325+
/// supported (such as Cloudflare Workers with Hyperdrive).
326+
///
327+
/// Executes a statement which returns a single row, returning it.
328+
///
329+
/// Returns an error if the query does not return exactly one row.
330+
///
331+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
332+
/// provided, 1-indexed.
333+
pub fn query_typed_one(
334+
&mut self,
335+
query: &str,
336+
params: &[(&(dyn ToSql + Sync), Type)],
337+
) -> Result<Row, Error> {
338+
self.connection
339+
.block_on(self.client.query_typed_one(query, params))
340+
}
341+
342+
/// Like `query_opt`, but requires the types of query parameters to be explicitly specified.
343+
///
344+
/// Compared to `query_opt`, this method allows performing queries without three round trips (for
345+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
346+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
347+
/// supported (such as Cloudflare Workers with Hyperdrive).
348+
/// Executes a statement which returns zero or one rows, returning it.
349+
///
350+
/// Returns an error if the query returns more than one row.
351+
///
352+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
353+
/// provided, 1-indexed.
354+
pub fn query_typed_opt(
355+
&mut self,
356+
query: &str,
357+
params: &[(&(dyn ToSql + Sync), Type)],
358+
) -> Result<Option<Row>, Error> {
359+
self.connection
360+
.block_on(self.client.query_typed_opt(query, params))
361+
}
362+
278363
/// The maximally flexible version of [`query_typed`].
279364
///
280365
/// Compared to `query`, this method allows performing queries without three round trips (for

postgres/src/generic_client.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ pub trait GenericClient: private::Sealed {
1717
where
1818
T: ?Sized + ToStatement;
1919

20+
/// Like `Client::execute_typed`.
21+
fn execute_typed(
22+
&mut self,
23+
query: &str,
24+
params: &[(&(dyn ToSql + Sync), Type)],
25+
) -> Result<u64, Error>;
26+
2027
/// Like `Client::query`.
2128
fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>
2229
where
@@ -51,6 +58,20 @@ pub trait GenericClient: private::Sealed {
5158
params: &[(&(dyn ToSql + Sync), Type)],
5259
) -> Result<Vec<Row>, Error>;
5360

61+
/// Like `Client::query_typed_one`.
62+
fn query_typed_one(
63+
&mut self,
64+
query: &str,
65+
params: &[(&(dyn ToSql + Sync), Type)],
66+
) -> Result<Row, Error>;
67+
68+
/// Like `Client::query_typed_opt`.
69+
fn query_typed_opt(
70+
&mut self,
71+
query: &str,
72+
params: &[(&(dyn ToSql + Sync), Type)],
73+
) -> Result<Option<Row>, Error>;
74+
5475
/// Like [`Client::query_typed_raw`]
5576
fn query_typed_raw<P, I>(&mut self, statement: &str, params: I) -> Result<RowIter<'_>, Error>
5677
where
@@ -136,6 +157,22 @@ impl GenericClient for Client {
136157
self.query_typed(statement, params)
137158
}
138159

160+
fn query_typed_one(
161+
&mut self,
162+
query: &str,
163+
params: &[(&(dyn ToSql + Sync), Type)],
164+
) -> Result<Row, Error> {
165+
self.query_typed_one(query, params)
166+
}
167+
168+
fn query_typed_opt(
169+
&mut self,
170+
query: &str,
171+
params: &[(&(dyn ToSql + Sync), Type)],
172+
) -> Result<Option<Row>, Error> {
173+
self.query_typed_opt(query, params)
174+
}
175+
139176
fn query_typed_raw<P, I>(&mut self, statement: &str, params: I) -> Result<RowIter<'_>, Error>
140177
where
141178
P: BorrowToSql,
@@ -177,6 +214,14 @@ impl GenericClient for Client {
177214
fn transaction(&mut self) -> Result<Transaction<'_>, Error> {
178215
self.transaction()
179216
}
217+
218+
fn execute_typed(
219+
&mut self,
220+
query: &str,
221+
params: &[(&(dyn ToSql + Sync), Type)],
222+
) -> Result<u64, Error> {
223+
self.execute_typed(query, params)
224+
}
180225
}
181226

182227
impl private::Sealed for Transaction<'_> {}
@@ -273,4 +318,28 @@ impl GenericClient for Transaction<'_> {
273318
fn transaction(&mut self) -> Result<Transaction<'_>, Error> {
274319
self.transaction()
275320
}
321+
322+
fn query_typed_one(
323+
&mut self,
324+
query: &str,
325+
params: &[(&(dyn ToSql + Sync), Type)],
326+
) -> Result<Row, Error> {
327+
self.query_typed_one(query, params)
328+
}
329+
330+
fn query_typed_opt(
331+
&mut self,
332+
query: &str,
333+
params: &[(&(dyn ToSql + Sync), Type)],
334+
) -> Result<Option<Row>, Error> {
335+
self.query_typed_opt(query, params)
336+
}
337+
338+
fn execute_typed(
339+
&mut self,
340+
query: &str,
341+
params: &[(&(dyn ToSql + Sync), Type)],
342+
) -> Result<u64, Error> {
343+
self.execute_typed(query, params)
344+
}
276345
}

postgres/src/transaction.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ impl<'a> Transaction<'a> {
7070
.block_on(self.transaction.as_ref().unwrap().execute(query, params))
7171
}
7272

73+
/// Like `Client::execute_typed`.
74+
pub fn execute_typed(
75+
&mut self,
76+
query: &str,
77+
params: &[(&(dyn ToSql + Sync), Type)],
78+
) -> Result<u64, Error> {
79+
self.connection.block_on(
80+
self.transaction
81+
.as_ref()
82+
.unwrap()
83+
.execute_typed(query, params),
84+
)
85+
}
86+
7387
/// Like `Client::query`.
7488
pub fn query<T>(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>
7589
where
@@ -129,6 +143,34 @@ impl<'a> Transaction<'a> {
129143
)
130144
}
131145

146+
/// Like `Client::query_typed_one`.
147+
pub fn query_typed_one(
148+
&mut self,
149+
query: &str,
150+
params: &[(&(dyn ToSql + Sync), Type)],
151+
) -> Result<Row, Error> {
152+
self.connection.block_on(
153+
self.transaction
154+
.as_ref()
155+
.unwrap()
156+
.query_typed_one(query, params),
157+
)
158+
}
159+
160+
/// Like `Client::query_typed_opt`.
161+
pub fn query_typed_opt(
162+
&mut self,
163+
query: &str,
164+
params: &[(&(dyn ToSql + Sync), Type)],
165+
) -> Result<Option<Row>, Error> {
166+
self.connection.block_on(
167+
self.transaction
168+
.as_ref()
169+
.unwrap()
170+
.query_typed_opt(query, params),
171+
)
172+
}
173+
132174
/// Like `Client::query_typed_raw`.
133175
pub fn query_typed_raw<P, I>(&mut self, query: &str, params: I) -> Result<RowIter<'_>, Error>
134176
where

tokio-postgres/src/client.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,70 @@ impl Client {
450450
.await
451451
}
452452

453+
/// Like `query_one`, but requires the types of query parameters to be explicitly specified.
454+
///
455+
/// Compared to `query_one`, this method allows performing queries without three round trips (for
456+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
457+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
458+
/// supported (such as Cloudflare Workers with Hyperdrive).
459+
///
460+
/// Executes a statement which returns a single row, returning it.
461+
///
462+
/// Returns an error if the query does not return exactly one row.
463+
///
464+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
465+
/// provided, 1-indexed.
466+
///
467+
pub async fn query_typed_one(
468+
&self,
469+
statement: &str,
470+
params: &[(&(dyn ToSql + Sync), Type)],
471+
) -> Result<Row, Error> {
472+
self.query_typed_opt(statement, params)
473+
.await
474+
.and_then(|res| res.ok_or_else(Error::row_count))
475+
}
476+
477+
/// Like `query_one`, but requires the types of query parameters to be explicitly specified.
478+
///
479+
/// Compared to `query_one`, this method allows performing queries without three round trips (for
480+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
481+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
482+
/// supported (such as Cloudflare Workers with Hyperdrive).
483+
///
484+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the
485+
/// parameter of the list provided, 1-indexed.
486+
/// Executes a statements which returns zero or one rows, returning it.
487+
///
488+
/// Returns an error if the query returns more than one row.
489+
pub async fn query_typed_opt(
490+
&self,
491+
statement: &str,
492+
params: &[(&(dyn ToSql + Sync), Type)],
493+
) -> Result<Option<Row>, Error> {
494+
let mut stream = pin!(
495+
self.query_typed_raw(statement, params.iter().map(|(v, t)| (*v, t.clone())))
496+
.await?
497+
);
498+
499+
let mut first = None;
500+
501+
// Originally this was two calls to `try_next().await?`,
502+
// once for the first element, and second to error if more than one.
503+
//
504+
// However, this new form with only one .await in a loop generates
505+
// slightly smaller codegen/stack usage for the resulting future.
506+
while let Some(row) = stream.try_next().await? {
507+
if first.is_some() {
508+
return Err(Error::row_count());
509+
}
510+
511+
first = Some(row);
512+
}
513+
514+
Ok(first)
515+
}
516+
453517
/// The maximally flexible version of [`query_typed`].
454518
///
455519
/// Compared to `query`, this method allows performing queries without three round trips (for
@@ -515,6 +579,29 @@ impl Client {
515579
self.execute_raw(statement, slice_iter(params)).await
516580
}
517581

582+
/// Executes a statement, returning the number of rows modified.
583+
///
584+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
585+
/// provided, 1-indexed.
586+
///
587+
/// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be
588+
/// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front
589+
/// with the `prepare` method.
590+
///
591+
/// If the statement does not modify any rows (e.g. `SELECT`), 0 is returned.
592+
pub async fn execute_typed(
593+
&self,
594+
statement: &str,
595+
params: &[(&(dyn ToSql + Sync), Type)],
596+
) -> Result<u64, Error> {
597+
query::execute_typed(
598+
&self.inner,
599+
statement,
600+
params.iter().map(|(v, t)| (*v, t.clone())),
601+
)
602+
.await
603+
}
604+
518605
/// The maximally flexible version of [`execute`].
519606
///
520607
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list

0 commit comments

Comments
 (0)