Skip to content

Commit

Permalink
combine depricated on saga and view, in faviour of merge
Browse files Browse the repository at this point in the history
  • Loading branch information
idugalic committed Jan 28, 2025
1 parent 04efe12 commit b97e50f
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 144 deletions.
6 changes: 6 additions & 0 deletions src/saga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ impl<'a, AR, A> Saga<'a, AR, A> {

/// Combines two sagas into one.
/// Creates a new instance of a Saga by combining two sagas of type `AR`, `A` and `AR2`, `A2` into a new saga of type `Sum<AR, AR2>`, `Sum<A2, A>`
#[deprecated(
since = "0.8.0",
note = "Use the `merge` function instead. This ensures all your sagas can subscribe to all `Event`/`E` in the system."
)]
pub fn combine<AR2, A2>(self, saga2: Saga<'a, AR2, A2>) -> Saga<'a, Sum<AR, AR2>, Sum<A2, A>> {
let new_react = Box::new(move |ar: &Sum<AR, AR2>| match ar {
Sum::First(ar) => {
Expand All @@ -134,6 +138,8 @@ impl<'a, AR, A> Saga<'a, AR, A> {

/// Merges two sagas into one.
/// Creates a new instance of a Saga by merging two sagas of type `AR`, `A` and `AR`, `A2` into a new saga of type `AR`, `Sum<A, A2>`
/// Similar to `combine`, but the event type is the same for both sagas.
/// This ensures all your sagas can subscribe to all `Event`/`E` in the system.
pub fn merge<A2>(self, saga2: Saga<'a, AR, A2>) -> Saga<'a, AR, Sum<A2, A>> {
let new_react = Box::new(move |ar: &AR| {
let a: Vec<Sum<A2, A>> = (self.react)(ar)
Expand Down
6 changes: 5 additions & 1 deletion src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ impl<'a, S, E> View<'a, S, E> {
/// Combines two views into one.
/// Creates a new instance of a View by combining two views of type `S`, `E` and `S2`, `E2` into a new view of type `(S, S2)`, `Sum<E, E2>`
/// Combines two views that operate on different event types (`E`` and `E2``) into a new view operating on `Sum<E, E2>`
#[deprecated(
since = "0.8.0",
note = "Use the `merge` function instead. This ensures all your views can subscribe to all `Event`/`E` in the system."
)]
pub fn combine<S2, E2>(self, view2: View<'a, S2, E2>) -> View<'a, (S, S2), Sum<E, E2>>
where
S: Clone,
Expand Down Expand Up @@ -161,7 +165,7 @@ impl<'a, S, E> View<'a, S, E> {
/// Merges two views into one.
/// Creates a new instance of a View by merging two views of type `S`, `E` and `S2`, `E` into a new view of type `(S, S2)`, `E`
/// Similar to `combine`, but the event type is the same for both views.
/// Composes two views that operate on the same/shared event type (`E`) into a new view operating on `E`
/// This ensures all your views can subscribe to all `Event`/`E` in the system.
pub fn merge<S2>(self, view2: View<'a, S2, E>) -> View<'a, (S, S2), E>
where
S: Clone,
Expand Down
37 changes: 24 additions & 13 deletions tests/aggregate_combined_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,36 +211,49 @@ fn shipment_decider<'a>() -> Decider<'a, ShipmentCommand, ShipmentState, Shipmen
}
}

fn order_saga<'a>() -> Saga<'a, OrderEvent, ShipmentCommand> {
fn order_saga<'a>() -> Saga<'a, Event, ShipmentCommand> {
Saga {
react: Box::new(|event| match event {
OrderEvent::Created(evt) => {
Event::OrderCreated(evt) => {
vec![ShipmentCommand::Create(CreateShipmentCommand {
shipment_id: evt.order_id,
order_id: evt.order_id,
customer_name: evt.customer_name.to_owned(),
items: evt.items.to_owned(),
})]
}
OrderEvent::Updated(_) => {
Event::OrderUpdated(_) => {
vec![]
}
OrderEvent::Cancelled(_) => {
Event::OrderCancelled(_) => {
vec![]
}
Event::ShipmentCreated(_) => {
vec![]
}
}),
}
}

fn shipment_saga<'a>() -> Saga<'a, ShipmentEvent, OrderCommand> {
fn shipment_saga<'a>() -> Saga<'a, Event, OrderCommand> {
Saga {
react: Box::new(|event| match event {
ShipmentEvent::Created(evt) => {
vec![OrderCommand::Update(api::UpdateOrderCommand {
Event::ShipmentCreated(evt) => {
vec![OrderCommand::Update(UpdateOrderCommand {
order_id: evt.order_id,
new_items: evt.items.to_owned(),
})]
}

Event::OrderCreated(_) => {
vec![]
}
Event::OrderUpdated(_) => {
vec![]
}
Event::OrderCancelled(_) => {
vec![]
}
}),
}
}
Expand Down Expand Up @@ -367,9 +380,8 @@ async fn orchestrated_event_sourced_aggregate_test() {
.map_command(&command_from_sum) // Decider<Command, (OrderState, ShipmentState), Sum<OrderEvent, ShipmentEvent>>
.map_event(&event_from_sum, &sum_to_event); // Decider<Command, (OrderState, ShipmentState), Event>
let combined_saga = order_saga()
.combine(shipment_saga())
.map_action(&sum_to_command)
.map_action_result(&event_from_sum);
.merge(shipment_saga())
.map_action(&sum_to_command);
let repository = InMemoryEventRepository::new();
let aggregate = Arc::new(EventSourcedOrchestratingAggregate::new(
repository,
Expand Down Expand Up @@ -700,9 +712,8 @@ async fn state_stored_combined_test() {
.map_event(&event_from_sum, &sum_to_event); // Decider<Command, (OrderState, ShipmentState), Event>

let combined_saga = order_saga()
.combine(shipment_saga())
.map_action(&sum_to_command)
.map_action_result(&event_from_sum);
.merge(shipment_saga())
.map_action(&sum_to_command);

let repository = InMemoryStateRepository::new();
let aggregate = Arc::new(StateStoredOrchestratingAggregate::new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,30 @@ use fmodel_rust::view::View;
use fmodel_rust::Identifier;

use crate::api::{
OrderCancelledEvent, OrderCreatedEvent, OrderEvent, OrderUpdatedEvent, OrderViewState,
ShipmentEvent, ShipmentViewState,
OrderCancelledEvent, OrderCreatedEvent, OrderUpdatedEvent, OrderViewState, ShipmentViewState,
};
use crate::application::{event_from_sum, Event, MaterializedViewError};
use crate::application::{Event, MaterializedViewError};

mod api;
mod application;

fn order_view<'a>() -> View<'a, OrderViewState, OrderEvent> {
fn order_view<'a>() -> View<'a, OrderViewState, Event> {
View {
evolve: Box::new(|state, event| {
let mut new_state = state.clone();
match event {
OrderEvent::Created(evt) => {
Event::OrderCreated(evt) => {
new_state.order_id = evt.order_id;
new_state.customer_name = evt.customer_name.to_owned();
new_state.items = evt.items.to_owned();
}
OrderEvent::Updated(evt) => {
Event::OrderUpdated(evt) => {
new_state.items = evt.updated_items.to_owned();
}
OrderEvent::Cancelled(_) => {
Event::OrderCancelled(_) => {
new_state.is_cancelled = true;
}
Event::ShipmentCreated(_) => {}
}
new_state
}),
Expand All @@ -43,17 +43,20 @@ fn order_view<'a>() -> View<'a, OrderViewState, OrderEvent> {
}
}

fn shipment_view<'a>() -> View<'a, ShipmentViewState, ShipmentEvent> {
fn shipment_view<'a>() -> View<'a, ShipmentViewState, Event> {
View {
evolve: Box::new(|state, event| {
let mut new_state = state.clone();
match event {
ShipmentEvent::Created(evt) => {
Event::ShipmentCreated(evt) => {
new_state.shipment_id = evt.shipment_id;
new_state.order_id = evt.order_id;
new_state.customer_name = evt.customer_name.to_owned();
new_state.items = evt.items.to_owned();
}
Event::OrderCreated(_) => {}
Event::OrderUpdated(_) => {}
Event::OrderCancelled(_) => {}
}
new_state
}),
Expand Down Expand Up @@ -108,9 +111,7 @@ impl ViewStateRepository<Event, (OrderViewState, ShipmentViewState), Materialize

#[tokio::test]
async fn test() {
let combined_view = order_view()
.combine(shipment_view())
.map_event(&event_from_sum);
let combined_view = order_view().merge(shipment_view());
let repository = InMemoryViewStateRepository::new();
let materialized_view = Arc::new(MaterializedView::new(repository, combined_view));
let materialized_view1 = Arc::clone(&materialized_view);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,59 @@ use fmodel_rust::saga::Saga;
use fmodel_rust::saga_manager::{ActionPublisher, SagaManager};

use crate::api::{
CreateShipmentCommand, OrderCommand, OrderCreatedEvent, OrderEvent, ShipmentCommand,
ShipmentEvent, UpdateOrderCommand,
CreateShipmentCommand, OrderCommand, OrderCreatedEvent, ShipmentCommand, UpdateOrderCommand,
};
use crate::application::{event_from_sum2, sum_to_command2, Command, Event, SagaManagerError};
use crate::application::{sum_to_command2, Command, Event, SagaManagerError};

mod api;
mod application;

fn order_saga<'a>() -> Saga<'a, OrderEvent, ShipmentCommand> {
fn order_saga<'a>() -> Saga<'a, Event, ShipmentCommand> {
Saga {
react: Box::new(|event| match event {
OrderEvent::Created(evt) => {
Event::OrderCreated(evt) => {
vec![ShipmentCommand::Create(CreateShipmentCommand {
shipment_id: evt.order_id,
order_id: evt.order_id,
customer_name: evt.customer_name.to_owned(),
items: evt.items.to_owned(),
})]
}
OrderEvent::Updated(_) => {
Event::OrderUpdated(_) => {
vec![]
}
OrderEvent::Cancelled(_) => {
Event::OrderCancelled(_) => {
vec![]
}
Event::ShipmentCreated(_) => {
vec![]
}
}),
}
}

fn shipment_saga<'a>() -> Saga<'a, ShipmentEvent, OrderCommand> {
fn shipment_saga<'a>() -> Saga<'a, Event, OrderCommand> {
Saga {
react: Box::new(|event| match event {
ShipmentEvent::Created(evt) => {
Event::ShipmentCreated(evt) => {
vec![OrderCommand::Update(UpdateOrderCommand {
order_id: evt.order_id,
new_items: evt.items.to_owned(),
})]
}

Event::OrderCreated(_) => {
vec![]
}
Event::OrderUpdated(_) => {
vec![]
}
Event::OrderCancelled(_) => {
vec![]
}
}),
}
}

/// Simple action publisher that just returns the action/command.
/// It is used for testing. In real life, it would publish the action/command to some external system. or to an aggregate that is able to handel the action/command.
struct SimpleActionPublisher;
Expand Down Expand Up @@ -71,9 +82,8 @@ async fn test() {
let saga_manager = SagaManager::new(
SimpleActionPublisher::new(),
shipment_saga()
.combine(order_saga())
.map_action(&sum_to_command2)
.map_action_result(&event_from_sum2),
.merge(order_saga())
.map_action(&sum_to_command2),
);
let result = saga_manager.handle(&order_created_event).await;
assert!(result.is_ok());
Expand Down
34 changes: 2 additions & 32 deletions tests/saga_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use fmodel_rust::saga::{ActionComputation, Saga};

use crate::api::{
CreateShipmentCommand, OrderCommand, OrderCreatedEvent, OrderEvent, ShipmentCommand,
ShipmentEvent, UpdateOrderCommand,
UpdateOrderCommand,
};
use crate::application::{event_from_sum, sum_to_command, Command, Event};
use crate::application::{sum_to_command, Command, Event};

mod api;
mod application;
Expand Down Expand Up @@ -54,19 +54,6 @@ fn order_saga_2<'a>() -> Saga<'a, Event, ShipmentCommand> {
}
}

fn shipment_saga<'a>() -> Saga<'a, ShipmentEvent, OrderCommand> {
Saga {
react: Box::new(|event| match event {
ShipmentEvent::Created(evt) => {
vec![OrderCommand::Update(UpdateOrderCommand {
order_id: evt.order_id,
new_items: evt.items.to_owned(),
})]
}
}),
}
}

fn shipment_saga_2<'a>() -> Saga<'a, Event, OrderCommand> {
Saga {
react: Box::new(|event| match event {
Expand All @@ -93,14 +80,8 @@ fn shipment_saga_2<'a>() -> Saga<'a, Event, OrderCommand> {
#[test]
fn test() {
let order_saga: Saga<OrderEvent, ShipmentCommand> = order_saga();
let order_saga2: Saga<OrderEvent, ShipmentCommand> = crate::order_saga();
let order_saga_2: Saga<Event, ShipmentCommand> = crate::order_saga_2();
let shipment_saga: Saga<ShipmentEvent, OrderCommand> = shipment_saga();
let shipment_saga_2: Saga<Event, OrderCommand> = crate::shipment_saga_2();
let combined_saga = order_saga2
.combine(shipment_saga)
.map_action(&sum_to_command)
.map_action_result(&event_from_sum);
let merged_saga = order_saga_2
.merge(shipment_saga_2)
.map_action(&sum_to_command);
Expand All @@ -126,17 +107,6 @@ fn test() {
items: vec!["Item 1".to_string(), "Item 2".to_string()],
});

let combined_commands = combined_saga.compute_new_actions(&order_created_event2);
assert_eq!(
combined_commands,
[Command::ShipmentCreate(CreateShipmentCommand {
shipment_id: 1,
order_id: 1,
customer_name: "John Doe".to_string(),
items: vec!["Item 1".to_string(), "Item 2".to_string()],
})]
);

let merged_commands = merged_saga.compute_new_actions(&order_created_event2);
assert_eq!(
merged_commands,
Expand Down
Loading

0 comments on commit b97e50f

Please sign in to comment.