vanikam/src/ordering/application/services/update_customization_service.rs
Aravinth Manivannan cddba71eb5
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
feat: import inventory services&domain obj to implement pantry
2024-09-16 14:55:48 +05:30

210 lines
7.1 KiB
Rust

// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::sync::Arc;
use derive_builder::Builder;
use mockall::predicate::*;
use mockall::*;
use super::errors::*;
use crate::ordering::{
application::port::output::db::{
customization_id_exists::*, customization_name_exists_for_product::*, product_id_exists::*,
},
domain::{
customization_aggregate::*, customization_updated_event::*, update_customization_command::*,
},
};
use crate::utils::uuid::*;
#[automock]
#[async_trait::async_trait]
pub trait UpdateCustomizationUseCase: Send + Sync {
async fn update_customization(
&self,
cmd: UpdateCustomizationCommand,
) -> OrderingResult<CustomizationUpdatedEvent>;
}
pub type UpdateCustomizationServiceObj = Arc<dyn UpdateCustomizationUseCase>;
#[derive(Clone, Builder)]
pub struct UpdateCustomizationService {
// TODO: check if product ID exists
db_customization_name_exists_for_product: CustomizationNameExistsForProductDBPortObj,
db_customization_id_exists: CustomizationIDExistsDBPortObj,
db_product_id_exists: ProductIDExistsDBPortObj,
}
#[async_trait::async_trait]
impl UpdateCustomizationUseCase for UpdateCustomizationService {
async fn update_customization(
&self,
cmd: UpdateCustomizationCommand,
) -> OrderingResult<CustomizationUpdatedEvent> {
if !self
.db_customization_id_exists
.customization_id_exists(cmd.old_customization().customization_id())
.await?
{
return Err(OrderingError::CustomizationIDNotFound);
}
if !self
.db_product_id_exists
.product_id_exists(cmd.old_customization().product_id())
.await?
{
return Err(OrderingError::ProductIDNotFound);
}
let updated_customization = CustomizationBuilder::default()
.name(cmd.name().into())
.product_id(*cmd.old_customization().product_id())
.customization_id(*cmd.old_customization().customization_id())
.deleted(*cmd.old_customization().deleted())
.build()
.unwrap();
if updated_customization.name() != cmd.old_customization().name() {
if self
.db_customization_name_exists_for_product
.customization_name_exists_for_product(&updated_customization)
.await?
{
return Err(OrderingError::DuplicateCustomizationName);
}
}
Ok(CustomizationUpdatedEventBuilder::default()
.added_by_user(*cmd.adding_by())
.old_customization(cmd.old_customization().clone())
.new_customization(updated_customization)
.build()
.unwrap())
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::ordering::domain::customization_updated_event;
use crate::ordering::domain::update_customization_command::tests::get_update_customization_command;
use crate::tests::bdd::*;
pub fn mock_update_customization_service(
times: Option<usize>,
cmd: UpdateCustomizationCommand,
) -> UpdateCustomizationServiceObj {
let mut m = MockUpdateCustomizationUseCase::new();
let res =
customization_updated_event::tests::get_customization_updated_event_from_command(&cmd);
if let Some(times) = times {
m.expect_update_customization()
.times(times)
.returning(move |_| Ok(res.clone()));
} else {
m.expect_update_customization()
.returning(move |_| Ok(res.clone()));
}
Arc::new(m)
}
#[actix_rt::test]
async fn test_service() {
let cmd = get_update_customization_command();
let s = UpdateCustomizationServiceBuilder::default()
.db_product_id_exists(mock_product_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
.db_customization_name_exists_for_product(
mock_customization_name_exists_for_product_db_port_false(IS_CALLED_ONLY_ONCE),
)
.db_customization_id_exists(mock_customization_id_exists_db_port_true(
IS_CALLED_ONLY_ONCE,
))
.build()
.unwrap();
let res = s.update_customization(cmd.clone()).await.unwrap();
assert_eq!(res.new_customization().name(), cmd.name());
assert_eq!(
res.new_customization().product_id(),
cmd.old_customization().product_id()
);
assert_eq!(
res.new_customization().customization_id(),
cmd.old_customization().customization_id()
);
assert_eq!(res.old_customization(), cmd.old_customization());
assert_eq!(res.added_by_user(), cmd.adding_by());
}
#[actix_rt::test]
async fn test_service_product_doesnt_exist() {
let cmd = get_update_customization_command();
let s = UpdateCustomizationServiceBuilder::default()
.db_product_id_exists(mock_product_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
.db_customization_name_exists_for_product(
mock_customization_name_exists_for_product_db_port_false(IS_NEVER_CALLED),
)
.db_customization_id_exists(mock_customization_id_exists_db_port_true(
IS_CALLED_ONLY_ONCE,
))
.build()
.unwrap();
assert_eq!(
s.update_customization(cmd.clone()).await,
Err(OrderingError::ProductIDNotFound)
);
}
#[actix_rt::test]
async fn test_customization_id_not_found() {
let cmd = get_update_customization_command();
let s = UpdateCustomizationServiceBuilder::default()
.db_product_id_exists(mock_product_id_exists_db_port_true(IS_NEVER_CALLED))
.db_customization_name_exists_for_product(
mock_customization_name_exists_for_product_db_port_false(IS_NEVER_CALLED),
)
.db_customization_id_exists(mock_customization_id_exists_db_port_false(
IS_CALLED_ONLY_ONCE,
))
.build()
.unwrap();
assert_eq!(
s.update_customization(cmd.clone()).await,
Err(OrderingError::CustomizationIDNotFound)
);
}
#[actix_rt::test]
async fn test_duplicate_new_name() {
let cmd = get_update_customization_command();
let s = UpdateCustomizationServiceBuilder::default()
.db_product_id_exists(mock_product_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
.db_customization_name_exists_for_product(
mock_customization_name_exists_for_product_db_port_true(IS_CALLED_ONLY_ONCE),
)
.db_customization_id_exists(mock_customization_id_exists_db_port_true(
IS_CALLED_ONLY_ONCE,
))
.build()
.unwrap();
assert_eq!(
s.update_customization(cmd.clone()).await,
Err(OrderingError::DuplicateCustomizationName)
);
}
}