Skip to content

Commit b563da1

Browse files
author
Tomas Lycken
authored
Fix assembly registry bug (#16)
* Improve error handling in SimpleEventRegistry construction * Utilize new error handling in derived registries * Split registry interface in two * Whitespace * Give translating registry some love * Add tests for assembly event registry
1 parent d0c04bd commit b563da1

7 files changed

Lines changed: 92 additions & 29 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using RdbmsEventStore.EventRegistry;
3+
using Xunit;
4+
5+
namespace RdbmsEventStore.Tests
6+
{
7+
public class AssemblyEventRegistryTests
8+
{
9+
// Create two types with lambdas in them, to test handling of closure types
10+
private class FooContainer { private Func<object, bool> Foo = _ => true; }
11+
private class BarContainer { private Func<object, bool> Bar = _ => false; }
12+
13+
[Fact]
14+
public void AssemblyRegistryCanHandleLambdaClosureTypes()
15+
{
16+
var _ = new AssemblyEventRegistry(typeof(AssemblyEventRegistryTests));
17+
}
18+
19+
[Fact]
20+
public void AssemblyRegistryThrowsNiceExceptionsWithSameNamedTypes()
21+
{
22+
// use a really stupid namer, to create naming conflicts
23+
string StupidNamer(Type type) => type.Name.Substring(0, 1);
24+
25+
Assert.Throws<EventTypeRegistrationException>(() => new AssemblyEventRegistry(typeof(AssemblyEventRegistryTests), (Func<Type, string>)StupidNamer));
26+
}
27+
}
28+
}

src/RdbmsEventStore/EventRegistry/AssemblyEventRegistry.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ public AssemblyEventRegistry(Type markerType, Func<Type, string> namer, Func<Typ
2626
.GetTypeInfo()
2727
.Assembly
2828
.GetTypes()
29-
.Where(inclusionPredicate)
30-
.ToDictionary(namer, type => type))
29+
.Where(type => !type.Name.StartsWith("<>"))
30+
.Where(inclusionPredicate), namer)
3131
{
3232
}
3333
}

