From 3a19d7099d444c6a8bf21d9e9b6ae322d177c89b Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Tue, 23 Jul 2024 19:20:31 +0530 Subject: [PATCH] feat: service to add order aggregate --- .../application/services/add_order_service.rs | 108 ++++++++++++++++++ src/ordering/application/services/errors.rs | 6 + src/ordering/application/services/mod.rs | 7 ++ 3 files changed, 121 insertions(+) create mode 100644 src/ordering/application/services/add_order_service.rs diff --git a/src/ordering/application/services/add_order_service.rs b/src/ordering/application/services/add_order_service.rs new file mode 100644 index 0000000..d66b45e --- /dev/null +++ b/src/ordering/application/services/add_order_service.rs @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: 2024 Aravinth Manivannan +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use std::sync::Arc; + +use derive_builder::Builder; +use mockall::predicate::*; +use mockall::*; +use time::OffsetDateTime; + +use super::errors::*; +use crate::ordering::{ + application::port::output::db::order_id_exists::*, + domain::{add_order_command::*, order_added_event::*, order_aggregate::*}, +}; +use crate::utils::uuid::*; + +#[automock] +#[async_trait::async_trait] +pub trait AddOrderUseCase: Send + Sync { + async fn add_order(&self, cmd: AddOrderCommand) -> OrderingResult; +} + +pub type AddOrderServiceObj = Arc; + +#[derive(Clone, Builder)] +pub struct AddOrderService { + db_order_id_exists: OrderIDExistsDBPortObj, + get_uuid: GetUUIDInterfaceObj, +} + +#[async_trait::async_trait] +impl AddOrderUseCase for AddOrderService { + async fn add_order(&self, cmd: AddOrderCommand) -> OrderingResult { + let mut order_id = self.get_uuid.get_uuid(); + + loop { + if self + .db_order_id_exists + .order_id_exists(&order_id) + .await? + { + order_id = self.get_uuid.get_uuid(); + continue; + } else { + break; + } + } + + let order = OrderBuilder::default() + .created_time(OffsetDateTime::now_utc()) + .customer_name(cmd.customer_name().into()) + .order_id(order_id) + .deleted(false) + .build() + .unwrap(); + + Ok(OrderAddedEventBuilder::default() + .added_by_user(*cmd.adding_by()) + .order(order) + .build() + .unwrap()) + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + + use crate::ordering::domain::order_added_event::tests::get_added_order_event_from_command; + use crate::utils::uuid::tests::UUID; + use crate::{tests::bdd::*, utils::uuid::tests::mock_get_uuid}; + + pub fn mock_add_order_service( + times: Option, + cmd: AddOrderCommand, + ) -> AddOrderServiceObj { + let mut m = MockAddOrderUseCase::new(); + + let res = get_added_order_event_from_command(&cmd); + if let Some(times) = times { + m.expect_add_order() + .times(times) + .returning(move |_| Ok(res.clone())); + } else { + m.expect_add_order().returning(move |_| Ok(res.clone())); + } + + Arc::new(m) + } + + #[actix_rt::test] + async fn test_service() { + let cmd = AddOrderCommand::get_cmd(); + + let s = AddOrderServiceBuilder::default() + .db_order_id_exists(mock_order_id_exists_db_port_false(IS_CALLED_ONLY_ONCE)) + .get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE)) + .build() + .unwrap(); + + let res = s.add_order(cmd.clone()).await.unwrap(); + assert_eq!(res.order().customer_name(), cmd.customer_name()); + assert!(!res.order().deleted()); + assert_eq!(res.added_by_user(), cmd.adding_by()); + } +} diff --git a/src/ordering/application/services/errors.rs b/src/ordering/application/services/errors.rs index 175d921..de37b9e 100644 --- a/src/ordering/application/services/errors.rs +++ b/src/ordering/application/services/errors.rs @@ -14,6 +14,7 @@ pub type OrderingResult = Result; pub enum OrderingError { LineItemIDNotFound, InternalError, + OrderIDNotFound, } // impl From for OrderingError { @@ -24,6 +25,11 @@ impl From for OrderingError { Self::InternalError } OrderingDBError::LineItemIDNotFound => OrderingError::LineItemIDNotFound, + OrderingDBError::DuplicateOrderID => { + error!("DuplicateOrderID"); + Self::InternalError + } + OrderingDBError::OrderIDNotFound => OrderingError::OrderIDNotFound, OrderingDBError::InternalError => Self::InternalError, } } diff --git a/src/ordering/application/services/mod.rs b/src/ordering/application/services/mod.rs index 705fc2f..170139c 100644 --- a/src/ordering/application/services/mod.rs +++ b/src/ordering/application/services/mod.rs @@ -12,12 +12,14 @@ pub mod errors; pub mod add_line_item_service; pub mod delete_line_item_service; pub mod update_line_item_service; +pub mod add_order_service; #[automock] pub trait OrderingServicesInterface: Send + Sync { fn add_line_item(&self) -> add_line_item_service::AddLineItemServiceObj; fn update_line_item(&self) -> update_line_item_service::UpdateLineItemServiceObj; fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj; + fn add_order(&self) -> add_order_service::AddOrderServiceObj; } #[derive(Clone, Builder)] @@ -25,6 +27,7 @@ pub struct OrderingServices { add_line_item: add_line_item_service::AddLineItemServiceObj, update_line_item: update_line_item_service::UpdateLineItemServiceObj, delete_line_item: delete_line_item_service::DeleteLineItemServiceObj, + add_order: add_order_service::AddOrderServiceObj, } impl OrderingServicesInterface for OrderingServices { @@ -38,4 +41,8 @@ impl OrderingServicesInterface for OrderingServices { fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj { self.delete_line_item.clone() } + + fn add_order(&self) -> add_order_service::AddOrderServiceObj { + self.add_order.clone() + } }