Пример #1
0
        public void When_the_EventStoreDbContext_seeds_it_calls_the_specified_seed_action_if_it_has_been_set()
        {
            var numberOfEventsToSeed = Any.PositiveInt(100);
            var methodName = MethodBase.GetCurrentMethod().Name;

            var eventStoreInitializer1 = new EventStoreDatabaseInitializer<EventStoreDbContext>();
            eventStoreInitializer1.OnSeed = ctx =>
            {
                var aggregateId = Guid.NewGuid();
                Enumerable.Range(20, numberOfEventsToSeed)
                          .ForEach(i => ctx.Events.Add(new StorableEvent
                          {
                              AggregateId = aggregateId,
                              SequenceNumber = i,
                              Body = "test event!",
                              StreamName = GetType().Name,
                              Type = methodName
                          }));
            };

            using (var eventStore = new EventStoreDbContext())
            {
                eventStoreInitializer1.InitializeDatabase(eventStore);
                eventStore.Events.Count().Should().Be(numberOfEventsToSeed);
            }
        }
Пример #2
0
        public void RelatedEvents_handles_circular_references()
        {
            var relatedId1 = Any.Guid();
            var relatedId2 = Any.Guid();
            var relatedId3 = Any.Guid();

            Console.WriteLine(new
            {
                relatedId1,
                relatedId2,
                relatedId3,
            }.ToLogString());

            using (var db = new EventStoreDbContext())
            {
                db.Events.Add(new StorableEvent
                {
                    AggregateId    = relatedId1,
                    SequenceNumber = 1,
                    Body           = new { relatedId2 }.ToJson(),
                    Timestamp      = Clock.Now(),
                    StreamName     = "one",
                    Type           = "Event"
                });

                db.Events.Add(new StorableEvent
                {
                    AggregateId    = relatedId2,
                    SequenceNumber = 1,
                    Body           = new { relatedId3 }.ToJson(),
                    Timestamp      = Clock.Now(),
                    StreamName     = "two",
                    Type           = "Event"
                });

                db.Events.Add(new StorableEvent
                {
                    AggregateId    = relatedId3,
                    SequenceNumber = 1,
                    Body           = new { relatedId1 }.ToJson(),
                    Timestamp      = Clock.Now(),
                    StreamName     = "three",
                    Type           = "Event"
                });

                db.SaveChanges();
            }

            // assert
            using (var db = new EventStoreDbContext())
            {
                var events = db.Events.RelatedEvents(relatedId1).ToArray();

                events.Count().Should().Be(3);
                events.Should().Contain(e => e.AggregateId == relatedId1);
                events.Should().Contain(e => e.AggregateId == relatedId2);
                events.Should().Contain(e => e.AggregateId == relatedId3);
            }
        }
Пример #3
0
 private EventStore(IDomainEventDispatcher domainEventDispatcher)
 {
     _eventStoreContext = new EventStoreDbContext(new DbContextOptionsBuilder <EventStoreDbContext>()
                                                  .UseInMemoryDatabase(databaseName: "EventStore")
                                                  .EnableSensitiveDataLogging()
                                                  .Options);
     _domainEventDispatcher = domainEventDispatcher;
 }
 public void event_store_type_and_id_are_indexed()
 {
     using (var context = new EventStoreDbContext())
     {
         var result = context.QueryDynamic(@"SELECT * FROM sys.indexes WHERE name='IX_Id_and_Type' AND object_id = OBJECT_ID('eventstore.events')").Single();
         result.Should().NotBeEmpty();
     }
 }
