Skip to main content

sentinel_driver/
generic_client.rs

1use crate::error::Result;
2use crate::row::{Row, SimpleQueryMessage};
3use crate::types::ToSql;
4use crate::Connection;
5
6/// A trait for types that can execute PostgreSQL queries.
7///
8/// Allows writing code that is generic over [`Connection`](crate::Connection)
9/// and [`PooledConnection`](crate::PooledConnection).
10///
11/// ```rust,no_run
12/// use sentinel_driver::{GenericClient, Result, Row};
13///
14/// async fn get_user_name(client: &mut impl GenericClient, id: i32) -> Result<String> {
15///     let row = client.query_one("SELECT name FROM users WHERE id = $1", &[&id]).await?;
16///     row.try_get(0)
17/// }
18/// ```
19#[allow(async_fn_in_trait)]
20pub trait GenericClient {
21    /// Execute a query that returns rows.
22    async fn query(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>>;
23
24    /// Execute a query that returns a single row.
25    async fn query_one(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Row>;
26
27    /// Execute a query that returns an optional single row.
28    async fn query_opt(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)])
29        -> Result<Option<Row>>;
30
31    /// Execute a non-SELECT query, returning rows affected.
32    async fn execute(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<u64>;
33
34    /// Execute a simple query (text protocol, no parameters).
35    async fn simple_query(&mut self, sql: &str) -> Result<Vec<SimpleQueryMessage>>;
36
37    /// Execute a typed query (skips the prepare round-trip).
38    async fn query_typed(
39        &mut self,
40        sql: &str,
41        params: &[(&(dyn ToSql + Sync), crate::Oid)],
42    ) -> Result<Vec<Row>>;
43
44    /// Execute a typed query that returns a single row.
45    async fn query_typed_one(
46        &mut self,
47        sql: &str,
48        params: &[(&(dyn ToSql + Sync), crate::Oid)],
49    ) -> Result<Row>;
50
51    /// Execute a typed query that returns an optional row.
52    async fn query_typed_opt(
53        &mut self,
54        sql: &str,
55        params: &[(&(dyn ToSql + Sync), crate::Oid)],
56    ) -> Result<Option<Row>>;
57
58    /// Execute a typed non-SELECT, returning rows affected.
59    async fn execute_typed(
60        &mut self,
61        sql: &str,
62        params: &[(&(dyn ToSql + Sync), crate::Oid)],
63    ) -> Result<u64>;
64
65    /// Run a pre-built `PipelineBatch` in one round-trip.
66    async fn execute_pipeline(
67        &mut self,
68        batch: crate::pipeline::batch::PipelineBatch,
69    ) -> Result<Vec<crate::pipeline::QueryResult>>;
70}
71
72impl GenericClient for Connection {
73    async fn query(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>> {
74        Connection::query(self, sql, params).await
75    }
76
77    async fn query_one(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Row> {
78        Connection::query_one(self, sql, params).await
79    }
80
81    async fn query_opt(
82        &mut self,
83        sql: &str,
84        params: &[&(dyn ToSql + Sync)],
85    ) -> Result<Option<Row>> {
86        Connection::query_opt(self, sql, params).await
87    }
88
89    async fn execute(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<u64> {
90        Connection::execute(self, sql, params).await
91    }
92
93    async fn simple_query(&mut self, sql: &str) -> Result<Vec<SimpleQueryMessage>> {
94        Connection::simple_query(self, sql).await
95    }
96
97    async fn query_typed(
98        &mut self,
99        sql: &str,
100        params: &[(&(dyn ToSql + Sync), crate::Oid)],
101    ) -> Result<Vec<Row>> {
102        Connection::query_typed(self, sql, params).await
103    }
104
105    async fn query_typed_one(
106        &mut self,
107        sql: &str,
108        params: &[(&(dyn ToSql + Sync), crate::Oid)],
109    ) -> Result<Row> {
110        Connection::query_typed_one(self, sql, params).await
111    }
112
113    async fn query_typed_opt(
114        &mut self,
115        sql: &str,
116        params: &[(&(dyn ToSql + Sync), crate::Oid)],
117    ) -> Result<Option<Row>> {
118        Connection::query_typed_opt(self, sql, params).await
119    }
120
121    async fn execute_typed(
122        &mut self,
123        sql: &str,
124        params: &[(&(dyn ToSql + Sync), crate::Oid)],
125    ) -> Result<u64> {
126        Connection::execute_typed(self, sql, params).await
127    }
128
129    async fn execute_pipeline(
130        &mut self,
131        batch: crate::pipeline::batch::PipelineBatch,
132    ) -> Result<Vec<crate::pipeline::QueryResult>> {
133        Connection::execute_pipeline(self, batch).await
134    }
135}
136
137/// Types from which a `Connection` can be borrowed for the duration of one
138/// closure. The blanket `impl GenericClient for &P` builds on this.
139///
140/// Implemented on `Pool` and re-implementable by user wrappers (e.g. a
141/// load-balanced multi-pool router).
142pub trait AsPool {
143    /// Acquire a connection, run `f` on it, release on drop.
144    fn with_conn<'a, R, F>(
145        &'a self,
146        f: F,
147    ) -> impl std::future::Future<Output = Result<R>> + Send + 'a
148    where
149        F: FnOnce(&'a mut Connection) -> futures_core::future::BoxFuture<'a, Result<R>> + Send + 'a,
150        R: Send + 'a;
151}
152
153impl<P> GenericClient for &P
154where
155    P: AsPool + Sync,
156{
157    async fn query(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>> {
158        let sql = sql.to_owned();
159        let params_vec: Vec<&(dyn ToSql + Sync)> = params.to_vec();
160        (**self)
161            .with_conn(move |c| Box::pin(async move { c.query(&sql, &params_vec).await }))
162            .await
163    }
164
165    async fn query_one(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Row> {
166        let sql = sql.to_owned();
167        let params_vec: Vec<&(dyn ToSql + Sync)> = params.to_vec();
168        (**self)
169            .with_conn(move |c| Box::pin(async move { c.query_one(&sql, &params_vec).await }))
170            .await
171    }
172
173    async fn query_opt(
174        &mut self,
175        sql: &str,
176        params: &[&(dyn ToSql + Sync)],
177    ) -> Result<Option<Row>> {
178        let sql = sql.to_owned();
179        let params_vec: Vec<&(dyn ToSql + Sync)> = params.to_vec();
180        (**self)
181            .with_conn(move |c| Box::pin(async move { c.query_opt(&sql, &params_vec).await }))
182            .await
183    }
184
185    async fn execute(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<u64> {
186        let sql = sql.to_owned();
187        let params_vec: Vec<&(dyn ToSql + Sync)> = params.to_vec();
188        (**self)
189            .with_conn(move |c| Box::pin(async move { c.execute(&sql, &params_vec).await }))
190            .await
191    }
192
193    async fn simple_query(&mut self, sql: &str) -> Result<Vec<crate::row::SimpleQueryMessage>> {
194        let sql = sql.to_owned();
195        (**self)
196            .with_conn(move |c| Box::pin(async move { c.simple_query(&sql).await }))
197            .await
198    }
199
200    async fn query_typed(
201        &mut self,
202        sql: &str,
203        params: &[(&(dyn ToSql + Sync), crate::Oid)],
204    ) -> Result<Vec<Row>> {
205        let sql = sql.to_owned();
206        let params_vec: Vec<(&(dyn ToSql + Sync), crate::Oid)> = params.to_vec();
207        (**self)
208            .with_conn(move |c| Box::pin(async move { c.query_typed(&sql, &params_vec).await }))
209            .await
210    }
211
212    async fn query_typed_one(
213        &mut self,
214        sql: &str,
215        params: &[(&(dyn ToSql + Sync), crate::Oid)],
216    ) -> Result<Row> {
217        let sql = sql.to_owned();
218        let params_vec: Vec<(&(dyn ToSql + Sync), crate::Oid)> = params.to_vec();
219        (**self)
220            .with_conn(move |c| Box::pin(async move { c.query_typed_one(&sql, &params_vec).await }))
221            .await
222    }
223
224    async fn query_typed_opt(
225        &mut self,
226        sql: &str,
227        params: &[(&(dyn ToSql + Sync), crate::Oid)],
228    ) -> Result<Option<Row>> {
229        let sql = sql.to_owned();
230        let params_vec: Vec<(&(dyn ToSql + Sync), crate::Oid)> = params.to_vec();
231        (**self)
232            .with_conn(move |c| Box::pin(async move { c.query_typed_opt(&sql, &params_vec).await }))
233            .await
234    }
235
236    async fn execute_typed(
237        &mut self,
238        sql: &str,
239        params: &[(&(dyn ToSql + Sync), crate::Oid)],
240    ) -> Result<u64> {
241        let sql = sql.to_owned();
242        let params_vec: Vec<(&(dyn ToSql + Sync), crate::Oid)> = params.to_vec();
243        (**self)
244            .with_conn(move |c| Box::pin(async move { c.execute_typed(&sql, &params_vec).await }))
245            .await
246    }
247
248    async fn execute_pipeline(
249        &mut self,
250        batch: crate::pipeline::batch::PipelineBatch,
251    ) -> Result<Vec<crate::pipeline::QueryResult>> {
252        (**self)
253            .with_conn(move |c| Box::pin(async move { c.execute_pipeline(batch).await }))
254            .await
255    }
256}
257
258impl GenericClient for crate::PooledConnection {
259    async fn query(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Vec<Row>> {
260        Connection::query(self, sql, params).await
261    }
262
263    async fn query_one(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<Row> {
264        Connection::query_one(self, sql, params).await
265    }
266
267    async fn query_opt(
268        &mut self,
269        sql: &str,
270        params: &[&(dyn ToSql + Sync)],
271    ) -> Result<Option<Row>> {
272        Connection::query_opt(self, sql, params).await
273    }
274
275    async fn execute(&mut self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> Result<u64> {
276        Connection::execute(self, sql, params).await
277    }
278
279    async fn simple_query(&mut self, sql: &str) -> Result<Vec<SimpleQueryMessage>> {
280        Connection::simple_query(self, sql).await
281    }
282
283    async fn query_typed(
284        &mut self,
285        sql: &str,
286        params: &[(&(dyn ToSql + Sync), crate::Oid)],
287    ) -> Result<Vec<Row>> {
288        Connection::query_typed(self, sql, params).await
289    }
290
291    async fn query_typed_one(
292        &mut self,
293        sql: &str,
294        params: &[(&(dyn ToSql + Sync), crate::Oid)],
295    ) -> Result<Row> {
296        Connection::query_typed_one(self, sql, params).await
297    }
298
299    async fn query_typed_opt(
300        &mut self,
301        sql: &str,
302        params: &[(&(dyn ToSql + Sync), crate::Oid)],
303    ) -> Result<Option<Row>> {
304        Connection::query_typed_opt(self, sql, params).await
305    }
306
307    async fn execute_typed(
308        &mut self,
309        sql: &str,
310        params: &[(&(dyn ToSql + Sync), crate::Oid)],
311    ) -> Result<u64> {
312        Connection::execute_typed(self, sql, params).await
313    }
314
315    async fn execute_pipeline(
316        &mut self,
317        batch: crate::pipeline::batch::PipelineBatch,
318    ) -> Result<Vec<crate::pipeline::QueryResult>> {
319        Connection::execute_pipeline(self, batch).await
320    }
321}