Skip to content

Commit

Permalink
Decouple id types (#19)
Browse files Browse the repository at this point in the history
* Add type argument for stream id

* Add tests for querying for events + adjust to genericity

* Increment next version
  • Loading branch information
Tomas Lycken committed Oct 4, 2017
1 parent b563da1 commit d3bf1ce
Show file tree
Hide file tree
Showing 19 changed files with 126 additions and 75 deletions.
2 changes: 1 addition & 1 deletion GitVersion.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mode: ContinuousDelivery
next-version: 0.2.0
next-version: 0.3.0
branches:
master:
tag: beta
Expand Down
Original file line number Diff line number Diff line change
@@ -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<long, string, LongStringEvent>
{
public QueryEventsTests(EventStoreFixture<long, string, LongStringEvent> 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());
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

namespace RdbmsEventStore.EntityFramework.Tests.EventStoreTests
{
public class WriteEventTests : EventStoreTestBase
public class WriteEventTests : EventStoreTestBase<Guid, Guid, GuidGuidEvent>
{
public WriteEventTests(EventStoreFixture fixture, AssemblyInitializerFixture initializer) : base(fixture, initializer)
public WriteEventTests(EventStoreFixture<Guid, Guid, GuidGuidEvent> fixture, AssemblyInitializerFixture initializer) : base(fixture, initializer)
{
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<TId, TStreamId, TEvent>
where TId : IEquatable<TId>
where TStreamId : IEquatable<TStreamId>
where TEvent : Event<TId, TStreamId>, 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<Guid, TestEvent>(EventRegistry, EventSerializer);
EventFactory = new DefaultEventFactory<TId, TStreamId, TEvent>(EventRegistry, EventSerializer);
WriteLock = new WriteLock();
}

public IEventRegistry EventRegistry { get; }
public IEventSerializer EventSerializer { get; }
public IEventFactory<Guid, TestEvent> EventFactory { get; }
public DefaultEventFactory<TId, TStreamId, TEvent> EventFactory { get; }
public IWriteLock WriteLock { get; }

public EntityFrameworkEventStore<Guid, EventStoreContext<TestEvent>, TestEvent> BuildEventStore(EventStoreContext<TestEvent> dbContext)
=> new EntityFrameworkEventStore<Guid, EventStoreContext<TestEvent>, TestEvent>(dbContext, EventFactory, WriteLock);
public EntityFrameworkEventStore<TId, TStreamId, EventStoreContext<TEvent>, TEvent> BuildEventStore(EventStoreContext<TEvent> dbContext)
=> new EntityFrameworkEventStore<TId, TStreamId, EventStoreContext<TEvent>, TEvent>(dbContext, EventFactory, WriteLock);
}
}
Original file line number Diff line number Diff line change
@@ -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<EventStoreFixture>,
IDisposable
public class EventStoreTestBase<TId, TStreamId, TEvent> : IClassFixture<EventStoreFixture<TId, TStreamId, TEvent>>, IDisposable
where TId : IEquatable<TId>
where TStreamId : IEquatable<TStreamId>
where TEvent : Event<TId, TStreamId>, new()
{
protected readonly EventStoreFixture _fixture;
protected readonly EventStoreContext<TestEvent> _dbContext;
protected readonly EventStoreFixture<TId, TStreamId, TEvent> _fixture;
protected readonly EventStoreContext<TEvent> _dbContext;

public EventStoreTestBase(EventStoreFixture fixture, AssemblyInitializerFixture initializer)
public EventStoreTestBase(EventStoreFixture<TId, TStreamId, TEvent> fixture, AssemblyInitializerFixture initializer)
{
EffortProviderFactory.ResetDb();
_fixture = fixture;
_dbContext = new EventStoreContext<TestEvent>();
_dbContext = new EventStoreContext<TEvent>();
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
@@ -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<long, long, LongLongEvent>
{
public SmokeTest(EventStoreFixture fixture, AssemblyInitializerFixture assemblyInitializer)
public SmokeTest(EventStoreFixture<long, long, LongLongEvent> fixture, AssemblyInitializerFixture assemblyInitializer)
: base(fixture, assemblyInitializer)
{
}
Expand Down
18 changes: 18 additions & 0 deletions src/RdbmsEventStore.EntityFramework.Tests/TestData/EventTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace RdbmsEventStore.EntityFramework.Tests.TestData
{
public class GuidGuidEvent : Event<Guid, Guid> { }
public class LongStringEvent : Event<long, string> { }
public class LongLongEvent : Event<long, long> { }

public class FooEvent
{
public string Foo { get; set; }
}

public class BarEvent
{
public string Bar { get; set; }
}
}
12 changes: 0 additions & 12 deletions src/RdbmsEventStore.EntityFramework.Tests/TestData/FooEvent.cs

This file was deleted.

This file was deleted.

15 changes: 8 additions & 7 deletions src/RdbmsEventStore.EntityFramework/EntityFrameworkEventStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,33 @@

namespace RdbmsEventStore.EntityFramework
{
public class EntityFrameworkEventStore<TId, TContext, TEvent> : IEventStore<TId, TEvent>
public class EntityFrameworkEventStore<TId, TStreamId, TContext, TEvent> : IEventStore<TId, TStreamId, TEvent>
where TId : IEquatable<TId>
where TStreamId : IEquatable<TStreamId>
where TContext : DbContext, IEventDbContext<TEvent>
where TEvent : Event<TId>, IEvent<TId>, new()
where TEvent : Event<TId, TStreamId>, IEvent<TId, TStreamId>, new()
{
private readonly TContext context;
private readonly IEventFactory<TId, TEvent> _eventFactory;
private readonly IEventFactory<TId, TStreamId, TEvent> _eventFactory;
private readonly IWriteLock _writeLock;

public EntityFrameworkEventStore(TContext context, IEventFactory<TId, TEvent> eventFactory, IWriteLock writeLock)
public EntityFrameworkEventStore(TContext context, IEventFactory<TId, TStreamId, TEvent> eventFactory, IWriteLock writeLock)
{
this.context = context;
_eventFactory = eventFactory;
_writeLock = writeLock;
}

public Task<IEnumerable<TEvent>> Events(TId streamId) => Events(streamId, query => query);
public Task<IEnumerable<TEvent>> Events(TStreamId streamId) => Events(streamId, query => query);

public async Task<IEnumerable<TEvent>> Events(TId streamId, Func<IQueryable<TEvent>, IQueryable<TEvent>> query)
public async Task<IEnumerable<TEvent>> Events(TStreamId streamId, Func<IQueryable<TEvent>, IQueryable<TEvent>> 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())
{
Expand Down
4 changes: 2 additions & 2 deletions src/RdbmsEventStore.EntityFramework/Event.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace RdbmsEventStore.EntityFramework
{
public class Event<TId> : IEvent<TId>, IMutableEvent<TId>
public class Event<TId, TStreamId> : IEvent<TId, TStreamId>, IMutableEvent<TId, TStreamId>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
Expand All @@ -15,7 +15,7 @@ public class Event<TId> : IEvent<TId>, IMutableEvent<TId>

[Index(Order = 1)]
[Required]
public TId StreamId { get; set; }
public TStreamId StreamId { get; set; }

[Required]
[Index(Order = 2)]
Expand Down
6 changes: 3 additions & 3 deletions src/RdbmsEventStore.Tests/EventCollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace RdbmsEventStore.Tests
{
public class EventCollectionTests
{
private class TestEvent : IEvent<Guid>
private class TestEvent : IEvent<Guid, Guid>
{
public DateTimeOffset Timestamp { get; set; }
public Guid EventId { get; set; }
Expand All @@ -29,12 +29,12 @@ private static TestEvent Factory(Guid stream, long version, object payload)
Payload = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload))
};

private readonly EventCollection<Guid, TestEvent> _collection;
private readonly EventCollection<Guid, Guid, TestEvent> _collection;

public EventCollectionTests()
{
var streamId = Guid.NewGuid();
_collection = new EventCollection<Guid, TestEvent>(streamId, 0, Factory, new { Foo = "Foo" }, new { Bar = "Bar" });
_collection = new EventCollection<Guid, Guid, TestEvent>(streamId, 0, Factory, new { Foo = "Foo" }, new { Bar = "Bar" });
}

[Fact]
Expand Down
10 changes: 5 additions & 5 deletions src/RdbmsEventStore/DefaultEventFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

namespace RdbmsEventStore
{
public class DefaultEventFactory<TId, TEvent> : IEventFactory<TId, TEvent>
where TEvent : IMutableEvent<TId>, new()
public class DefaultEventFactory<TId, TStreamId, TEvent> : IEventFactory<TId, TStreamId, TEvent>
where TEvent : IMutableEvent<TId, TStreamId>, new()
{
private readonly IEventRegistry _registry;
private readonly IEventSerializer _serializer;
Expand All @@ -15,12 +15,12 @@ public DefaultEventFactory(IEventRegistry registry, IEventSerializer serializer)
_serializer = serializer;
}

public virtual IEnumerable<TEvent> Create(TId streamId, long version, params object[] payloads)
public virtual IEnumerable<TEvent> Create(TStreamId streamId, long version, params object[] payloads)
{
return new EventCollection<TId, TEvent>(streamId, version, CreateSingle, payloads);
return new EventCollection<TId, TStreamId, TEvent>(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
{
Expand Down
2 changes: 1 addition & 1 deletion src/RdbmsEventStore/DefaultMaterializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public DefaultMaterializer(IEventRegistry registry, IEventSerializer serializer)
_serializer = serializer;
}

public TState Unfold<TState, TId>(TState initialState, IEnumerable<IEvent<TId>> events, Func<TState, object, TState> applicator)
public TState Unfold<TState, TId, TStreamId>(TState initialState, IEnumerable<IEvent<TId, TStreamId>> events, Func<TState, object, TState> applicator)
=> events
.Select(@event =>
{
Expand Down
4 changes: 2 additions & 2 deletions src/RdbmsEventStore/EventCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

namespace RdbmsEventStore
{
public class EventCollection<TId, TEvent> : IEnumerable<TEvent> where TEvent : IEvent<TId>
public class EventCollection<TId, TStreamId, TEvent> : IEnumerable<TEvent> where TEvent : IEvent<TId, TStreamId>
{
private readonly IEnumerable<TEvent> _events;

public EventCollection(TId streamId, long currentVersion, Func<TId, long, object, TEvent> factory, params object[] payloads)
public EventCollection(TStreamId streamId, long currentVersion, Func<TStreamId, long, object, TEvent> factory, params object[] payloads)
{
_events = payloads.Select((payload, i) => factory(streamId, currentVersion + 1 + i, payload));
}
Expand Down
8 changes: 4 additions & 4 deletions src/RdbmsEventStore/IEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

namespace RdbmsEventStore
{
public interface IEvent<out TId>
public interface IEvent<out TId, out TStreamId>
{
DateTimeOffset Timestamp { get; }

TId EventId { get; }

TId StreamId { get; }
TStreamId StreamId { get; }

long Version { get; }

Expand All @@ -17,13 +17,13 @@ public interface IEvent<out TId>
byte[] Payload { get; }
}

public interface IMutableEvent<TId> : IEvent<TId>
public interface IMutableEvent<TId, TStreamId> : IEvent<TId, TStreamId>
{
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; }

Expand Down
4 changes: 2 additions & 2 deletions src/RdbmsEventStore/IEventFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace RdbmsEventStore
{
public interface IEventFactory<in TId, out TEvent> where TEvent : IEvent<TId>
public interface IEventFactory<in TId, in TStreamId, out TEvent> where TEvent : IEvent<TId, TStreamId>
{
IEnumerable<TEvent> Create(TId streamId, long version, params object[] payloads);
IEnumerable<TEvent> Create(TStreamId streamId, long version, params object[] payloads);
}
}
Loading

0 comments on commit d3bf1ce

Please sign in to comment.