serde-sqlx 0.0.1

Allows deserializing Postgres rows into Rust types using serde
Documentation
use sqlx::{postgres::PgPoolOptions, PgPool};
use tokio::sync::OnceCell;

#[allow(unused)]
pub async fn fetch_one<T: for<'de> serde::Deserialize<'de>>(query: &str) -> anyhow::Result<T> {
    let conn = conn().await;

    let row = sqlx::query(query).fetch_one(&conn).await.unwrap();

    serde_sqlx::from_pg_row(row).map_err(Into::into)
}

#[allow(unused)]
pub async fn fetch_all<T: for<'de> serde::Deserialize<'de>>(query: &str) -> anyhow::Result<Vec<T>> {
    let conn = conn().await;

    let row = sqlx::query(query).fetch_all(&conn).await.unwrap();
    let result: Result<Vec<_>, _> = row.into_iter().map(serde_sqlx::from_pg_row).collect();

    result.map_err(Into::into)
}

#[allow(unused)]
pub async fn fetch_optional<T: for<'de> serde::Deserialize<'de>>(
    query: &str,
) -> anyhow::Result<Option<T>> {
    let conn = conn().await;

    let row = sqlx::query(query).fetch_optional(&conn).await.unwrap();

    row.map(|row| serde_sqlx::from_pg_row(row))
        .transpose()
        .map_err(Into::into)
}

async fn conn() -> PgPool {
    static CONN: OnceCell<PgPool> = OnceCell::const_new();

    async fn init() -> PgPool {
        let conn_string = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
        PgPoolOptions::new().connect(&conn_string).await.unwrap()
    }

    CONN.get_or_init(init).await.clone()
}