tide_sqlx/
postgres.rs

1use async_std::sync::RwLockWriteGuard;
2use tide::utils::async_trait;
3use tide::Request;
4
5use sqlx::postgres::Postgres;
6
7#[cfg(all(feature = "tracing", debug_assertions))]
8use tracing_crate::{debug_span, Instrument};
9
10use crate::{ConnectionWrap, ConnectionWrapInner, SQLxMiddleware};
11
12/// An alias for `tide_sqlx::SQLxMiddleware<Postgres>`.
13#[allow(dead_code)]
14pub type PostgresMiddleware = SQLxMiddleware<Postgres>;
15
16/// An extension trait for [tide::Request][] which does proper unwrapping of the connection from [`req.ext()`][].
17///
18/// Specialized for Postgres connections.
19///
20/// [`req.ext()`]: https://docs.rs/tide/0.15.0/tide/struct.Request.html#method.ext
21/// [tide::Request]: https://docs.rs/tide/0.15.0/tide/struct.Request.html
22#[cfg(feature = "postgres")]
23#[cfg_attr(feature = "docs", doc(cfg(feature = "postgres")))]
24#[async_trait]
25pub trait PostgresRequestExt {
26    /// Get the SQLx connection for the current Request.
27    ///
28    /// This will return a "write" guard from a read-write lock.
29    /// Under the hood this will transparently be either a postgres transaction or a direct pooled connection.
30    ///
31    /// This will panic with an expect message if the `SQLxMiddleware` has not been run.
32    ///
33    /// ## Example
34    ///
35    /// ```no_run
36    /// # #[async_std::main]
37    /// # async fn main() -> anyhow::Result<()> {
38    /// # use tide_sqlx::postgres::PostgresMiddleware;
39    /// # use sqlx::postgres::Postgres;
40    /// #
41    /// # let mut app = tide::new();
42    /// # app.with(PostgresMiddleware::new("postgres://localhost/a_database").await?);
43    /// #
44    /// use sqlx::Acquire; // Or sqlx::prelude::*;
45    ///
46    /// use tide_sqlx::postgres::PostgresRequestExt;
47    ///
48    /// app.at("/").post(|req: tide::Request<()>| async move {
49    ///     let mut pg_conn = req.pg_conn().await;
50    ///
51    ///     sqlx::query("SELECT * FROM users")
52    ///         .fetch_optional(pg_conn.acquire().await?)
53    ///         .await;
54    ///
55    ///     Ok("")
56    /// });
57    /// # Ok(())
58    /// # }
59    /// ```
60    async fn pg_conn<'req>(&'req self) -> RwLockWriteGuard<'req, ConnectionWrapInner<Postgres>>;
61}
62
63#[async_trait]
64impl<T: Send + Sync + 'static> PostgresRequestExt for Request<T> {
65    async fn pg_conn<'req>(&'req self) -> RwLockWriteGuard<'req, ConnectionWrapInner<Postgres>> {
66        let pg_conn: &ConnectionWrap<Postgres> = self
67            .ext()
68            .expect("You must install SQLx middleware providing Postgres ConnectionWrap");
69        let rwlock_fut = pg_conn.write();
70        #[cfg(all(feature = "tracing", debug_assertions))]
71        let rwlock_fut =
72            rwlock_fut.instrument(debug_span!("Postgres connection RwLockWriteGuard acquire"));
73        rwlock_fut.await
74    }
75}