Skip to content

Commit

Permalink
Added Event Store and Versioning related classes for Simple Event Ver…
Browse files Browse the repository at this point in the history
…sioning patterns talk
  • Loading branch information
oskardudycz committed Nov 4, 2024
1 parent cf425a4 commit 4612f03
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 1 deletion.
16 changes: 16 additions & 0 deletions Sample/EventsVersioning/Talk/EventsVersioning.Talk.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotelManagement", "HotelManagement\HotelManagement.csproj", "{8B5F91C2-572B-4B2D-B67B-3EA98584888E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8B5F91C2-572B-4B2D-B67B-3EA98584888E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B5F91C2-572B-4B2D-B67B-3EA98584888E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B5F91C2-572B-4B2D-B67B-3EA98584888E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B5F91C2-572B-4B2D-B67B-3EA98584888E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Text.Json;

namespace HotelManagement.EventStore;

public class EventSerializer(EventTypeMapping mapping, EventTransformations transformations)
{
public object? Deserialize(string eventTypeName, string json) =>
transformations.TryTransform(eventTypeName, json, out var transformed)
? transformed
: JsonSerializer.Deserialize(json, mapping.Map(eventTypeName));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Text.Json;

namespace HotelManagement.EventStore;

public class EventTransformations
{
private readonly Dictionary<string, Func<string, object>> jsonTransformations = new();

public bool TryTransform(string eventTypeName, string json, out object? result)
{
if (!jsonTransformations.TryGetValue(eventTypeName, out var transformJson))
{
result = null;
return false;
}

result = transformJson(json);
return true;
}

public EventTransformations Register<TEvent>(string eventTypeName, Func<JsonDocument, TEvent> transformJson)
where TEvent : notnull
{
jsonTransformations.Add(
eventTypeName,
json => transformJson(JsonDocument.Parse(json))
);
return this;
}

public EventTransformations Register<TOldEvent, TEvent>(string eventTypeName,
Func<TOldEvent, TEvent> transformEvent)
where TOldEvent : notnull
where TEvent : notnull
{
jsonTransformations.Add(
eventTypeName,
json => transformEvent(JsonSerializer.Deserialize<TOldEvent>(json)!)
);
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace HotelManagement.EventStore;

public class EventTypeMapping
{
private readonly Dictionary<string, Type> mappings = new();

public EventTypeMapping Register<TEvent>(params string[] typeNames)
{
var eventType = typeof(TEvent);

foreach (var typeName in typeNames)
{
mappings.Add(typeName, eventType);
}

return this;
}

public Type Map(string eventType) => mappings[eventType];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Text.Json;

namespace HotelManagement.EventStore;

public interface IEventStore
{
ValueTask AppendToStream(Guid streamId, IEnumerable<object> newEvents, CancellationToken ct = default);
ValueTask<TEvent[]> ReadStream<TEvent>(Guid streamId, CancellationToken ct = default) where TEvent : notnull;
}

public class InMemoryEventStore: IEventStore
{
private readonly Dictionary<Guid, List<(string EventType, string Json)>> events = new();

public ValueTask AppendToStream(Guid streamId, IEnumerable<object> newEvents, CancellationToken _ = default)
{
if (!events.ContainsKey(streamId))
events[streamId] = [];

var serializedEvents = newEvents.Select(e => (e.GetType().FullName!, JsonSerializer.Serialize(e)));

events[streamId].AddRange(serializedEvents);

return ValueTask.CompletedTask;
}

public ValueTask<TEvent[]> ReadStream<TEvent>(Guid streamId, CancellationToken _ = default) where TEvent : notnull
{
var streamEvents = events.TryGetValue(streamId, out var stream)
? stream
: [];

var deserializedEvents = streamEvents
.Select(@event =>
Type.GetType(@event.EventType, true) is { } clrEventType
? JsonSerializer.Deserialize(@event.Json, clrEventType)
: null
)
.Where(e => e != null)
.Cast<TEvent>().ToArray();

return ValueTask.FromResult(deserializedEvents);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace HotelManagement.EventStore;

public record EventMetadata(
Guid CorrelationId
);

public record EventData(
string EventType,
string Data,
string MetaData
);

public class StreamTransformations
{
private readonly List<Func<List<EventData>, List<EventData>>> jsonTransformations = [];

public List<EventData> Transform(List<EventData> events)
{
if (!jsonTransformations.Any())
return events;

var result = jsonTransformations
.Aggregate(events, (current, transform) => transform(current));

return result;
}

public StreamTransformations Register(
Func<List<EventData>, List<EventData>> transformJson
)
{
jsonTransformations.Add(transformJson);
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ public class Retry
return TimeSpan.FromMilliseconds(1);
});

public Task UntilSucceeds(Func<CancellationToken, ValueTask> handle, CancellationToken token = default) =>
public static Task UntilSucceeds(Func<CancellationToken, ValueTask> handle, CancellationToken token = default) =>
retryPolicy.ExecuteAsync(async ct => await handle(ct), token);
}

0 comments on commit 4612f03

Please sign in to comment.