Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test and some doc updates for using the aggregate handler workflow wi… #1190

Merged
merged 1 commit into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/guide/durability/marten/event-sourcing.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,4 +477,13 @@ to consume Wolverine + Marten commands within Hot Chocolate mutations and always
the projected aggregate being updated to the user interface.
:::

### Passing the Aggregate to Before/Validate/Load Methods

The "[compound handler](/guide/handlers/#compound-handlers)" feature is a valuable way in Wolverine to organize your handler code, and fully supported
within the aggregate handler workflow as well. If you have a command handler method marked with `[AggregateHandler]` or
the `[Aggregate]` attribute in HTTP usage, you can also pass the aggregate type as an argument to any `Before` / `LoadAsync` / `Validate`
method on that handler to do validation before the main handler method. Here's a sample from the tests of doing just that:

snippet: sample_passing_aggregate_into_validate_method


45 changes: 45 additions & 0 deletions src/Persistence/MartenTests/aggregate_handler_workflow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,33 @@ public async Task using_updated_aggregate_as_response()
updated.ACount.ShouldBe(3);
updated.BCount.ShouldBe(4);
}

[Fact]
public async Task using_the_aggregate_in_a_before_method()
{
var streamId = Guid.NewGuid();
var streamId2 = Guid.NewGuid();
using (var session = theStore.LightweightSession())
{
session.Events.StartStream<Aggregate>(streamId, new AEvent(), new CEvent());
session.Events.StartStream<Aggregate>(streamId2, new CEvent(), new CEvent());
await session.SaveChangesAsync();
}

await theHost.InvokeMessageAndWaitAsync(new RaiseIfValidated(streamId));
await theHost.InvokeMessageAndWaitAsync(new RaiseIfValidated(streamId2));

using (var session = theStore.LightweightSession())
{
// Should not apply anything new if there is a value for ACount
var existing1 = await session.LoadAsync<LetterAggregate>(streamId);
existing1.BCount.ShouldBe(0);

// Should apply anything new if there was no value for ACount
var existing2 = await session.LoadAsync<LetterAggregate>(streamId2);
existing2.BCount.ShouldBe(1);
}
}
}

public record Event1(Guid AggregateId);
Expand Down Expand Up @@ -376,6 +403,24 @@ public record RaiseAABCC(Guid LetterAggregateId);

public record RaiseBBCCC(Guid LetterAggregateId);

#region sample_passing_aggregate_into_validate_method

public record RaiseIfValidated(Guid LetterAggregateId);

public static class RaiseIfValidatedHandler
{
public static HandlerContinuation Validate(LetterAggregate aggregate) =>
aggregate.ACount == 0 ? HandlerContinuation.Continue : HandlerContinuation.Stop;

[AggregateHandler]
public static IEnumerable<object> Handle(RaiseIfValidated command, LetterAggregate aggregate)
{
yield return new BEvent();
}
}

#endregion

public class Response
{
public static Response For(LetterAggregate aggregate)
Expand Down
Loading