Skip to content

Commit

Permalink
Updated exercises on events definitions and getting state to include …
Browse files Browse the repository at this point in the history
…union type for events
  • Loading branch information
oskardudycz committed Apr 26, 2024
1 parent 1cfa74b commit d83b85b
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 144 deletions.
Expand Up @@ -2,32 +2,39 @@
using Xunit;

namespace IntroductionToEventSourcing.GettingStateFromEvents.Immutable;
using static ShoppingCartEvent;

// EVENTS
public record ShoppingCartOpened(
Guid ShoppingCartId,
Guid ClientId
);
public abstract record ShoppingCartEvent
{
public record ShoppingCartOpened(
Guid ShoppingCartId,
Guid ClientId
): ShoppingCartEvent;

public record ProductItemAddedToShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
);
public record ProductItemAddedToShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ProductItemRemovedFromShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
);
public record ProductItemRemovedFromShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ShoppingCartConfirmed(
Guid ShoppingCartId,
DateTime ConfirmedAt
);
public record ShoppingCartConfirmed(
Guid ShoppingCartId,
DateTime ConfirmedAt
): ShoppingCartEvent;

public record ShoppingCartCanceled(
Guid ShoppingCartId,
DateTime CanceledAt
);
public record ShoppingCartCanceled(
Guid ShoppingCartId,
DateTime CanceledAt
): ShoppingCartEvent;

// This won't allow
private ShoppingCartEvent(){}
}

