bazzar/actors/database_manager/src/lib.rs

150 lines
3.9 KiB
Rust

pub use account_orders::*;
pub use accounts::*;
use actix::{Actor, Context};
use config::SharedAppConfig;
pub use order_items::*;
pub use products::*;
pub use shopping_cart_items::*;
pub use shopping_carts::*;
use sqlx::PgPool;
pub use stocks::*;
pub use tokens::*;
pub mod account_orders;
pub mod accounts;
pub mod order_items;
pub mod products;
pub mod shopping_cart_items;
pub mod shopping_carts;
pub mod stocks;
pub mod tokens;
#[macro_export]
macro_rules! db_async_handler {
($msg: ty, $async: ident, $res: ty) => {
impl actix::Handler<$msg> for Database {
type Result = actix::ResponseActFuture<Self, Result<$res>>;
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
use actix::WrapFuture;
let pool = self.pool.clone();
Box::pin(async { $async(msg, pool).await }.into_actor(self))
}
}
};
($msg: ty, $async: ident, $res: ty, $inner_async: ident) => {
async fn $inner_async(msg: $msg, pool: sqlx::PgPool) -> Result<$res> {
let mut t = pool.begin().await?;
match $async(msg, &mut t).await {
Ok(res) => {
t.commit().await?;
Ok(res)
}
Err(e) => {
let _ = t.rollback().await;
Err(e)
}
}
}
impl actix::Handler<$msg> for Database {
type Result = actix::ResponseActFuture<Self, Result<$res>>;
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
use actix::WrapFuture;
let pool = self.pool.clone();
Box::pin(async { $inner_async(msg, pool).await }.into_actor(self))
}
}
};
}
#[macro_export]
macro_rules! query_db {
($db: expr, $msg: expr, default $fail: expr) => {
match $db.send($msg).await {
Ok(Ok(r)) => r,
Ok(Err(e)) => {
log::error!("{e}");
$fail
}
Err(e) => {
log::error!("{e:?}");
$fail
}
}
};
($db: expr, $msg: expr, $fail: expr) => {
$crate::query_db!($db, $msg, $fail, $fail)
};
($db: expr, $msg: expr, $db_fail: expr, $act_fail: expr) => {
match $db.send($msg).await {
Ok(Ok(r)) => r,
Ok(Err(e)) => {
log::error!("{e}");
return Err($db_fail);
}
Err(e) => {
log::error!("{e:?}");
return Err($act_fail);
}
}
};
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Failed to connect to database. {0:?}")]
Connect(#[from] sqlx::Error),
#[error("{0}")]
Account(#[from] accounts::Error),
#[error("{0}")]
AccountOrder(#[from] account_orders::Error),
#[error("{0}")]
Product(#[from] products::Error),
#[error("{0}")]
Stock(#[from] stocks::Error),
#[error("{0}")]
OrderItem(#[from] order_items::Error),
#[error("{0}")]
ShoppingCart(#[from] shopping_carts::Error),
#[error("{0}")]
ShoppingCartItem(#[from] shopping_cart_items::Error),
#[error("{0}")]
Token(#[from] tokens::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
pub struct Database {
pool: PgPool,
}
pub type SharedDatabase = actix::Addr<Database>;
impl Clone for Database {
fn clone(&self) -> Self {
Self {
pool: self.pool.clone(),
}
}
}
impl Database {
pub async fn build(config: SharedAppConfig) -> Result<Self> {
let url = config.lock().database().url();
let pool = sqlx::PgPool::connect(&url).await.map_err(Error::Connect)?;
Ok(Database { pool })
}
pub fn pool(&self) -> &PgPool {
&self.pool
}
}
impl Actor for Database {
type Context = Context<Self>;
}