Пример #5
0
 protected override async Task DeleteEventsFromEventStore(Guid aggregateId)
 {
     using (var db = new EventStoreDbContext())
     {
         db.Database.ExecuteSqlCommand(string.Format("DELETE FROM EventStore.Events WHERE AggregateId = '{0}'", aggregateId));
         await db.SaveChangesAsync();
     }
 }
 private List <Event> ExtractEventsFromChangeTracker(EventStoreDbContext ctx)
 {
     return(ctx.ChangeTracker
            .Entries()
            .Where(e => e.State != EntityState.Deleted && e.State != EntityState.Detached && e.Entity is Event)
            .Select(e => (Event)e.Entity)
            .WhereNotNull()
            .ToList());
 }
 public void event_store_etag_is_nullable()
 {
     using (var context = new EventStoreDbContext())
     {
         var  result      = context.QueryDynamic(@"SELECT * FROM sys.columns WHERE name='ETag' AND object_id = OBJECT_ID('eventstore.events')").Single();
         bool is_nullable = result.Single().is_nullable;
         is_nullable.Should().BeTrue();
     }
 }
Пример #8
0
 public IntegrationEventLogService(DbConnection dbConnection)
 {
     _dbConnection      = dbConnection ?? throw new ArgumentNullException("dbConnection");
     _eventStoreContext = new EventStoreDbContext(
         new DbContextOptionsBuilder <EventStoreDbContext>()
         .UseMySql(_dbConnection)
         .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning))
         .Options);
 }
Пример #9
0
        private EventStore(IProjectorHost projectorHost, IDomainEventDispatcher domainEventDispatcher)
        {
            _eventStoreContext = new EventStoreDbContext(new DbContextOptionsBuilder <EventStoreDbContext>()
                                                         .UseInMemoryDatabase(databaseName: "EventStore")
                                                         .EnableSensitiveDataLogging()
                                                         .Options);

            (_projectorHost, _domainEventDispatcher) = (projectorHost, domainEventDispatcher);
        }
Пример #10
0
 private void CleanDatabases()
 {
     using (var ctx = new EventStoreDbContext(GetDbOptions()))
     {
         ctx.RemoveRange(ctx.Set <Event>());
         ctx.RemoveRange(ctx.Set <Snapshot>());
         ctx.SaveChanges();
     }
 }
Пример #11
0
        public void Init()
        {
            EventStoreDbContext.NameOrConnectionString =
                @"Data Source=(localdb)\v11.0; Integrated Security=True; MultipleActiveResultSets=False; Initial Catalog=ItsCqrsTestsEventStore";

            using (var eventStore = new EventStoreDbContext())
            {
                new EventStoreDatabaseInitializer <EventStoreDbContext>().InitializeDatabase(eventStore);
            }
        }
Пример #12
0
 public void Dispose()
 {
     using (var context = new EventStoreDbContext(this.connectionString))
     {
         if (context.Database.Exists())
         {
             context.Database.Delete();
         }
     }
 }
        public void EventStore_polling_continues_even_if_connection_gets_closed_during_replay()
        {
            Events.Write(3);
            var scheduler = new TestScheduler();

            var projector = new Projector <Order.ItemAdded>(() => new ReadModels1DbContext())
            {
                OnUpdate = (work, e) => { }
            };

            var statusReports = new List <ReadModelCatchupStatus>();
            var catchup       = CreateReadModelCatchup <ReadModels1DbContext>(projector);

            DbConnection dbConnection = new SqlConnection();

            catchup.CreateEventStoreDbContext = () =>
            {
                var context = new EventStoreDbContext();
                dbConnection = ((IObjectContextAdapter)context).ObjectContext.Connection;
                return(context);
            };

            using (catchup)
            {
                catchup.Progress
                .ForEachAsync(s =>
                {
                    Console.WriteLine(s);
                    if (!s.IsStartOfBatch && !s.IsEndOfBatch)
                    {
                        Console.WriteLine("closing the connection");
                        // close the connection
                        dbConnection.Close();
                    }
                    statusReports.Add(s);
                });

                catchup.PollEventStore(TimeSpan.FromSeconds(5), scheduler);

                // Advance to trigger the first catchup
                scheduler.AdvanceBy(TimeSpan.FromSeconds(5).Ticks);

                // Trigger an empty batch replay
                scheduler.AdvanceBy(TimeSpan.FromSeconds(5).Ticks);

                Events.Write(2);

                // Advance to trigger the polling catchup
                scheduler.AdvanceBy(TimeSpan.FromSeconds(9).Ticks);

                statusReports.Count(s => s.IsStartOfBatch)
                .Should()
                .Be(3);
            }
        }
