diff --git a/actors/database_manager/src/account_addresses.rs b/actors/database_manager/src/account_addresses.rs index 87f3c33..45c74aa 100644 --- a/actors/database_manager/src/account_addresses.rs +++ b/actors/database_manager/src/account_addresses.rs @@ -70,8 +70,6 @@ WHERE account_id = $1 AND id = $2 .map_err(|_| Error::AccountAddresses.into()) } -///// - #[derive(actix::Message)] #[rtype(result = "Result")] pub struct DefaultAccountAddress { @@ -139,14 +137,15 @@ WHERE account_id = $1 .fetch_all(&mut *pool) .await { - log::error!("{}", e); + log::error!("{e}"); + eprintln!("{e}") } } sqlx::query_as( r#" -INSERT INTO account_addresses ( name, email, phone, street, city, country, zip, account_id ) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8) +INSERT INTO account_addresses ( name, email, phone, street, city, country, zip, account_id, is_default) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, name, email, phone, street, city, country, zip, account_id, is_default "#, ) @@ -161,7 +160,11 @@ RETURNING id, name, email, phone, street, city, country, zip, account_id, is_def .bind(msg.is_default) .fetch_one(pool) .await - .map_err(|_| Error::CreateAccountAddress.into()) + .map_err(|e| { + log::error!("{e}"); + eprintln!("{e}"); + Error::CreateAccountAddress.into() + }) } #[derive(actix::Message)] @@ -215,7 +218,6 @@ RETURNING id, name, email, phone, street, city, country, zip, account_id, is_def #[cfg(test)] mod test { - use actix::{Actor, Addr}; use config::*; use fake::Fake; use model::*; @@ -226,20 +228,22 @@ mod test { impl UpdateConfig for NoOpts {} - async fn test_create_account(db: Addr) -> FullAccount { + async fn test_create_account(pool: &mut sqlx::Transaction<'_, sqlx::Postgres>) -> FullAccount { let login: String = fake::faker::internet::en::Username().fake(); let email: String = fake::faker::internet::en::FreeEmail().fake(); let hash: String = fake::faker::internet::en::Password(10..20).fake(); - db.send(CreateAccount { - email: Email::new(email), - login: Login::new(login), - pass_hash: PassHash::new(hash), - role: Role::Admin, - }) + crate::create_account( + CreateAccount { + email: Email::new(email), + login: Login::new(login), + pass_hash: PassHash::new(hash), + role: Role::Admin, + }, + pool, + ) .await .unwrap() - .unwrap() } #[actix::test] @@ -250,10 +254,12 @@ mod test { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); // account - let account = test_create_account(db.clone()).await; + let account = test_create_account(&mut t).await; // address let mut address: AccountAddress = { @@ -265,35 +271,36 @@ mod test { let country: String = fake::faker::address::en::CountryName().fake(); let zip: String = fake::faker::address::en::ZipCode().fake(); let account_id = Some(account.id); - let is_default: bool = fake::faker::boolean::en::Boolean(6).fake(); + let is_default: bool = true; - let address = db - .send(CreateAccountAddress { - name: model::Name::new(name.clone()), - email: model::Email::new(email.clone()), - phone: model::Phone::new(phone.clone()), - street: model::Street::new(street.clone()), - city: model::City::new(city.clone()), - country: model::Country::new(country.clone()), - zip: model::Zip::new(zip.clone()), + let address = super::create_address( + CreateAccountAddress { + name: Name::new(name.clone()), + email: Email::new(email.clone()), + phone: Phone::new(phone.clone()), + street: Street::new(street.clone()), + city: City::new(city.clone()), + country: Country::new(country.clone()), + zip: Zip::new(zip.clone()), account_id: account_id.clone(), - is_default: is_default.clone(), - }) - .await - .unwrap() - .unwrap(); + is_default, + }, + &mut t, + ) + .await + .unwrap(); assert_eq!( address, - model::AccountAddress { + AccountAddress { id: address.id, - name: model::Name::new(name.clone()), - email: model::Email::new(email.clone()), - phone: model::Phone::new(phone.clone()), - street: model::Street::new(street.clone()), - city: model::City::new(city.clone()), - country: model::Country::new(country.clone()), - zip: model::Zip::new(zip.clone()), + name: Name::new(name.clone()), + email: Email::new(email.clone()), + phone: Phone::new(phone.clone()), + street: Street::new(street.clone()), + city: City::new(city.clone()), + country: Country::new(country.clone()), + zip: Zip::new(zip.clone()), account_id: account.id, is_default, } @@ -301,19 +308,20 @@ mod test { address }; - let found = db - .send(FindAccountAddress { + let found = super::find_account_address( + FindAccountAddress { account_id: account.id, address_id: address.id, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); assert_eq!(found, address); - let changed = db - .send(UpdateAccountAddress { + let changed = super::update_account_address( + UpdateAccountAddress { id: address.id, name: address.name.clone(), email: address.email.clone(), @@ -324,23 +332,26 @@ mod test { zip: address.zip.clone(), account_id: address.account_id.clone(), is_default: true, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); address.is_default = true; assert_eq!(changed, address); - let default_address = db - .send(DefaultAccountAddress { + let default_address = super::default_account_address( + DefaultAccountAddress { account_id: account.id, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); + t.rollback().await.unwrap(); assert_eq!(default_address, address); } } diff --git a/actors/database_manager/src/accounts.rs b/actors/database_manager/src/accounts.rs index f402b3f..c2a798f 100644 --- a/actors/database_manager/src/accounts.rs +++ b/actors/database_manager/src/accounts.rs @@ -1,7 +1,6 @@ #[cfg(feature = "dummy")] use fake::Fake; -use model::{AccountId, AccountState, Email, FullAccount, Login, PassHash, Role}; -use sqlx::PgPool; +use model::*; use crate::{db_async_handler, Result}; @@ -24,16 +23,24 @@ pub enum Error { #[rtype(result = "Result>")] pub struct AllAccounts; -db_async_handler!(AllAccounts, all_accounts, Vec); +db_async_handler!( + AllAccounts, + all_accounts, + Vec, + inner_all_accounts +); -pub(crate) async fn all_accounts(_msg: AllAccounts, pool: PgPool) -> Result> { +pub(crate) async fn all_accounts( + _msg: AllAccounts, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result> { sqlx::query_as( r#" SELECT id, email, login, pass_hash, role, customer_id, state FROM accounts "#, ) - .fetch_all(&pool) + .fetch_all(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -51,9 +58,17 @@ pub struct CreateAccount { pub role: Role, } -db_async_handler!(CreateAccount, create_account, FullAccount); +db_async_handler!( + CreateAccount, + create_account, + FullAccount, + inner_create_account +); -pub(crate) async fn create_account(msg: CreateAccount, db: PgPool) -> Result { +pub(crate) async fn create_account( + msg: CreateAccount, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result { sqlx::query_as( r#" INSERT INTO accounts (login, email, role, pass_hash) @@ -65,7 +80,7 @@ RETURNING id, email, login, pass_hash, role, customer_id, state .bind(msg.email) .bind(msg.role) .bind(msg.pass_hash) - .fetch_one(&db) + .fetch_one(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -85,9 +100,17 @@ pub struct UpdateAccount { pub state: AccountState, } -db_async_handler!(UpdateAccount, update_account, FullAccount); +db_async_handler!( + UpdateAccount, + update_account, + FullAccount, + inner_update_account +); -pub(crate) async fn update_account(msg: UpdateAccount, db: PgPool) -> Result { +pub(crate) async fn update_account( + msg: UpdateAccount, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result { match msg.pass_hash { Some(hash) => sqlx::query_as( r#" @@ -117,7 +140,7 @@ RETURNING id, email, login, pass_hash, role, customer_id, state .bind(msg.role) .bind(msg.state), } - .fetch_one(&db) + .fetch_one(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -131,9 +154,12 @@ pub struct FindAccount { pub account_id: AccountId, } -db_async_handler!(FindAccount, find_account, FullAccount); +db_async_handler!(FindAccount, find_account, FullAccount, inner_find_account); -pub(crate) async fn find_account(msg: FindAccount, db: PgPool) -> Result { +pub(crate) async fn find_account( + msg: FindAccount, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result { sqlx::query_as( r#" SELECT id, email, login, pass_hash, role, customer_id, state @@ -142,7 +168,7 @@ WHERE id = $1 "#, ) .bind(msg.account_id) - .fetch_one(&db) + .fetch_one(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -157,9 +183,17 @@ pub struct AccountByIdentity { pub email: Option, } -db_async_handler!(AccountByIdentity, account_by_identity, FullAccount); +db_async_handler!( + AccountByIdentity, + account_by_identity, + FullAccount, + inner_account_by_identity +); -pub(crate) async fn account_by_identity(msg: AccountByIdentity, db: PgPool) -> Result { +pub(crate) async fn account_by_identity( + msg: AccountByIdentity, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result { match (msg.login, msg.email) { (Some(login), None) => sqlx::query_as( r#" @@ -188,7 +222,7 @@ WHERE login = $1 AND email = $2 .bind(email), _ => return Err(super::Error::Account(Error::NoIdentity)), } - .fetch_one(&db) + .fetch_one(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -198,7 +232,6 @@ WHERE login = $1 AND email = $2 #[cfg(test)] mod tests { - use actix::Addr; use config::UpdateConfig; use fake::Fake; use model::*; @@ -210,7 +243,7 @@ mod tests { impl UpdateConfig for NoOpts {} async fn test_create_account( - db: Addr, + t: &mut sqlx::Transaction<'_, sqlx::Postgres>, login: Option, email: Option, hash: Option, @@ -220,15 +253,17 @@ mod tests { let email: String = email.unwrap_or_else(|| en::FreeEmail().fake()); let hash: String = hash.unwrap_or_else(|| en::Password(10..20).fake()); - db.send(CreateAccount { - email: Email::new(email), - login: Login::new(login), - pass_hash: PassHash::new(hash), - role: Role::Admin, - }) + super::create_account( + CreateAccount { + email: Email::new(email), + login: Login::new(login), + pass_hash: PassHash::new(hash), + role: Role::Admin, + }, + t, + ) .await .unwrap() - .unwrap() } #[actix::test] @@ -239,22 +274,25 @@ mod tests { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); let login: String = fake::faker::internet::en::Username().fake(); let email: String = fake::faker::internet::en::FreeEmail().fake(); let hash: String = fake::faker::internet::en::Password(10..20).fake(); - let account: FullAccount = db - .send(CreateAccount { + let account: FullAccount = super::create_account( + CreateAccount { email: Email::new(&email), login: Login::new(&login), pass_hash: PassHash::new(&hash), role: Role::Admin, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); let expected = FullAccount { login: Login::new(login), @@ -266,6 +304,7 @@ mod tests { state: AccountState::Active, }; + t.rollback().await.unwrap(); assert_eq!(account, expected); } @@ -277,14 +316,17 @@ mod tests { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); - test_create_account(db.clone(), None, None, None).await; - test_create_account(db.clone(), None, None, None).await; - test_create_account(db.clone(), None, None, None).await; + test_create_account(&mut t, None, None, None).await; + test_create_account(&mut t, None, None, None).await; + test_create_account(&mut t, None, None, None).await; - let v: Vec = db.send(AllAccounts).await.unwrap().unwrap(); + let v: Vec = super::all_accounts(AllAccounts, &mut t).await.unwrap(); assert!(v.len() >= 3); + t.rollback().await.unwrap(); } #[actix::test] @@ -295,14 +337,16 @@ mod tests { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); let original_login: String = fake::faker::internet::en::Username().fake(); let original_email: String = fake::faker::internet::en::FreeEmail().fake(); let original_hash: String = fake::faker::internet::en::Password(10..20).fake(); let original_account = test_create_account( - db.clone(), + &mut t, Some(original_login.clone()), Some(original_email.clone()), Some(original_hash.clone()), @@ -312,18 +356,19 @@ mod tests { let updated_login: String = fake::faker::internet::en::Username().fake(); let updated_email: String = fake::faker::internet::en::FreeEmail().fake(); - let updated_account: FullAccount = db - .send(UpdateAccount { + let updated_account: FullAccount = super::update_account( + UpdateAccount { id: original_account.id, email: Email::new(updated_email.clone()), login: Login::new(updated_login.clone()), pass_hash: None, role: Role::Admin, state: AccountState::Active, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); let expected = FullAccount { id: original_account.id, @@ -335,6 +380,7 @@ mod tests { state: AccountState::Active, }; + t.rollback().await.unwrap(); assert_ne!(original_account, expected); assert_eq!(updated_account, expected); } @@ -347,14 +393,16 @@ mod tests { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); let original_login: String = fake::faker::internet::en::Username().fake(); let original_email: String = fake::faker::internet::en::FreeEmail().fake(); let original_hash: String = fake::faker::internet::en::Password(10..20).fake(); let original_account = test_create_account( - db.clone(), + &mut t, Some(original_login.clone()), Some(original_email.clone()), Some(original_hash.clone()), @@ -365,18 +413,19 @@ mod tests { let updated_email: String = fake::faker::internet::en::FreeEmail().fake(); let updated_hash: String = fake::faker::internet::en::Password(10..20).fake(); - let updated_account: FullAccount = db - .send(UpdateAccount { + let updated_account: FullAccount = super::update_account( + UpdateAccount { id: original_account.id, email: Email::new(updated_email.clone()), login: Login::new(updated_login.clone()), pass_hash: Some(PassHash::new(updated_hash.clone())), role: Role::Admin, state: AccountState::Active, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); let expected = FullAccount { id: original_account.id, @@ -388,6 +437,7 @@ mod tests { state: AccountState::Active, }; + t.rollback().await.unwrap(); assert_ne!(original_account, expected); assert_eq!(updated_account, expected); } @@ -400,18 +450,22 @@ mod tests { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); - let account = test_create_account(db.clone(), None, None, None).await; + let account = test_create_account(&mut t, None, None, None).await; - let res: FullAccount = db - .send(FindAccount { + let res: FullAccount = super::find_account( + FindAccount { account_id: account.id, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); + t.rollback().await.unwrap(); assert_eq!(account, res); } @@ -423,19 +477,23 @@ mod tests { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); - let account = test_create_account(db.clone(), None, None, None).await; + let account = test_create_account(&mut t, None, None, None).await; - let res: FullAccount = db - .send(AccountByIdentity { + let res: FullAccount = super::account_by_identity( + AccountByIdentity { email: Some(account.email.clone()), login: None, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); + t.rollback().await.unwrap(); assert_eq!(account, res); } @@ -447,19 +505,23 @@ mod tests { .database_mut() .set_url("postgres://postgres@localhost/bazzar_test"); - let db = Database::build(config).await.start(); + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); - let account = test_create_account(db.clone(), None, None, None).await; + let account = test_create_account(&mut t, None, None, None).await; - let res: FullAccount = db - .send(AccountByIdentity { + let res: FullAccount = super::account_by_identity( + AccountByIdentity { login: Some(account.login.clone()), email: None, - }) - .await - .unwrap() - .unwrap(); + }, + &mut t, + ) + .await + .unwrap(); + t.rollback().await.unwrap(); assert_eq!(account, res); } } diff --git a/actors/database_manager/src/products.rs b/actors/database_manager/src/products.rs index 1ba4088..e039a71 100644 --- a/actors/database_manager/src/products.rs +++ b/actors/database_manager/src/products.rs @@ -133,6 +133,7 @@ RETURNING id, .await .map_err(|e| { log::error!("{e:?}"); + eprintln!("{e:?}"); crate::Error::Product(Error::Create) }) } diff --git a/actors/database_manager/src/stocks.rs b/actors/database_manager/src/stocks.rs index 817b44a..93ad515 100644 --- a/actors/database_manager/src/stocks.rs +++ b/actors/database_manager/src/stocks.rs @@ -1,6 +1,5 @@ use actix::Message; use model::{ProductId, Quantity, QuantityUnit, Stock, StockId}; -use sqlx::PgPool; use crate::{MultiLoad, Result}; @@ -22,16 +21,19 @@ pub enum Error { #[rtype(result = "Result>")] pub struct AllStocks; -crate::db_async_handler!(AllStocks, all_stocks, Vec); +crate::db_async_handler!(AllStocks, all_stocks, Vec, inner_all_stocks); -async fn all_stocks(_msg: AllStocks, pool: PgPool) -> Result> { +async fn all_stocks( + _msg: AllStocks, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result> { sqlx::query_as( r#" SELECT id, product_id, quantity, quantity_unit FROM stocks "#, ) - .fetch_all(&pool) + .fetch_all(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -47,9 +49,12 @@ pub struct CreateStock { pub quantity_unit: QuantityUnit, } -crate::db_async_handler!(CreateStock, create_stock, Stock); +crate::db_async_handler!(CreateStock, create_stock, Stock, inner_create_stock); -async fn create_stock(msg: CreateStock, pool: PgPool) -> Result { +async fn create_stock( + msg: CreateStock, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result { sqlx::query_as( r#" INSERT INTO stocks (product_id, quantity, quantity_unit) @@ -60,10 +65,11 @@ RETURNING id, product_id, quantity, quantity_unit .bind(msg.product_id) .bind(msg.quantity) .bind(msg.quantity_unit) - .fetch_one(&pool) + .fetch_one(pool) .await .map_err(|e| { log::error!("{e:?}"); + eprintln!("{e:?}"); crate::Error::Stock(Error::Create) }) } @@ -77,9 +83,12 @@ pub struct UpdateStock { pub quantity_unit: QuantityUnit, } -crate::db_async_handler!(UpdateStock, update_stock, Stock); +crate::db_async_handler!(UpdateStock, update_stock, Stock, inner_update_stock); -async fn update_stock(msg: UpdateStock, pool: PgPool) -> Result { +async fn update_stock( + msg: UpdateStock, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result { sqlx::query_as( r#" UPDATE stocks @@ -94,7 +103,7 @@ RETURNING id, product_id, quantity, quantity_unit .bind(msg.quantity) .bind(msg.quantity_unit) .bind(msg.id) - .fetch_one(&pool) + .fetch_one(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -108,9 +117,17 @@ pub struct DeleteStock { pub stock_id: StockId, } -crate::db_async_handler!(DeleteStock, delete_stock, Option); +crate::db_async_handler!( + DeleteStock, + delete_stock, + Option, + inner_delete_stock +); -async fn delete_stock(msg: DeleteStock, pool: PgPool) -> Result> { +async fn delete_stock( + msg: DeleteStock, + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, +) -> Result> { sqlx::query_as( r#" DELETE FROM stocks @@ -119,7 +136,7 @@ RETURNING id, product_id, quantity, quantity_unit "#, ) .bind(msg.stock_id) - .fetch_optional(&pool) + .fetch_optional(pool) .await .map_err(|e| { log::error!("{e:?}"); @@ -143,7 +160,7 @@ crate::db_async_handler!( async fn product_stock( msg: ProductsStock, pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, -) -> Result> { +) -> Result> { Ok(MultiLoad::new( pool, r#" @@ -160,3 +177,102 @@ async fn product_stock( ) .await?) } + +#[cfg(test)] +mod tests { + use config::UpdateConfig; + use fake::faker::lorem::en as lorem; + use fake::Fake; + use model::*; + use uuid::Uuid; + + pub struct NoOpts; + + impl UpdateConfig for NoOpts {} + + use crate::*; + + async fn test_product(pool: &mut sqlx::Transaction<'_, sqlx::Postgres>) -> Product { + create_product( + CreateProduct { + name: ProductName::new(format!("db stocks test product {}", Uuid::new_v4())), + short_description: ProductShortDesc::new(lorem::Paragraph(1..2).fake::()), + long_description: ProductLongDesc::new(lorem::Paragraph(4..5).fake::()), + category: None, + price: Price::from_u32(12321), + deliver_days_flag: Days(vec![Day::Friday, Day::Sunday]), + }, + pool, + ) + .await + .unwrap() + } + + async fn test_stock( + pool: &mut sqlx::Transaction<'_, sqlx::Postgres>, + product_id: Option, + quantity: Option, + quantity_unit: Option, + ) -> Stock { + let product_id = match product_id { + Some(id) => id, + _ => test_product(&mut *pool).await.id, + }; + let quantity = quantity.unwrap_or_else(|| Quantity::from_u32(345)); + let quantity_unit = quantity_unit.unwrap_or_else(|| QuantityUnit::Piece); + + super::create_stock( + CreateStock { + product_id, + quantity_unit, + quantity, + }, + &mut *pool, + ) + .await + .unwrap() + } + + #[actix::test] + async fn create_stock() { + let config = config::default_load(&mut NoOpts); + config + .lock() + .database_mut() + .set_url("postgres://postgres@localhost/bazzar_test"); + + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); + test_stock(&mut t, None, None, None).await; + t.rollback().await.unwrap(); + } + + #[actix::test] + async fn products_stock() { + let config = config::default_load(&mut NoOpts); + config + .lock() + .database_mut() + .set_url("postgres://postgres@localhost/bazzar_test"); + + let db = Database::build(config).await; + let pool = db.pool(); + let mut t = pool.begin().await.unwrap(); + + let first = test_stock(&mut t, None, None, None).await; + let second = test_stock(&mut t, None, None, None).await; + + let stocks: Vec = super::product_stock( + ProductsStock { + product_ids: vec![first.product_id, second.product_id], + }, + &mut t, + ) + .await + .unwrap(); + + t.rollback().await.unwrap(); + assert_eq!(stocks, vec![first, second]); + } +} diff --git a/shared/model/src/lib.rs b/shared/model/src/lib.rs index 5ca84b4..5f0092d 100644 --- a/shared/model/src/lib.rs +++ b/shared/model/src/lib.rs @@ -172,7 +172,7 @@ impl Role { #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] -#[derive(Copy, Clone, Debug, Hash, Display, Deserialize, Serialize)] +#[derive(Copy, Clone, Debug, PartialEq, Hash, Display, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum QuantityUnit { #[cfg_attr(feature = "db", sqlx(rename = "g"))] @@ -283,6 +283,12 @@ impl Default for Audience { #[serde(transparent)] pub struct Price(NonNegative); +impl Price { + pub fn from_u32(price: u32) -> Self { + Self(NonNegative(price as i32)) + } +} + impl ops::Mul for Price { type Output = Self; @@ -294,7 +300,7 @@ impl ops::Mul for Price { #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] -#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Hash, Deref, From)] +#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Copy, Clone, Hash, Deref, From)] #[serde(transparent)] pub struct Quantity(NonNegative); @@ -429,7 +435,7 @@ impl<'de> serde::Deserialize<'de> for Email { #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] -#[derive(Serialize, Default, Debug, Copy, Clone, Hash, Deref, Display)] +#[derive(Serialize, Default, Debug, PartialEq, Copy, Clone, Hash, Deref, Display)] #[serde(transparent)] pub struct NonNegative(i32); @@ -591,7 +597,7 @@ impl TryFrom for Day { #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[derive(Serialize, Deserialize, Hash, Debug)] #[serde(transparent)] -pub struct Days(Vec); +pub struct Days(pub Vec); impl ops::Deref for Days { type Target = Vec; @@ -856,13 +862,13 @@ pub struct Product { #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::Type))] #[cfg_attr(feature = "db", sqlx(transparent))] -#[derive(Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(transparent)] pub struct StockId(pub RecordId); #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[cfg_attr(feature = "db", derive(sqlx::FromRow))] -#[derive(Serialize, Deserialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct Stock { pub id: StockId, pub product_id: ProductId,