From d727d0b5b0b5afd039380b8de0ca356c83f18d31 Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Sat, 21 Sep 2024 15:34:14 +0530 Subject: [PATCH] feat: inventory: category ID is provided by caller --- .../services/add_category_service.rs | 60 +++++++-------- src/inventory/application/services/errors.rs | 6 +- .../services/update_category_service.rs | 1 - src/inventory/domain/add_category_command.rs | 73 ++++++++++++------- src/inventory/domain/category_aggregate.rs | 10 ++- 5 files changed, 88 insertions(+), 62 deletions(-) diff --git a/src/inventory/application/services/add_category_service.rs b/src/inventory/application/services/add_category_service.rs index 8e16448..8958a59 100644 --- a/src/inventory/application/services/add_category_service.rs +++ b/src/inventory/application/services/add_category_service.rs @@ -14,12 +14,11 @@ use crate::inventory::{ category_id_exists::*, category_name_exists_for_store::*, store_id_exists::*, }, domain::{ - add_category_command::AddCategoryCommand, + add_category_command::*, category_added_event::{CategoryAddedEvent, CategoryAddedEventBuilder}, category_aggregate::*, }, }; -use crate::utils::uuid::*; #[automock] #[async_trait::async_trait] @@ -34,7 +33,6 @@ pub struct AddCategoryService { db_store_id_exists: StoreIDExistsDBPortObj, db_category_name_exists_for_store: CategoryNameExistsForStoreDBPortObj, db_category_id_exists: CategoryIDExistsDBPortObj, - get_uuid: GetUUIDInterfaceObj, } #[async_trait::async_trait] @@ -48,27 +46,19 @@ impl AddCategoryUseCase for AddCategoryService { return Err(InventoryError::StoreIDNotFound); } - let mut category_id = self.get_uuid.get_uuid(); - - loop { - if self - .db_category_id_exists - .category_id_exists(&category_id) - .await? - { - category_id = self.get_uuid.get_uuid(); - - continue; - } else { - break; - } + if self + .db_category_id_exists + .category_id_exists(cmd.category_id()) + .await? + { + return Err(InventoryError::DuplicateCategoryID); } let category = CategoryBuilder::default() .name(cmd.name().into()) .description(cmd.description().as_ref().map(|s| s.to_string())) .store_id(*cmd.store_id()) - .category_id(category_id) + .category_id(*cmd.category_id()) .build() .unwrap(); @@ -97,8 +87,8 @@ pub mod tests { use uuid::Uuid; + use crate::tests::bdd::*; use crate::utils::uuid::tests::UUID; - use crate::{tests::bdd::*, utils::uuid::tests::mock_get_uuid}; pub fn mock_add_category_service( times: Option, @@ -111,7 +101,7 @@ pub mod tests { .description(cmd.description().as_ref().map(|s| s.to_string())) .added_by_user(*cmd.adding_by()) .store_id(*cmd.store_id()) - .category_id(UUID) + .category_id(*cmd.category_id()) .build() .unwrap(); @@ -133,8 +123,13 @@ pub mod tests { let user_id = UUID; let store_id = Uuid::new_v4(); - // description = None - let cmd = AddCategoryCommand::new(name.into(), Some(description.into()), store_id, user_id) + let cmd = AddCategoryCommandBuilder::default() + .name(name.into()) + .description(Some(description.into())) + .store_id(store_id) + .adding_by(user_id) + .category_id(UUID) + .build() .unwrap(); let s = AddCategoryServiceBuilder::default() @@ -143,7 +138,6 @@ pub mod tests { IS_CALLED_ONLY_ONCE, )) .db_category_id_exists(mock_category_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) - .get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE)) .build() .unwrap(); @@ -162,8 +156,13 @@ pub mod tests { let user_id = UUID; let store_id = Uuid::new_v4(); - // description = None - let cmd = AddCategoryCommand::new(name.into(), Some(description.into()), store_id, user_id) + let cmd = AddCategoryCommandBuilder::default() + .name(name.into()) + .description(Some(description.into())) + .store_id(store_id) + .adding_by(user_id) + .category_id(UUID) + .build() .unwrap(); let s = AddCategoryServiceBuilder::default() @@ -172,7 +171,6 @@ pub mod tests { IS_CALLED_ONLY_ONCE, )) .db_category_id_exists(mock_category_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) - .get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE)) .build() .unwrap(); @@ -189,8 +187,13 @@ pub mod tests { let user_id = UUID; let store_id = Uuid::new_v4(); - // description = None - let cmd = AddCategoryCommand::new(name.into(), Some(description.into()), store_id, user_id) + let cmd = AddCategoryCommandBuilder::default() + .name(name.into()) + .description(Some(description.into())) + .store_id(store_id) + .adding_by(user_id) + .category_id(UUID) + .build() .unwrap(); let s = AddCategoryServiceBuilder::default() @@ -199,7 +202,6 @@ pub mod tests { IS_NEVER_CALLED, )) .db_category_id_exists(mock_category_id_exists_db_port_false(IS_NEVER_CALLED)) - .get_uuid(mock_get_uuid(IS_NEVER_CALLED)) .build() .unwrap(); diff --git a/src/inventory/application/services/errors.rs b/src/inventory/application/services/errors.rs index 8d256f5..5373fed 100644 --- a/src/inventory/application/services/errors.rs +++ b/src/inventory/application/services/errors.rs @@ -20,6 +20,7 @@ pub enum InventoryError { DuplicateCustomizationName, DuplicateCustomizationID, DuplicateStoreID, + DuplicateCategoryID, ProductIDNotFound, CategoryIDNotFound, CustomizationIDNotFound, @@ -39,10 +40,7 @@ impl From for InventoryError { error!("DuplicateProductID"); Self::InternalError } - InventoryDBError::DuplicateCategoryID => { - error!("DuplicateCategoryID"); - Self::InternalError - } + InventoryDBError::DuplicateCategoryID => Self::DuplicateCategoryID, InventoryDBError::DuplicateCustomizationID => Self::DuplicateCustomizationID, InventoryDBError::InternalError => Self::InternalError, InventoryDBError::ProductIDNotFound => InventoryError::ProductIDNotFound, diff --git a/src/inventory/application/services/update_category_service.rs b/src/inventory/application/services/update_category_service.rs index be6f876..b2a9c61 100644 --- a/src/inventory/application/services/update_category_service.rs +++ b/src/inventory/application/services/update_category_service.rs @@ -15,7 +15,6 @@ use crate::inventory::{ }, domain::{category_aggregate::*, category_updated_event::*, update_category_command::*}, }; -use crate::utils::uuid::*; #[automock] #[async_trait::async_trait] diff --git a/src/inventory/domain/add_category_command.rs b/src/inventory/domain/add_category_command.rs index 9c8d0eb..406ab70 100644 --- a/src/inventory/domain/add_category_command.rs +++ b/src/inventory/domain/add_category_command.rs @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later +use derive_builder::Builder; use derive_getters::Getters; use derive_more::{Display, Error}; use serde::{Deserialize, Serialize}; @@ -12,21 +13,22 @@ pub enum AddCategoryCommandError { NameIsEmpty, } -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters)] +#[derive( + Clone, Debug, Builder, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters, +)] +#[builder(build_fn(validate = "Self::validate"))] pub struct AddCategoryCommand { + #[builder(setter(custom))] name: String, + #[builder(setter(custom))] description: Option, store_id: Uuid, + category_id: Uuid, adding_by: Uuid, } -impl AddCategoryCommand { - pub fn new( - name: String, - description: Option, - store_id: Uuid, - adding_by: Uuid, - ) -> Result { +impl AddCategoryCommandBuilder { + pub fn description(&mut self, description: Option) -> &mut Self { let description: Option = if let Some(description) = description { let description = description.trim(); if description.is_empty() { @@ -37,18 +39,22 @@ impl AddCategoryCommand { } else { None }; + self.description = Some(description); + self + } + pub fn name(&mut self, name: String) -> &mut Self { let name = name.trim().to_owned(); - if name.is_empty() { - return Err(AddCategoryCommandError::NameIsEmpty); + self.name = Some(name); + self + } + + pub fn validate(&self) -> Result<(), String> { + if self.name.as_ref().unwrap().is_empty() { + return Err(AddCategoryCommandError::NameIsEmpty.to_string()); } - Ok(Self { - name, - store_id, - description, - adding_by, - }) + Ok(()) } } @@ -65,26 +71,41 @@ mod tests { let adding_by = UUID; let store_id = Uuid::new_v4(); - // description = None - let cmd = AddCategoryCommand::new(name.into(), None, store_id, adding_by).unwrap(); + let cmd = AddCategoryCommandBuilder::default() + .name(name.into()) + .description(None) + .store_id(store_id) + .adding_by(adding_by) + .category_id(UUID) + .build() + .unwrap(); assert_eq!(cmd.name(), name); assert_eq!(cmd.description(), &None); assert_eq!(cmd.adding_by(), &adding_by); assert_eq!(cmd.store_id(), &store_id); - // description = Some - let cmd = - AddCategoryCommand::new(name.into(), Some(description.into()), store_id, adding_by) - .unwrap(); + let cmd = AddCategoryCommandBuilder::default() + .name(name.into()) + .description(Some(description.into())) + .store_id(store_id) + .adding_by(adding_by) + .category_id(UUID) + .build() + .unwrap(); + assert_eq!(cmd.name(), name); assert_eq!(cmd.description(), &Some(description.to_owned())); assert_eq!(cmd.adding_by(), &adding_by); assert_eq!(cmd.store_id(), &store_id); // AddCategoryCommandError::NameIsEmpty - assert_eq!( - AddCategoryCommand::new("".into(), Some(description.into()), store_id, adding_by,), - Err(AddCategoryCommandError::NameIsEmpty) - ) + assert!(AddCategoryCommandBuilder::default() + .name("".into()) + .description(Some(description.into())) + .store_id(store_id) + .adding_by(adding_by) + .category_id(UUID) + .build() + .is_err()) } } diff --git a/src/inventory/domain/category_aggregate.rs b/src/inventory/domain/category_aggregate.rs index faeabb7..09bf84e 100644 --- a/src/inventory/domain/category_aggregate.rs +++ b/src/inventory/domain/category_aggregate.rs @@ -107,8 +107,14 @@ mod aggregate_tests { let store_id = Uuid::new_v4(); let category_id = UUID; - let cmd = - AddCategoryCommand::new(name.into(), description.clone(), store_id, adding_by).unwrap(); + let cmd = AddCategoryCommandBuilder::default() + .name(name.into()) + .description(description.clone()) + .store_id(store_id) + .adding_by(adding_by) + .category_id(category_id) + .build() + .unwrap(); let expected = CategoryAddedEventBuilder::default() .name(cmd.name().into())