124 lines
3.7 KiB
Rust
124 lines
3.7 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::inventory::{
|
|
application::port::output::db::{errors::InventoryDBError, store_id_exists::*},
|
|
domain::{
|
|
add_store_command::AddStoreCommand,
|
|
store_added_event::{StoreAddedEvent, StoreAddedEventBuilder},
|
|
store_aggregate::*,
|
|
},
|
|
};
|
|
use crate::utils::uuid::*;
|
|
|
|
#[automock]
|
|
#[async_trait::async_trait]
|
|
pub trait AddStoreUseCase: Send + Sync {
|
|
async fn add_store(&self, cmd: AddStoreCommand) -> InventoryResult<StoreAddedEvent>;
|
|
}
|
|
|
|
pub type AddStoreServiceObj = Arc<dyn AddStoreUseCase>;
|
|
|
|
#[derive(Clone, Builder)]
|
|
pub struct AddStoreService {
|
|
db_store_id_exists: StoreIDExistsDBPortObj,
|
|
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();
|
|
let mut store = StoreBuilder::default()
|
|
.name(cmd.name().into())
|
|
.address(cmd.address().as_ref().map(|s| s.to_string()))
|
|
.owner(cmd.owner().into())
|
|
.store_id(store_id.clone())
|
|
.build()
|
|
.unwrap();
|
|
loop {
|
|
if self.db_store_id_exists.store_id_exists(&store).await? {
|
|
store_id = self.get_uuid.get_uuid();
|
|
store = StoreBuilder::default()
|
|
.name(cmd.name().into())
|
|
.address(cmd.address().as_ref().map(|s| s.to_string()))
|
|
.store_id(store_id.clone())
|
|
.build()
|
|
.unwrap();
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ok(StoreAddedEventBuilder::default()
|
|
.name(store.name().into())
|
|
.address(store.address().as_ref().map(|s| s.to_string()))
|
|
.owner(cmd.owner().into())
|
|
.store_id(store_id.clone())
|
|
.build()
|
|
.unwrap())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub mod tests {
|
|
use super::*;
|
|
|
|
use crate::tests::bdd::*;
|
|
use crate::utils::uuid::tests::*;
|
|
|
|
pub fn mock_add_store_service(
|
|
times: Option<usize>,
|
|
cmd: AddStoreCommand,
|
|
) -> AddStoreServiceObj {
|
|
let mut m = MockAddStoreUseCase::new();
|
|
|
|
let res = StoreAddedEventBuilder::default()
|
|
.name(cmd.name().into())
|
|
.address(cmd.address().as_ref().map(|s| s.to_string()))
|
|
.owner(cmd.owner().into())
|
|
.store_id(UUID.clone())
|
|
.build()
|
|
.unwrap();
|
|
|
|
if let Some(times) = times {
|
|
m.expect_add_store()
|
|
.times(times)
|
|
.returning(move |_| Ok(res.clone()));
|
|
} else {
|
|
m.expect_add_store().returning(move |_| Ok(res.clone()));
|
|
}
|
|
|
|
Arc::new(m)
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn test_service_store_id_doesnt_exist() {
|
|
let name = "foo";
|
|
let address = "bar";
|
|
let username = "baz";
|
|
|
|
// address = None
|
|
let cmd = AddStoreCommand::new(name.into(), Some(address.into()), username.into()).unwrap();
|
|
|
|
let s = AddStoreServiceBuilder::default()
|
|
.db_store_id_exists(mock_store_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
|
|
.get_uuid(mock_get_uuid(IS_CALLED_ONLY_ONCE))
|
|
.build()
|
|
.unwrap();
|
|
|
|
let res = s.add_store(cmd.clone()).await.unwrap();
|
|
assert_eq!(res.name(), cmd.name());
|
|
assert_eq!(res.address(), cmd.address());
|
|
assert_eq!(res.owner(), cmd.owner());
|
|
assert_eq!(res.store_id(), &UUID);
|
|
}
|
|
}
|