fix: consistency check for category before creating product #47

Merged
realaravinth merged 1 commit from category-exists-check into master 2024-07-16 17:31:04 +05:30

View file

@ -10,7 +10,9 @@ use mockall::*;
use super::errors::*; use super::errors::*;
use crate::inventory::{ use crate::inventory::{
application::port::output::db::{product_id_exists::*, product_name_exists_for_category::*}, application::port::output::db::{
category_id_exists::*, product_id_exists::*, product_name_exists_for_category::*,
},
domain::{ domain::{
add_product_command::AddProductCommand, add_product_command::AddProductCommand,
product_added_event::{ProductAddedEvent, ProductAddedEventBuilder}, product_added_event::{ProductAddedEvent, ProductAddedEventBuilder},
@ -29,7 +31,7 @@ pub type AddProductServiceObj = Arc<dyn AddProductUseCase>;
#[derive(Clone, Builder)] #[derive(Clone, Builder)]
pub struct AddProductService { pub struct AddProductService {
// TODO: check if category ID exists db_category_id_exists: CategoryIDExistsDBPortObj,
db_product_name_exists_for_category: ProductNameExistsForCategoryDBPortObj, db_product_name_exists_for_category: ProductNameExistsForCategoryDBPortObj,
db_product_id_exists: ProductIDExistsDBPortObj, db_product_id_exists: ProductIDExistsDBPortObj,
get_uuid: GetUUIDInterfaceObj, get_uuid: GetUUIDInterfaceObj,
@ -38,6 +40,14 @@ pub struct AddProductService {
#[async_trait::async_trait] #[async_trait::async_trait]
impl AddProductUseCase for AddProductService { impl AddProductUseCase for AddProductService {
async fn add_product(&self, cmd: AddProductCommand) -> InventoryResult<ProductAddedEvent> { async fn add_product(&self, cmd: AddProductCommand) -> InventoryResult<ProductAddedEvent> {
if !self
.db_category_id_exists
.category_id_exists(cmd.category_id())
.await?
{
return Err(InventoryError::CategoryIDNotFound);
}
let mut product_id = self.get_uuid.get_uuid(); let mut product_id = self.get_uuid.get_uuid();
loop { loop {
@ -138,6 +148,7 @@ pub mod tests {
mock_product_name_exists_for_category_db_port_false(IS_CALLED_ONLY_ONCE), mock_product_name_exists_for_category_db_port_false(IS_CALLED_ONLY_ONCE),
) )
.db_product_id_exists(mock_product_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) .db_product_id_exists(mock_product_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.db_category_id_exists(mock_category_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
.get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE)) .get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE))
.build() .build()
.unwrap(); .unwrap();
@ -162,6 +173,7 @@ pub mod tests {
.db_product_name_exists_for_category( .db_product_name_exists_for_category(
mock_product_name_exists_for_category_db_port_true(IS_CALLED_ONLY_ONCE), mock_product_name_exists_for_category_db_port_true(IS_CALLED_ONLY_ONCE),
) )
.db_category_id_exists(mock_category_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
.get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE)) .get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE))
.db_product_id_exists(mock_product_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) .db_product_id_exists(mock_product_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.build() .build()
@ -172,4 +184,24 @@ pub mod tests {
Err(InventoryError::DuplicateProductName) Err(InventoryError::DuplicateProductName)
) )
} }
#[actix_rt::test]
async fn test_service_category_id_doesnt_exist() {
let cmd = get_command();
let s = AddProductServiceBuilder::default()
.db_product_name_exists_for_category(
mock_product_name_exists_for_category_db_port_false(IS_NEVER_CALLED),
)
.db_product_id_exists(mock_product_id_exists_db_port_false(IS_NEVER_CALLED))
.db_category_id_exists(mock_category_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.get_uuid(mock_get_uuid(IS_NEVER_CALLED))
.build()
.unwrap();
assert_eq!(
s.add_product(cmd.clone()).await,
Err(InventoryError::CategoryIDNotFound)
)
}
} }