Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfdc1fcf

Browse files
committed
# This is a combination of 3 commits.
# This is the 1st commit message:add other query_typed helper functions# This is the commit message#2:add the same methods to sync version and add tests# This is the commit message#3:fix tests with appropriate placeholders
1 parentad78c1d commitfdc1fcf

File tree

7 files changed

+325
-0
lines changed

7 files changed

+325
-0
lines changed

‎postgres/src/client.rs‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,4 +621,47 @@ impl Client {
621621
}
622622
})
623623
}
624+
625+
/// Like `query_one`, but requires the types of query parameters to be explicitly specified.
626+
///
627+
/// Compared to `query_one`, this method allows performing queries without three round trips (for
628+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
629+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
630+
/// supported (such as Cloudflare Workers with Hyperdrive).
631+
///
632+
/// Executes a statement which returns a single row, returning it.
633+
///
634+
/// Returns an error if the query does not return exactly one row.
635+
///
636+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
637+
/// provided, 1-indexed.
638+
pubfnquery_typed_one(
639+
&mutself,
640+
query:&str,
641+
params:&[(&(dynToSql +Sync),Type)],
642+
) ->Result<Row,Error>{
643+
self.connection
644+
.block_on(self.client.query_typed_one(query, params))
645+
}
646+
647+
/// Like `query_opt`, but requires the types of query parameters to be explicitly specified.
648+
///
649+
/// Compared to `query_opt`, this method allows performing queries without three round trips (for
650+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
651+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
652+
/// supported (such as Cloudflare Workers with Hyperdrive).
653+
/// Executes a statement which returns zero or one rows, returning it.
654+
///
655+
/// Returns an error if the query returns more than one row.
656+
///
657+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
658+
/// provided, 1-indexed.
659+
pubfnquery_typed_opt(
660+
&mutself,
661+
query:&str,
662+
params:&[(&(dynToSql +Sync),Type)],
663+
) ->Result<Option<Row>,Error>{
664+
self.connection
665+
.block_on(self.client.query_typed_opt(query, params))
666+
}
624667
}

‎postgres/src/generic_client.rs‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ pub trait GenericClient: private::Sealed {
5757
P:BorrowToSql,
5858
I:IntoIterator<Item =(P,Type)> +Sync +Send;
5959

60+
/// Like `Client::query_typed_one`.
61+
fnquery_typed_one(
62+
&mutself,
63+
query:&str,
64+
params:&[(&(dynToSql +Sync),Type)],
65+
) ->Result<Row,Error>;
66+
67+
/// Like `Client::query_typed_opt`.
68+
fnquery_typed_opt(
69+
&mutself,
70+
query:&str,
71+
params:&[(&(dynToSql +Sync),Type)],
72+
) ->Result<Option<Row>,Error>;
73+
6074
/// Like `Client::prepare`.
6175
fnprepare(&mutself,query:&str) ->Result<Statement,Error>;
6276

@@ -177,6 +191,24 @@ impl GenericClient for Client {
177191
fntransaction(&mutself) ->Result<Transaction<'_>,Error>{
178192
self.transaction()
179193
}
194+
195+
fnquery_typed_one(
196+
&mutself,
197+
query:&str,
198+
199+
params:&[(&(dynToSql +Sync),Type)],
200+
) ->Result<Row,Error>{
201+
self.query_typed_one(query, params)
202+
}
203+
204+
fnquery_typed_opt(
205+
&mutself,
206+
query:&str,
207+
208+
params:&[(&(dynToSql +Sync),Type)],
209+
) ->Result<Option<Row>,Error>{
210+
self.query_typed_opt(query, params)
211+
}
180212
}
181213

182214
impl private::SealedforTransaction<'_>{}
@@ -273,4 +305,20 @@ impl GenericClient for Transaction<'_> {
273305
fntransaction(&mutself) ->Result<Transaction<'_>,Error>{
274306
self.transaction()
275307
}
308+
309+
fnquery_typed_one(
310+
&mutself,
311+
query:&str,
312+
params:&[(&(dynToSql +Sync),Type)],
313+
) ->Result<Row,Error>{
314+
self.query_typed_one(query, params)
315+
}
316+
317+
fnquery_typed_opt(
318+
&mutself,
319+
query:&str,
320+
params:&[(&(dynToSql +Sync),Type)],
321+
) ->Result<Option<Row>,Error>{
322+
self.query_typed_opt(query, params)
323+
}
276324
}

