use actix::{Handler, Message, ResponseActFuture, WrapFuture}; use sqlx::PgPool; use super::Result; use crate::database::Database; use crate::model::{ProductId, Quantity, QuantityUnit, Stock, StockId}; use crate::{database, model}; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Unable to load all stocks")] All, #[error("Unable to create stock")] Create, #[error("Unable to update stock")] Update, #[error("Unable to delete stock")] Delete, } #[derive(Message)] #[rtype(result = "Result>")] pub struct AllStocks; crate::db_async_handler!(AllStocks, all_stocks, Vec); async fn all_stocks(_msg: AllStocks, pool: PgPool) -> Result> { sqlx::query_as( r#" SELECT id, product_id, quantity, quantity_unit FROM stocks "#, ) .fetch_all(&pool) .await .map_err(|e| { log::error!("{e:?}"); database::Error::Stock(Error::All) }) } #[derive(Message)] #[rtype(result = "Result")] pub struct CreateStock { pub product_id: ProductId, pub quantity: Quantity, pub quantity_unit: QuantityUnit, } crate::db_async_handler!(CreateStock, create_stock, Stock); async fn create_stock(msg: CreateStock, pool: PgPool) -> Result { sqlx::query_as( r#" INSERT INTO stocks (product_id, quantity) VALUES ($1, $2, $3) RETURNING id, product_id, quantity, quantity_unit "#, ) .bind(msg.product_id) .bind(msg.quantity) .bind(msg.quantity_unit) .fetch_one(&pool) .await .map_err(|e| { log::error!("{e:?}"); database::Error::Stock(Error::Create) }) } #[derive(Message)] #[rtype(result = "Result")] pub struct UpdateStock { pub id: StockId, pub product_id: ProductId, pub quantity: Quantity, pub quantity_unit: QuantityUnit, } crate::db_async_handler!(UpdateStock, update_stock, Stock); async fn update_stock(msg: UpdateStock, pool: PgPool) -> Result { sqlx::query_as( r#" UPDATE stocks SET product_id = $1 AND quantity = $2 quantity_unit = $3 WHERE id = $4 RETURNING id, product_id, quantity, quantity_unit "#, ) .bind(msg.product_id) .bind(msg.quantity) .bind(msg.quantity_unit) .bind(msg.id) .fetch_one(&pool) .await .map_err(|e| { log::error!("{e:?}"); database::Error::Stock(Error::Update) }) } #[derive(Message)] #[rtype(result = "Result>")] pub struct DeleteStock { pub stock_id: StockId, } crate::db_async_handler!(DeleteStock, delete_stock, Option); async fn delete_stock(msg: DeleteStock, pool: PgPool) -> Result> { sqlx::query_as( r#" DELETE FROM stocks WHERE id = $1 RETURNING id, product_id, quantity, quantity_unit "#, ) .bind(msg.stock_id) .fetch_optional(&pool) .await .map_err(|e| { log::error!("{e:?}"); database::Error::Stock(Error::Delete) }) }