Skip to main content

postgres_query/
client.rs

1//! Abstractions over client-like types.
2
3mod cache;
4
5pub use cache::Caching;
6
7use async_trait::async_trait;
8use postgres_types::ToSql;
9use tokio_postgres::{error::Error as SqlError, Client, RowStream, Statement, Transaction};
10
11/// A generic client with basic functionality.
12#[async_trait]
13pub trait GenericClient {
14    /// Prepare a SQL query for execution. See [`Client::prepare`] for more info.
15    ///
16    /// [`Client::prepare`]:
17    /// https://docs.rs/tokio-postgres/0.5.1/tokio_postgres/struct.Client.html#method.prepare
18    async fn prepare(&self, sql: &str) -> Result<Statement, SqlError>;
19
20    /// Implementors may choose to override this method if they, for whatever reason (performance
21    /// being one), want to cache a specific query.
22    ///
23    /// Because of the `'static` lifetime associated with the query string, we can assert that its
24    /// value is never going to change. For instance, if a `HashMap` is used to build a cache of
25    /// queries, it is enough to hash the pointer to the query instead of the whole string, since we
26    /// know it will be unique for the duration of the program.
27    async fn prepare_static(&self, sql: &'static str) -> Result<Statement, SqlError> {
28        self.prepare(sql).await
29    }
30
31    /// Execute the given statement with the parameters specified and return the number of affected
32    /// rows. See [`Client::execute_raw`] for more info.
33    ///
34    /// [`Client::execute_raw`]:
35    /// https://docs.rs/tokio-postgres/0.5.1/tokio_postgres/struct.Client.html#method.execute_raw
36    async fn execute_raw<'a>(
37        &'a self,
38        statement: &Statement,
39        parameters: &[&'a (dyn ToSql + Sync)],
40    ) -> Result<u64, SqlError>;
41
42    /// Execute the given statement with the parameters specified and return the resulting rows as
43    /// an asynchronous stream. See [`Client::query_raw`] for more info.
44    ///
45    /// [`Client::query_raw`]:
46    /// https://docs.rs/tokio-postgres/0.5.1/tokio_postgres/struct.Client.html#method.query_raw
47    async fn query_raw<'a>(
48        &'a self,
49        statement: &Statement,
50        parameters: &[&'a (dyn ToSql + Sync)],
51    ) -> Result<RowStream, SqlError>;
52}
53
54fn slice_iter<'a>(
55    s: &'a [&'a (dyn ToSql + Sync)],
56) -> impl ExactSizeIterator<Item = &'a dyn ToSql> + 'a {
57    s.iter().map(|s| *s as _)
58}
59
60#[async_trait]
61impl GenericClient for Client {
62    async fn prepare(&self, sql: &str) -> Result<Statement, SqlError> {
63        Client::prepare(self, sql).await
64    }
65
66    async fn execute_raw<'a>(
67        &'a self,
68        statement: &Statement,
69        parameters: &[&'a (dyn ToSql + Sync)],
70    ) -> Result<u64, SqlError> {
71        Client::execute_raw(self, statement, slice_iter(parameters)).await
72    }
73
74    async fn query_raw<'a>(
75        &'a self,
76        statement: &Statement,
77        parameters: &[&'a (dyn ToSql + Sync)],
78    ) -> Result<RowStream, SqlError> {
79        Client::query_raw(self, statement, slice_iter(parameters)).await
80    }
81}
82
83#[async_trait]
84impl GenericClient for Transaction<'_> {
85    async fn prepare(&self, sql: &str) -> Result<Statement, SqlError> {
86        Transaction::prepare(self, sql).await
87    }
88
89    async fn execute_raw<'a>(
90        &'a self,
91        statement: &Statement,
92        parameters: &[&'a (dyn ToSql + Sync)],
93    ) -> Result<u64, SqlError> {
94        Transaction::execute_raw::<_, Statement>(self, statement, slice_iter(parameters)).await
95    }
96
97    async fn query_raw<'a>(
98        &'a self,
99        statement: &Statement,
100        parameters: &[&'a (dyn ToSql + Sync)],
101    ) -> Result<RowStream, SqlError> {
102        Transaction::query_raw(self, statement, slice_iter(parameters)).await
103    }
104}
105
106macro_rules! client_deref_impl {
107    ($($target:tt)+) => {
108        #[async_trait]
109        impl<T> GenericClient for $($target)+ where T: GenericClient + Sync {
110            async fn prepare(&self, sql: &str) -> Result<Statement, SqlError> {
111                T::prepare(self, sql).await
112            }
113
114            async fn execute_raw<'a>(
115                &'a self,
116                statement: &Statement,
117                parameters: &[&'a (dyn ToSql + Sync)],
118            ) -> Result<u64, SqlError> {
119                T::execute_raw(self, statement, parameters).await
120            }
121
122            async fn query_raw<'a>(
123                &'a self,
124                statement: &Statement,
125                parameters: &[&'a (dyn ToSql + Sync)],
126            ) -> Result<RowStream, SqlError> {
127                T::query_raw(self, statement, parameters).await
128            }
129        }
130    }
131}
132
133client_deref_impl!(&T);