#[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> {
pub async fn connect(&self) -> Result<Connection<'_>> {
Ok(self.2.get().await.expect("ERROR_OISEAU_PSQL_CON"))
}
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),+]
};
}