Browse Source

Migrations improved

pull/218/head
Sebastian Stehle 8 years ago
parent
commit
5ff426ae0d
  1. 3
      src/Squidex.Domain.Apps.Core.Model/SquidexCoreModel.cs
  2. 1
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  3. 3
      src/Squidex.Domain.Apps.Events/SquidexEvents.cs
  4. 81
      src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs
  5. 1
      src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEvent.cs
  6. 10
      src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Writer.cs
  7. 1
      src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs
  8. 2
      src/Squidex.Infrastructure/EventSourcing/DefaultEventDataFormatter.cs
  9. 7
      src/Squidex.Infrastructure/Migrations/IMigration.cs
  10. 16
      src/Squidex.Infrastructure/Migrations/IMigrationPath.cs
  11. 58
      src/Squidex.Infrastructure/Migrations/Migrator.cs
  12. 3
      src/Squidex.Infrastructure/SquidexInfrastructure.cs
  13. 8
      src/Squidex/Config/Domain/SerializationServices.cs
  14. 13
      src/Squidex/Config/Domain/WriteServices.cs
  15. 4
      tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventDataFormatterTests.cs
  16. 79
      tests/Squidex.Infrastructure.Tests/Migrations/MigratorTests.cs
  17. 1
      tools/Migrate_01/Migrate_01.csproj
  18. 64
      tools/Migrate_01/MigrationPath.cs
  19. 13
      tools/Migrate_01/Migrations/AddPatterns.cs
  20. 13
      tools/Migrate_01/Migrations/ConvertEventStore.cs
  21. 19
      tools/Migrate_01/Migrations/RebuildContentCollections.cs
  22. 13
      tools/Migrate_01/Migrations/RebuildSnapshots.cs
  23. 16
      tools/Migrate_01/SquidexMigrations.cs

3
src/Squidex.Domain.Apps.Core.Model/SquidexCoreModel.cs

@ -5,9 +5,12 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Reflection;
namespace Squidex.Domain.Apps.Core
{
public static class SquidexCoreModel
{
public static readonly Assembly Assembly = typeof(SquidexCoreModel).Assembly;
}
}

1
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.OData.UriParser;
using MongoDB.Bson;
using MongoDB.Driver;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Apps;

3
src/Squidex.Domain.Apps.Events/SquidexEvents.cs

@ -5,9 +5,12 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Reflection;
namespace Squidex.Domain.Apps.Events
{
public static class SquidexEvents
{
public static readonly Assembly Assembly = typeof(SquidexEvents).Assembly;
}
}

81
src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionClient.cs

