public bool Equals(StoredEvent other)
        {
            if (ReferenceEquals(this, other))
                return true;
            if (ReferenceEquals(null, other))
                return false;

            return EventId.Equals(other.EventId);
        }
        public async Task StoreEvents_WillStoreMappedEvents_WhenStreamExistsAndIsNotBroken()
        {
            // arrange
            var streamId = Guid.NewGuid();
            var eventMetadata = new Metadata(streamId, typeof (TestAggregateChanged));
            var currentStreamVersion = Fixture.Create<long>();

            var event1 = Fixture
                .Build<TestAggregateChanged>()
                .With(e => e.Metadata, eventMetadata)
                .Create();
            var event2 = Fixture
                .Build<TestAggregateChanged>()
                .With(e => e.Metadata, eventMetadata)
                .Create();

            var lastStreamEvent = new StoredEvent(
                typeof (TestAggregateCreated).AssemblyQualifiedName,
                Fixture.Create<DateTime>(),
                Fixture.Create<string>(),
                Guid.NewGuid(),
                currentStreamVersion);

            A.CallTo(() => Faker.Resolve<IEventRepository>()
                .GetLast(streamId))
                .Returns(Task.FromResult(lastStreamEvent));

            var event1Serialiazed = Fixture.Create<string>();
            var event2Serialiazed = Fixture.Create<string>();

            A.CallTo(() => Faker.Resolve<IEventSerializer>()
                .Serialize(event1))
                .Returns(event1Serialiazed);

            A.CallTo(() => Faker.Resolve<IEventSerializer>()
                .Serialize(event2))
                .Returns(event2Serialiazed);

            var batchId = Guid.NewGuid();

            Faker.Provide<Func<Guid>>(() => batchId);

            var expectedEventName = typeof (TestAggregateChanged).AssemblyQualifiedName;

            var expectedEvents = new List<StoredEvent>
            {
                new StoredEvent(expectedEventName, event1.Metadata.OccorredOn, event1Serialiazed, batchId, currentStreamVersion + 1),
                new StoredEvent(expectedEventName, event2.Metadata.OccorredOn, event2Serialiazed, batchId, currentStreamVersion + 2)
            };

            var sut = Faker.Resolve<EventStore>();

            // act
            await sut
                .StoreEvents(streamId, currentStreamVersion, new DomainEvent[] { event1, event2 })
                .ConfigureAwait(false);

            // assert
            A.CallTo(() => Faker.Resolve<IEventRepository>()
                .Add(
                    streamId,
                    A<ICollection<StoredEvent>>.That.Matches(evts => expectedEvents.All(evts.Contains))))
                .MustHaveHappened(Repeated.Exactly.Once);
        }
        public void StoreEvents_WillThrowException_WhenStreamExistsAndIsBroken()
        {
            // arrange
            var streamId = Guid.NewGuid();
            var eventMetadata = new Metadata(streamId, typeof(TestAggregateChanged));
            var currentStreamVersion = Fixture.Create<long>();

            var event1 = Fixture
                .Build<TestAggregateChanged>()
                .With(e => e.Metadata, eventMetadata)
                .Create();
            var event2 = Fixture
                .Build<TestAggregateChanged>()
                .With(e => e.Metadata, eventMetadata)
                .Create();

            var lastStreamEvent = new StoredEvent(
                typeof(TestAggregateCreated).AssemblyQualifiedName,
                Fixture.Create<DateTime>(),
                Fixture.Create<string>(),
                Guid.NewGuid(),
                currentStreamVersion + 1);

            A.CallTo(() => Faker.Resolve<IEventRepository>()
                .GetLast(streamId))
                .Returns(Task.FromResult(lastStreamEvent));

            Faker.Provide<Func<Guid>>(Guid.NewGuid);
            var sut = Faker.Resolve<EventStore>();

            Func<Task> exceptionThrower = async () => await sut
                .StoreEvents(streamId, currentStreamVersion, new DomainEvent[] { event1, event2 })
                .ConfigureAwait(false);

            // act & assert
            exceptionThrower
                .ShouldThrow<InvalidOperationException>()
                .And
                .Message
                .Should()
                .Contain($"Cant add new events on version {currentStreamVersion} as current storage version is {lastStreamEvent.EventId}");

            A.CallTo(() => Faker.Resolve<IEventRepository>()
                .Add(streamId, A<ICollection<StoredEvent>>._))
                .MustNotHaveHappened();
        }
        public static async Task CreateEvent(Guid streamId, StoredEvent storedEvent)
        {
            using (var connection = new NpgsqlConnection(GetConnectionStringBuilder()))
            {
                await connection
                    .OpenAsync()
                    .ConfigureAwait(false);

                using (var command = connection.CreateCommand())
                {
                    command.CommandText = CreateEventSql;

                    command.Parameters.AddWithValue("@streamId", streamId);
                    command.Parameters.AddWithValue("@eventId", storedEvent.EventId);
                    command.Parameters.AddWithValue("@typeName", storedEvent.TypeName);
                    command.Parameters.AddWithValue("@occurredOn", storedEvent.OccurredOn);
                    command.Parameters.AddWithValue("@batchId", storedEvent.BatchId);
                    command.Parameters.AddWithValue("@body", NpgsqlDbType.Json, storedEvent.EventBody);

                    await command
                        .ExecuteNonQueryAsync()
                        .ConfigureAwait(false);
                }
            }
        }
 public Task Add(Guid streamId, StoredEvent storedEvent)
 {
     throw new NotImplementedException();
 }
        public void Add_WillThrowException_WhenStreamDoesNotExist()
        {
            // arrange
            var streamId = Fixture.Create<Guid>();

            var now = GetDateTimeToMillisecond(DateTime.UtcNow);

            var batchId = Guid.NewGuid();

            var evt1 = new StoredEvent("some type", now, "{\"prop\":\"value\"}", batchId, 1L);
            var evt2 = new StoredEvent("some type2", now, "{\"prop\":\"value1\"}", batchId, 3L);
            
            var events = new[] { evt1, evt2 };

            Func<Task> exceptionThrower = async () => await _sut
                .Add(streamId, events)
                .ConfigureAwait(false);

            // act/assert
            exceptionThrower
                .ShouldThrow<PostgresException>();
        }
        public async Task Add_WillAddEvents_ToStreamWithEvents()
        {
            // arrange
            var streamId = Fixture.Create<Guid>();
            var streamName = Fixture.Create<string>();

            await DatabaseHelper
                .CreateEventStream(streamId, streamName)
                .ConfigureAwait(false);

            var now = GetDateTimeToMillisecond(DateTime.UtcNow);

            var batchId = Guid.NewGuid();

            var evt1 = new StoredEvent("some type", now, "{\"prop\":\"value\"}", batchId, 1L);
            var evt2 = new StoredEvent("some type2", now, "{\"prop\":\"value1\"}", batchId, 2L);

            await DatabaseHelper
                .CreateEvent(streamId, evt1)
                .ConfigureAwait(false);
            await DatabaseHelper
                .CreateEvent(streamId, evt2)
                .ConfigureAwait(false);

            var batchId2 = Guid.NewGuid();

            var evtToAdd1 = new StoredEvent("some type", now.AddMinutes(2), "{\"prop\":\"value\"}", batchId2, 5L);
            var evtToAdd2 = new StoredEvent("some type2", now.AddMinutes(2), "{\"prop\":\"value1\"}", batchId2, 6L);
            var evtToAdd3 = new StoredEvent("some type", now.AddMinutes(5), "{}", batchId2, 7L);

            var eventsToAdd = new[] { evtToAdd1, evtToAdd2, evtToAdd3 };
            var events = new[] {evt1, evt2, evtToAdd1, evtToAdd2, evtToAdd3};

            // act
            await _sut
                .Add(streamId, eventsToAdd)
                .ConfigureAwait(false);

            // assert
            var actualEvents = await DatabaseHelper
                .GetStreamEvents(streamId)
                .ConfigureAwait(false);

            actualEvents
                .Should()
                .ContainInOrder(events);
        }
        public async Task GetLast_WillReturnLastEvent_WhenThereAreMultipleEvents()
        {
            // arrange
            var streamId = Fixture.Create<Guid>();
            var streamName = Fixture.Create<string>();

            await DatabaseHelper
                .CreateEventStream(streamId, streamName)
                .ConfigureAwait(false);

            var now = GetDateTimeToMillisecond(DateTime.UtcNow);

            var batchId = Guid.NewGuid();

            var event1 = new StoredEvent("some type", now, "{\"prop\":\"value\"}", batchId, 1L);
            var event2 = new StoredEvent("some type", now, "{}", batchId, 2L);

            await DatabaseHelper
                .CreateEvent(streamId, event1)
                .ConfigureAwait(false);
            await DatabaseHelper
                .CreateEvent(streamId, event2)
                .ConfigureAwait(false);

            // act
            var lastEvent = await _sut
                .GetLast(streamId)
                .ConfigureAwait(false);

            // assert
            lastEvent.ShouldBeEquivalentTo(event2);
        }
        public async Task GetSelected_WillReturnEmptyList_WhenThereAreNoEventsForSelectedBitOfStream()
        {
            // arrange
            var streamId = Fixture.Create<Guid>();
            var streamName = Fixture.Create<string>();

            await DatabaseHelper
                .CreateEventStream(streamId, streamName)
                .ConfigureAwait(false);

            var now = GetDateTimeToMillisecond(DateTime.UtcNow);
            var batchId = Guid.NewGuid();

            var event1 = new StoredEvent("some type", now, "{\"prop\":\"value\"}", batchId, 1L);
            var event2 = new StoredEvent("some type", now.AddSeconds(1), "{}", batchId, 2L);

            await DatabaseHelper
                .CreateEvent(streamId, event1)
                .ConfigureAwait(false);
            await DatabaseHelper
                .CreateEvent(streamId, event2)
                .ConfigureAwait(false);

            // act
            var events = await _sut
                .GetSelected(streamId, 3L)
                .ConfigureAwait(false);

            // assert
            events.Should().BeEmpty();
        }
        public async Task GetAll_WillReturnAllEvents_WhenThereAreEventsForStream()
        {
            // arrange
            var streamId = Fixture.Create<Guid>();
            var streamName = Fixture.Create<string>();

            var now = GetDateTimeToMillisecond(DateTime.UtcNow); 

            await DatabaseHelper
                .CreateEventStream(streamId, streamName)
                .ConfigureAwait(false);

            var batchId = Guid.NewGuid();

            var event1 = new StoredEvent("some type", now, "{\"prop\":\"value\"}", batchId, 1L);
            var event2 = new StoredEvent("some type", now.AddSeconds(1), "{}", batchId, 2L);

            await DatabaseHelper
                .CreateEvent(streamId, event1)
                .ConfigureAwait(false);
            await DatabaseHelper
                .CreateEvent(streamId, event2)
                .ConfigureAwait(false);

            var expectedEvents = new[]
            {
                event1,
                event2
            };

            // act
            var events = await _sut
                .GetAll(streamId)
                .ConfigureAwait(false);

            // assert
            events
                .Should()
                .ContainInOrder(expectedEvents);
        }