Files
demo-ddd-without-oop/csharp-es/Program.cs
T
2026-05-04 19:39:49 +01:00

91 lines
3.3 KiB
C#

using System.Collections.Immutable;
using CsharpEs.Domain;
using CsharpEs.Infrastructure;
using CsharpEs.Library;
using static CsharpEs.Library.ResultModule;
public abstract record DemoError
{
public sealed record Account(AccountError Error) : DemoError;
public sealed record ReadModel(ReadModelError Error) : DemoError;
}
public class Program
{
private static Guid accountId;
private static ImmutableList<AccountCommand> demoCommands = ImmutableList<AccountCommand>.Empty;
static Program()
{
accountId = Guid.NewGuid();
demoCommands = demoCommands.AddRange([
// bring this in to see an error right from the start
// new AccountCommand.OpenAccount(accountId, new Money(-200m)),
new AccountCommand.OpenAccount(accountId, new Money(200m)),
new AccountCommand.WithdrawMoney(accountId, new Money(100m)),
new AccountCommand.WithdrawMoney(accountId, new Money(200m)),
// or maybe an exception in between?
// new AccountCommand.UnhandledTestCommand(),
new AccountCommand.DepositMoney(accountId, new Money(500m)),
]);
}
static ImmutableList<AccountEvent> eventStore = ImmutableList<AccountEvent>.Empty;
static Result<AccountState?, DemoError> ApplyEvent(
AccountBalanceReadModel balanceProjection,
AccountState? state,
AccountEvent @event
)
{
eventStore = eventStore.Add(@event);
Logging.Output(
"ae",
$"Applying event {Logging.Format(@event)} to state {Logging.Format(state)}"
);
return AccountDecider
.Evolve(state, @event)
.MapError(e => (DemoError)new DemoError.Account(e))
.Bind(newState =>
balanceProjection
.Project(@event)
.MapError(e => (DemoError)new DemoError.ReadModel(e))
.Log("ae ad", "Account details")
.Map(_ => newState)
)
.Log("ae", $"Applied and projected {Logging.Format(@event)}");
}
public static void Main(string[] args)
{
Logging.Output("csharp-es", "Starting money handling demo...");
AccountBalanceReadModelModule
.Create()
.MapError(e => (DemoError)new DemoError.ReadModel(e))
.Bind(readModel =>
demoCommands
.Aggregate(
OkNone<AccountState?, DemoError>(),
(stateResult, command) =>
stateResult
.Bind(state =>
AccountDecider
.Decide(state, command)
.MapError(e => (DemoError)new DemoError.Account(e))
.Bind(@event => ApplyEvent(readModel, state, @event))
)
.Log("loop", "Intermediate state")
)
.Bind(s =>
readModel
.Query()
.Log("query", "Read model data")
.MapError(e => (DemoError)new DemoError.ReadModel(e))
)
)
.Log("csharp-es done", "Demo completed.");
}
}