Fix order, add non negative constructor

This commit is contained in:
eraden 2022-04-16 07:31:19 +02:00
parent 5354d909b3
commit 388bfd634a
8 changed files with 199 additions and 21 deletions

View File

@ -3,11 +3,13 @@ use sqlx::PgPool;
pub use account_orders::*;
pub use accounts::*;
pub use order_items::*;
pub use products::*;
pub use stocks::*;
mod account_orders;
mod accounts;
mod order_items;
mod products;
mod stocks;
@ -37,6 +39,8 @@ pub enum Error {
Product(products::Error),
#[error("{0}")]
Stock(stocks::Error),
#[error("{0}")]
OrderItem(order_items::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

View File

@ -9,13 +9,13 @@ use super::Result;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Can't create account")]
#[error("Can't create account order")]
CantCreate,
#[error("Can't find account does to lack of identity")]
#[error("Can't find account order does to lack of identity")]
NoIdentity,
#[error("Account order does not exists")]
NotExists,
#[error("Failed to load all accounts")]
#[error("Failed to load all account orders")]
All,
}

View File

@ -0,0 +1,93 @@
use crate::async_handler;
use actix::{Handler, ResponseActFuture, WrapFuture};
use sqlx::PgPool;
use crate::database::Database;
use crate::model::*;
use super::Result;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Can't create order item")]
CantCreate,
#[error("Can't find order item does to lack of identity")]
NoIdentity,
#[error("Order item does not exists")]
NotExists,
#[error("Failed to load all order items")]
All,
}
#[derive(actix::Message)]
#[rtype(result = "Result<Vec<OrderItem>>")]
pub struct AllOrderItems;
async_handler!(AllOrderItems, all_order_items, Vec<OrderItem>);
pub async fn all_order_items(_msg: AllOrderItems, pool: PgPool) -> Result<Vec<OrderItem>> {
sqlx::query_as(
r#"
SELECT id, buyer_id, status
FROM order_items
"#,
)
.fetch_all(&pool)
.await
.map_err(|e| {
log::error!("{e:?}");
super::Error::OrderItem(Error::All)
})
}
#[derive(actix::Message)]
#[rtype(result = "Result<OrderItem>")]
pub struct CreateOrderItem {
pub buyer_id: AccountId,
pub status: OrderStatus,
}
async_handler!(CreateOrderItem, create_order_item, OrderItem);
async fn create_order_item(msg: CreateOrderItem, db: PgPool) -> Result<OrderItem> {
sqlx::query_as(
r#"
INSERT INTO order_items (buyer_id, status)
VALUES ($1, $2)
RETURNING id, buyer_id, status
"#,
)
.bind(msg.buyer_id)
.bind(msg.status)
.fetch_one(&db)
.await
.map_err(|e| {
log::error!("{e:?}");
super::Error::OrderItem(Error::CantCreate)
})
}
#[derive(actix::Message)]
#[rtype(result = "Result<OrderItem>")]
pub struct FindOrderItem {
pub id: OrderItemId,
}
async_handler!(FindOrderItem, find_order_item, OrderItem);
async fn find_order_item(msg: FindOrderItem, db: PgPool) -> Result<OrderItem> {
sqlx::query_as(
r#"
SELECT id, buyer_id, status
FROM order_items
WHERE id = $1
"#,
)
.bind(msg.id)
.fetch_one(&db)
.await
.map_err(|e| {
log::error!("{e:?}");
super::Error::OrderItem(Error::NotExists)
})
}

View File

