From d3bf1cef533d25c77f6d5fa5437ab0d897ea3ffc Mon Sep 17 00:00:00 2001 From: Tomas Lycken Date: Wed, 4 Oct 2017 10:46:58 +0200 Subject: [PATCH] Decouple id types (#19) * Add type argument for stream id * Add tests for querying for events + adjust to genericity * Increment next version --- GitVersion.yml | 2 +- .../EventStoreTests/QueryEventsTests.cs | 44 +++++++++++++++++++ .../EventStoreTests/WriteEventTests.cs | 4 +- .../Infrastructure/EventStoreFixture.cs | 16 ++++--- .../Infrastructure/EventStoreTestBase.cs | 16 +++---- .../Infrastructure/SmokeTest.cs | 7 +-- .../TestData/EventTypes.cs | 18 ++++++++ .../TestData/FooEvent.cs | 12 ----- .../TestData/TestEvent.cs | 6 --- .../EntityFrameworkEventStore.cs | 15 ++++--- src/RdbmsEventStore.EntityFramework/Event.cs | 4 +- .../EventCollectionTests.cs | 6 +-- src/RdbmsEventStore/DefaultEventFactory.cs | 10 ++--- src/RdbmsEventStore/DefaultMaterializer.cs | 2 +- src/RdbmsEventStore/EventCollection.cs | 4 +- src/RdbmsEventStore/IEvent.cs | 8 ++-- src/RdbmsEventStore/IEventFactory.cs | 4 +- src/RdbmsEventStore/IEventStore.cs | 21 +++++---- src/RdbmsEventStore/IMaterializer.cs | 2 +- 19 files changed, 126 insertions(+), 75 deletions(-) create mode 100644 src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/QueryEventsTests.cs create mode 100644 src/RdbmsEventStore.EntityFramework.Tests/TestData/EventTypes.cs delete mode 100644 src/RdbmsEventStore.EntityFramework.Tests/TestData/FooEvent.cs delete mode 100644 src/RdbmsEventStore.EntityFramework.Tests/TestData/TestEvent.cs diff --git a/GitVersion.yml b/GitVersion.yml index d1cf1d5..4052b63 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,5 +1,5 @@ mode: ContinuousDelivery -next-version: 0.2.0 +next-version: 0.3.0 branches: master: tag: beta diff --git a/src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/QueryEventsTests.cs b/src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/QueryEventsTests.cs new file mode 100644 index 0000000..53a71bd --- /dev/null +++ b/src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/QueryEventsTests.cs @@ -0,0 +1,44 @@ +using System.Linq; +using System.Threading.Tasks; +using RdbmsEventStore.EntityFramework.Tests.Infrastructure; +using RdbmsEventStore.EntityFramework.Tests.TestData; +using Xunit; + +namespace RdbmsEventStore.EntityFramework.Tests.EventStoreTests +{ + public class QueryEventsTests : EventStoreTestBase + { + public QueryEventsTests(EventStoreFixture fixture, AssemblyInitializerFixture initializer) : base(fixture, initializer) + { + _dbContext.Events.AddRange(_fixture.EventFactory.Create("stream-1", 0, + new FooEvent{Foo = "Foo"}, + new BarEvent{Bar = "Bar"}, + new FooEvent{Foo = "Baz"})); + _dbContext.Events.AddRange(_fixture.EventFactory.Create("stream-2", 0, + new FooEvent {Foo = "Boo"}, + new BarEvent {Bar = "Far"})); + _dbContext.SaveChanges(); + } + + [Theory] + [InlineData("stream-1", 3)] + [InlineData("stream-2", 2)] + public async Task ReturnsEventsFromCorrectStreamOnly(string streamId, long expectedCount) + { + var store = _fixture.BuildEventStore(_dbContext); + var events = await store.Events(streamId); + Assert.Equal(expectedCount, events.Count()); + } + + [Theory] + [InlineData("stream-1", 2)] + [InlineData("stream-2", 1)] + public async Task ReturnsEventsAccordingToQuery(string streamId, long expectedCount) + { + var store = _fixture.BuildEventStore(_dbContext); + var events = await store.Events(streamId, es => es.Where(e => e.Type == "FooEvent")); + Assert.Equal(expectedCount, events.Count()); + } + + } +} \ No newline at end of file diff --git a/src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/WriteEventTests.cs b/src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/WriteEventTests.cs index 07fa7a2..9a54208 100644 --- a/src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/WriteEventTests.cs +++ b/src/RdbmsEventStore.EntityFramework.Tests/EventStoreTests/WriteEventTests.cs @@ -9,9 +9,9 @@ namespace RdbmsEventStore.EntityFramework.Tests.EventStoreTests { - public class WriteEventTests : EventStoreTestBase + public class WriteEventTests : EventStoreTestBase { - public WriteEventTests(EventStoreFixture fixture, AssemblyInitializerFixture initializer) : base(fixture, initializer) + public WriteEventTests(EventStoreFixture fixture, AssemblyInitializerFixture initializer) : base(fixture, initializer) { } diff --git a/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreFixture.cs b/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreFixture.cs index 71ed88b..916d78a 100644 --- a/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreFixture.cs +++ b/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreFixture.cs @@ -1,25 +1,27 @@ using System; -using RdbmsEventStore.EntityFramework.Tests.TestData; using RdbmsEventStore.EventRegistry; namespace RdbmsEventStore.EntityFramework.Tests.Infrastructure { - public class EventStoreFixture + public class EventStoreFixture + where TId : IEquatable + where TStreamId : IEquatable + where TEvent : Event, new() { public EventStoreFixture() { - EventRegistry = new AssemblyEventRegistry(typeof(TestEvent), type => type.Name, type => !type.Name.StartsWith("<>")); + EventRegistry = new AssemblyEventRegistry(typeof(TEvent), type => type.Name, type => !type.Name.StartsWith("<>")); EventSerializer = new DefaultEventSerializer(); - EventFactory = new DefaultEventFactory(EventRegistry, EventSerializer); + EventFactory = new DefaultEventFactory(EventRegistry, EventSerializer); WriteLock = new WriteLock(); } public IEventRegistry EventRegistry { get; } public IEventSerializer EventSerializer { get; } - public IEventFactory EventFactory { get; } + public DefaultEventFactory EventFactory { get; } public IWriteLock WriteLock { get; } - public EntityFrameworkEventStore, TestEvent> BuildEventStore(EventStoreContext dbContext) - => new EntityFrameworkEventStore, TestEvent>(dbContext, EventFactory, WriteLock); + public EntityFrameworkEventStore, TEvent> BuildEventStore(EventStoreContext dbContext) + => new EntityFrameworkEventStore, TEvent>(dbContext, EventFactory, WriteLock); } } \ No newline at end of file diff --git a/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreTestBase.cs b/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreTestBase.cs index d3ea3cd..19a9011 100644 --- a/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreTestBase.cs +++ b/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/EventStoreTestBase.cs @@ -1,22 +1,22 @@ using System; -using RdbmsEventStore.EntityFramework.Tests.TestData; using Xunit; namespace RdbmsEventStore.EntityFramework.Tests.Infrastructure { [Collection(nameof(InMemoryDatabaseCollection))] - public class EventStoreTestBase : - IClassFixture, - IDisposable + public class EventStoreTestBase : IClassFixture>, IDisposable + where TId : IEquatable + where TStreamId : IEquatable + where TEvent : Event, new() { - protected readonly EventStoreFixture _fixture; - protected readonly EventStoreContext _dbContext; + protected readonly EventStoreFixture _fixture; + protected readonly EventStoreContext _dbContext; - public EventStoreTestBase(EventStoreFixture fixture, AssemblyInitializerFixture initializer) + public EventStoreTestBase(EventStoreFixture fixture, AssemblyInitializerFixture initializer) { EffortProviderFactory.ResetDb(); _fixture = fixture; - _dbContext = new EventStoreContext(); + _dbContext = new EventStoreContext(); } public void Dispose() diff --git a/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/SmokeTest.cs b/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/SmokeTest.cs index 5145d7a..5b211f5 100644 --- a/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/SmokeTest.cs +++ b/src/RdbmsEventStore.EntityFramework.Tests/Infrastructure/SmokeTest.cs @@ -1,10 +1,11 @@ -using Xunit; +using RdbmsEventStore.EntityFramework.Tests.TestData; +using Xunit; namespace RdbmsEventStore.EntityFramework.Tests.Infrastructure { - public class SmokeTest : EventStoreTestBase + public class SmokeTest : EventStoreTestBase { - public SmokeTest(EventStoreFixture fixture, AssemblyInitializerFixture assemblyInitializer) + public SmokeTest(EventStoreFixture fixture, AssemblyInitializerFixture assemblyInitializer) : base(fixture, assemblyInitializer) { } diff --git a/src/RdbmsEventStore.EntityFramework.Tests/TestData/EventTypes.cs b/src/RdbmsEventStore.EntityFramework.Tests/TestData/EventTypes.cs new file mode 100644 index 0000000..c0062ef --- /dev/null +++ b/src/RdbmsEventStore.EntityFramework.Tests/TestData/EventTypes.cs @@ -0,0 +1,18 @@ +using System; + +namespace RdbmsEventStore.EntityFramework.Tests.TestData +{ + public class GuidGuidEvent : Event { } + public class LongStringEvent : Event { } + public class LongLongEvent : Event { } + + public class FooEvent + { + public string Foo { get; set; } + } + + public class BarEvent + { + public string Bar { get; set; } + } +} \ No newline at end of file diff --git a/src/RdbmsEventStore.EntityFramework.Tests/TestData/FooEvent.cs b/src/RdbmsEventStore.EntityFramework.Tests/TestData/FooEvent.cs deleted file mode 100644 index 1038e62..0000000 --- a/src/RdbmsEventStore.EntityFramework.Tests/TestData/FooEvent.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace RdbmsEventStore.EntityFramework.Tests.TestData -{ - public class FooEvent - { - public string Foo { get; set; } - } - - public class BarEvent - { - public string Bar { get; set; } - } -} \ No newline at end of file diff --git a/src/RdbmsEventStore.EntityFramework.Tests/TestData/TestEvent.cs b/src/RdbmsEventStore.EntityFramework.Tests/TestData/TestEvent.cs deleted file mode 100644 index 1dbef80..0000000 --- a/src/RdbmsEventStore.EntityFramework.Tests/TestData/TestEvent.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; - -namespace RdbmsEventStore.EntityFramework.Tests.TestData -{ - public class TestEvent : Event { } -} \ No newline at end of file diff --git a/src/RdbmsEventStore.EntityFramework/EntityFrameworkEventStore.cs b/src/RdbmsEventStore.EntityFramework/EntityFrameworkEventStore.cs index 958a51d..107b77f 100644 --- a/src/RdbmsEventStore.EntityFramework/EntityFrameworkEventStore.cs +++ b/src/RdbmsEventStore.EntityFramework/EntityFrameworkEventStore.cs @@ -6,32 +6,33 @@ namespace RdbmsEventStore.EntityFramework { - public class EntityFrameworkEventStore : IEventStore + public class EntityFrameworkEventStore : IEventStore where TId : IEquatable + where TStreamId : IEquatable where TContext : DbContext, IEventDbContext - where TEvent : Event, IEvent, new() + where TEvent : Event, IEvent, new() { private readonly TContext context; - private readonly IEventFactory _eventFactory; + private readonly IEventFactory _eventFactory; private readonly IWriteLock _writeLock; - public EntityFrameworkEventStore(TContext context, IEventFactory eventFactory, IWriteLock writeLock) + public EntityFrameworkEventStore(TContext context, IEventFactory eventFactory, IWriteLock writeLock) { this.context = context; _eventFactory = eventFactory; _writeLock = writeLock; } - public Task> Events(TId streamId) => Events(streamId, query => query); + public Task> Events(TStreamId streamId) => Events(streamId, query => query); - public async Task> Events(TId streamId, Func, IQueryable> query) + public async Task> Events(TStreamId streamId, Func, IQueryable> query) => await context.Events .Where(e => e.StreamId.Equals(streamId)) .Apply(query) .AsNoTracking() .ToListAsync(); - public async Task Commit(TId streamId, long versionBefore, params object[] payloads) + public async Task Commit(TStreamId streamId, long versionBefore, params object[] payloads) { using (await _writeLock.Aquire()) { diff --git a/src/RdbmsEventStore.EntityFramework/Event.cs b/src/RdbmsEventStore.EntityFramework/Event.cs index b56d6d7..a8ecded 100644 --- a/src/RdbmsEventStore.EntityFramework/Event.cs +++ b/src/RdbmsEventStore.EntityFramework/Event.cs @@ -4,7 +4,7 @@ namespace RdbmsEventStore.EntityFramework { - public class Event : IEvent, IMutableEvent + public class Event : IEvent, IMutableEvent { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -15,7 +15,7 @@ public class Event : IEvent, IMutableEvent [Index(Order = 1)] [Required] - public TId StreamId { get; set; } + public TStreamId StreamId { get; set; } [Required] [Index(Order = 2)] diff --git a/src/RdbmsEventStore.Tests/EventCollectionTests.cs b/src/RdbmsEventStore.Tests/EventCollectionTests.cs index 81ed1ea..0d364ac 100644 --- a/src/RdbmsEventStore.Tests/EventCollectionTests.cs +++ b/src/RdbmsEventStore.Tests/EventCollectionTests.cs @@ -8,7 +8,7 @@ namespace RdbmsEventStore.Tests { public class EventCollectionTests { - private class TestEvent : IEvent + private class TestEvent : IEvent { public DateTimeOffset Timestamp { get; set; } public Guid EventId { get; set; } @@ -29,12 +29,12 @@ private static TestEvent Factory(Guid stream, long version, object payload) Payload = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload)) }; - private readonly EventCollection _collection; + private readonly EventCollection _collection; public EventCollectionTests() { var streamId = Guid.NewGuid(); - _collection = new EventCollection(streamId, 0, Factory, new { Foo = "Foo" }, new { Bar = "Bar" }); + _collection = new EventCollection(streamId, 0, Factory, new { Foo = "Foo" }, new { Bar = "Bar" }); } [Fact] diff --git a/src/RdbmsEventStore/DefaultEventFactory.cs b/src/RdbmsEventStore/DefaultEventFactory.cs index 122e6f7..5b0c553 100644 --- a/src/RdbmsEventStore/DefaultEventFactory.cs +++ b/src/RdbmsEventStore/DefaultEventFactory.cs @@ -3,8 +3,8 @@ namespace RdbmsEventStore { - public class DefaultEventFactory : IEventFactory - where TEvent : IMutableEvent, new() + public class DefaultEventFactory : IEventFactory + where TEvent : IMutableEvent, new() { private readonly IEventRegistry _registry; private readonly IEventSerializer _serializer; @@ -15,12 +15,12 @@ public DefaultEventFactory(IEventRegistry registry, IEventSerializer serializer) _serializer = serializer; } - public virtual IEnumerable Create(TId streamId, long version, params object[] payloads) + public virtual IEnumerable Create(TStreamId streamId, long version, params object[] payloads) { - return new EventCollection(streamId, version, CreateSingle, payloads); + return new EventCollection(streamId, version, CreateSingle, payloads); } - protected virtual TEvent CreateSingle(TId streamId, long version, object payload) + protected virtual TEvent CreateSingle(TStreamId streamId, long version, object payload) { return new TEvent { diff --git a/src/RdbmsEventStore/DefaultMaterializer.cs b/src/RdbmsEventStore/DefaultMaterializer.cs index 595947b..55de1b6 100644 --- a/src/RdbmsEventStore/DefaultMaterializer.cs +++ b/src/RdbmsEventStore/DefaultMaterializer.cs @@ -16,7 +16,7 @@ public DefaultMaterializer(IEventRegistry registry, IEventSerializer serializer) _serializer = serializer; } - public TState Unfold(TState initialState, IEnumerable> events, Func applicator) + public TState Unfold(TState initialState, IEnumerable> events, Func applicator) => events .Select(@event => { diff --git a/src/RdbmsEventStore/EventCollection.cs b/src/RdbmsEventStore/EventCollection.cs index 79716cc..910a9fe 100644 --- a/src/RdbmsEventStore/EventCollection.cs +++ b/src/RdbmsEventStore/EventCollection.cs @@ -5,11 +5,11 @@ namespace RdbmsEventStore { - public class EventCollection : IEnumerable where TEvent : IEvent + public class EventCollection : IEnumerable where TEvent : IEvent { private readonly IEnumerable _events; - public EventCollection(TId streamId, long currentVersion, Func factory, params object[] payloads) + public EventCollection(TStreamId streamId, long currentVersion, Func factory, params object[] payloads) { _events = payloads.Select((payload, i) => factory(streamId, currentVersion + 1 + i, payload)); } diff --git a/src/RdbmsEventStore/IEvent.cs b/src/RdbmsEventStore/IEvent.cs index 4d160ae..4aeb5f1 100644 --- a/src/RdbmsEventStore/IEvent.cs +++ b/src/RdbmsEventStore/IEvent.cs @@ -2,13 +2,13 @@ namespace RdbmsEventStore { - public interface IEvent + public interface IEvent { DateTimeOffset Timestamp { get; } TId EventId { get; } - TId StreamId { get; } + TStreamId StreamId { get; } long Version { get; } @@ -17,13 +17,13 @@ public interface IEvent byte[] Payload { get; } } - public interface IMutableEvent : IEvent + public interface IMutableEvent : IEvent { new DateTimeOffset Timestamp { get; set; } new TId EventId { get; set; } - new TId StreamId { get; set; } + new TStreamId StreamId { get; set; } new long Version { get; set; } diff --git a/src/RdbmsEventStore/IEventFactory.cs b/src/RdbmsEventStore/IEventFactory.cs index 212be69..b5dbdb1 100644 --- a/src/RdbmsEventStore/IEventFactory.cs +++ b/src/RdbmsEventStore/IEventFactory.cs @@ -2,8 +2,8 @@ namespace RdbmsEventStore { - public interface IEventFactory where TEvent : IEvent + public interface IEventFactory where TEvent : IEvent { - IEnumerable Create(TId streamId, long version, params object[] payloads); + IEnumerable Create(TStreamId streamId, long version, params object[] payloads); } } \ No newline at end of file diff --git a/src/RdbmsEventStore/IEventStore.cs b/src/RdbmsEventStore/IEventStore.cs index 2fd92a6..94acbbb 100644 --- a/src/RdbmsEventStore/IEventStore.cs +++ b/src/RdbmsEventStore/IEventStore.cs @@ -5,24 +5,27 @@ namespace RdbmsEventStore { - public interface IEventStore : IEventStream, IEventWriter + public interface IEventStore : IEventStream, IEventWriter where TId : IEquatable - where TEvent : IEvent + where TStreamId : IEquatable + where TEvent : IEvent { } - public interface IEventStream + public interface IEventStream where TId : IEquatable - where TEvent : IEvent + where TStreamId : IEquatable + where TEvent : IEvent { - Task> Events(TId streamId); + Task> Events(TStreamId streamId); - Task> Events(TId streamId, Func, IQueryable> query); + Task> Events(TStreamId streamId, Func, IQueryable> query); } - public interface IEventWriter + public interface IEventWriter where TId : IEquatable - where TEvent : IEvent + where TStreamId : IEquatable + where TEvent : IEvent { - Task Commit(TId streamId, long versionBefore, params object[] payloads); + Task Commit(TStreamId streamId, long versionBefore, params object[] payloads); } } \ No newline at end of file diff --git a/src/RdbmsEventStore/IMaterializer.cs b/src/RdbmsEventStore/IMaterializer.cs index 576de98..265dcd9 100644 --- a/src/RdbmsEventStore/IMaterializer.cs +++ b/src/RdbmsEventStore/IMaterializer.cs @@ -5,6 +5,6 @@ namespace RdbmsEventStore { public interface IMaterializer { - TState Unfold(TState initialState, IEnumerable> events, Func applicator); + TState Unfold(TState initialState, IEnumerable> events, Func applicator); } } \ No newline at end of file