Пример #14
0
        private async Task <AggregateState> GetRehydratedAggregateStateAsync(
            object aggregateId,
            Type aggregateType,
            EventStoreDbContext externalCtx = null)
        {
            List <IDomainEvent> events = new List <IDomainEvent>();

#if NETSTANDARD2_0
            events = await
                     GetAllEventsByAggregateId(aggregateType, aggregateId)
                     .ToList().ConfigureAwait(false);
#elif NETSTANDARD2_1
            await foreach (var @event in GetAllEventsByAggregateId(aggregateType, aggregateId))
            {
                events.Add(@event);
            }
#endif
            if (externalCtx != null)
            {
                var eventsInChangeTracker = ExtractEventsFromChangeTracker(externalCtx).Select(GetRehydratedEventFromDbEvent);
                events = events.Concat(eventsInChangeTracker).OrderBy(s => s.Sequence).ToList();
            }
            Snapshot snapshot = null;
            using (var ctx = new EventStoreDbContext(_dbContextOptions, _archiveBehavior))
            {
                var hashedAggregateId = aggregateId.ToJson(true).GetHashCode();
                snapshot = await ctx.Set <Snapshot>()
                           .Where(t => t.AggregateType == aggregateType.AssemblyQualifiedName && t.HashedAggregateId == hashedAggregateId)
                           .FirstOrDefaultAsync().ConfigureAwait(false);
            }

            PropertyInfo   stateProp  = aggregateType.GetAllProperties().FirstOrDefault(p => p.PropertyType.IsSubclassOf(typeof(AggregateState)));
            FieldInfo      stateField = aggregateType.GetAllFields().FirstOrDefault(f => f.FieldType.IsSubclassOf(typeof(AggregateState)));
            Type           stateType  = stateProp?.PropertyType ?? stateField?.FieldType;
            AggregateState state      = null;
            if (stateType != null)
            {
                if (snapshot != null)
                {
                    state = snapshot.SnapshotData.FromJson(stateType) as AggregateState;
                }
                else
                {
                    state = stateType.CreateInstance() as AggregateState;
                }
            }
            else
            {
                throw new InvalidOperationException("EFEventStore.GetRehydratedAggregateAsync() : Cannot find property/field that manage state for aggregate" +
                                                    $" type {aggregateType.FullName}. State should be a property or a field of the aggregate");
            }

            state.ApplyRange(events);
            return(state);
        }
        public InProcessEventStreamReaderTestsFixture()
        {
            var options = new DbContextOptionsBuilder <EventStoreDbContext>()
                          .UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=EventStreamReadersIntegrationTests;Integrated Security=False")
                          .Options;

            using (var dbContext = new EventStoreDbContext(options))
            {
                DatabaseSeeder.Seed(dbContext);
            }
        }
 public MySqlEventStore(
     IdentityAccessDbContext context
     )
 {
     _context             = context ?? throw new ArgumentNullException(nameof(context));
     _eventStoreDbContext = new EventStoreDbContext(
         new DbContextOptionsBuilder <EventStoreDbContext>()
         .UseMySql(_context.Database.GetDbConnection())
         .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning))
         .Options);
 }
        private async Task ManageSnapshotBehavior(
            IDomainEvent @event,
            EventStoreDbContext ctx,
            int hashedAggregateId)
        {
            bool IsSnaphostEnabled()
            {
                return(_snapshotBehaviorProvider != null &&
                       _archiveBehavior != SnapshotEventsArchiveBehavior.Disabled);
            }

            if (@event.AggregateId != null && @event.AggregateType != null)
            {
                var evtType = @event.GetType();
                if (IsSnaphostEnabled())
                {
                    var behavior = _snapshotBehaviorProvider !.GetBehaviorForEventType(evtType);
                    if (behavior?.IsSnapshotNeeded(@event) == true)
                    {
                        var aggState = await GetRehydratedAggregateStateAsync(@event.AggregateId, @event.AggregateType, ctx)
                                       .ConfigureAwait(false);

                        var eventsToArchive = behavior.GenerateSnapshot(aggState);

                        if (eventsToArchive?.Any() == true)
                        {
                            if (aggState != null)
                            {
                                var previousSnapshot = await ctx
                                                       .Set <Snapshot>()
                                                       .FirstOrDefaultAsync(s =>
                                                                            s.HashedAggregateId == hashedAggregateId &&
                                                                            s.AggregateType == @event.AggregateType.AssemblyQualifiedName)
                                                       .ConfigureAwait(false);

                                if (previousSnapshot != null)
                                {
                                    ctx.Remove(previousSnapshot);
                                }
                                ctx.Add(new Snapshot
                                {
                                    AggregateType        = @event.AggregateType.AssemblyQualifiedName,
                                    HashedAggregateId    = hashedAggregateId,
                                    SnapshotBehaviorType = behavior.GetType().AssemblyQualifiedName,
                                    SnapshotTime         = DateTime.Now,
                                    SnapshotData         = aggState.ToJson(new AggregateStateSerialisationContract())
                                });
                            }
                            await StoreArchiveEventsAsync(eventsToArchive, ctx).ConfigureAwait(false);
                        }
                    }
                }
            }
        }
        public MySqlEventStore(DbConnection dbConnection, IEventPublisher publisher)
        {
            _dbConnection      = dbConnection ?? throw new ArgumentNullException("dbConnection");
            _eventStoreContext = new EventStoreDbContext(
                new DbContextOptionsBuilder <EventStoreDbContext>()
                .UseMySql(_dbConnection)
                .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning))
                .Options);

            _publisher = publisher ?? throw new ArgumentNullException(nameof(publisher));
        }
