oiseau 0.3.0

Super simple SQL helper
Documentation
#[cfg(not(feature = "redis"))]
use crate::cache::no_cache::NoCache;
#[cfg(feature = "redis")]
use crate::cache::redis::RedisCache;

use crate::{cache::Cache, config::Configuration};

use bb8_postgres::{
    PostgresConnectionManager,
    bb8::{Pool, PooledConnection},
};
use std::str::FromStr;
use tokio_postgres::{Config as PgConfig, NoTls, Row, types::ToSql};

pub type Result<T> = std::result::Result<T, tokio_postgres::Error>;
pub type Connection<'a> = PooledConnection<'a, PostgresConnectionManager<NoTls>>;

#[derive(Clone)]
pub struct DataManager<T: Clone + Configuration>(
    pub T,
    #[cfg(feature = "redis")] pub RedisCache,
    #[cfg(not(feature = "redis"))] pub NoCache,
    pub Pool<PostgresConnectionManager<NoTls>>,
);

impl<T: Clone + Configuration> DataManager<T> {
    /// Obtain a connection to the staging database.
    pub async fn connect(&self) -> Result<Connection<'_>> {
        Ok(self.2.get().await.expect("ERROR_OISEAU_PSQL_CON"))
    }

    /// Create a new [`DataManager`] (and init database).
    pub async fn new(config: T) -> Result<Self> {
        let db_config = config.db_config();
        let con_url = &format!(
            "postgresql://{}:{}@{}/{}?target_session_attrs=read-write",
            db_config.user, db_config.password, db_config.url, db_config.name
        );

        println!("attempting connection on: {con_url}");
        let manager = PostgresConnectionManager::new(PgConfig::from_str(con_url).unwrap(), NoTls);

        let pool = Pool::builder().max_size(15).build(manager).await.unwrap();
        Ok(Self(
            config.clone(),
            #[cfg(feature = "redis")]
            RedisCache::new().await,
            #[cfg(not(feature = "redis"))]
            NoCache::new().await,
            pool,
        ))
    }
}

#[macro_export]
macro_rules! pg_get {
    ($row:ident->$idx:literal($t:ty)) => {
        $row.get::<usize, Option<$t>>($idx).unwrap()
    };

    ($row:ident->$idx:literal($t:ty) default ($default:expr)) => {
        $row.get::<usize, Option<$t>>($idx).unwrap_or($default)
    };

    ($row:ident->$idx:ident($t:ty)) => {
        $row.get::<usize, Option<$t>>($idx).unwrap()
    };

    ($row:ident->$idx:ident($t:ty) default ($default:expr)) => {
        $row.get::<usize, Option<$t>>($idx).unwrap_or($default)
    };
}

pub async fn query_row_helper<T, F>(
    conn: &Connection<'_>,
    sql: &str,
    params: &[&(dyn ToSql + Sync)],
    f: F,
) -> Result<T>
where
    F: FnOnce(&Row) -> Result<T>,
{
    let query = conn.prepare(sql).await.unwrap();
    let res = conn.query_one(&query, params).await;

    if let Ok(row) = res {
        Ok(f(&row).unwrap())
    } else {
        Err(res.unwrap_err())
    }
}

#[macro_export]
macro_rules! pg_query_row {
    ($conn:expr, $sql:expr, $params:expr, $f:expr) => {
        $crate::postgres::query_row_helper($conn, $sql, $params, $f).await
    };
}

pub async fn query_rows_helper<T, F>(
    conn: &Connection<'_>,
    sql: &str,
    params: &[&(dyn ToSql + Sync)],
    mut f: F,
) -> Result<Vec<T>>
where
    F: FnMut(&Row) -> T,
{
    let query = conn.prepare(sql).await.unwrap();
    let res = conn.query(&query, params).await;

    if let Ok(rows) = res {
        let mut out = Vec::new();

        for row in rows {
            out.push(f(&row));
        }

        return Ok(out);
    } else {
        Err(res.unwrap_err())
    }
}

#[macro_export]
macro_rules! pg_query_rows {
    ($conn:expr, $sql:expr, $params:expr, $f:expr) => {
        $crate::postgres::query_rows_helper($conn, $sql, $params, $f).await
    };
}

pub async fn execute_helper(
    conn: &Connection<'_>,
    sql: &str,
    params: &[&(dyn ToSql + Sync)],
) -> Result<()> {
    let query = conn.prepare(sql).await.unwrap();
    conn.execute(&query, params).await?;
    Ok(())
}

#[macro_export]
macro_rules! pg_execute {
    ($conn:expr, $sql:expr, $params:expr) => {
        $crate::postgres::execute_helper($conn, $sql, $params).await
    };

    ($conn:expr, $sql:expr) => {
        $crate::postgres::execute_helper($conn, $sql, &[]).await
    };
}

#[macro_export]
macro_rules! pg_params {
    () => {
        &[]
    };
    ($($x:expr),+ $(,)?) => {
        &[$(&$x),+]
    };
}