137 lines
5.4 KiB
C#
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<UserCreatedEventV1>(1);
|
|
///
|
|
/// // Register V2 (adds Email property)
|
|
/// await registry.RegisterSchemaAsync<UserCreatedEventV2>(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);
|
|
}
|