@ -7,7 +7,6 @@
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
@ -34,73 +33,65 @@ namespace Squidex.Infrastructure.EventSourcing
this.projectionHost = projectionHost;
}
private string CreateFilterStreamName(string filter)
private string CreateFilterProjectionName(string filter)
{
return $"by-{StreamByFilter}-{prefix.Simplify()}-{filter.Simplify()}";
return $"by-{prefix.Simplify()}-{filter.Simplify()}";
}
private string CreatePropertyStreamName(string property)
private string CreatePropertyProjectionName(string property)
{
return $"by-{StreamByFilter}-{prefix.Simplify()}-{property.Simplify()}-property";
return $"by-{prefix.Simplify()}-{property.Simplify()}-property";
}
public async Task<string> CreateProjectionAsync(string property, object value)
{
var streamName = CreatePropertyStreamName(property);
if (projections.TryAdd(streamName, true))
{
var projectionConfig =
$@"fromAll()
.when({{
$any: function (s, e) {{
if (e.streamId.indexOf('{prefix}') === 0 && e.data.{property}) {{
linkTo('{streamName}-' + e.data.{property}, e);
}}
var name = CreatePropertyProjectionName(property);
var query =
$@"fromAll()
.when({{
$any: function (s, e) {{
if (e.streamId.indexOf('{prefix}') === 0 && e.data.{property}) {{
linkTo('{name}-' + e.data.{property}, e);
}}
}});";
try
{
var credentials = connection.Settings.DefaultUserCredentials;
}}
}});";
await projectionsManager.CreateContinuousAsync($"{streamName}", projectionConfig, credentials);
}
catch (Exception ex)
{
if (!ex.Is<ProjectionCommandConflictException>())
{
throw;
}
}
}
await CreateProjectionAsync(name, query);
return $"{streamName}-{value}";
return $"{name}-{value}";
}
public async Task<string> CreateProjectionAsync(string streamFilter = null)
{
streamFilter = streamFilter ?? ".*";
var streamName = CreateFilterStreamName(streamFilter);
var name = CreateFilterProjectionName(streamFilter);
if (projections.TryAdd(streamName, true))
{
var projectionConfig =
$@"fromAll()
.when({{
$any: function (s, e) {{
if (e.streamId.indexOf('{prefix}') === 0 && /{streamFilter}/.test(e.streamId.substring({prefix.Length + 1}))) {{
linkTo('{streamName}', e);
}}
var query =
$@"fromAll()
.when({{
$any: function (s, e) {{
if (e.streamId.indexOf('{prefix}') === 0 && /{streamFilter}/.test(e.streamId.substring({prefix.Length + 1}))) {{
linkTo('{name}', e);
}}
}});";
}}
}});";
await CreateProjectionAsync(name, query);
return name;
}
private async Task CreateProjectionAsync(string name, string query)
{
if (projections.TryAdd(name, true))
{
try
{
var credentials = connection.Settings.DefaultUserCredentials;
await projectionsManager.CreateContinuousAsync($"{streamName}", projectionConfig, credentials);
await projectionsManager.CreateContinuousAsync(name, query, credentials);
}
catch (Exception ex)
{
@ -110,8 +101,6 @@ namespace Squidex.Infrastructure.EventSourcing
}
}
}
return streamName;
}
public async Task ConnectAsync()

1
src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEvent.cs

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json.Linq;
using Squidex.Infrastructure.Reflection;

10
src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Writer.cs

@ -21,18 +21,12 @@ namespace Squidex.Infrastructure.EventSourcing
public Task AppendAsync(Guid commitId, string streamName, ICollection<EventData> events)
{
return AppendEventsInternalAsync(commitId, streamName, EtagVersion.Any, events);
return AppendAsync(commitId, streamName, EtagVersion.Any, events);
}
public Task AppendAsync(Guid commitId, string streamName, long expectedVersion, ICollection<EventData> events)
public async Task AppendAsync(Guid commitId, string streamName, long expectedVersion, ICollection<EventData> events)
{
Guard.GreaterEquals(expectedVersion, EtagVersion.Any, nameof(expectedVersion));
return AppendEventsInternalAsync(commitId, streamName, expectedVersion, events);
}
private async Task AppendEventsInternalAsync(Guid commitId, string streamName, long expectedVersion, ICollection<EventData> events)
{
Guard.NotNullOrEmpty(streamName, nameof(streamName));
Guard.NotNull(events, nameof(events));

1
src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs

@ -8,7 +8,6 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using Squidex.Infrastructure.Tasks;

2
src/Squidex.Infrastructure/EventSourcing/DefaultEventDataFormatter.cs

@ -30,7 +30,7 @@ namespace Squidex.Infrastructure.EventSourcing
var eventType = typeNameRegistry.GetType(eventData.Type);
var headers = eventData.Metadata.ToObject<EnvelopeHeaders>();
var content = eventData.Metadata.ToObject(eventType, serializer) as IEvent;
var content = eventData.Payload.ToObject(eventType, serializer) as IEvent;
if (migrate && content is IMigratedEvent migratedEvent)
{

7
src/Squidex.Infrastructure/Migrations/IMigration.cs

@ -5,17 +5,12 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Squidex.Infrastructure.Migrations
{
public interface IMigration
{
int FromVersion { get; }
int ToVersion { get; }
Task UpdateAsync(IEnumerable<IMigration> previousMigrations);
Task UpdateAsync();
}
}

16
src/Squidex.Infrastructure/Migrations/IMigrationPath.cs

@ -0,0 +1,16 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Infrastructure.Migrations
{
public interface IMigrationPath
{
(int Version, IEnumerable<IMigration> Migrations) GetNext(int version);
}
}

58
src/Squidex.Infrastructure/Migrations/Migrator.cs

@ -5,8 +5,6 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Squidex.Infrastructure.Log;
@ -15,20 +13,20 @@ namespace Squidex.Infrastructure.Migrations
{
public sealed class Migrator
{
private readonly IMigrationStatus migrationStatus;
private readonly IEnumerable<IMigration> migrations;
private readonly ISemanticLog log;
private readonly IMigrationStatus migrationStatus;
private readonly IMigrationPath migrationPath;
public int LockWaitMs { get; set; } = 5000;
public Migrator(IMigrationStatus migrationStatus, IEnumerable<IMigration> migrations, ISemanticLog log)
public Migrator(IMigrationStatus migrationStatus, IMigrationPath migrationPath, ISemanticLog log)
{
Guard.NotNull(migrationStatus, nameof(migrationStatus));
Guard.NotNull(migrations, nameof(migrations));
Guard.NotNull(migrationPath, nameof(migrationPath));
Guard.NotNull(log, nameof(log));
this.migrationStatus = migrationStatus;
this.migrations = migrations.OrderByDescending(x => x.ToVersion).ToList();
this.migrationPath = migrationPath;
this.log = log;
}
@ -39,8 +37,6 @@ namespace Squidex.Infrastructure.Migrations
try
{
var lastMigrator = migrations.FirstOrDefault();
while (!await migrationStatus.TryLockAsync())
{
log.LogInformation(w => w
@ -52,13 +48,16 @@ namespace Squidex.Infrastructure.Migrations
version = await migrationStatus.GetVersionAsync();
if (lastMigrator != null && lastMigrator.ToVersion != version)
while (true)
{
var migrationPath = FindMigratorPath(version, lastMigrator.ToVersion).ToList();
var migrationStep = migrationPath.GetNext(version);
var previousMigrations = new List<IMigration>();
if (migrationStep.Migrations == null || !migrationStep.Migrations.Any())
{
break;
}
foreach (var migration in migrationPath)
foreach (var migration in migrationStep.Migrations)
{
var name = migration.GetType().ToString();
@ -72,13 +71,11 @@ namespace Squidex.Infrastructure.Migrations
.WriteProperty("status", "Completed")
.WriteProperty("migrator", name)))
{
await migration.UpdateAsync(previousMigrations.ToList());
version = migration.ToVersion;
await migration.UpdateAsync();
}
previousMigrations.Add(migration);
}
version = migrationStep.Version;
}
}
finally
@ -86,30 +83,5 @@ namespace Squidex.Infrastructure.Migrations
await migrationStatus.UnlockAsync(version);
}
}
private IEnumerable<IMigration> FindMigratorPath(int fromVersion, int toVersion)
{
var addedMigrators = new HashSet<IMigration>();
while (true)
{
var bestMigrator = migrations.Where(x => x.FromVersion < x.ToVersion).FirstOrDefault(x => x.FromVersion == fromVersion);
if (bestMigrator != null && addedMigrators.Add(bestMigrator))
{
fromVersion = bestMigrator.ToVersion;
yield return bestMigrator;
}
else if (fromVersion != toVersion)
{
throw new InvalidOperationException($"There is no migration path from {fromVersion} to {toVersion}.");
}
else
{
break;
}
}
}
}
}

3
src/Squidex.Infrastructure/SquidexInfrastructure.cs

@ -5,9 +5,12 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Reflection;
namespace Squidex.Infrastructure
{
public static class SquidexInfrastructure
{
public static readonly Assembly Assembly = typeof(SquidexInfrastructure).Assembly;
}
}

8
src/Squidex/Config/Domain/SerializationServices.cs

@ -28,10 +28,10 @@ namespace Squidex.Config.Domain
{
private static readonly TypeNameRegistry TypeNameRegistry =
new TypeNameRegistry()
.MapUnmapped(typeof(Migration01_FromCqrs).Assembly)
.MapUnmapped(typeof(SquidexCoreModel).Assembly)
.MapUnmapped(typeof(SquidexEvents).Assembly)
.MapUnmapped(typeof(SquidexInfrastructure).Assembly);
.MapUnmapped(SquidexCoreModel.Assembly)
.MapUnmapped(SquidexEvents.Assembly)
.MapUnmapped(SquidexInfrastructure.Assembly)
.MapUnmapped(SquidexMigrations.Assembly);
private static readonly FieldRegistry FieldRegistry = new FieldRegistry(TypeNameRegistry);

13
src/Squidex/Config/Domain/WriteServices.cs

@ -9,6 +9,7 @@ using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Migrate_01;
using Migrate_01.Migrations;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Entities.Apps;
@ -63,13 +64,19 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<RuleCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddTransientAs<Migration01_FromCqrs>()
services.AddTransientAs<MigrationPath>()
.As<IMigrationPath>();
services.AddTransientAs<AddPatterns>()
.As<IMigration>();
services.AddTransientAs<ConvertEventStore>()
.As<IMigration>();
services.AddTransientAs<Migration02_AddPatterns>()
services.AddTransientAs<RebuildContentCollections>()
.As<IMigration>();
services.AddTransientAs<Migration03_SplitContentCollections>()
services.AddTransientAs<RebuildSnapshots>()
.As<IMigration>();
services.AddTransientAs<Rebuilder>()

4
tests/Squidex.Infrastructure.Tests/EventSourcing/EventDataFormatterTests.cs → tests/Squidex.Infrastructure.Tests/EventSourcing/DefaultEventDataFormatterTests.cs

@ -15,7 +15,7 @@ using Xunit;
namespace Squidex.Infrastructure.EventSourcing
{
public class EventDataFormatterTests
public class DefaultEventDataFormatterTests
{
public sealed class MyOldEvent : IEvent, IMigratedEvent
{
@ -31,7 +31,7 @@ namespace Squidex.Infrastructure.EventSourcing
private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry();
private readonly DefaultEventDataFormatter sut;
public EventDataFormatterTests()
public DefaultEventDataFormatterTests()
{
serializerSettings.Converters.Add(new PropertiesBagConverter<EnvelopeHeaders>());

79
tests/Squidex.Infrastructure.Tests/Migrations/MigratorTests.cs

@ -19,7 +19,9 @@ namespace Squidex.Infrastructure.Migrations
public sealed class MigratorTests
{
private readonly IMigrationStatus status = A.Fake<IMigrationStatus>();
private readonly IMigrationPath path = A.Fake<IMigrationPath>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly List<(int From, int To, IMigration Migration)> migrations = new List<(int From, int To, IMigration Migration)>();
public sealed class InMemoryStatus : IMigrationStatus
{
@ -64,6 +66,14 @@ namespace Squidex.Infrastructure.Migrations
public MigratorTests()
{
A.CallTo(() => path.GetNext(A<int>.Ignored))
.ReturnsLazily((int v) =>
{
var m = migrations.Where(x => x.From == v).ToList();
return m.Count == 0 ? (0, null) : (migrations.Max(x => x.To), migrations.Select(x => x.Migration));
});
A.CallTo(() => status.GetVersionAsync()).Returns(0);
A.CallTo(() => status.TryLockAsync()).Returns(true);
}
@ -75,13 +85,13 @@ namespace Squidex.Infrastructure.Migrations
var migrator_1_2 = BuildMigration(1, 2);
var migrator_2_3 = BuildMigration(2, 3);
var migrator = new Migrator(status, new[] { migrator_0_1, migrator_1_2, migrator_2_3 }, log);
var sut = new Migrator(status, path, log);
await migrator.MigrateAsync();
await sut.MigrateAsync();
A.CallTo(() => migrator_0_1.UpdateAsync(A<IEnumerable<IMigration>>.That.IsEmpty())).MustHaveHappened();
A.CallTo(() => migrator_1_2.UpdateAsync(A<IEnumerable<IMigration>>.That.IsSameSequenceAs(migrator_0_1))).MustHaveHappened();
A.CallTo(() => migrator_2_3.UpdateAsync(A<IEnumerable<IMigration>>.That.IsSameSequenceAs(migrator_0_1, migrator_1_2))).MustHaveHappened();
A.CallTo(() => migrator_0_1.UpdateAsync()).MustHaveHappened();
A.CallTo(() => migrator_1_2.UpdateAsync()).MustHaveHappened();
A.CallTo(() => migrator_2_3.UpdateAsync()).MustHaveHappened();
A.CallTo(() => status.UnlockAsync(3)).MustHaveHappened();
}
@ -93,51 +103,15 @@ namespace Squidex.Infrastructure.Migrations
var migrator_1_2 = BuildMigration(1, 2);
var migrator_2_3 = BuildMigration(2, 3);
var migrator = new Migrator(status, new[] { migrator_0_1, migrator_1_2, migrator_2_3 }, log);
A.CallTo(() => migrator_1_2.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).Throws(new ArgumentException());
await Assert.ThrowsAsync<ArgumentException>(migrator.MigrateAsync);
A.CallTo(() => migrator_0_1.UpdateAsync(A<IEnumerable<IMigration>>.That.IsEmpty())).MustHaveHappened();
A.CallTo(() => migrator_1_2.UpdateAsync(A<IEnumerable<IMigration>>.That.IsSameSequenceAs(migrator_0_1))).MustHaveHappened();
A.CallTo(() => migrator_2_3.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).MustNotHaveHappened();
A.CallTo(() => status.UnlockAsync(1)).MustHaveHappened();
}
[Fact]
public async Task Should_migrate_with_fastest_path()
{
var migrator_0_1 = BuildMigration(0, 1);
var migrator_0_2 = BuildMigration(0, 2);
var migrator_1_2 = BuildMigration(1, 2);
var migrator_2_3 = BuildMigration(2, 3);
var migrator = new Migrator(status, new[] { migrator_0_1, migrator_0_2, migrator_1_2, migrator_2_3 }, log);
await migrator.MigrateAsync();
A.CallTo(() => migrator_0_2.UpdateAsync(A<IEnumerable<IMigration>>.That.IsEmpty())).MustHaveHappened();
A.CallTo(() => migrator_0_1.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).MustNotHaveHappened();
A.CallTo(() => migrator_1_2.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).MustNotHaveHappened();
A.CallTo(() => migrator_2_3.UpdateAsync(A<IEnumerable<IMigration>>.That.IsSameSequenceAs(migrator_0_2))).MustHaveHappened();
A.CallTo(() => status.UnlockAsync(3)).MustHaveHappened();
}
[Fact]
public async Task Should_throw_if_no_path_found()
{
var migrator_0_1 = BuildMigration(0, 1);
var migrator_2_3 = BuildMigration(2, 3);
var sut = new Migrator(status, path, log);
var migrator = new Migrator(status, new[] { migrator_0_1, migrator_2_3 }, log);
A.CallTo(() => migrator_1_2.UpdateAsync()).Throws(new ArgumentException());
await Assert.ThrowsAsync<InvalidOperationException>(migrator.MigrateAsync);
await Assert.ThrowsAsync<ArgumentException>(sut.MigrateAsync);
A.CallTo(() => migrator_0_1.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).MustNotHaveHappened();
A.CallTo(() => migrator_2_3.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).MustNotHaveHappened();
A.CallTo(() => migrator_0_1.UpdateAsync()).MustHaveHappened();
A.CallTo(() => migrator_1_2.UpdateAsync()).MustHaveHappened();
A.CallTo(() => migrator_2_3.UpdateAsync()).MustNotHaveHappened();
A.CallTo(() => status.UnlockAsync(0)).MustHaveHappened();
}
@ -148,20 +122,19 @@ namespace Squidex.Infrastructure.Migrations
var migrator_0_1 = BuildMigration(0, 1);
var migrator_1_2 = BuildMigration(1, 2);
var migrator = new Migrator(new InMemoryStatus(), new[] { migrator_0_1, migrator_1_2 }, log) { LockWaitMs = 2 };
var sut = new Migrator(new InMemoryStatus(), path, log) { LockWaitMs = 2 };
await Task.WhenAll(Enumerable.Repeat(0, 10).Select(x => Task.Run(migrator.MigrateAsync)));
await Task.WhenAll(Enumerable.Repeat(0, 10).Select(x => Task.Run(sut.MigrateAsync)));
A.CallTo(() => migrator_0_1.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => migrator_1_2.UpdateAsync(A<IEnumerable<IMigration>>.Ignored)).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => migrator_0_1.UpdateAsync()).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => migrator_1_2.UpdateAsync()).MustHaveHappened(Repeated.Exactly.Once);
}
private IMigration BuildMigration(int fromVersion, int toVersion)
{
var migration = A.Fake<IMigration>();
A.CallTo(() => migration.FromVersion).Returns(fromVersion);
A.CallTo(() => migration.ToVersion).Returns(toVersion);
migrations.Add((fromVersion, toVersion, migration));
return migration;
}

1
tools/Migrate_01/Migrate_01.csproj

@ -6,6 +6,7 @@
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Core.Model\Squidex.Domain.Apps.Core.Model.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Entities\Squidex.Domain.Apps.Entities.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Events\Squidex.Domain.Apps.Events.csproj" />
<ProjectReference Include="..\..\src\Squidex.Infrastructure.MongoDb\Squidex.Infrastructure.MongoDb.csproj" />
<ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup>
<PropertyGroup>

64
tools/Migrate_01/MigrationPath.cs

@ -0,0 +1,64 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Migrate_01.Migrations;
using Squidex.Infrastructure.Migrations;
namespace Migrate_01
{
public class MigrationMatrix
{
private readonly IServiceProvider serviceProvider;
public MigrationMatrix(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public (int Version, IEnumerable<IMigration> Migrations) MigrationPath(int version)
{
switch (version)
{
case 0:
return (4,
new IMigration[]
{
serviceProvider.GetRequiredService<ConvertEventStore>(),
serviceProvider.GetRequiredService<RebuildSnapshots>(),
serviceProvider.GetRequiredService<AddPatterns>()
});
case 1:
return (4,
new IMigration[]
{
serviceProvider.GetRequiredService<ConvertEventStore>(),
serviceProvider.GetRequiredService<AddPatterns>(),
serviceProvider.GetRequiredService<RebuildContentCollections>()
});
case 2:
return (4,
new IMigration[]
{
serviceProvider.GetRequiredService<ConvertEventStore>(),
serviceProvider.GetRequiredService<AddPatterns>(),
serviceProvider.GetRequiredService<RebuildContentCollections>()
});
case 3:
return (4,
new IMigration[]
{
serviceProvider.GetRequiredService<ConvertEventStore>()
});
}
return (0, null);
}
}
}

13
tools/Migrate_01/Migration02_AddPatterns.cs → tools/Migrate_01/Migrations/AddPatterns.cs

@ -6,7 +6,6 @@
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
@ -15,26 +14,22 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.Migrations;
using Squidex.Infrastructure.States;
namespace Migrate_01
namespace Migrate_01.Migrations
{
public sealed class Migration02_AddPatterns : IMigration
public sealed class AddPatterns : IMigration
{
private readonly InitialPatterns initialPatterns;
private readonly IStateFactory stateFactory;
private readonly IAppRepository appRepository;
public int FromVersion { get; } = 1;
public int ToVersion { get; } = 2;
public Migration02_AddPatterns(InitialPatterns initialPatterns, IAppRepository appRepository, IStateFactory stateFactory)
public AddPatterns(InitialPatterns initialPatterns, IAppRepository appRepository, IStateFactory stateFactory)
{
this.initialPatterns = initialPatterns;
this.appRepository = appRepository;
this.stateFactory = stateFactory;
}
public async Task UpdateAsync(IEnumerable<IMigration> previousMigrations)
public async Task UpdateAsync()
{
var ids = await appRepository.QueryAppIdsAsync();

13
tools/Migrate_01/Migration00_ConvertEventStore.cs → tools/Migrate_01/Migrations/ConvertEventStore.cs

@ -5,29 +5,24 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Migrations;
namespace Migrate_01
namespace Migrate_01.Migrations
{
public sealed class Migration00_ConvertEventStore : IMigration
public sealed class ConvertEventStore : IMigration
{
private readonly IEventStore eventStore;
public int FromVersion { get; } = 0;
public int ToVersion { get; } = 1;
public Migration00_ConvertEventStore(IEventStore eventStore)
public ConvertEventStore(IEventStore eventStore)
{
this.eventStore = eventStore;
}
public async Task UpdateAsync(IEnumerable<IMigration> previousMigrations)
public async Task UpdateAsync()
{
if (eventStore is MongoEventStore mongoEventStore)
{

19
tools/Migrate_01/Migration03_SplitContentCollections.cs → tools/Migrate_01/Migrations/RebuildContentCollections.cs

@ -5,32 +5,23 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Squidex.Infrastructure.Migrations;
namespace Migrate_01
namespace Migrate_01.Migrations
{
public class Migration03_SplitContentCollections : IMigration
public class RebuildContentCollections : IMigration
{
private readonly Rebuilder rebuilder;
public int FromVersion { get; } = 2;
public int ToVersion { get; } = 3;
public Migration03_SplitContentCollections(Rebuilder rebuilder)
public RebuildContentCollections(Rebuilder rebuilder)
{
this.rebuilder = rebuilder;
}
public async Task UpdateAsync(IEnumerable<IMigration> previousMigrations)
public Task UpdateAsync()
{
if (!previousMigrations.Any(x => x is Migration01_FromCqrs))
{
await rebuilder.RebuildContentAsync();
}
return rebuilder.RebuildContentAsync();
}
}
}

13
tools/Migrate_01/Migration01_FromCqrs.cs → tools/Migrate_01/Migrations/RebuildSnapshots.cs

@ -5,26 +5,21 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Infrastructure.Migrations;
namespace Migrate_01
namespace Migrate_01.Migrations
{
public sealed class Migration01_FromCqrs : IMigration
public sealed class RebuildSnapshots : IMigration
{
private readonly Rebuilder rebuilder;
public int FromVersion { get; } = 0;
public int ToVersion { get; } = 1;
public Migration01_FromCqrs(Rebuilder rebuilder)
public RebuildSnapshots(Rebuilder rebuilder)
{
this.rebuilder = rebuilder;
}
public async Task UpdateAsync(IEnumerable<IMigration> previousMigrations)
public async Task UpdateAsync()
{
await rebuilder.RebuildConfigAsync();
await rebuilder.RebuildContentAsync();

16
tools/Migrate_01/SquidexMigrations.cs

@ -0,0 +1,16 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Reflection;
namespace Migrate_01
{
public static class SquidexMigrations
{
public static readonly Assembly Assembly = typeof(SquidexMigrations).Assembly;
}
}
Loading…
Cancel
Save