using System; using Svrnty.CQRS.Events.Abstractions.Subscriptions; using System.Collections.Generic; using Svrnty.CQRS.Events.Abstractions; namespace Svrnty.CQRS.Events.Subscriptions; /// /// Default implementation of . /// Represents a subscription configuration for consuming events from a stream. /// public class Subscription : ISubscription { /// /// Initializes a new instance of the class. /// /// Unique subscription identifier. /// Name of the stream to subscribe to. /// Subscription mode (Broadcast, Exclusive, etc.). public Subscription(string subscriptionId, string streamName, SubscriptionMode mode = SubscriptionMode.Broadcast) { if (string.IsNullOrWhiteSpace(subscriptionId)) throw new ArgumentException("Subscription ID cannot be null or whitespace.", nameof(subscriptionId)); if (string.IsNullOrWhiteSpace(streamName)) throw new ArgumentException("Stream name cannot be null or whitespace.", nameof(streamName)); SubscriptionId = subscriptionId; StreamName = streamName; Mode = mode; CreatedAt = DateTimeOffset.UtcNow; IsActive = true; VisibilityTimeout = TimeSpan.FromSeconds(30); // Default 30 seconds } /// public string SubscriptionId { get; } /// public string StreamName { get; } /// public SubscriptionMode Mode { get; set; } /// public HashSet? EventTypeFilter { get; set; } /// public bool IsActive { get; set; } /// public DateTimeOffset CreatedAt { get; } /// public string? Description { get; set; } /// public int? MaxConcurrentConsumers { get; set; } /// public TimeSpan VisibilityTimeout { get; set; } /// public IReadOnlyDictionary? Metadata { get; set; } // ======================================================================== // Phase 5: Schema Evolution Support // ======================================================================== /// public bool EnableUpcasting { get; set; } /// public int? TargetEventVersion { get; set; } /// /// Validates the subscription configuration. /// /// Thrown if configuration is invalid. public void Validate() { if (string.IsNullOrWhiteSpace(SubscriptionId)) throw new InvalidOperationException("Subscription ID cannot be null or whitespace."); if (string.IsNullOrWhiteSpace(StreamName)) throw new InvalidOperationException("Stream name cannot be null or whitespace."); if (VisibilityTimeout <= TimeSpan.Zero) throw new InvalidOperationException($"Visibility timeout must be positive. Got: {VisibilityTimeout}"); if (MaxConcurrentConsumers.HasValue && MaxConcurrentConsumers.Value <= 0) throw new InvalidOperationException($"MaxConcurrentConsumers must be positive if set. Got: {MaxConcurrentConsumers}"); // Validate mode-specific constraints if (Mode == SubscriptionMode.ConsumerGroup && MaxConcurrentConsumers.HasValue && MaxConcurrentConsumers.Value == 1) { throw new InvalidOperationException( "ConsumerGroup mode with MaxConcurrentConsumers=1 is inefficient. Use Exclusive mode instead."); } } }