feat: delete order service #68
9 changed files with 240 additions and 30 deletions
|
@ -38,7 +38,6 @@ pub struct LineItemView {
|
||||||
deleted: bool,
|
deleted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Default for LineItemView {
|
impl Default for LineItemView {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -57,8 +56,6 @@ impl Default for LineItemView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl From<LineItemView> for LineItem {
|
impl From<LineItemView> for LineItem {
|
||||||
fn from(v: LineItemView) -> Self {
|
fn from(v: LineItemView) -> Self {
|
||||||
let quantity = QuantityBuilder::default()
|
let quantity = QuantityBuilder::default()
|
||||||
|
|
115
src/ordering/application/services/delete_order_service.rs
Normal file
115
src/ordering/application/services/delete_order_service.rs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
// 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 time::OffsetDateTime;
|
||||||
|
|
||||||
|
use super::errors::*;
|
||||||
|
use crate::ordering::{
|
||||||
|
application::port::output::db::order_id_exists::*,
|
||||||
|
domain::{delete_order_command::*, order_aggregate::*, order_deleted_event::*},
|
||||||
|
};
|
||||||
|
use crate::utils::uuid::*;
|
||||||
|
|
||||||
|
#[automock]
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait DeleteOrderUseCase: Send + Sync {
|
||||||
|
async fn delete_order(&self, cmd: DeleteOrderCommand) -> OrderingResult<OrderDeletedEvent>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DeleteOrderServiceObj = Arc<dyn DeleteOrderUseCase>;
|
||||||
|
|
||||||
|
#[derive(Clone, Builder)]
|
||||||
|
pub struct DeleteOrderService {
|
||||||
|
db_order_id_exists: OrderIDExistsDBPortObj,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl DeleteOrderUseCase for DeleteOrderService {
|
||||||
|
async fn delete_order(&self, cmd: DeleteOrderCommand) -> OrderingResult<OrderDeletedEvent> {
|
||||||
|
if !self
|
||||||
|
.db_order_id_exists
|
||||||
|
.order_id_exists(cmd.order().order_id())
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
return Err(OrderingError::OrderIDNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
let deleted_order = OrderBuilder::default()
|
||||||
|
.created_time(cmd.order().created_time().clone())
|
||||||
|
.customer_name(cmd.order().customer_name().into())
|
||||||
|
.order_id(*cmd.order().order_id())
|
||||||
|
.deleted(true)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(OrderDeletedEventBuilder::default()
|
||||||
|
.added_by_user(*cmd.adding_by())
|
||||||
|
.order(deleted_order)
|
||||||
|
.build()
|
||||||
|
.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use crate::ordering::domain::order_deleted_event::tests::get_deleted_order_event_from_command;
|
||||||
|
use crate::tests::bdd::*;
|
||||||
|
|
||||||
|
pub fn mock_delete_order_service(
|
||||||
|
times: Option<usize>,
|
||||||
|
cmd: DeleteOrderCommand,
|
||||||
|
) -> DeleteOrderServiceObj {
|
||||||
|
let mut m = MockDeleteOrderUseCase::new();
|
||||||
|
|
||||||
|
let res = get_deleted_order_event_from_command(&cmd);
|
||||||
|
if let Some(times) = times {
|
||||||
|
m.expect_delete_order()
|
||||||
|
.times(times)
|
||||||
|
.returning(move |_| Ok(res.clone()));
|
||||||
|
} else {
|
||||||
|
m.expect_delete_order().returning(move |_| Ok(res.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc::new(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_service() {
|
||||||
|
let cmd = DeleteOrderCommand::get_cmd();
|
||||||
|
|
||||||
|
let s = DeleteOrderServiceBuilder::default()
|
||||||
|
.db_order_id_exists(mock_order_id_exists_db_port_true(IS_CALLED_ONLY_ONCE))
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let res = s.delete_order(cmd.clone()).await.unwrap();
|
||||||
|
assert_eq!(res.order().customer_name(), cmd.order().customer_name());
|
||||||
|
assert_eq!(res.order().order_id(), cmd.order().order_id());
|
||||||
|
assert!(res.order().deleted());
|
||||||
|
|
||||||
|
assert_eq!(res.added_by_user(), cmd.adding_by());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_service_order_id_doesnt_exist() {
|
||||||
|
let cmd = DeleteOrderCommand::get_cmd();
|
||||||
|
|
||||||
|
let s = DeleteOrderServiceBuilder::default()
|
||||||
|
.db_order_id_exists(mock_order_id_exists_db_port_false(IS_CALLED_ONLY_ONCE))
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
s.delete_order(cmd.clone()).await,
|
||||||
|
Err(OrderingError::OrderIDNotFound)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ pub mod errors;
|
||||||
pub mod add_line_item_service;
|
pub mod add_line_item_service;
|
||||||
pub mod add_order_service;
|
pub mod add_order_service;
|
||||||
pub mod delete_line_item_service;
|
pub mod delete_line_item_service;
|
||||||
|
pub mod delete_order_service;
|
||||||
pub mod update_line_item_service;
|
pub mod update_line_item_service;
|
||||||
pub mod update_order_service;
|
pub mod update_order_service;
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ pub trait OrderingServicesInterface: Send + Sync {
|
||||||
fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj;
|
fn delete_line_item(&self) -> delete_line_item_service::DeleteLineItemServiceObj;
|
||||||
fn add_order(&self) -> add_order_service::AddOrderServiceObj;
|
fn add_order(&self) -> add_order_service::AddOrderServiceObj;
|
||||||
fn update_order(&self) -> update_order_service::UpdateOrderServiceObj;
|
fn update_order(&self) -> update_order_service::UpdateOrderServiceObj;
|
||||||
|
fn delete_order(&self) -> delete_order_service::DeleteOrderServiceObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Builder)]
|
#[derive(Clone, Builder)]
|
||||||
|
@ -31,6 +33,7 @@ pub struct OrderingServices {
|
||||||
delete_line_item: delete_line_item_service::DeleteLineItemServiceObj,
|
delete_line_item: delete_line_item_service::DeleteLineItemServiceObj,
|
||||||
add_order: add_order_service::AddOrderServiceObj,
|
add_order: add_order_service::AddOrderServiceObj,
|
||||||
update_order: update_order_service::UpdateOrderServiceObj,
|
update_order: update_order_service::UpdateOrderServiceObj,
|
||||||
|
delete_order: delete_order_service::DeleteOrderServiceObj,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrderingServicesInterface for OrderingServices {
|
impl OrderingServicesInterface for OrderingServices {
|
||||||
|
@ -52,4 +55,8 @@ impl OrderingServicesInterface for OrderingServices {
|
||||||
fn update_order(&self) -> update_order_service::UpdateOrderServiceObj {
|
fn update_order(&self) -> update_order_service::UpdateOrderServiceObj {
|
||||||
self.update_order.clone()
|
self.update_order.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn delete_order(&self) -> delete_order_service::DeleteOrderServiceObj {
|
||||||
|
self.delete_order.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
add_line_item_command::AddLineItemCommand, add_order_command::AddOrderCommand,
|
add_line_item_command::AddLineItemCommand, add_order_command::AddOrderCommand,
|
||||||
delete_line_item_command::DeleteLineItemCommand,
|
delete_line_item_command::DeleteLineItemCommand, delete_order_command::DeleteOrderCommand,
|
||||||
update_line_item_command::UpdateLineItemCommand, update_order_command::UpdateOrderCommand,
|
update_line_item_command::UpdateLineItemCommand, update_order_command::UpdateOrderCommand,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,4 +18,5 @@ pub enum OrderingCommand {
|
||||||
DeleteLineItem(DeleteLineItemCommand),
|
DeleteLineItem(DeleteLineItemCommand),
|
||||||
AddOrder(AddOrderCommand),
|
AddOrder(AddOrderCommand),
|
||||||
UpdateOrder(UpdateOrderCommand),
|
UpdateOrder(UpdateOrderCommand),
|
||||||
|
DeleteOrder(DeleteOrderCommand),
|
||||||
}
|
}
|
||||||
|
|
37
src/ordering/domain/delete_order_command.rs
Normal file
37
src/ordering/domain/delete_order_command.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use derive_builder::Builder;
|
||||||
|
use derive_getters::Getters;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::order_aggregate::Order;
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Builder, Getters,
|
||||||
|
)]
|
||||||
|
pub struct DeleteOrderCommand {
|
||||||
|
adding_by: Uuid,
|
||||||
|
order: Order,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::utils::uuid::tests::UUID;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl DeleteOrderCommand {
|
||||||
|
pub fn get_cmd() -> Self {
|
||||||
|
let adding_by = UUID;
|
||||||
|
|
||||||
|
DeleteOrderCommandBuilder::default()
|
||||||
|
.adding_by(adding_by)
|
||||||
|
.order(Order::get_order())
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use super::{
|
use super::{
|
||||||
line_item_added_event::LineItemAddedEvent, line_item_deleted_event::LineItemDeletedEvent,
|
line_item_added_event::LineItemAddedEvent, line_item_deleted_event::LineItemDeletedEvent,
|
||||||
line_item_updated_event::LineItemUpdatedEvent, order_added_event::OrderAddedEvent,
|
line_item_updated_event::LineItemUpdatedEvent, order_added_event::OrderAddedEvent,
|
||||||
order_updated_event::OrderUpdatedEvent,
|
order_deleted_event::OrderDeletedEvent, order_updated_event::OrderUpdatedEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
@ -18,6 +18,7 @@ pub enum OrderingEvent {
|
||||||
LineItemDeleted(LineItemDeletedEvent),
|
LineItemDeleted(LineItemDeletedEvent),
|
||||||
OrderAdded(OrderAddedEvent),
|
OrderAdded(OrderAddedEvent),
|
||||||
OrderUpdated(OrderUpdatedEvent),
|
OrderUpdated(OrderUpdatedEvent),
|
||||||
|
OrderDeleted(OrderDeletedEvent),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DomainEvent for OrderingEvent {
|
impl DomainEvent for OrderingEvent {
|
||||||
|
@ -32,6 +33,7 @@ impl DomainEvent for OrderingEvent {
|
||||||
OrderingEvent::LineItemDeleted { .. } => "OrderingLineItemDeleted",
|
OrderingEvent::LineItemDeleted { .. } => "OrderingLineItemDeleted",
|
||||||
OrderingEvent::OrderAdded { .. } => "OrderingOrderAdded",
|
OrderingEvent::OrderAdded { .. } => "OrderingOrderAdded",
|
||||||
OrderingEvent::OrderUpdated { .. } => "OrderingOrderUpdated",
|
OrderingEvent::OrderUpdated { .. } => "OrderingOrderUpdated",
|
||||||
|
OrderingEvent::OrderDeleted { .. } => "OrderingOrderDeleted",
|
||||||
};
|
};
|
||||||
|
|
||||||
e.to_string()
|
e.to_string()
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub mod add_line_item_command;
|
||||||
pub mod add_order_command;
|
pub mod add_order_command;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod delete_line_item_command;
|
pub mod delete_line_item_command;
|
||||||
|
pub mod delete_order_command;
|
||||||
pub mod update_line_item_command;
|
pub mod update_line_item_command;
|
||||||
pub mod update_order_command;
|
pub mod update_order_command;
|
||||||
|
|
||||||
|
@ -21,4 +22,5 @@ pub mod line_item_added_event;
|
||||||
pub mod line_item_deleted_event;
|
pub mod line_item_deleted_event;
|
||||||
pub mod line_item_updated_event;
|
pub mod line_item_updated_event;
|
||||||
pub mod order_added_event;
|
pub mod order_added_event;
|
||||||
|
pub mod order_deleted_event;
|
||||||
pub mod order_updated_event;
|
pub mod order_updated_event;
|
||||||
|
|
|
@ -87,6 +87,10 @@ impl Aggregate for Order {
|
||||||
let res = services.update_order().update_order(cmd).await?;
|
let res = services.update_order().update_order(cmd).await?;
|
||||||
Ok(vec![OrderingEvent::OrderUpdated(res)])
|
Ok(vec![OrderingEvent::OrderUpdated(res)])
|
||||||
}
|
}
|
||||||
|
OrderingCommand::DeleteOrder(cmd) => {
|
||||||
|
let res = services.delete_order().delete_order(cmd).await?;
|
||||||
|
Ok(vec![OrderingEvent::OrderDeleted(res)])
|
||||||
|
}
|
||||||
_ => Ok(Vec::default()),
|
_ => Ok(Vec::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +99,7 @@ impl Aggregate for Order {
|
||||||
match event {
|
match event {
|
||||||
OrderingEvent::OrderAdded(e) => *self = e.order().clone(),
|
OrderingEvent::OrderAdded(e) => *self = e.order().clone(),
|
||||||
OrderingEvent::OrderUpdated(e) => *self = e.new_order().clone(),
|
OrderingEvent::OrderUpdated(e) => *self = e.new_order().clone(),
|
||||||
// OrderingEvent::OrderDeleted(e) => *self = e.order().clone(),
|
OrderingEvent::OrderDeleted(e) => *self = e.order().clone(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,13 +111,13 @@ mod aggregate_tests {
|
||||||
|
|
||||||
use add_order_service::tests::mock_add_order_service;
|
use add_order_service::tests::mock_add_order_service;
|
||||||
use cqrs_es::test::TestFramework;
|
use cqrs_es::test::TestFramework;
|
||||||
// use delete_order_service::tests::mock_delete_order_service;
|
use delete_order_service::tests::mock_delete_order_service;
|
||||||
use update_order_service::tests::mock_update_order_service;
|
use update_order_service::tests::mock_update_order_service;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// use crate::ordering::domain::delete_order_command::DeleteOrderCommand;
|
use crate::ordering::domain::delete_order_command::DeleteOrderCommand;
|
||||||
// use crate::ordering::domain::order_deleted_event::tests::get_deleted_order_event_from_command;
|
use crate::ordering::domain::order_deleted_event::tests::get_deleted_order_event_from_command;
|
||||||
use crate::ordering::domain::order_updated_event::tests::get_updated_order_event_from_command;
|
use crate::ordering::domain::order_updated_event::tests::get_updated_order_event_from_command;
|
||||||
use crate::ordering::domain::update_order_command::UpdateOrderCommand;
|
use crate::ordering::domain::update_order_command::UpdateOrderCommand;
|
||||||
use crate::tests::bdd::*;
|
use crate::tests::bdd::*;
|
||||||
|
@ -159,25 +163,22 @@ mod aggregate_tests {
|
||||||
.when(OrderingCommand::UpdateOrder(cmd))
|
.when(OrderingCommand::UpdateOrder(cmd))
|
||||||
.then_expect_events(vec![expected]);
|
.then_expect_events(vec![expected]);
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn test_delete_order() {
|
fn test_delete_order() {
|
||||||
// let cmd = DeleteOrderCommand::get_cmd();
|
let cmd = DeleteOrderCommand::get_cmd();
|
||||||
// let expected = get_deleted_order_event_from_command(&cmd);
|
let expected = get_deleted_order_event_from_command(&cmd);
|
||||||
// let expected = OrderingEvent::OrderDeleted(expected);
|
let expected = OrderingEvent::OrderDeleted(expected);
|
||||||
//
|
|
||||||
// let mut services = MockOrderingServicesInterface::new();
|
let mut services = MockOrderingServicesInterface::new();
|
||||||
// services
|
services
|
||||||
// .expect_delete_order()
|
.expect_delete_order()
|
||||||
// .times(IS_CALLED_ONLY_ONCE.unwrap())
|
.times(IS_CALLED_ONLY_ONCE.unwrap())
|
||||||
// .return_const(mock_delete_order_service(
|
.return_const(mock_delete_order_service(IS_CALLED_ONLY_ONCE, cmd.clone()));
|
||||||
// IS_CALLED_ONLY_ONCE,
|
|
||||||
// cmd.clone(),
|
OrderTestFramework::with(Arc::new(services))
|
||||||
// ));
|
.given_no_previous_events()
|
||||||
//
|
.when(OrderingCommand::DeleteOrder(cmd))
|
||||||
// OrderTestFramework::with(Arc::new(services))
|
.then_expect_events(vec![expected]);
|
||||||
// .given_no_previous_events()
|
}
|
||||||
// .when(OrderingCommand::DeleteOrder(cmd))
|
|
||||||
// .then_expect_events(vec![expected]);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
48
src/ordering/domain/order_deleted_event.rs
Normal file
48
src/ordering/domain/order_deleted_event.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
use derive_builder::Builder;
|
||||||
|
use derive_getters::Getters;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::order_aggregate::*;
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone, Debug, Builder, Serialize, Deserialize, Getters, Eq, PartialEq, Ord, PartialOrd,
|
||||||
|
)]
|
||||||
|
pub struct OrderDeletedEvent {
|
||||||
|
added_by_user: Uuid,
|
||||||
|
|
||||||
|
order: Order,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use crate::ordering::domain::delete_order_command::DeleteOrderCommand;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub fn get_deleted_order_event_from_command(cmd: &DeleteOrderCommand) -> OrderDeletedEvent {
|
||||||
|
let deleted_order = OrderBuilder::default()
|
||||||
|
.created_time(cmd.order().created_time().clone())
|
||||||
|
.customer_name(cmd.order().customer_name().into())
|
||||||
|
.order_id(*cmd.order().order_id())
|
||||||
|
.deleted(true)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
OrderDeletedEventBuilder::default()
|
||||||
|
.added_by_user(cmd.adding_by().clone())
|
||||||
|
.order(deleted_order)
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_event() {
|
||||||
|
let event = get_deleted_order_event_from_command(&DeleteOrderCommand::get_cmd());
|
||||||
|
assert!(event.order().deleted());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue