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; /// /// Projection that builds user statistics from UserAddedEvent and UserRemovedEvent. /// Demonstrates dynamic projection handling multiple event types. /// /// /// /// This projection maintains a simple in-memory read model tracking: /// - Total users added /// - Total users removed /// - Current user count /// - Last user details /// /// /// In production, this would typically update a database, cache, or other persistent store. /// /// public sealed class UserStatisticsProjection : IDynamicProjection, IResettableProjection { private readonly UserStatistics _statistics; private readonly ILogger _logger; public UserStatisticsProjection( UserStatistics statistics, ILogger logger) { _statistics = statistics ?? throw new ArgumentNullException(nameof(statistics)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// /// Gets the current statistics (for querying). /// public UserStatistics Statistics => _statistics; /// 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; } } /// 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; } }