‎postgres/src/transaction.rs‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,32 @@ impl<'a> Transaction<'a> {
247247
.block_on(self.transaction.as_mut().unwrap().savepoint(name))?;
248248
Ok(Transaction::new(self.connection.as_ref(), transaction))
249249
}
250+
251+
/// Like `Client::query_typed_one`.
252+
pubfnquery_typed_one(
253+
&mutself,
254+
query:&str,
255+
params:&[(&(dynToSql +Sync),Type)],
256+
) ->Result<Row,Error>{
257+
self.connection.block_on(
258+
self.transaction
259+
.as_ref()
260+
.unwrap()
261+
.query_typed_one(query, params),
262+
)
263+
}
264+
265+
/// Like `Client::query_typed_opt`.
266+
pubfnquery_typed_opt(
267+
&mutself,
268+
query:&str,
269+
params:&[(&(dynToSql +Sync),Type)],
270+
) ->Result<Option<Row>,Error>{
271+
self.connection.block_on(
272+
self.transaction
273+
.as_ref()
274+
.unwrap()
275+
.query_typed_opt(query, params),
276+
)
277+
}
250278
}

‎tokio-postgres/src/client.rs‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,70 @@ impl Client {
321321
Ok(first)
322322
}
323323

324+
/// Like `query_one`, but requires the types of query parameters to be explicitly specified.
325+
///
326+
/// Compared to `query_one`, this method allows performing queries without three round trips (for
327+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
328+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
329+
/// supported (such as Cloudflare Workers with Hyperdrive).
330+
///
331+
/// Executes a statement which returns a single row, returning it.
332+
///
333+
/// Returns an error if the query does not return exactly one row.
334+
///
335+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list
336+
/// provided, 1-indexed.
337+
///
338+
pubasyncfnquery_typed_one(
339+
&self,
340+
statement:&str,
341+
params:&[(&(dynToSql +Sync),Type)],
342+
) ->Result<Row,Error>{
343+
self.query_typed_opt(statement, params)
344+
.await
345+
.and_then(|res| res.ok_or_else(Error::row_count))
346+
}
347+
348+
/// Like `query_one`, but requires the types of query parameters to be explicitly specified.
349+
///
350+
/// Compared to `query_one`, this method allows performing queries without three round trips (for
351+
/// prepare, execute, and close) by requiring the caller to specify parameter values along with
352+
/// their Postgres type. Thus, this is suitable in environments where prepared statements aren't
353+
/// supported (such as Cloudflare Workers with Hyperdrive).
354+
///
355+
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the
356+
/// parameter of the list provided, 1-indexed.
357+
/// Executes a statements which returns zero or one rows, returning it.
358+
///
359+
/// Returns an error if the query returns more than one row.
360+
pubasyncfnquery_typed_opt(
361+
&self,
362+
statement:&str,
363+
params:&[(&(dynToSql +Sync),Type)],
364+
) ->Result<Option<Row>,Error>{
365+
let stream =self
366+
.query_typed_raw(statement, params.iter().map(|(v, t)|(*v, t.clone())))
367+
.await?;
368+
pin_mut!(stream);
369+
370+
letmut first =None;
371+
372+
// Originally this was two calls to `try_next().await?`,
373+
// once for the first element, and second to error if more than one.
374+
//
375+
// However, this new form with only one .await in a loop generates
376+
// slightly smaller codegen/stack usage for the resulting future.
377+
whileletSome(row) = stream.try_next().await?{
378+
if first.is_some(){
379+
returnErr(Error::row_count());
380+
}
381+
382+
first =Some(row);
383+
}
384+
385+
Ok(first)
386+
}
387+
324388
/// The maximally flexible version of [`query`].
325389
///
326390
/// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list

‎tokio-postgres/src/generic_client.rs‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ pub trait GenericClient: private::Sealed {
6969
P:BorrowToSql,
7070
I:IntoIterator<Item =(P,Type)> +Sync +Send;
7171

72+
/// Like [`Client::query_one_typed`].
73+
asyncfnquery_typed_one(
74+
&self,
75+
statement:&str,
76+
params:&[(&(dynToSql +Sync),Type)],
77+
) ->Result<Row,Error>;
78+
79+
/// Like [`Client::query_opt_typed`].
80+
asyncfnquery_typed_opt(
81+
&self,
82+
statement:&str,
83+
params:&[(&(dynToSql +Sync),Type)],
84+
) ->Result<Option<Row>,Error>;
85+
7286
/// Like [`Client::prepare`].
7387
asyncfnprepare(&self,query:&str) ->Result<Statement,Error>;
7488

@@ -195,6 +209,23 @@ impl GenericClient for Client {
195209
fnclient(&self) ->&Client{
196210
self
197211
}
212+
213+
asyncfnquery_typed_one(
214+
&self,
215+
statement:&str,
216+
params:&[(&(dynToSql +Sync),Type)],
217+
) ->Result<Row,Error>{
218+
self.query_typed_one(statement, params).await
219+
}
220+
221+
/// Like [`Client::query_opt_typed`].
222+
asyncfnquery_typed_opt(
223+
&self,
224+
statement:&str,
225+
params:&[(&(dynToSql +Sync),Type)],
226+
) ->Result<Option<Row>,Error>{
227+
self.query_typed_opt(statement, params).await
228+
}
198229
}
199230

200231
impl private::SealedforTransaction<'_>{}
@@ -302,4 +333,21 @@ impl GenericClient for Transaction<'_> {
302333
fnclient(&self) ->&Client{
303334
self.client()
304335
}
336+
337+
asyncfnquery_typed_one(
338+
&self,
339+
statement:&str,
340+
params:&[(&(dynToSql +Sync),Type)],
341+
) ->Result<Row,Error>{
342+
self.query_typed_one(statement, params).await
343+
}
344+
345+
/// Like [`Client::query_opt_typed`].
346+
asyncfnquery_typed_opt(
347+
&self,
348+
statement:&str,
349+
params:&[(&(dynToSql +Sync),Type)],
350+
) ->Result<Option<Row>,Error>{
351+
self.query_typed_opt(statement, params).await
352+
}
305353
}

