From a47810e4e7c74e49adf3af7b936d966c9daa53fe Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Tue, 23 Jul 2024 19:19:18 +0530 Subject: [PATCH] feat: define order aggregate --- src/ordering/domain/order_aggregate.rs | 185 +++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/ordering/domain/order_aggregate.rs diff --git a/src/ordering/domain/order_aggregate.rs b/src/ordering/domain/order_aggregate.rs new file mode 100644 index 0000000..2768f7c --- /dev/null +++ b/src/ordering/domain/order_aggregate.rs @@ -0,0 +1,185 @@ +// SPDX-FileCopyrightText: 2024 Aravinth Manivannan +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +use async_trait::async_trait; +use cqrs_es::Aggregate; +use derive_builder::Builder; +use derive_getters::Getters; +use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; +use uuid::Uuid; + +use crate::ordering::{ + application::services::{errors::*, *}, + domain::{commands::*, events::*}, +}; + + +#[derive( + Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Builder, Getters, +)] +pub struct Order { + #[builder(default = "OffsetDateTime::now_utc()")] + created_time: OffsetDateTime, + // kot_ids: Vec, + order_id: Uuid, + #[builder(default = "false")] + deleted: bool, + customer_name: String, +} + +impl Default for Order { + fn default() -> Self { + Self { + created_time: OffsetDateTime::now_utc(), + order_id: Default::default(), + deleted: false, + customer_name: Default::default(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ordering::domain::add_order_command::AddOrderCommand, utils::uuid::tests::UUID}; + + use super::*; + + impl Order { + pub fn get_order() -> Self { + let cmd = AddOrderCommand::get_cmd(); + + OrderBuilder::default() + .created_time(cmd.created_time().clone()) + .customer_name("test_product".into()) + .order_id(UUID) + .build() + .unwrap() + } + } +} + + +#[async_trait] +impl Aggregate for Order { + type Command = OrderingCommand; + type Event = OrderingEvent; + type Error = OrderingError; + type Services = std::sync::Arc; + + // This identifier should be unique to the system. + fn aggregate_type() -> String { + "ordering.order".to_string() + } + + // The aggregate logic goes here. Note that this will be the _bulk_ of a CQRS system + // so expect to use helper functions elsewhere to keep the code clean. + async fn handle( + &self, + command: Self::Command, + services: &Self::Services, + ) -> Result, Self::Error> { + match command { + OrderingCommand::AddOrder(cmd) => { + let res = services.add_order().add_order(cmd).await?; + Ok(vec![OrderingEvent::OrderAdded(res)]) + } + _ => Ok(Vec::default()), + } + } + + fn apply(&mut self, event: Self::Event) { + match event { + OrderingEvent::OrderAdded(e) => *self = e.order().clone(), + // OrderingEvent::OrderUpdated(e) => *self = e.new_order().clone(), + // OrderingEvent::OrderDeleted(e) => *self = e.order().clone(), + _ => (), + } + } +} + +#[cfg(test)] +mod aggregate_tests { + use std::sync::Arc; + + use add_order_service::tests::mock_add_order_service; + use cqrs_es::test::TestFramework; + // use delete_order_service::tests::mock_delete_order_service; + // use update_order_service::tests::mock_update_order_service; + + use super::*; + +// 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_updated_event::tests::get_updated_order_event_from_command; +// use crate::ordering::domain::update_order_command::UpdateOrderCommand; + use crate::tests::bdd::*; + + use crate::ordering::domain::{ + add_order_command::*, + order_added_event::tests::get_added_order_event_from_command, + }; + + type OrderTestFramework = TestFramework; + + #[test] + fn test_add_order() { + let cmd = AddOrderCommand::get_cmd(); + let expected = get_added_order_event_from_command(&cmd); + let expected = OrderingEvent::OrderAdded(expected); + + let mut services = MockOrderingServicesInterface::new(); + services + .expect_add_order() + .times(IS_CALLED_ONLY_ONCE.unwrap()) + .return_const(mock_add_order_service(IS_CALLED_ONLY_ONCE, cmd.clone())); + + OrderTestFramework::with(Arc::new(services)) + .given_no_previous_events() + .when(OrderingCommand::AddOrder(cmd)) + .then_expect_events(vec![expected]); + } +// +// #[test] +// fn test_update_order() { +// let cmd = UpdateOrderCommand::get_cmd(); +// let expected = get_updated_order_event_from_command(&cmd); +// let expected = OrderingEvent::OrderUpdated(expected); +// +// let mut services = MockOrderingServicesInterface::new(); +// services +// .expect_update_order() +// .times(IS_CALLED_ONLY_ONCE.unwrap()) +// .return_const(mock_update_order_service( +// IS_CALLED_ONLY_ONCE, +// cmd.clone(), +// )); +// +// OrderTestFramework::with(Arc::new(services)) +// .given_no_previous_events() +// .when(OrderingCommand::UpdateOrder(cmd)) +// .then_expect_events(vec![expected]); +// } +// +// #[test] +// fn test_delete_order() { +// let cmd = DeleteOrderCommand::get_cmd(); +// let expected = get_deleted_order_event_from_command(&cmd); +// let expected = OrderingEvent::OrderDeleted(expected); +// +// let mut services = MockOrderingServicesInterface::new(); +// services +// .expect_delete_order() +// .times(IS_CALLED_ONLY_ONCE.unwrap()) +// .return_const(mock_delete_order_service( +// IS_CALLED_ONLY_ONCE, +// cmd.clone(), +// )); +// +// OrderTestFramework::with(Arc::new(services)) +// .given_no_previous_events() +// .when(OrderingCommand::DeleteOrder(cmd)) +// .then_expect_events(vec![expected]); +// } +}