fix: inventory: aggregate IDs are provided by the caller #112
4 changed files with 89 additions and 49 deletions
|
@ -12,12 +12,11 @@ use super::errors::*;
|
|||
use crate::inventory::{
|
||||
application::port::output::db::{store_id_exists::*, store_name_exists::*},
|
||||
domain::{
|
||||
add_store_command::AddStoreCommand,
|
||||
add_store_command::*,
|
||||
store_added_event::{StoreAddedEvent, StoreAddedEventBuilder},
|
||||
store_aggregate::*,
|
||||
},
|
||||
};
|
||||
use crate::utils::uuid::*;
|
||||
|
||||
#[automock]
|
||||
#[async_trait::async_trait]
|
||||
|
@ -31,28 +30,24 @@ pub type AddStoreServiceObj = Arc<dyn AddStoreUseCase>;
|
|||
pub struct AddStoreService {
|
||||
db_store_id_exists: StoreIDExistsDBPortObj,
|
||||
db_store_name_exists: StoreNameExistsDBPortObj,
|
||||
get_uuid: GetUUIDInterfaceObj,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl AddStoreUseCase for AddStoreService {
|
||||
async fn add_store(&self, cmd: AddStoreCommand) -> InventoryResult<StoreAddedEvent> {
|
||||
let mut store_id = self.get_uuid.get_uuid();
|
||||
|
||||
loop {
|
||||
if self.db_store_id_exists.store_id_exists(&store_id).await? {
|
||||
store_id = self.get_uuid.get_uuid();
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if self
|
||||
.db_store_id_exists
|
||||
.store_id_exists(cmd.store_id())
|
||||
.await?
|
||||
{
|
||||
return Err(InventoryError::DuplicateStoreID);
|
||||
}
|
||||
|
||||
let store = StoreBuilder::default()
|
||||
.name(cmd.name().into())
|
||||
.address(cmd.address().as_ref().map(|s| s.to_string()))
|
||||
.owner(*cmd.owner())
|
||||
.store_id(store_id)
|
||||
.store_id(*cmd.store_id())
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
@ -64,7 +59,7 @@ impl AddStoreUseCase for AddStoreService {
|
|||
.name(store.name().into())
|
||||
.address(store.address().as_ref().map(|s| s.to_string()))
|
||||
.owner(*cmd.owner())
|
||||
.store_id(store_id)
|
||||
.store_id(*cmd.store_id())
|
||||
.build()
|
||||
.unwrap())
|
||||
}
|
||||
|
@ -109,12 +104,17 @@ pub mod tests {
|
|||
let owner = UUID;
|
||||
|
||||
// address = None
|
||||
let cmd = AddStoreCommand::new(name.into(), Some(address.into()), owner).unwrap();
|
||||
let cmd = AddStoreCommandBuilder::default()
|
||||
.name(name.into())
|
||||
.address(None)
|
||||
.owner(owner)
|
||||
.store_id(UUID)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let s = AddStoreServiceBuilder::default()
|
||||
.db_store_id_exists(mock_store_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
|
||||
.db_store_name_exists(mock_store_name_exists_db_port_false(IS_CALLED_ONLY_ONCE))
|
||||
.get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
@ -132,12 +132,17 @@ pub mod tests {
|
|||
let owner = UUID;
|
||||
|
||||
// address = None
|
||||
let cmd = AddStoreCommand::new(name.into(), Some(address.into()), owner).unwrap();
|
||||
let cmd = AddStoreCommandBuilder::default()
|
||||
.name(name.into())
|
||||
.address(Some(address.into()))
|
||||
.owner(owner)
|
||||
.store_id(UUID)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let s = AddStoreServiceBuilder::default()
|
||||
.db_store_id_exists(mock_store_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
|
||||
.db_store_name_exists(mock_store_name_exists_db_port_true(IS_CALLED_ONLY_ONCE))
|
||||
.get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ pub enum InventoryError {
|
|||
DuplicateStoreName,
|
||||
DuplicateProductName,
|
||||
DuplicateCustomizationName,
|
||||
DuplicateStoreID,
|
||||
ProductIDNotFound,
|
||||
CategoryIDNotFound,
|
||||
CustomizationIDNotFound,
|
||||
|
@ -32,10 +33,7 @@ impl From<InventoryDBError> for InventoryError {
|
|||
InventoryDBError::DuplicateStoreName => Self::DuplicateStoreName,
|
||||
InventoryDBError::DuplicateProductName => Self::DuplicateProductName,
|
||||
InventoryDBError::DuplicateCustomizationName => Self::DuplicateCustomizationName,
|
||||
InventoryDBError::DuplicateStoreID => {
|
||||
error!("DuplicateStoreID");
|
||||
Self::InternalError
|
||||
}
|
||||
InventoryDBError::DuplicateStoreID => Self::DuplicateStoreID,
|
||||
InventoryDBError::DuplicateProductID => {
|
||||
error!("DuplicateProductID");
|
||||
Self::InternalError
|
||||
|
|
|
@ -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,46 +13,56 @@ pub enum AddStoreCommandError {
|
|||
NameIsEmpty,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters)]
|
||||
#[derive(
|
||||
Clone, Builder, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Getters,
|
||||
)]
|
||||
#[builder(build_fn(validate = "Self::validate"))]
|
||||
pub struct AddStoreCommand {
|
||||
#[builder(setter(custom))]
|
||||
name: String,
|
||||
#[builder(setter(custom))]
|
||||
address: Option<String>,
|
||||
store_id: Uuid,
|
||||
owner: Uuid,
|
||||
}
|
||||
|
||||
impl AddStoreCommand {
|
||||
pub fn new(
|
||||
name: String,
|
||||
address: Option<String>,
|
||||
owner: Uuid,
|
||||
) -> Result<Self, AddStoreCommandError> {
|
||||
let address: Option<String> = if let Some(address) = address {
|
||||
impl AddStoreCommandBuilder {
|
||||
// pub fn custom_address(&mut self, address: Option<String>) -> &mut Self {
|
||||
// fn address(&mut self, address: Option<String>) {
|
||||
pub fn address(&mut self, address: Option<String>) -> &mut Self {
|
||||
self.address = if let Some(address) = address {
|
||||
let address = address.trim();
|
||||
if address.is_empty() {
|
||||
None
|
||||
Some(None)
|
||||
} else {
|
||||
Some(address.to_owned())
|
||||
Some(Some(address.to_owned()))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
Some(None)
|
||||
};
|
||||
|
||||
let name = name.trim().to_owned();
|
||||
if name.is_empty() {
|
||||
return Err(AddStoreCommandError::NameIsEmpty);
|
||||
self
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
address,
|
||||
owner,
|
||||
})
|
||||
//pub fn custom_name(&mut self, name: String) -> &mut Self {
|
||||
//fn name(&mut self, name: String) {
|
||||
pub fn name(&mut self, name: String) -> &mut Self {
|
||||
self.name = Some(name.trim().to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
fn validate(&self) -> Result<(), String> {
|
||||
let name = self.name.as_ref().unwrap().trim().to_owned();
|
||||
if name.is_empty() {
|
||||
return Err(AddStoreCommandError::NameIsEmpty.to_string());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::utils::uuid::tests::UUID;
|
||||
use crate::tests::bdd::*;
|
||||
use crate::utils::uuid::tests::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -62,21 +73,41 @@ mod tests {
|
|||
let owner = UUID;
|
||||
|
||||
// address = None
|
||||
let cmd = AddStoreCommand::new(name.into(), None, owner).unwrap();
|
||||
let cmd = AddStoreCommandBuilder::default()
|
||||
.name(name.into())
|
||||
.address(None)
|
||||
.owner(owner)
|
||||
.store_id(UUID)
|
||||
.build()
|
||||
.unwrap();
|
||||
// let cmd = AddStoreCommand::new(name.into(), None, owner, UUID).unwrap();
|
||||
assert_eq!(cmd.name(), name);
|
||||
assert_eq!(cmd.address(), &None);
|
||||
assert_eq!(cmd.owner(), &owner);
|
||||
assert_eq!(*cmd.store_id(), UUID);
|
||||
|
||||
// address = Some
|
||||
let cmd = AddStoreCommand::new(name.into(), Some(address.into()), owner).unwrap();
|
||||
let cmd = AddStoreCommandBuilder::default()
|
||||
.name(name.into())
|
||||
.address(Some(address.into()))
|
||||
.owner(owner)
|
||||
.store_id(UUID)
|
||||
.build()
|
||||
.unwrap();
|
||||
// let cmd = AddStoreCommand::new(name.into(), Some(address.into()), owner, UUID).unwrap();
|
||||
assert_eq!(cmd.name(), name);
|
||||
assert_eq!(cmd.address(), &Some(address.to_owned()));
|
||||
assert_eq!(cmd.owner(), &owner);
|
||||
assert_eq!(*cmd.store_id(), UUID);
|
||||
|
||||
// AddStoreCommandError::NameIsEmpty
|
||||
assert_eq!(
|
||||
AddStoreCommand::new("".into(), Some(address.into()), owner),
|
||||
Err(AddStoreCommandError::NameIsEmpty)
|
||||
)
|
||||
|
||||
assert!(AddStoreCommandBuilder::default()
|
||||
.name("".into())
|
||||
.address(Some(address.into()))
|
||||
.owner(owner)
|
||||
.store_id(UUID)
|
||||
.build()
|
||||
.is_err())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,13 @@ mod tests {
|
|||
.unwrap();
|
||||
let expected = InventoryEvent::StoreAdded(expected);
|
||||
|
||||
let cmd = AddStoreCommand::new(name.into(), address.clone(), owner).unwrap();
|
||||
let cmd = AddStoreCommandBuilder::default()
|
||||
.name(name.into())
|
||||
.address(address.clone())
|
||||
.owner(owner)
|
||||
.store_id(UUID)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut services = MockInventoryServicesInterface::new();
|
||||
services
|
||||
|
|
Loading…
Reference in a new issue