@ -8,13 +8,13 @@ use crate::{database, model};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Unable to load all products")]
#[error("Unable to load all stocks")]
All,
#[error("Unable to create product")]
#[error("Unable to create stock")]
Create,
#[error("Unable to update product")]
#[error("Unable to update stock")]
Update,
#[error("Unable to delete product")]
#[error("Unable to delete stock")]
Delete,
}
@ -22,9 +22,9 @@ pub enum Error {
#[rtype(result = "Result<Vec<model::Stock>>")]
pub struct AllStocks;
crate::async_handler!(AllStocks, all, Vec<Stock>);
crate::async_handler!(AllStocks, all_stocks, Vec<Stock>);
async fn all(_msg: AllStocks, pool: PgPool) -> Result<Vec<model::Stock>> {
async fn all_stocks(_msg: AllStocks, pool: PgPool) -> Result<Vec<model::Stock>> {
sqlx::query_as(
r#"
SELECT id, product_id, quantity, quantity_unit
@ -47,9 +47,9 @@ pub struct CreateStock {
pub quantity_unit: QuantityUnit,
}
crate::async_handler!(CreateStock, create_product, Stock);
crate::async_handler!(CreateStock, create_stock, Stock);
async fn create_product(msg: CreateStock, pool: PgPool) -> Result<model::Stock> {
async fn create_stock(msg: CreateStock, pool: PgPool) -> Result<model::Stock> {
sqlx::query_as(
r#"
INSERT INTO stocks (product_id, quantity)
@ -77,9 +77,9 @@ pub struct UpdateStock {
pub quantity_unit: QuantityUnit,
}
crate::async_handler!(UpdateStock, update_product, Stock);
crate::async_handler!(UpdateStock, update_stock, Stock);
async fn update_product(msg: UpdateStock, pool: PgPool) -> Result<model::Stock> {
async fn update_stock(msg: UpdateStock, pool: PgPool) -> Result<model::Stock> {
sqlx::query_as(
r#"
UPDATE stocks
@ -108,9 +108,9 @@ pub struct DeleteStock {
pub stock_id: StockId,
}
crate::async_handler!(DeleteStock, delete_product, Option<model::Stock>);
crate::async_handler!(DeleteStock, delete_stock, Option<model::Stock>);
async fn delete_product(msg: DeleteStock, pool: PgPool) -> Result<Option<Stock>> {
async fn delete_stock(msg: DeleteStock, pool: PgPool) -> Result<Option<Stock>> {
sqlx::query_as(
r#"
DELETE FROM stocks

View File

@ -5,7 +5,7 @@ use actix_session::{storage::RedisActorSessionStore, SessionMiddleware};
use actix_web::cookie::Key;
use actix_web::middleware::Logger;
use actix_web::web::Data;
use actix_web::{web, App, HttpResponse, HttpServer};
use actix_web::{App, HttpServer};
use gumdrop::Options;
use password_hash::SaltString;
use validator::{validate_email, validate_length};

View File

@ -4,6 +4,12 @@ use derive_more::{Deref, Display};
use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
#[derive(Debug, thiserror::Error)]
pub enum TransformError {
#[error("Given value is below minimal value")]
BelowMinimal,
}
pub type RecordId = i32;
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
@ -41,6 +47,13 @@ pub enum QuantityUnit {
Unit,
}
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
#[sqlx(rename_all = "lowercase")]
pub enum PaymentMethod {
PayU,
PaymentOnTheSpot,
}
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
#[sqlx(transparent)]
#[serde(transparent)]
@ -56,6 +69,22 @@ pub struct PriceMinor(NonNegative);
#[serde(transparent)]
pub struct Quantity(NonNegative);
impl TryFrom<NonNegative> for Quantity {
type Error = TransformError;
fn try_from(value: NonNegative) -> Result<Self, Self::Error> {
Ok(Self(value))
}
}
impl TryFrom<i32> for Quantity {
type Error = TransformError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
Ok(Self(value.try_into()?))
}
}
#[derive(sqlx::Type, Deserialize, Serialize, Deref, Debug)]
#[sqlx(transparent)]
#[serde(transparent)]
@ -98,7 +127,19 @@ impl<'de> serde::Deserialize<'de> for Email {
#[derive(sqlx::Type, Serialize, Deref)]
#[sqlx(transparent)]
#[serde(transparent)]
pub struct NonNegative(pub i32);
pub struct NonNegative(i32);
impl TryFrom<i32> for NonNegative {
type Error = TransformError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value < 0 {
return Err(TransformError::BelowMinimal);
} else {
Ok(Self(value))
}
}
}
impl<'de> serde::Deserialize<'de> for NonNegative {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@ -227,7 +268,7 @@ pub struct Stock {
pub quantity_unit: QuantityUnit,
}
#[derive(sqlx::Type, Serialize, Deserialize)]
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
#[sqlx(transparent)]
#[serde(transparent)]
pub struct AccountOrderId(pub RecordId);
@ -238,3 +279,43 @@ pub struct AccountOrder {
pub buyer_id: AccountId,
pub status: OrderStatus,
}
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
#[sqlx(transparent)]
#[serde(transparent)]
pub struct OrderItemId(pub RecordId);
#[derive(sqlx::FromRow, Serialize, Deserialize)]
pub struct OrderItem {
pub id: OrderItemId,
pub product_id: ProductId,
pub order_id: OrderItemId,
pub quantity: Quantity,
pub quantity_unit: QuantityUnit,
}
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
#[sqlx(transparent)]
#[serde(transparent)]
pub struct ShoppingCartId(pub RecordId);
#[derive(sqlx::FromRow, Serialize, Deserialize)]
pub struct ShoppingCart {
pub id: ShoppingCartId,
pub buyer_id: AccountId,
pub payment_method: PaymentMethod,
}
#[derive(sqlx::Type, Serialize, Deserialize, Deref)]
#[sqlx(transparent)]
#[serde(transparent)]
pub struct ShoppingCartItemId(pub RecordId);
#[derive(sqlx::FromRow, Serialize, Deserialize)]
pub struct ShoppingCartItem {
pub id: ShoppingCartId,
pub product_id: ProductId,
pub shopping_cart_id: ShoppingCartId,
pub quantity: Quantity,
pub quantity_unit: QuantityUnit,
}

View File

@ -68,7 +68,7 @@ CREATE TABLE order_items
CONSTRAINT positive_quantity check ( quantity >= 0 )
);
CREATE TABLE statistics
CREATE TABLE "statistics"
(
id serial not null primary key,
url varchar not null,

View File

@ -1,5 +1,5 @@
CREATE TYPE "PaymentMethod" AS ENUM (
'payu',
'pay_u',
'payment_on_the_spot'
);
@ -14,7 +14,7 @@ CREATE TABLE shopping_cart_items
(
id serial not null primary key,
product_id int references products (id) not null,
order_id int references shopping_carts (id),
shopping_cart_id int references shopping_carts (id),
quantity int not null default 0,
quantity_unit "QuantityUnit" not null,
CONSTRAINT positive_quantity check ( quantity >= 0 )