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}