Logic for add item
This commit is contained in:
parent
5d757e84d5
commit
39d65f5e12
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -963,6 +963,8 @@ dependencies = [
|
||||
"chrono",
|
||||
"derive_more",
|
||||
"dotenv",
|
||||
"futures",
|
||||
"futures-util",
|
||||
"gumdrop",
|
||||
"log",
|
||||
"parking_lot 0.12.0",
|
||||
@ -974,6 +976,7 @@ dependencies = [
|
||||
"sqlx",
|
||||
"tera",
|
||||
"thiserror",
|
||||
"tokio 1.17.0",
|
||||
"toml",
|
||||
"tracing",
|
||||
"uuid",
|
||||
@ -3636,9 +3639,21 @@ dependencies = [
|
||||
"pin-project-lite 0.2.8",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.4.4",
|
||||
"tokio-macros",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.22.0"
|
||||
|
@ -47,3 +47,7 @@ parking_lot = { version = "0.12.0" }
|
||||
password-hash = { version = "0.4.0", features = ["alloc"] }
|
||||
argon2 = { version = "0.4.0", features = ["parallel", "password-hash"] }
|
||||
rand_core = { version = "0.6", features = ["std"] }
|
||||
|
||||
tokio = { version = "1.17.0", features = ["full"] }
|
||||
futures = { version = "0.3.21" }
|
||||
futures-util = { version = "0.3.21" }
|
||||
|
82
api/src/actors/cart_manager.rs
Normal file
82
api/src/actors/cart_manager.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use crate::database::Database;
|
||||
use crate::model::{
|
||||
AccountId, ProductId, Quantity, QuantityUnit, ShoppingCartItem, ShoppingCartState,
|
||||
};
|
||||
use crate::{cart_async_handler, database};
|
||||
use actix::{Actor, Addr, Context, Handler, Message, ResponseActFuture, WrapFuture};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("System can't ensure shopping cart existence")]
|
||||
ShoppingCartFailed,
|
||||
#[error("Shopping cart is not available for unknown reason")]
|
||||
CartNotAvailable,
|
||||
#[error("Failed to add item to cart")]
|
||||
CantAddItem,
|
||||
#[error("{0}")]
|
||||
Db(#[from] database::Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub struct CartManager {
|
||||
db: Addr<Database>,
|
||||
}
|
||||
|
||||
impl Actor for CartManager {
|
||||
type Context = Context<Self>;
|
||||
}
|
||||
|
||||
impl CartManager {
|
||||
pub fn new(db: Addr<Database>) -> Self {
|
||||
Self { db }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Message)]
|
||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
||||
pub struct AddItem {
|
||||
pub buyer_id: AccountId,
|
||||
pub product_id: ProductId,
|
||||
pub quantity: Quantity,
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
cart_async_handler!(AddItem, add_item, ShoppingCartItem);
|
||||
|
||||
async fn add_item(msg: AddItem, db: Addr<Database>) -> Result<ShoppingCartItem> {
|
||||
match db.send(database::EnsureActiveShoppingCart { buyer_id: msg.buyer_id }).await {
|
||||
Ok(Ok(_)) => {}
|
||||
_ => return Err(Error::ShoppingCartFailed),
|
||||
};
|
||||
let cart = match db
|
||||
.send(database::AccountShoppingCarts {
|
||||
account_id: msg.buyer_id,
|
||||
state: Some(ShoppingCartState::Active),
|
||||
})
|
||||
.await
|
||||
.map(|res| match res {
|
||||
Ok(mut v) if !v.is_empty() => Ok(v.remove(0)),
|
||||
Err(e) => return Err(Error::Db(e)),
|
||||
_ => Err(Error::CartNotAvailable),
|
||||
}) {
|
||||
Ok(Ok(cart)) => cart,
|
||||
Ok(Err(e)) => {
|
||||
log::error!("{e:?}");
|
||||
return Err(e);
|
||||
}
|
||||
_ => return Err(Error::CartNotAvailable),
|
||||
};
|
||||
match db
|
||||
.send(database::CreateShoppingCartItem {
|
||||
product_id: msg.product_id,
|
||||
shopping_cart_id: cart.id,
|
||||
quantity: msg.quantity,
|
||||
quantity_unit: msg.quantity_unit,
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(res) => res.map_err(Into::into),
|
||||
_ => Err(Error::CantAddItem),
|
||||
}
|
||||
}
|
@ -9,27 +9,13 @@ pub use shopping_cart_items::*;
|
||||
pub use shopping_carts::*;
|
||||
pub use stocks::*;
|
||||
|
||||
mod account_orders;
|
||||
mod accounts;
|
||||
mod order_items;
|
||||
mod products;
|
||||
mod shopping_cart_items;
|
||||
mod shopping_carts;
|
||||
mod stocks;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! async_handler {
|
||||
($msg: ty, $async: ident, $res: ty) => {
|
||||
impl Handler<$msg> for Database {
|
||||
type Result = ResponseActFuture<Self, Result<$res>>;
|
||||
|
||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let pool = self.pool.clone();
|
||||
Box::pin(async { $async(msg, pool).await }.into_actor(self))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
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;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::async_handler;
|
||||
use crate::db_async_handler;
|
||||
use actix::{Handler, ResponseActFuture, WrapFuture};
|
||||
use sqlx::PgPool;
|
||||
|
||||
@ -23,9 +23,12 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<AccountOrder>>")]
|
||||
pub struct AllAccountOrders;
|
||||
|
||||
async_handler!(AllAccountOrders, all_account_orders, Vec<AccountOrder>);
|
||||
db_async_handler!(AllAccountOrders, all_account_orders, Vec<AccountOrder>);
|
||||
|
||||
pub async fn all_account_orders(_msg: AllAccountOrders, pool: PgPool) -> Result<Vec<AccountOrder>> {
|
||||
pub(crate) async fn all_account_orders(
|
||||
_msg: AllAccountOrders,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<AccountOrder>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, status
|
||||
@ -47,9 +50,12 @@ pub struct CreateAccountOrder {
|
||||
pub status: OrderStatus,
|
||||
}
|
||||
|
||||
async_handler!(CreateAccountOrder, create_account_order, AccountOrder);
|
||||
db_async_handler!(CreateAccountOrder, create_account_order, AccountOrder);
|
||||
|
||||
async fn create_account_order(msg: CreateAccountOrder, db: PgPool) -> Result<AccountOrder> {
|
||||
pub(crate) async fn create_account_order(
|
||||
msg: CreateAccountOrder,
|
||||
db: PgPool,
|
||||
) -> Result<AccountOrder> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO account_orders (buyer_id, status)
|
||||
@ -73,9 +79,9 @@ pub struct FindAccountOrder {
|
||||
pub id: AccountOrderId,
|
||||
}
|
||||
|
||||
async_handler!(FindAccountOrder, find_account_order, AccountOrder);
|
||||
db_async_handler!(FindAccountOrder, find_account_order, AccountOrder);
|
||||
|
||||
async fn find_account_order(msg: FindAccountOrder, db: PgPool) -> Result<AccountOrder> {
|
||||
pub(crate) async fn find_account_order(msg: FindAccountOrder, db: PgPool) -> Result<AccountOrder> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, status
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::async_handler;
|
||||
use crate::db_async_handler;
|
||||
use actix::{Handler, ResponseActFuture, WrapFuture};
|
||||
use sqlx::PgPool;
|
||||
|
||||
@ -23,9 +23,9 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<FullAccount>>")]
|
||||
pub struct AllAccounts;
|
||||
|
||||
async_handler!(AllAccounts, all_accounts, Vec<FullAccount>);
|
||||
db_async_handler!(AllAccounts, all_accounts, Vec<FullAccount>);
|
||||
|
||||
pub async fn all_accounts(_msg: AllAccounts, pool: PgPool) -> Result<Vec<FullAccount>> {
|
||||
pub(crate) async fn all_accounts(_msg: AllAccounts, pool: PgPool) -> Result<Vec<FullAccount>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, email, login, pass_hash, role
|
||||
@ -49,9 +49,9 @@ pub struct CreateAccount {
|
||||
pub role: Role,
|
||||
}
|
||||
|
||||
async_handler!(CreateAccount, create_account, FullAccount);
|
||||
db_async_handler!(CreateAccount, create_account, FullAccount);
|
||||
|
||||
async fn create_account(msg: CreateAccount, db: PgPool) -> Result<FullAccount> {
|
||||
pub(crate) async fn create_account(msg: CreateAccount, db: PgPool) -> Result<FullAccount> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO accounts (login, email, role, pass_hash)
|
||||
@ -77,9 +77,9 @@ pub struct FindAccount {
|
||||
pub account_id: AccountId,
|
||||
}
|
||||
|
||||
async_handler!(FindAccount, find_account, FullAccount);
|
||||
db_async_handler!(FindAccount, find_account, FullAccount);
|
||||
|
||||
async fn find_account(msg: FindAccount, db: PgPool) -> Result<FullAccount> {
|
||||
pub(crate) async fn find_account(msg: FindAccount, db: PgPool) -> Result<FullAccount> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, email, login, pass_hash, role
|
||||
@ -103,9 +103,9 @@ pub struct AccountByIdentity {
|
||||
pub email: Option<Email>,
|
||||
}
|
||||
|
||||
async_handler!(AccountByIdentity, account_by_identity, FullAccount);
|
||||
db_async_handler!(AccountByIdentity, account_by_identity, FullAccount);
|
||||
|
||||
async fn account_by_identity(msg: AccountByIdentity, db: PgPool) -> Result<FullAccount> {
|
||||
pub(crate) async fn account_by_identity(msg: AccountByIdentity, db: PgPool) -> Result<FullAccount> {
|
||||
match (msg.login, msg.email) {
|
||||
(Some(login), None) => sqlx::query_as(
|
||||
r#"
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::async_handler;
|
||||
use crate::db_async_handler;
|
||||
use actix::{Handler, ResponseActFuture, WrapFuture};
|
||||
use sqlx::PgPool;
|
||||
|
||||
@ -23,9 +23,9 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<OrderItem>>")]
|
||||
pub struct AllOrderItems;
|
||||
|
||||
async_handler!(AllOrderItems, all_order_items, Vec<OrderItem>);
|
||||
db_async_handler!(AllOrderItems, all_order_items, Vec<OrderItem>);
|
||||
|
||||
pub async fn all_order_items(_msg: AllOrderItems, pool: PgPool) -> Result<Vec<OrderItem>> {
|
||||
pub(crate) async fn all_order_items(_msg: AllOrderItems, pool: PgPool) -> Result<Vec<OrderItem>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, status
|
||||
@ -47,9 +47,9 @@ pub struct CreateOrderItem {
|
||||
pub status: OrderStatus,
|
||||
}
|
||||
|
||||
async_handler!(CreateOrderItem, create_order_item, OrderItem);
|
||||
db_async_handler!(CreateOrderItem, create_order_item, OrderItem);
|
||||
|
||||
async fn create_order_item(msg: CreateOrderItem, db: PgPool) -> Result<OrderItem> {
|
||||
pub(crate) async fn create_order_item(msg: CreateOrderItem, db: PgPool) -> Result<OrderItem> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO order_items (buyer_id, status)
|
||||
@ -73,9 +73,9 @@ pub struct FindOrderItem {
|
||||
pub id: OrderItemId,
|
||||
}
|
||||
|
||||
async_handler!(FindOrderItem, find_order_item, OrderItem);
|
||||
db_async_handler!(FindOrderItem, find_order_item, OrderItem);
|
||||
|
||||
async fn find_order_item(msg: FindOrderItem, db: PgPool) -> Result<OrderItem> {
|
||||
pub(crate) async fn find_order_item(msg: FindOrderItem, db: PgPool) -> Result<OrderItem> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, status
|
||||
|
@ -25,9 +25,9 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<model::Product>>")]
|
||||
pub struct AllProducts;
|
||||
|
||||
crate::async_handler!(AllProducts, all, Vec<Product>);
|
||||
crate::db_async_handler!(AllProducts, all, Vec<Product>);
|
||||
|
||||
async fn all(_msg: AllProducts, pool: PgPool) -> Result<Vec<model::Product>> {
|
||||
pub(crate) async fn all(_msg: AllProducts, pool: PgPool) -> Result<Vec<model::Product>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id,
|
||||
@ -59,9 +59,9 @@ pub struct CreateProduct {
|
||||
pub price_minor: PriceMinor,
|
||||
}
|
||||
|
||||
crate::async_handler!(CreateProduct, create_product, Product);
|
||||
crate::db_async_handler!(CreateProduct, create_product, Product);
|
||||
|
||||
async fn create_product(msg: CreateProduct, pool: PgPool) -> Result<model::Product> {
|
||||
pub(crate) async fn create_product(msg: CreateProduct, pool: PgPool) -> Result<model::Product> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO products (name, short_description, long_description, category, price_major, price_minor)
|
||||
@ -101,9 +101,9 @@ pub struct UpdateProduct {
|
||||
pub price_minor: PriceMinor,
|
||||
}
|
||||
|
||||
crate::async_handler!(UpdateProduct, update_product, Product);
|
||||
crate::db_async_handler!(UpdateProduct, update_product, Product);
|
||||
|
||||
async fn update_product(msg: UpdateProduct, pool: PgPool) -> Result<model::Product> {
|
||||
pub(crate) async fn update_product(msg: UpdateProduct, pool: PgPool) -> Result<model::Product> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
UPDATE products
|
||||
@ -144,9 +144,9 @@ pub struct DeleteProduct {
|
||||
pub product_id: ProductId,
|
||||
}
|
||||
|
||||
crate::async_handler!(DeleteProduct, delete_product, Option<model::Product>);
|
||||
crate::db_async_handler!(DeleteProduct, delete_product, Option<model::Product>);
|
||||
|
||||
async fn delete_product(msg: DeleteProduct, pool: PgPool) -> Result<Option<Product>> {
|
||||
pub(crate) async fn delete_product(msg: DeleteProduct, pool: PgPool) -> Result<Option<Product>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
DELETE FROM products
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::async_handler;
|
||||
use crate::db_async_handler;
|
||||
use actix::{Handler, ResponseActFuture, WrapFuture};
|
||||
use sqlx::PgPool;
|
||||
|
||||
@ -27,9 +27,9 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<ShoppingCartItem>>")]
|
||||
pub struct AllShoppingCartItems;
|
||||
|
||||
async_handler!(AllShoppingCartItems, all_shopping_cart_items, Vec<ShoppingCartItem>);
|
||||
db_async_handler!(AllShoppingCartItems, all_shopping_cart_items, Vec<ShoppingCartItem>);
|
||||
|
||||
pub async fn all_shopping_cart_items(
|
||||
pub(crate) async fn all_shopping_cart_items(
|
||||
_msg: AllShoppingCartItems,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<ShoppingCartItem>> {
|
||||
@ -53,9 +53,9 @@ pub struct AccountShoppingCartItems {
|
||||
pub account_id: AccountId,
|
||||
}
|
||||
|
||||
async_handler!(AccountShoppingCartItems, account_shopping_cart_items, Vec<ShoppingCartItem>);
|
||||
db_async_handler!(AccountShoppingCartItems, account_shopping_cart_items, Vec<ShoppingCartItem>);
|
||||
|
||||
pub async fn account_shopping_cart_items(
|
||||
pub(crate) async fn account_shopping_cart_items(
|
||||
msg: AccountShoppingCartItems,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<ShoppingCartItem>> {
|
||||
@ -84,9 +84,9 @@ pub struct CreateShoppingCartItem {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
async_handler!(CreateShoppingCartItem, create_shopping_cart_item, ShoppingCartItem);
|
||||
db_async_handler!(CreateShoppingCartItem, create_shopping_cart_item, ShoppingCartItem);
|
||||
|
||||
async fn create_shopping_cart_item(
|
||||
pub(crate) async fn create_shopping_cart_item(
|
||||
msg: CreateShoppingCartItem,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCartItem> {
|
||||
@ -119,9 +119,9 @@ pub struct UpdateShoppingCartItem {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
async_handler!(UpdateShoppingCartItem, update_shopping_cart_item, ShoppingCartItem);
|
||||
db_async_handler!(UpdateShoppingCartItem, update_shopping_cart_item, ShoppingCartItem);
|
||||
|
||||
async fn update_shopping_cart_item(
|
||||
pub(crate) async fn update_shopping_cart_item(
|
||||
msg: UpdateShoppingCartItem,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCartItem> {
|
||||
@ -152,9 +152,9 @@ pub struct FindShoppingCartItem {
|
||||
pub id: ShoppingCartItemId,
|
||||
}
|
||||
|
||||
async_handler!(FindShoppingCartItem, find_shopping_cart_item, ShoppingCartItem);
|
||||
db_async_handler!(FindShoppingCartItem, find_shopping_cart_item, ShoppingCartItem);
|
||||
|
||||
async fn find_shopping_cart_item(
|
||||
pub(crate) async fn find_shopping_cart_item(
|
||||
msg: FindShoppingCartItem,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCartItem> {
|
||||
@ -180,9 +180,9 @@ pub struct CartItems {
|
||||
pub shopping_cart_id: ShoppingCartId,
|
||||
}
|
||||
|
||||
async_handler!(CartItems, cart_items, Vec<ShoppingCartItem>);
|
||||
db_async_handler!(CartItems, cart_items, Vec<ShoppingCartItem>);
|
||||
|
||||
async fn cart_items(msg: CartItems, pool: PgPool) -> Result<Vec<ShoppingCartItem>> {
|
||||
pub(crate) async fn cart_items(msg: CartItems, pool: PgPool) -> Result<Vec<ShoppingCartItem>> {
|
||||
let shopping_cart_id = msg.shopping_cart_id;
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::async_handler;
|
||||
use crate::db_async_handler;
|
||||
use actix::{Handler, ResponseActFuture, WrapFuture};
|
||||
use sqlx::PgPool;
|
||||
|
||||
@ -25,9 +25,12 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<ShoppingCart>>")]
|
||||
pub struct AllShoppingCarts;
|
||||
|
||||
async_handler!(AllShoppingCarts, all_shopping_carts, Vec<ShoppingCart>);
|
||||
db_async_handler!(AllShoppingCarts, all_shopping_carts, Vec<ShoppingCart>);
|
||||
|
||||
pub async fn all_shopping_carts(_msg: AllShoppingCarts, pool: PgPool) -> Result<Vec<ShoppingCart>> {
|
||||
pub(crate) async fn all_shopping_carts(
|
||||
_msg: AllShoppingCarts,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<ShoppingCart>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, payment_method, state
|
||||
@ -46,14 +49,26 @@ FROM shopping_carts
|
||||
#[rtype(result = "Result<Vec<ShoppingCart>>")]
|
||||
pub struct AccountShoppingCarts {
|
||||
pub account_id: AccountId,
|
||||
pub state: Option<ShoppingCartState>,
|
||||
}
|
||||
|
||||
async_handler!(AccountShoppingCarts, account_shopping_carts, Vec<ShoppingCart>);
|
||||
db_async_handler!(AccountShoppingCarts, account_shopping_carts, Vec<ShoppingCart>);
|
||||
|
||||
pub async fn account_shopping_carts(
|
||||
pub(crate) async fn account_shopping_carts(
|
||||
msg: AccountShoppingCarts,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<ShoppingCart>> {
|
||||
if let Some(state) = msg.state {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, payment_method, state
|
||||
FROM shopping_carts
|
||||
WHERE buyer_id = $1 AND state = $2
|
||||
"#,
|
||||
)
|
||||
.bind(msg.account_id)
|
||||
.bind(state)
|
||||
} else {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, payment_method, state
|
||||
@ -62,6 +77,7 @@ WHERE buyer_id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(msg.account_id)
|
||||
}
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@ -77,9 +93,12 @@ pub struct CreateShoppingCart {
|
||||
pub payment_method: PaymentMethod,
|
||||
}
|
||||
|
||||
async_handler!(CreateShoppingCart, create_shopping_cart, ShoppingCart);
|
||||
db_async_handler!(CreateShoppingCart, create_shopping_cart, ShoppingCart);
|
||||
|
||||
async fn create_shopping_cart(msg: CreateShoppingCart, db: PgPool) -> Result<ShoppingCart> {
|
||||
pub(crate) async fn create_shopping_cart(
|
||||
msg: CreateShoppingCart,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCart> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO shopping_carts (buyer_id, payment_method)
|
||||
@ -106,9 +125,12 @@ pub struct UpdateShoppingCart {
|
||||
pub state: ShoppingCartState,
|
||||
}
|
||||
|
||||
async_handler!(UpdateShoppingCart, update_shopping_cart, ShoppingCart);
|
||||
db_async_handler!(UpdateShoppingCart, update_shopping_cart, ShoppingCart);
|
||||
|
||||
async fn update_shopping_cart(msg: UpdateShoppingCart, db: PgPool) -> Result<ShoppingCart> {
|
||||
pub(crate) async fn update_shopping_cart(
|
||||
msg: UpdateShoppingCart,
|
||||
db: PgPool,
|
||||
) -> Result<ShoppingCart> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
UPDATE shopping_carts
|
||||
@ -135,9 +157,9 @@ pub struct FindShoppingCart {
|
||||
pub id: ShoppingCartId,
|
||||
}
|
||||
|
||||
async_handler!(FindShoppingCart, find_shopping_cart, ShoppingCart);
|
||||
db_async_handler!(FindShoppingCart, find_shopping_cart, ShoppingCart);
|
||||
|
||||
async fn find_shopping_cart(msg: FindShoppingCart, db: PgPool) -> Result<ShoppingCart> {
|
||||
pub(crate) async fn find_shopping_cart(msg: FindShoppingCart, db: PgPool) -> Result<ShoppingCart> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, payment_method, state
|
||||
@ -153,3 +175,33 @@ WHERE id = $1
|
||||
super::Error::ShoppingCart(Error::NotExists)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<Option<ShoppingCart>>")]
|
||||
pub struct EnsureActiveShoppingCart {
|
||||
pub buyer_id: AccountId,
|
||||
}
|
||||
|
||||
db_async_handler!(EnsureActiveShoppingCart, ensure_active_shopping_cart, Option<ShoppingCart>);
|
||||
|
||||
pub(crate) async fn ensure_active_shopping_cart(
|
||||
msg: EnsureActiveShoppingCart,
|
||||
pool: PgPool,
|
||||
) -> Result<Option<ShoppingCart>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO shopping_carts (buyer_id, state)
|
||||
VALUES ($1, 'active')
|
||||
ON CONFLICT
|
||||
DO NOTHING
|
||||
RETURNING id, buyer_id, payment_method, state;
|
||||
"#,
|
||||
)
|
||||
.bind(msg.buyer_id)
|
||||
.fetch_optional(&pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCart(Error::NotExists)
|
||||
})
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<model::Stock>>")]
|
||||
pub struct AllStocks;
|
||||
|
||||
crate::async_handler!(AllStocks, all_stocks, Vec<Stock>);
|
||||
crate::db_async_handler!(AllStocks, all_stocks, Vec<Stock>);
|
||||
|
||||
async fn all_stocks(_msg: AllStocks, pool: PgPool) -> Result<Vec<model::Stock>> {
|
||||
sqlx::query_as(
|
||||
@ -47,7 +47,7 @@ pub struct CreateStock {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
crate::async_handler!(CreateStock, create_stock, Stock);
|
||||
crate::db_async_handler!(CreateStock, create_stock, Stock);
|
||||
|
||||
async fn create_stock(msg: CreateStock, pool: PgPool) -> Result<model::Stock> {
|
||||
sqlx::query_as(
|
||||
@ -77,7 +77,7 @@ pub struct UpdateStock {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
crate::async_handler!(UpdateStock, update_stock, Stock);
|
||||
crate::db_async_handler!(UpdateStock, update_stock, Stock);
|
||||
|
||||
async fn update_stock(msg: UpdateStock, pool: PgPool) -> Result<model::Stock> {
|
||||
sqlx::query_as(
|
||||
@ -108,7 +108,7 @@ pub struct DeleteStock {
|
||||
pub stock_id: StockId,
|
||||
}
|
||||
|
||||
crate::async_handler!(DeleteStock, delete_stock, Option<model::Stock>);
|
||||
crate::db_async_handler!(DeleteStock, delete_stock, Option<model::Stock>);
|
||||
|
||||
async fn delete_stock(msg: DeleteStock, pool: PgPool) -> Result<Option<Stock>> {
|
||||
sqlx::query_as(
|
||||
|
@ -1 +1,2 @@
|
||||
pub mod cart_manager;
|
||||
pub mod database;
|
||||
|
@ -18,6 +18,7 @@ pub mod actors;
|
||||
pub mod logic;
|
||||
pub mod model;
|
||||
pub mod routes;
|
||||
mod utils;
|
||||
|
||||
trait ResolveDbUrl {
|
||||
fn own_db_url(&self) -> Option<String>;
|
||||
|
@ -198,10 +198,10 @@ impl PartialEq<PasswordConfirmation> for Password {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
|
||||
#[derive(sqlx::Type, Serialize, Deserialize, Copy, Clone, Deref, Display)]
|
||||
#[sqlx(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct AccountId(pub RecordId);
|
||||
pub struct AccountId(RecordId);
|
||||
|
||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
||||
pub struct FullAccount {
|
||||
|
27
api/src/utils.rs
Normal file
27
api/src/utils.rs
Normal file
@ -0,0 +1,27 @@
|
||||
#[macro_export]
|
||||
macro_rules! db_async_handler {
|
||||
($msg: ty, $async: ident, $res: ty) => {
|
||||
impl Handler<$msg> for Database {
|
||||
type Result = ResponseActFuture<Self, Result<$res>>;
|
||||
|
||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let pool = self.pool.clone();
|
||||
Box::pin(async { $async(msg, pool).await }.into_actor(self))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cart_async_handler {
|
||||
($msg: ty, $async: ident, $res: ty) => {
|
||||
impl Handler<$msg> for CartManager {
|
||||
type Result = ResponseActFuture<Self, Result<$res>>;
|
||||
|
||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let db = self.db.clone();
|
||||
Box::pin(async { $async(msg, db).await }.into_actor(self))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user