// VALUE OBJECTS
public record PricedProductItem(
Expand Down Expand Up @@ -55,7 +62,7 @@ public enum ShoppingCartStatus

public class GettingStateFromEventsTests
{
private static ShoppingCart GetShoppingCart(IEnumerable<object> events)
private static ShoppingCart GetShoppingCart(IEnumerable<ShoppingCartEvent> events)
{
// 1. Add logic here
throw new NotImplementedException();
Expand All @@ -73,7 +80,7 @@ public void GettingState_ForSequenceOfEvents_ShouldSucceed()
var pairOfShoes = new PricedProductItem(shoesId, 1, 100);
var tShirt = new PricedProductItem(tShirtId, 1, 50);

var events = new object[]
var events = new ShoppingCartEvent[]
{
new ShoppingCartOpened(shoppingCartId, clientId),
new ProductItemAddedToShoppingCart(shoppingCartId, twoPairsOfShoes),
Expand Down
Expand Up @@ -2,32 +2,39 @@
using Xunit;

namespace IntroductionToEventSourcing.GettingStateFromEvents.Mutable;
using static ShoppingCartEvent;

// EVENTS
public record ShoppingCartOpened(
Guid ShoppingCartId,
Guid ClientId
);

public record ProductItemAddedToShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
);

public record ProductItemRemovedFromShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
);

public record ShoppingCartConfirmed(
Guid ShoppingCartId,
DateTime ConfirmedAt
);

public record ShoppingCartCanceled(
Guid ShoppingCartId,
DateTime CanceledAt
);
public abstract record ShoppingCartEvent
{
public record ShoppingCartOpened(
Guid ShoppingCartId,
Guid ClientId
): ShoppingCartEvent;

public record ProductItemAddedToShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ProductItemRemovedFromShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ShoppingCartConfirmed(
Guid ShoppingCartId,
DateTime ConfirmedAt
): ShoppingCartEvent;

public record ShoppingCartCanceled(
Guid ShoppingCartId,
DateTime CanceledAt
): ShoppingCartEvent;

// This won't allow
private ShoppingCartEvent(){}
}

// VALUE OBJECTS
public class PricedProductItem
Expand Down Expand Up @@ -60,7 +67,7 @@ public enum ShoppingCartStatus

public class GettingStateFromEventsTests
{
private static ShoppingCart GetShoppingCart(IEnumerable<object> events)
private static ShoppingCart GetShoppingCart(IEnumerable<ShoppingCartEvent> events)
{
// 1. Add logic here
throw new NotImplementedException();
Expand Down Expand Up @@ -90,7 +97,7 @@ public void GettingState_ForSequenceOfEvents_ShouldSucceed()
ProductId = tShirtId, Quantity = 1, UnitPrice = 50
};

var events = new object[]
var events = new ShoppingCartEvent[]
{
new ShoppingCartOpened(shoppingCartId, clientId),
new ProductItemAddedToShoppingCart(shoppingCartId, twoPairsOfShoes),
Expand Down
Expand Up @@ -16,3 +16,6 @@ Create sample events that represent a specific shopping cart. You can do that in
Events model:

![events](./assets/events.jpg)

1. Simple events structure [Solution1/EventsDefinitionTests.cs](./Solution1/EventsDefinitionTests.cs).
2. Events structure with union type to give option to tell that Shopping Cart event is one of the defined types [Solution2/EventsDefinitionTests.cs](./Solution2/EventsDefinitionTests.cs). Read more in [Union types in C#](https://event-driven.io/en/union_types_in_csharp/).
@@ -1,7 +1,7 @@
using FluentAssertions;
using Xunit;

namespace IntroductionToEventSourcing.EventsDefinition;
namespace IntroductionToEventSourcing.EventsDefinition.Solution1;

// 1. Define your events and entity here

Expand Down
@@ -0,0 +1,119 @@
using FluentAssertions;
using Xunit;

namespace IntroductionToEventSourcing.EventsDefinition.Solution2;
using static ShoppingCartEvent;

// 1. Define your events and entity here

// EVENTS
public abstract record ShoppingCartEvent
{
public record ShoppingCartOpened(
Guid ShoppingCartId,
Guid ClientId
): ShoppingCartEvent;

public record ProductItemAddedToShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ProductItemRemovedFromShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ShoppingCartConfirmed(
Guid ShoppingCartId,
DateTime ConfirmedAt
): ShoppingCartEvent;

public record ShoppingCartCanceled(
Guid ShoppingCartId,
DateTime CanceledAt
): ShoppingCartEvent;

// This won't allow
private ShoppingCartEvent(){}
}

// VALUE OBJECTS

public class PricedProductItem
{
public Guid ProductId { get; set; }
public decimal UnitPrice { get; set; }

public int Quantity { get; set; }

public decimal TotalPrice => Quantity * UnitPrice;
}

public record ImmutablePricedProductItem(
Guid ProductId,
int Quantity,
decimal UnitPrice
)
{
public decimal TotalPrice => Quantity * UnitPrice;
}

// ENTITY

// regular one
public class ShoppingCart
{
public Guid Id { get; set; }
public Guid ClientId { get; set; }
public ShoppingCartStatus Status { get; set; }
public IList<PricedProductItem> ProductItems { get; set; } = new List<PricedProductItem>();
public DateTime? ConfirmedAt { get; set; }
public DateTime? CanceledAt { get; set; }
}

// immutable one
public record ImmutableShoppingCart(
Guid Id,
Guid ClientId,
ShoppingCartStatus Status,
PricedProductItem[] ProductItems,
DateTime? ConfirmedAt = null,
DateTime? CanceledAt = null
);

public enum ShoppingCartStatus
{
Pending = 1,
Confirmed = 2,
Canceled = 4
}

public class EventsDefinitionTests
{
[Fact]
public void AllEventTypes_ShouldBeDefined()
{
var shoppingCartId = Guid.NewGuid();
var clientId = Guid.NewGuid();
var pairOfShoes = new PricedProductItem
{
ProductId = Guid.NewGuid(),
Quantity = 1,
UnitPrice = 100
};

var events = new object[]
{
new ShoppingCartOpened(shoppingCartId, clientId),
new ProductItemAddedToShoppingCart(shoppingCartId, pairOfShoes),
new ProductItemRemovedFromShoppingCart(shoppingCartId, pairOfShoes),
new ShoppingCartConfirmed(shoppingCartId, DateTime.UtcNow),
new ShoppingCartCanceled(shoppingCartId, DateTime.UtcNow)
};

const int expectedEventTypesCount = 5;
events.Should().HaveCount(expectedEventTypesCount);
events.GroupBy(e => e.GetType()).Should().HaveCount(expectedEventTypesCount);
}
}
Expand Up @@ -2,32 +2,39 @@
using Xunit;

namespace IntroductionToEventSourcing.GettingStateFromEvents.Immutable.Solution1;
using static ShoppingCartEvent;

// EVENTS
public record ShoppingCartOpened(
Guid ShoppingCartId,
Guid ClientId
);

public record ProductItemAddedToShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
);

public record ProductItemRemovedFromShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
);

public record ShoppingCartConfirmed(
Guid ShoppingCartId,
DateTime ConfirmedAt
);

public record ShoppingCartCanceled(
Guid ShoppingCartId,
DateTime CanceledAt
);
public abstract record ShoppingCartEvent
{
public record ShoppingCartOpened(
Guid ShoppingCartId,
Guid ClientId
): ShoppingCartEvent;

public record ProductItemAddedToShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ProductItemRemovedFromShoppingCart(
Guid ShoppingCartId,
PricedProductItem ProductItem
): ShoppingCartEvent;

public record ShoppingCartConfirmed(
Guid ShoppingCartId,
DateTime ConfirmedAt
): ShoppingCartEvent;

public record ShoppingCartCanceled(
Guid ShoppingCartId,
DateTime CanceledAt
): ShoppingCartEvent;

// This won't allow
private ShoppingCartEvent(){}
}

// VALUE OBJECTS
public record PricedProductItem(
Expand Down Expand Up @@ -60,7 +67,7 @@ public class GettingStateFromEventsTests
/// </summary>
/// <param name="events"></param>
/// <returns></returns>
private static ShoppingCart GetShoppingCart(IEnumerable<object> events)
private static ShoppingCart GetShoppingCart(IEnumerable<ShoppingCartEvent> events)
{
ShoppingCart shoppingCart = null!;

Expand All @@ -73,7 +80,7 @@ private static ShoppingCart GetShoppingCart(IEnumerable<object> events)
opened.ShoppingCartId,
opened.ClientId,
ShoppingCartStatus.Pending,
Array.Empty<PricedProductItem>()
[]
);
break;
case ProductItemAddedToShoppingCart productItemAdded:
Expand All @@ -98,11 +105,7 @@ private static ShoppingCart GetShoppingCart(IEnumerable<object> events)
{
ProductItems = shoppingCart.ProductItems
.Select(pi => pi.ProductId == productItemRemoved.ProductItem.ProductId?
new PricedProductItem(
pi.ProductId,
pi.Quantity - productItemRemoved.ProductItem.Quantity,
pi.UnitPrice
)
pi with { Quantity = pi.Quantity - productItemRemoved.ProductItem.Quantity }
:pi
)
.Where(pi => pi.Quantity > 0)
Expand Down Expand Up @@ -140,7 +143,7 @@ public void GettingState_ForSequenceOfEvents_ShouldSucceed()
var pairOfShoes = new PricedProductItem(shoesId, 1, 100);
var tShirt = new PricedProductItem(tShirtId, 1, 50);

var events = new object[]
var events = new ShoppingCartEvent[]
{
new ShoppingCartOpened(shoppingCartId, clientId),
new ProductItemAddedToShoppingCart(shoppingCartId, twoPairsOfShoes),
Expand Down

0 comments on commit d83b85b

Please sign in to comment.