src/RdbmsEventStore/EventRegistry/ComposedEventRegistry.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ namespace RdbmsEventStore.EventRegistry
44
{
55
public class ComposedEventRegistry : SimpleEventRegistry
66
{
7-
public ComposedEventRegistry(params IEventRegistry[] registries)
8-
: base(registries
9-
.SelectMany(r => r.Registrations)
10-
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value))
7+
public ComposedEventRegistry(params IComposableEventRegistry[] registries)
8+
: base(registries.SelectMany(r => r.Registrations))
119
{
1210
}
1311
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace RdbmsEventStore.EventRegistry
4+
{
5+
public class EventTypeRegistrationException : InvalidOperationException
6+
{
7+
public EventTypeRegistrationException(string message, Exception innerException) : base(message, innerException)
8+
{
9+
}
10+
}
11+
}

src/RdbmsEventStore/EventRegistry/SimpleEventRegistry.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,27 @@
44

55
namespace RdbmsEventStore.EventRegistry
66
{
7-
public class SimpleEventRegistry : IEventRegistry
7+
public class SimpleEventRegistry : IComposableEventRegistry
88
{
99
private readonly IReadOnlyDictionary<Type, string> _typeToString;
10-
public SimpleEventRegistry(IReadOnlyDictionary<string, Type> eventTypes)
10+
public SimpleEventRegistry(IEnumerable<Type> eventTypes, Func<Type, string> namer)
11+
: this(eventTypes.Select(type => new KeyValuePair<string, Type>(namer(type), type)))
1112
{
12-
Registrations = eventTypes;
13-
_typeToString = eventTypes
14-
.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
13+
}
14+
15+
public SimpleEventRegistry(IEnumerable<KeyValuePair<string, Type>> registrations)
16+
{
17+
try
18+
{
19+
Registrations = registrations
20+
.ToDictionary(registration => registration.Key, registration => registration.Value);
21+
_typeToString = Registrations
22+
.ToDictionary(registration => registration.Value, kvp => kvp.Key);
23+
}
24+
catch (ArgumentException ex)
25+
{
26+
throw new EventTypeRegistrationException("Invalid event type registration; two or more types are either named the same, or registered twice", ex);
27+
}
1528
}
1629

1730
public Type TypeFor(string eventType)
@@ -20,7 +33,7 @@ public Type TypeFor(string eventType)
2033
: throw new EventTypeNotFoundException(eventType, Registrations);
2134

2235
public string NameFor(Type eventType)
23-
=>_typeToString.TryGetValue(eventType, out var name)
36+
=> _typeToString.TryGetValue(eventType, out var name)
2437
? name
2538
: throw new EventNameNotFoundException(eventType, _typeToString);
2639

src/RdbmsEventStore/EventRegistry/TranslatingEventRegistry.cs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,55 @@
44

55
namespace RdbmsEventStore.EventRegistry
66
{
7-
public class TranslatingEventRegistry : IEventRegistry
7+
public class TranslatingEventRegistry : IComposableEventRegistry
88
{
99
private readonly IReadOnlyDictionary<string, string> _translations;
1010
private readonly IReadOnlyDictionary<string, string> _inverseTranslations;
11-
private readonly IEventRegistry _registry;
11+
private readonly IComposableEventRegistry _inner;
1212
private readonly bool _translateNewEvents;
1313

14-
public TranslatingEventRegistry(IReadOnlyDictionary<string, string> translations, IEventRegistry registry, bool translateNewEvents = false)
14+
public TranslatingEventRegistry(IReadOnlyDictionary<string, string> translations, IComposableEventRegistry inner, bool translateNewEvents = false)
1515
{
1616
_translations = translations;
1717
if (translateNewEvents)
1818
{
19-
_inverseTranslations = translations.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
19+
try
20+
{
21+
_inverseTranslations = translations.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
22+
}
23+
catch (ArgumentException ex)
24+
{
25+
throw new EventTypeRegistrationException(
26+
"Invalid translation registration; two or more old names translate to the same new name.\n" +
27+
"If you want to translate both Foo and Bar to Baz, add Foo=>Bar and Bar=>Baz instead of Foo=>Baz and Bar=>Baz.", ex);
28+
}
2029
}
2130

22-
_registry = registry;
31+
_inner = inner;
2332
_translateNewEvents = translateNewEvents;
2433
}
2534

2635
public Type TypeFor(string eventType)
27-
=> _translations.TryGetValue(eventType, out var translated)
28-
? TypeFor(translated)
29-
: _registry.TypeFor(eventType);
36+
=> _inner.TypeFor(TranslationFor(eventType));
3037

3138
public string NameFor(Type eventType)
32-
=> InverseTranslate(this._registry.NameFor(eventType));
39+
=> InverseTranslationFor(_inner.NameFor(eventType));
40+
41+
private string TranslationFor(string eventType)
42+
=> _translations.TryGetValue(eventType, out var translated)
43+
? TranslationFor(translated)
44+
: eventType;
3345

34-
private string InverseTranslate(string registeredName)
35-
=> _translateNewEvents && _inverseTranslations.TryGetValue(registeredName, out var translated)
36-
? InverseTranslate(translated)
37-
: registeredName;
46+
private string InverseTranslationFor(string eventType)
47+
=> _inverseTranslations.TryGetValue(eventType, out var translated)
48+
? InverseTranslationFor(translated)
49+
: eventType;
3850

3951
public IReadOnlyDictionary<string, Type> Registrations
40-
=> _registry
52+
=> _inner
4153
.Registrations
4254
.ToDictionary(
43-
kvp => _translations.TryGetValue(kvp.Key, out var translated)
44-
? translated
45-
: kvp.Key,
55+
kvp => TranslationFor(kvp.Key),
4656
kvp => kvp.Value);
4757
}
4858
}

src/RdbmsEventStore/IEventRegistry.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ public interface IEventRegistry
88
Type TypeFor(string eventType);
99

1010
string NameFor(Type eventType);
11+
}
1112

13+
public interface IComposableEventRegistry : IEventRegistry
14+
{
1215
IReadOnlyDictionary<string, Type> Registrations { get; }
1316
}
1417
}

0 commit comments

Comments
 (0)