Пример #19
0
        public EventStoreDbTest()
        {
            Logging.Configure();

            SetConnectionStrings();

            Command <Order> .AuthorizeDefault           = (order, command) => true;
            Command <CustomerAccount> .AuthorizeDefault = (order, command) => true;

            lock (lockObj)
            {
                if (databasesInitialized)
                {
                    return;
                }

                // TODO: (EventStoreDbTest) figure out a db cleanup story
//#if !DEBUG
//            new EventStoreDbContext().Database.Delete();
//            new OtherEventStoreDbContext().Database.Delete();
//            new ReadModelDbContext().Database.Delete();
//            new ReadModels1DbContext().Database.Delete();
//            new ReadModels2DbContext().Database.Delete();
//            new CommandSchedulerDbContext().Database.Delete();
//#endif

                using (var eventStore = new EventStoreDbContext())
                {
                    new EventStoreDatabaseInitializer <EventStoreDbContext>().InitializeDatabase(eventStore);
                }
                using (var db = new CommandSchedulerDbContext())
                {
                    new CommandSchedulerDatabaseInitializer().InitializeDatabase(db);
                }
                using (var eventStore = new OtherEventStoreDbContext())
                {
                    new EventStoreDatabaseInitializer <OtherEventStoreDbContext>().InitializeDatabase(eventStore);
                }
                using (var db = new ReadModelDbContext())
                {
                    new ReadModelDatabaseInitializer <ReadModelDbContext>().InitializeDatabase(db);
                }
                using (var db = new ReadModels1DbContext())
                {
                    new ReadModelDatabaseInitializer <ReadModels1DbContext>().InitializeDatabase(db);
                }
                using (var db = new ReadModels2DbContext())
                {
                    new ReadModelDatabaseInitializer <ReadModels2DbContext>().InitializeDatabase(db);
                }

                databasesInitialized = true;
            }
        }
