using System; using Svrnty.CQRS.Events.Abstractions.EventStore; using System.Collections.Generic; using System.Linq; namespace Svrnty.CQRS.Events.Abstractions.Models; /// /// Wraps a command result with events to be emitted. /// The framework automatically handles correlation ID assignment and event emission. /// /// The type of the command result. public sealed class CommandResultWithEvents { private readonly List _events = new(); /// /// The result of the command execution. /// public TResult Result { get; } /// /// Events to be emitted with automatic correlation ID management. /// public IReadOnlyList Events => _events.AsReadOnly(); /// /// Correlation ID assigned by the framework. /// Available after the command is processed. /// This setter is public for framework use but should not be set by application code. /// public string? CorrelationId { get; set; } public CommandResultWithEvents(TResult result) { Result = result; } public CommandResultWithEvents(TResult result, params ICorrelatedEvent[] events) { Result = result; _events.AddRange(events); } public CommandResultWithEvents(TResult result, IEnumerable events) { Result = result; _events.AddRange(events); } /// /// Add an event to be emitted. The correlation ID will be automatically assigned. /// public CommandResultWithEvents AddEvent(ICorrelatedEvent @event) { _events.Add(@event); return this; } /// /// Add multiple events to be emitted. Correlation IDs will be automatically assigned. /// public CommandResultWithEvents AddEvents(params ICorrelatedEvent[] events) { _events.AddRange(events); return this; } /// /// Add multiple events to be emitted. Correlation IDs will be automatically assigned. /// public CommandResultWithEvents AddEvents(IEnumerable events) { _events.AddRange(events); return this; } /// /// Method used by the framework to assign correlation IDs to all events. /// This method is public for framework use but should not be called by application code. /// public void AssignCorrelationIds(string correlationId) { CorrelationId = correlationId; foreach (var @event in _events) { // Use reflection to set the correlation ID var correlationIdProperty = @event.GetType().GetProperty(nameof(ICorrelatedEvent.CorrelationId)); if (correlationIdProperty != null && correlationIdProperty.CanWrite) { correlationIdProperty.SetValue(@event, correlationId); } else if (correlationIdProperty != null && correlationIdProperty.GetSetMethod(nonPublic: true) != null) { // Handle init-only properties correlationIdProperty.GetSetMethod(nonPublic: true)!.Invoke(@event, new object[] { correlationId }); } } } } /// /// Wraps events to be emitted for commands that don't return a result. /// The framework automatically handles correlation ID assignment and event emission. /// public sealed class CommandResultWithEvents { private readonly List _events = new(); /// /// Events to be emitted with automatic correlation ID management. /// public IReadOnlyList Events => _events.AsReadOnly(); /// /// Correlation ID assigned by the framework. /// Available after the command is processed. /// This setter is public for framework use but should not be set by application code. /// public string? CorrelationId { get; set; } public CommandResultWithEvents() { } public CommandResultWithEvents(params ICorrelatedEvent[] events) { _events.AddRange(events); } public CommandResultWithEvents(IEnumerable events) { _events.AddRange(events); } /// /// Add an event to be emitted. The correlation ID will be automatically assigned. /// public CommandResultWithEvents AddEvent(ICorrelatedEvent @event) { _events.Add(@event); return this; } /// /// Add multiple events to be emitted. Correlation IDs will be automatically assigned. /// public CommandResultWithEvents AddEvents(params ICorrelatedEvent[] events) { _events.AddRange(events); return this; } /// /// Add multiple events to be emitted. Correlation IDs will be automatically assigned. /// public CommandResultWithEvents AddEvents(IEnumerable events) { _events.AddRange(events); return this; } /// /// Method used by the framework to assign correlation IDs to all events. /// This method is public for framework use but should not be called by application code. /// public void AssignCorrelationIds(string correlationId) { CorrelationId = correlationId; foreach (var @event in _events) { // Use reflection to set the correlation ID var correlationIdProperty = @event.GetType().GetProperty(nameof(ICorrelatedEvent.CorrelationId)); if (correlationIdProperty != null && correlationIdProperty.CanWrite) { correlationIdProperty.SetValue(@event, correlationId); } else if (correlationIdProperty != null && correlationIdProperty.GetSetMethod(nonPublic: true) != null) { // Handle init-only properties correlationIdProperty.GetSetMethod(nonPublic: true)!.Invoke(@event, new object[] { correlationId }); } } } }