using System;
using Svrnty.CQRS.Events.Abstractions.Models;
using Svrnty.CQRS.Events.Abstractions.Schema;
using Svrnty.CQRS.Events.Abstractions.EventStore;
using Svrnty.CQRS.Events.Abstractions;
namespace Svrnty.Sample.Events;
// ============================================================================
// PHASE 5: EVENT VERSIONING DEMONSTRATION
// ============================================================================
// This file demonstrates event schema evolution with automatic upcasting.
// Shows how to evolve event schemas over time without breaking compatibility.
// ============================================================================
///
/// Version 1 of UserCreatedEvent (initial schema).
/// Original design with a single "FullName" field.
///
///
///
/// Version 1 Schema:
/// - UserId: int
/// - FullName: string (combined first and last name)
///
///
[EventVersion(1)]
public sealed record UserCreatedEventV1 : CorrelatedEvent
{
public required int UserId { get; init; }
public required string FullName { get; init; }
}
///
/// Version 2 of UserCreatedEvent (evolved schema).
/// Improved design that separates name components and adds email.
///
///
///
/// Version 2 Schema:
/// - UserId: int
/// - FirstName: string (split from FullName)
/// - LastName: string (split from FullName)
/// - Email: string (new field)
///
///
/// Schema Changes from V1:
/// - FullName → FirstName + LastName (split transformation)
/// - Added Email field (default: "unknown@example.com")
///
///
/// Automatic Upcasting:
/// When a V1 event is consumed by a subscription configured for V2,
/// the framework automatically calls to transform it.
///
///
[EventVersion(2, UpcastFrom = typeof(UserCreatedEventV1))]
public sealed record UserCreatedEventV2 : CorrelatedEvent
{
public required int UserId { get; init; }
public required string FirstName { get; init; }
public required string LastName { get; init; }
public required string Email { get; init; }
///
/// Convention-based upcaster: Transforms V1 events to V2.
///
///
///
/// The framework discovers this method automatically via reflection.
/// Method signature must match: public static {ToType} UpcastFrom({FromType})
///
///
/// Transformation Logic:
/// - Split FullName on first space
/// - First part becomes FirstName
/// - Remaining parts become LastName
/// - Email defaults to "unknown@example.com" (data not available in V1)
/// - Preserve correlation metadata (EventId, CorrelationId, OccurredAt)
///
///
public static UserCreatedEventV2 UpcastFrom(UserCreatedEventV1 v1)
{
// Split full name into components
var parts = v1.FullName.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
var firstName = parts.Length > 0 ? parts[0] : "Unknown";
var lastName = parts.Length > 1 ? parts[1] : "";
return new UserCreatedEventV2
{
// Preserve correlation metadata from V1
EventId = v1.EventId,
CorrelationId = v1.CorrelationId,
OccurredAt = v1.OccurredAt,
// Transform data fields
UserId = v1.UserId,
FirstName = firstName,
LastName = lastName,
Email = "unknown@example.com" // Default for new field
};
}
}
///
/// Version 3 of UserCreatedEvent (further evolution).
/// Adds phone number and makes email optional.
///
///
///
/// Version 3 Schema:
/// - UserId: int
/// - FirstName: string
/// - LastName: string
/// - Email: string (now nullable)
/// - PhoneNumber: string? (new optional field)
///
///
/// Multi-Hop Upcasting:
/// The framework can automatically upcast V1 → V2 → V3 by chaining upcasters.
/// You only need to define V1→V2 and V2→V3; the framework handles V1→V3.
///
///
[EventVersion(3, UpcastFrom = typeof(UserCreatedEventV2))]
public sealed record UserCreatedEventV3 : CorrelatedEvent
{
public required int UserId { get; init; }
public required string FirstName { get; init; }
public required string LastName { get; init; }
public string? Email { get; init; }
public string? PhoneNumber { get; init; }
///
/// Upcaster: Transforms V2 events to V3.
///
public static UserCreatedEventV3 UpcastFrom(UserCreatedEventV2 v2)
{
return new UserCreatedEventV3
{
// Preserve correlation metadata
EventId = v2.EventId,
CorrelationId = v2.CorrelationId,
OccurredAt = v2.OccurredAt,
// Copy existing fields
UserId = v2.UserId,
FirstName = v2.FirstName,
LastName = v2.LastName,
Email = v2.Email != "unknown@example.com" ? v2.Email : null,
PhoneNumber = null // New field, no data available from V2
};
}
}