Пример #20
0
 public static async Task SaveToEventStore <TAggregate>(this TAggregate aggregate) where TAggregate : EventSourcedAggregate
 {
     using (var db = new EventStoreDbContext())
     {
         foreach (var e in aggregate.EventHistory.OfType <IEvent <TAggregate> >())
         {
             var storableEvent = e.ToStorableEvent();
             db.Events.Add(storableEvent);
         }
         await db.SaveChangesAsync();
     }
 }
Пример #21
0
 public IAsyncEnumerable <IDomainEvent> GetAllEventsByEventType(Type eventType)
 {
     using (var ctx = new EventStoreDbContext(_dbContextOptions))
     {
         var dbEvents = ctx
                        .Set <Event>()
                        .AsNoTracking()
                        .Where(c => c.EventType == eventType.AssemblyQualifiedName)
                        .ToList();
         return(dbEvents.Select(GetRehydratedEventFromDbEvent).ToAsyncEnumerable());
     }
 }
        private async Task StoreArchiveEventsAsync(IEnumerable <IDomainEvent> archiveEvents, EventStoreDbContext externalCtx)
        {
            switch (_archiveBehavior)
            {
            case SnapshotEventsArchiveBehavior.StoreToNewTable:
                using (var ctx = new EventStoreDbContext(_dbContextOptions))
                {
                    ctx.AddRange(archiveEvents.Select(GetArchiveEventFromIDomainEvent).ToList());
                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
                break;

            case SnapshotEventsArchiveBehavior.StoreToNewDatabase:
                if (_archiveBehaviorDbContextOptions != null)
                {
                    using (var ctx = new ArchiveEventStoreDbContext(_archiveBehaviorDbContextOptions))
                    {
                        ctx.AddRange(
                            archiveEvents.Select(GetArchiveEventFromIDomainEvent));
                        await ctx.SaveChangesAsync().ConfigureAwait(false);
                    }
                }
                else
                {
                    throw new InvalidOperationException("EFEventStore.StoreDomainEventAsync() : Snapshot will be created and event to archive cannot be saved because DbContextOptions for archive database weren't provided during configuration on Bootstrapper. Either specify DbContextOptions for event's archive database or change archive behavior");
                }
                break;
            }
            var eventsInContext = externalCtx
                                  .ChangeTracker
                                  .Entries()
                                  .Where(e => e.State != EntityState.Detached && e.State != EntityState.Deleted)
                                  .Select(e => e.Entity as Event)
                                  .WhereNotNull()
                                  .Where(e => archiveEvents.Any(ev => ev.Id == e !.Id))
                                  .ToList();

            if (eventsInContext.Count > 0)
            {
                eventsInContext.DoForEach(e => externalCtx.Entry(e).State = EntityState.Detached);
            }
            using (var ctx = new EventStoreDbContext(_dbContextOptions))
            {
                var archiveEventsIds = archiveEvents.Select(e => e.Id).ToList();
                var events           = await ctx.Set <Event>().Where(e => archiveEventsIds.Contains(e.Id)).ToListAsync().ConfigureAwait(false);

                if (events.Count > 0)
                {
                    ctx.RemoveRange(events);
                    await ctx.SaveChangesAsync().ConfigureAwait(false);
                }
            }
        }
Пример #23
0
        internal static void CreateDatabase(DatabaseType databaseType)
        {
            var options =
                databaseType == DatabaseType.SQLite
                ? new DbContextOptionsBuilder <EventStoreDbContext>().UseSqlite(GetConnectionString_SQLite()).Options
                : new DbContextOptionsBuilder <EventStoreDbContext>().UseSqlServer(GetConnectionString_SQLServer()).Options;

            using (var ctx = new EventStoreDbContext(options))
            {
                ctx.Database.EnsureDeleted();
                ctx.Database.EnsureCreated();
            }
        }
Пример #24
0
        private static void CreateDb()
        {
            Console.WriteLine("Creating Db...");
            using (var context = new EventStoreDbContext(FixedConnectionstring))
            {
                context.Database.Create();

                Console.WriteLine("Db created");
                Console.WriteLine("Adding subscriptions...");
                // promo
                AddSubscriptions(context);
            }
        }
Пример #25
0
 protected override void SaveEventsDirectly(params object[] events)
 {
     using (var db = new EventStoreDbContext())
     {
         events
         .Select(e => e.IfTypeIs <StorableEvent>()
                 .Else(() => e.IfTypeIs <IEvent>()
                       .Then(ee => ee.ToStorableEvent()))
                 .ElseDefault())
         .ForEach(e => { db.Events.Add(e); });
         db.SaveChanges();
     }
 }
Пример #26
0
 public IAsyncEnumerable <T> GetAllEventsByEventType <T>()
     where T : class, IDomainEvent
 {
     using (var ctx = new EventStoreDbContext(_dbContextOptions))
     {
         var dbEvents = ctx
                        .Set <Event>()
                        .AsNoTracking()
                        .Where(c => c.EventType == typeof(T).AssemblyQualifiedName)
                        .ToList();
         return(dbEvents.Select(e => GetRehydratedEventFromDbEvent(e) as T).WhereNotNull().ToAsyncEnumerable());
     }
 }
Пример #27
0
        static public void Initialize()
        {
            var options = new DbContextOptionsBuilder <EventStoreDbContext>()
                          .UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=EventStreamReactiveObservablesExample;Integrated Security=False")
                          .Options;

            using (var dbContext = new EventStoreDbContext(options))
            {
                dbContext.Database.EnsureDeleted();
                dbContext.Database.EnsureCreated();

                DatabaseSeeder.Seed(dbContext);
            }
        }
Пример #28
0
 public IAsyncEnumerable <IDomainEvent> GetAllEventsByAggregateId(Type aggregateType, object aggregateId)
 {
     using (var ctx = new EventStoreDbContext(_dbContextOptions))
     {
         var dbEvents = ctx
                        .Set <Event>()
                        .AsNoTracking()
                        .Where(c => c.AggregateType == aggregateType.AssemblyQualifiedName &&
                               c.AggregateIdType == aggregateId.GetType().AssemblyQualifiedName &&
                               c.HashedAggregateId == aggregateId.ToJson(true).GetHashCode())
                        .ToList();
         return(dbEvents.Select(GetRehydratedEventFromDbEvent).ToAsyncEnumerable());
     }
 }
Пример #29
0
        public void SeedFromFile_can_be_used_to_seed_the_event_store_from_config()
        {
            eventStoreInitializer.OnSeed = ctx =>
            {
                var file = Settings.GetFile(f => f.Name == "Events.json");
                ctx.SeedFromFile(file);
            };

            using (var eventStore = new EventStoreDbContext())
            {
                eventStoreInitializer.InitializeDatabase(eventStore);

                eventStore.Events.Count().Should().Be(8);
            }
        }
Пример #30
0
 public async IAsyncEnumerable <IDomainEvent> GetAllEventsByAggregateType(Type aggregateType)
 {
     using (var ctx = new EventStoreDbContext(_dbContextOptions))
     {
         var dbEvents = ctx
                        .Set <Event>()
                        .AsNoTracking()
                        .Where(c => c.AggregateType == aggregateType.AssemblyQualifiedName)
                        .AsAsyncEnumerable();
         await foreach (var @event in dbEvents)
         {
             yield return(GetRehydratedEventFromDbEvent(@event));
         }
     }
 }
Пример #31
0
        public void SeedFromFile_can_be_used_to_seed_the_event_store_from_config()
        {
            var eventStoreInitializer1 = new EventStoreDatabaseInitializer<EventStoreDbContext>();
            eventStoreInitializer1.OnSeed = ctx =>
            {
                var file = Settings.GetFile(f => f.Name == "Events.json");
                ctx.SeedFromFile(file);
            };

            using (var eventStore = new EventStoreDbContext())
            {
                eventStoreInitializer1.InitializeDatabase(eventStore);

                eventStore.Events.Count().Should().Be(8);
            }
        }
Пример #32
0
        public static AppDbContext WithDefaults()
        {
            var options = new DbContextOptionsBuilder()
                          .UseInMemoryDatabase($"{Guid.NewGuid()}")
                          .Options;

            var context      = new EventStoreDbContext(options);
            var dateTime     = new MachineDateTime();
            var eventStore   = new EventStore(context, dateTime, new TestCorrelationIdAccessor(Guid.NewGuid()));
            var aggregateSet = new AggregateSet(context, dateTime);

            var appDbContext = new AppDbContext(eventStore, aggregateSet);

            DbInitializer.Initialize(appDbContext, ConfigurationFactory.Create());

            appDbContext.SaveChangesAsync(default).GetAwaiter().GetResult();
        public async Task AzureSqlDatabase_can_be_configured_using_a_migration()
        {
            var databaseSettings = Settings.Get<AzureSqlDatabaseSettings>();
            databaseSettings.DatabaseName = "ItsCqrsMigrationsTest";
            var connectionString = databaseSettings.BuildConnectionString();

            using (var context = new EventStoreDbContext(connectionString))
            {
                new EventStoreDatabaseInitializer<EventStoreDbContext>().InitializeDatabase(context);

                var migrator = new AzureSqlDbMigrator(
                    "S0",
                    "10 GB",
                    new Version("0.0.42.1"));
                context.EnsureDatabaseIsUpToDate(migrator);

                context.OpenConnection()
                       .GetAppliedMigrationVersions()
                       .Should()
                       .Contain("0.0.42.1");
            }
        }
        public void AzureSqlDatabase_EventStore_can_be_configured_using_a_migration()
        {
            var databaseSettings = Settings.Get<AzureSqlDatabaseSettings>();
            databaseSettings.DatabaseName = "ItsCqrsMigrationsTestEventStore";
            var connectionString = databaseSettings.BuildConnectionString();

            using (var context = new EventStoreDbContext(connectionString))
            {
                new EventStoreDatabaseInitializer<EventStoreDbContext>().InitializeDatabase(context);

                var migrator = new AzureSqlDbMigrator(
                    serviceObjective: "S0",
                    edition: "standard",
                    maxSize: "500 MB",
                    migrationVersion: new Version("0.0.42.1"));

                context.EnsureDatabaseIsUpToDate(migrator);

                context.OpenConnection()
                       .GetLatestAppliedMigrationVersions()
                       .Should()
                       .Contain(v => v.MigrationVersion.ToString() == "0.0.42.1");
            }
        }
        public async Task RelatedEvents_can_return_several_nonintersecting_graphs_at_once()
        {
            var graph1Id1 = Any.Guid();
            var graph1Id2 = Any.Guid();
            var graph2Id1 = Any.Guid();
            var graph2Id2 = Any.Guid();

            Console.WriteLine(new
            {
                graph1Id1,
                graph1Id2,
                graph2Id1,
                graph2Id2
            }.ToLogString());

            using (var db = new EventStoreDbContext())
            {
                db.Events.Add(new StorableEvent
                {
                    AggregateId = graph1Id1,
                    SequenceNumber = 1,
                    Body = new { graph1Id2 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "one",
                    Type = "Event"
                });

                db.Events.Add(new StorableEvent
                {
                    AggregateId = graph1Id2,
                    SequenceNumber = 1,
                    Body = new { }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "one",
                    Type = "Event"
                });

                db.Events.Add(new StorableEvent
                {
                    AggregateId = graph2Id1,
                    SequenceNumber = 1,
                    Body = new { graph2Id2 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "two",
                    Type = "Event"
                });
                db.Events.Add(new StorableEvent
                {
                    AggregateId = graph2Id2,
                    SequenceNumber = 1,
                    Body = new { }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "two",
                    Type = "Event"
                });

                db.SaveChanges();
            }

            // assert
            using (var db = new EventStoreDbContext())
            {
                var events = (await db.Events.RelatedEvents(graph1Id1, graph2Id1)).ToArray();

                events.Count().Should().Be(4);
                events.Should().Contain(e => e.AggregateId == graph1Id1);
                events.Should().Contain(e => e.AggregateId == graph1Id2);
                events.Should().Contain(e => e.AggregateId == graph2Id1);
                events.Should().Contain(e => e.AggregateId == graph2Id2);
            }
        }
        public async Task RelatedEvents_handles_circular_references()
        {
            var relatedId1 = Any.Guid();
            var relatedId2 = Any.Guid();
            var relatedId3 = Any.Guid();
            Console.WriteLine(new
            {
                relatedId1,
                relatedId2,
                relatedId3,
            }.ToLogString());

            using (var db = new EventStoreDbContext())
            {
                db.Events.Add(new StorableEvent
                {
                    AggregateId = relatedId1,
                    SequenceNumber = 1,
                    Body = new { relatedId2 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "one",
                    Type = "Event"
                });

                db.Events.Add(new StorableEvent
                {
                    AggregateId = relatedId2,
                    SequenceNumber = 1,
                    Body = new { relatedId3 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "two",
                    Type = "Event"
                });

                db.Events.Add(new StorableEvent
                {
                    AggregateId = relatedId3,
                    SequenceNumber = 1,
                    Body = new { relatedId1 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "three",
                    Type = "Event"
                });

                db.SaveChanges();
            }

            // assert
            using (var db = new EventStoreDbContext())
            {
                var events = (await db.Events.RelatedEvents(relatedId1)).ToArray();

                events.Count().Should().Be(3);
                events.Should().Contain(e => e.AggregateId == relatedId1);
                events.Should().Contain(e => e.AggregateId == relatedId2);
                events.Should().Contain(e => e.AggregateId == relatedId3);
            }
        }
        public async Task RelatedEvents_returns_all_events_in_related_aggregates()
        {
            // arrange
            var relatedId1 = Any.Guid();
            var relatedId2 = Any.Guid();
            var relatedId3 = Any.Guid();
            var relatedId4 = Any.Guid();
            var unrelatedId = Any.Guid();

            Console.WriteLine(new
            {
                relatedId1,
                relatedId2,
                relatedId3,
                relatedId4,
                unrelatedId
            }.ToLogString());

            using (var db = new EventStoreDbContext())
            {
                Enumerable.Range(1, 20).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = relatedId1,
                    SequenceNumber = i,
                    Body = new { relatedId2 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "one",
                    Type = "Event" + i.ToString()
                }));

                Enumerable.Range(1, 20).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = relatedId2,
                    SequenceNumber = i,
                    Body = new { relatedId3 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "two",
                    Type = "Event" + i.ToString()
                }));

                Enumerable.Range(1, 20).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = relatedId3,
                    SequenceNumber = i,
                    Body = new { relatedId4 }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "three",
                    Type = "Event" + i.ToString()
                }));

                Enumerable.Range(1, 20).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = relatedId4,
                    SequenceNumber = i,
                    Body = new { }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "three",
                    Type = "Event" + i.ToString()
                }));

                Enumerable.Range(1, 20).ForEach(i => db.Events.Add(new StorableEvent
                {
                    AggregateId = unrelatedId,
                    SequenceNumber = i,
                    Body = new { }.ToJson(),
                    Timestamp = Clock.Now(),
                    StreamName = "three",
                    Type = "Event" + i.ToString()
                }));

                db.SaveChanges();
            }

            using (var db = new EventStoreDbContext())
            {
                //act
                var events = (await db.Events.RelatedEvents(relatedId1)).ToArray();

                // assert
                events.Count().Should().Be(80);
                events.Should().Contain(e => e.AggregateId == relatedId1);
                events.Should().Contain(e => e.AggregateId == relatedId2);
                events.Should().Contain(e => e.AggregateId == relatedId3);
                events.Should().Contain(e => e.AggregateId == relatedId4);
                events.Should().NotContain(e => e.AggregateId == unrelatedId);
            }
        }