92 lines
3.8 KiB
C#
92 lines
3.8 KiB
C#
using System;
|
|
using Svrnty.CQRS.Events.Abstractions.Models;
|
|
using Svrnty.CQRS.Events.Abstractions.EventStore;
|
|
|
|
namespace Svrnty.CQRS.Events.Abstractions.Models;
|
|
|
|
/// <summary>
|
|
/// Represents schema information for a versioned event type.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Schema information tracks the evolution of event types over time, enabling:
|
|
/// - Automatic upcasting from old versions to new versions
|
|
/// - JSON schema generation for external consumers
|
|
/// - Version compatibility checking
|
|
/// </para>
|
|
/// <para>
|
|
/// <strong>Example:</strong>
|
|
/// UserCreatedEventV1 → UserCreatedEventV2 (added Email property)
|
|
/// </para>
|
|
/// </remarks>
|
|
/// <param name="EventType">The fully qualified CLR type name of the event (e.g., "MyApp.UserCreatedEvent")</param>
|
|
/// <param name="Version">The semantic version of this schema (e.g., 1, 2, 3)</param>
|
|
/// <param name="ClrType">The .NET Type that represents this version</param>
|
|
/// <param name="JsonSchema">JSON Schema (Draft 7) describing the event structure (optional, for external consumers)</param>
|
|
/// <param name="UpcastFromType">The CLR type of the previous version (null for version 1)</param>
|
|
/// <param name="UpcastFromVersion">The version number this version can upcast from (null for version 1)</param>
|
|
/// <param name="RegisteredAt">When this schema was registered in the system</param>
|
|
public sealed record SchemaInfo(
|
|
string EventType,
|
|
int Version,
|
|
Type ClrType,
|
|
string? JsonSchema,
|
|
Type? UpcastFromType,
|
|
int? UpcastFromVersion,
|
|
DateTimeOffset RegisteredAt)
|
|
{
|
|
/// <summary>
|
|
/// Gets a value indicating whether this is the initial version of the event.
|
|
/// </summary>
|
|
public bool IsInitialVersion => Version == 1 && UpcastFromType == null;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether this schema can be upcast from a previous version.
|
|
/// </summary>
|
|
public bool SupportsUpcasting => UpcastFromType != null && UpcastFromVersion.HasValue;
|
|
|
|
/// <summary>
|
|
/// Gets the schema identifier (EventType:Version).
|
|
/// </summary>
|
|
public string SchemaId => $"{EventType}:v{Version}";
|
|
|
|
/// <summary>
|
|
/// Validates the schema information for correctness.
|
|
/// </summary>
|
|
/// <exception cref="InvalidOperationException">Thrown if the schema info is invalid.</exception>
|
|
public void Validate()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(EventType))
|
|
throw new InvalidOperationException("EventType cannot be null or whitespace.");
|
|
|
|
if (Version < 1)
|
|
throw new InvalidOperationException($"Version must be >= 1, got {Version}.");
|
|
|
|
if (ClrType == null)
|
|
throw new InvalidOperationException("ClrType cannot be null.");
|
|
|
|
if (!ClrType.IsAssignableTo(typeof(ICorrelatedEvent)))
|
|
throw new InvalidOperationException($"ClrType {ClrType.FullName} must implement ICorrelatedEvent.");
|
|
|
|
// Version 1 should not have upcast information
|
|
if (Version == 1)
|
|
{
|
|
if (UpcastFromType != null)
|
|
throw new InvalidOperationException("Version 1 should not have UpcastFromType.");
|
|
if (UpcastFromVersion.HasValue)
|
|
throw new InvalidOperationException("Version 1 should not have UpcastFromVersion.");
|
|
}
|
|
else
|
|
{
|
|
// Versions > 1 should have upcast information
|
|
if (UpcastFromType == null)
|
|
throw new InvalidOperationException($"Version {Version} must specify UpcastFromType.");
|
|
if (!UpcastFromVersion.HasValue)
|
|
throw new InvalidOperationException($"Version {Version} must specify UpcastFromVersion.");
|
|
if (UpcastFromVersion.Value != Version - 1)
|
|
throw new InvalidOperationException(
|
|
$"Version {Version} must upcast from version {Version - 1}, got {UpcastFromVersion.Value}.");
|
|
}
|
|
}
|
|
}
|