dotnet-cqrs/Svrnty.Sample/Projections/UserStatisticsProjection.cs

106 lines
3.5 KiB
C#

using System;
using Svrnty.CQRS.Events.Abstractions.Subscriptions;
using Svrnty.Sample.Events;
using Svrnty.CQRS.Events.Abstractions.EventStore;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Svrnty.CQRS.Events.Abstractions.Projections;
namespace Svrnty.Sample.Projections;
/// <summary>
/// Projection that builds user statistics from UserAddedEvent and UserRemovedEvent.
/// Demonstrates dynamic projection handling multiple event types.
/// </summary>
/// <remarks>
/// <para>
/// This projection maintains a simple in-memory read model tracking:
/// - Total users added
/// - Total users removed
/// - Current user count
/// - Last user details
/// </para>
/// <para>
/// In production, this would typically update a database, cache, or other persistent store.
/// </para>
/// </remarks>
public sealed class UserStatisticsProjection : IDynamicProjection, IResettableProjection
{
private readonly UserStatistics _statistics;
private readonly ILogger<UserStatisticsProjection> _logger;
public UserStatisticsProjection(
UserStatistics statistics,
ILogger<UserStatisticsProjection> logger)
{
_statistics = statistics ?? throw new ArgumentNullException(nameof(statistics));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
/// <summary>
/// Gets the current statistics (for querying).
/// </summary>
public UserStatistics Statistics => _statistics;
/// <inheritdoc />
public Task HandleAsync(ICorrelatedEvent @event, CancellationToken cancellationToken = default)
{
switch (@event)
{
case UserAddedEvent added:
return HandleUserAddedAsync(added, cancellationToken);
case UserRemovedEvent removed:
return HandleUserRemovedAsync(removed, cancellationToken);
default:
// Unknown event type - skip
_logger.LogWarning("Received unknown event type: {EventType}", @event.GetType().Name);
return Task.CompletedTask;
}
}
/// <inheritdoc />
public Task ResetAsync(CancellationToken cancellationToken = default)
{
_logger.LogInformation("Resetting user statistics projection");
_statistics.TotalUsersAdded = 0;
_statistics.TotalUsersRemoved = 0;
_statistics.LastUserId = 0;
_statistics.LastUserName = string.Empty;
_statistics.LastUserEmail = string.Empty;
_statistics.LastUpdated = DateTimeOffset.MinValue;
return Task.CompletedTask;
}
private Task HandleUserAddedAsync(UserAddedEvent @event, CancellationToken cancellationToken)
{
_statistics.TotalUsersAdded++;
_statistics.LastUserId = @event.UserId;
_statistics.LastUserName = @event.Name;
_statistics.LastUserEmail = @event.Email;
_statistics.LastUpdated = @event.OccurredAt;
_logger.LogInformation(
"User added: {UserId} ({Name}). Total users: {Total}",
@event.UserId, @event.Name, _statistics.CurrentUserCount);
return Task.CompletedTask;
}
private Task HandleUserRemovedAsync(UserRemovedEvent @event, CancellationToken cancellationToken)
{
_statistics.TotalUsersRemoved++;
_statistics.LastUpdated = @event.OccurredAt;
_logger.LogInformation(
"User removed: {UserId}. Total users: {Total}",
@event.UserId, _statistics.CurrentUserCount);
return Task.CompletedTask;
}
}