‎tokio-postgres/src/transaction.rs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,4 +329,22 @@ impl<'a> Transaction<'a> {
329329
pubfnclient(&self) ->&Client{
330330
self.client
331331
}
332+
333+
/// Like `Client::query_typed_one`.
334+
pubasyncfnquery_typed_one(
335+
&self,
336+
statement:&str,
337+
params:&[(&(dynToSql +Sync),Type)],
338+
) ->Result<Row,Error>{
339+
self.client.query_typed_one(statement, params).await
340+
}
341+
342+
/// Like `Client::query_typed_opt`.
343+
pubasyncfnquery_typed_opt(
344+
&self,
345+
statement:&str,
346+
params:&[(&(dynToSql +Sync),Type)],
347+
) ->Result<Option<Row>,Error>{
348+
self.client.query_typed_opt(statement, params).await
349+
}
332350
}

‎tokio-postgres/tests/test/main.rs‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,44 @@ async fn query_one() {
901901
.unwrap();
902902
}
903903

904+
#[tokio::test]
905+
asyncfnquery_typed_one(){
906+
let client =connect("user=postgres").await;
907+
908+
client
909+
.batch_execute(
910+
"
911+
CREATE TEMPORARY TABLE foo (
912+
name TEXT
913+
);
914+
INSERT INTO foo (name) VALUES ('alice'), ('bob'), ('carol');
915+
",
916+
)
917+
.await
918+
.unwrap();
919+
920+
client
921+
.query_typed_one(
922+
"SELECT * FROM foo WHERE name = $1",
923+
&[(&"dave",Type::TEXT)],
924+
)
925+
.await
926+
.err()
927+
.unwrap();
928+
client
929+
.query_typed_one(
930+
"SELECT * FROM foo WHERE name = $1",
931+
&[(&"alice",Type::TEXT)],
932+
)
933+
.await
934+
.unwrap();
935+
client
936+
.query_typed_one("SELECT * FROM foo",&[])
937+
.await
938+
.err()
939+
.unwrap();
940+
}
941+
904942
#[tokio::test]
905943
asyncfnquery_opt(){
906944
let client =connect("user=postgres").await;
@@ -933,6 +971,44 @@ async fn query_opt() {
933971
.err()
934972
.unwrap();
935973
}
974+
#[tokio::test]
975+
asyncfnquery_typed_opt(){
976+
let client =connect("user=postgres").await;
977+
978+
client
979+
.batch_execute(
980+
"
981+
CREATE TEMPORARY TABLE foo (
982+
name TEXT
983+
);
984+
INSERT INTO foo (name) VALUES ('alice'), ('bob'), ('carol');
985+
",
986+
)
987+
.await
988+
.unwrap();
989+
990+
assert!(client
991+
.query_typed_opt(
992+
"SELECT * FROM foo WHERE name = $1",
993+
&[(&"dave",Type::TEXT)]
994+
)
995+
.await
996+
.unwrap()
997+
.is_none());
998+
client
999+
.query_typed_opt(
1000+
"SELECT * FROM foo WHERE name = $1",
1001+
&[(&"alice",Type::TEXT)],
1002+
)
1003+
.await
1004+
.unwrap()
1005+
.unwrap();
1006+
client
1007+
.query_typed_one("SELECT * FROM foo",&[])
1008+
.await
1009+
.err()
1010+
.unwrap();
1011+
}
9361012

9371013
#[tokio::test]
9381014
asyncfndeferred_constraint(){

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp