129 lines
2.9 KiB
Rust
129 lines
2.9 KiB
Rust
|
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 products")]
|
||
|
All,
|
||
|
#[error("Unable to create product")]
|
||
|
Create,
|
||
|
#[error("Unable to update product")]
|
||
|
Update,
|
||
|
#[error("Unable to delete product")]
|
||
|
Delete,
|
||
|
}
|
||
|
|
||
|
#[derive(Message)]
|
||
|
#[rtype(result = "Result<Vec<model::Stock>>")]
|
||
|
pub struct AllStocks;
|
||
|
|
||
|
crate::async_handler!(AllStocks, all, Vec<Stock>);
|
||
|
|
||
|
async fn all(_msg: AllStocks, pool: PgPool) -> Result<Vec<model::Stock>> {
|
||
|
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<model::Stock>")]
|
||
|
pub struct CreateStock {
|
||
|
pub product_id: ProductId,
|
||
|
pub quantity: Quantity,
|
||
|
pub quantity_unit: QuantityUnit,
|
||
|
}
|
||
|
|
||
|
crate::async_handler!(CreateStock, create_product, Stock);
|
||
|
|
||
|
async fn create_product(msg: CreateStock, pool: PgPool) -> Result<model::Stock> {
|
||
|
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<model::Stock>")]
|
||
|
pub struct UpdateStock {
|
||
|
pub id: StockId,
|
||
|
pub product_id: ProductId,
|
||
|
pub quantity: Quantity,
|
||
|
pub quantity_unit: QuantityUnit,
|
||
|
}
|
||
|
|
||
|
crate::async_handler!(UpdateStock, update_product, Stock);
|
||
|
|
||
|
async fn update_product(msg: UpdateStock, pool: PgPool) -> Result<model::Stock> {
|
||
|
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<Option<model::Stock>>")]
|
||
|
pub struct DeleteStock {
|
||
|
pub stock_id: StockId,
|
||
|
}
|
||
|
|
||
|
crate::async_handler!(DeleteStock, delete_product, Option<model::Stock>);
|
||
|
|
||
|
async fn delete_product(msg: DeleteStock, pool: PgPool) -> Result<Option<Stock>> {
|
||
|
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)
|
||
|
})
|
||
|
}
|