dotnet-cqrs/Svrnty.CQRS.Events.Abstractions/Schema/ISchemaRegistry.cs

137 lines
5.4 KiB
C#

using System;
using Svrnty.CQRS.Events.Abstractions.Schema;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Svrnty.CQRS.Events.Abstractions.EventStore;
using Svrnty.CQRS.Events.Abstractions.Models;
namespace Svrnty.CQRS.Events.Abstractions.Schema;
/// <summary>
/// Registry for managing event schema versions and automatic upcasting.
/// </summary>
/// <remarks>
/// <para>
/// The schema registry tracks event evolution over time, enabling:
/// - Automatic discovery of event versions
/// - Multi-hop upcasting (V1 → V2 → V3)
/// - Schema storage for external consumers
/// - Type-safe version transitions
/// </para>
/// <para>
/// <strong>Usage Pattern:</strong>
/// 1. Register each event version with the registry
/// 2. Specify upcast relationships (V2 upcasts from V1)
/// 3. Framework automatically upcasts old events when consuming
/// </para>
/// </remarks>
public interface ISchemaRegistry
{
/// <summary>
/// Registers a schema for an event version.
/// </summary>
/// <typeparam name="TEvent">The event type to register.</typeparam>
/// <param name="version">The version number for this schema.</param>
/// <param name="upcastFromType">The previous version type this can upcast from (null for version 1).</param>
/// <param name="jsonSchema">Optional JSON schema for external consumers.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The registered schema information.</returns>
/// <remarks>
/// <para>
/// <strong>Example:</strong>
/// <code>
/// // Register V1 (initial version)
/// await registry.RegisterSchemaAsync&lt;UserCreatedEventV1&gt;(1);
///
/// // Register V2 (adds Email property)
/// await registry.RegisterSchemaAsync&lt;UserCreatedEventV2&gt;(2, upcastFromType: typeof(UserCreatedEventV1));
/// </code>
/// </para>
/// </remarks>
Task<SchemaInfo> RegisterSchemaAsync<TEvent>(
int version,
Type? upcastFromType = null,
string? jsonSchema = null,
CancellationToken cancellationToken = default)
where TEvent : ICorrelatedEvent;
/// <summary>
/// Gets schema information for a specific event type and version.
/// </summary>
/// <param name="eventType">The event type name.</param>
/// <param name="version">The version number.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Schema information if found; otherwise null.</returns>
Task<SchemaInfo?> GetSchemaAsync(
string eventType,
int version,
CancellationToken cancellationToken = default);
/// <summary>
/// Gets schema information for a CLR type.
/// </summary>
/// <param name="clrType">The .NET type.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Schema information if found; otherwise null.</returns>
Task<SchemaInfo?> GetSchemaByTypeAsync(
Type clrType,
CancellationToken cancellationToken = default);
/// <summary>
/// Gets the latest version number for an event type.
/// </summary>
/// <param name="eventType">The event type name.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The latest version number, or null if no versions registered.</returns>
Task<int?> GetLatestVersionAsync(
string eventType,
CancellationToken cancellationToken = default);
/// <summary>
/// Gets the complete schema history for an event type (all versions).
/// </summary>
/// <param name="eventType">The event type name.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>List of schema information ordered by version ascending.</returns>
Task<IReadOnlyList<SchemaInfo>> GetSchemaHistoryAsync(
string eventType,
CancellationToken cancellationToken = default);
/// <summary>
/// Upcasts an event from its current version to the latest version.
/// </summary>
/// <param name="event">The event to upcast.</param>
/// <param name="targetVersion">The target version (null = latest version).</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The upcast event at the target version.</returns>
/// <remarks>
/// <para>
/// Performs multi-hop upcasting if necessary. For example:
/// UserCreatedEventV1 → UserCreatedEventV2 → UserCreatedEventV3
/// </para>
/// <para>
/// Each hop is performed by:
/// 1. Looking for a static UpcastFrom method on the target type
/// 2. Looking for a registered IEventUpcaster implementation
/// 3. Throwing if no upcaster is found
/// </para>
/// </remarks>
Task<ICorrelatedEvent> UpcastAsync(
ICorrelatedEvent @event,
int? targetVersion = null,
CancellationToken cancellationToken = default);
/// <summary>
/// Determines if an event needs upcasting.
/// </summary>
/// <param name="event">The event to check.</param>
/// <param name="targetVersion">The target version (null = latest version).</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>True if the event needs upcasting; otherwise false.</returns>
Task<bool> NeedsUpcastingAsync(
ICorrelatedEvent @event,
int? targetVersion = null,
CancellationToken cancellationToken = default);
}