Skip to content

Commit

Permalink
fixed support for multiple registered IDatabaseMigrationProvider(s), …
Browse files Browse the repository at this point in the history
…added overridable AdoNetStubDatabaseMigrationProvider.GetSqlMigrationCommands, bumped version to 1.35.2
  • Loading branch information
martinzima committed Mar 14, 2024
1 parent 7e2b709 commit c063aca
Show file tree
Hide file tree
Showing 24 changed files with 194 additions and 93 deletions.
4 changes: 2 additions & 2 deletions Common.props
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project>

<PropertyGroup>
<VersionPrefix>1.35.1</VersionPrefix>
<VersionPrefix>1.35.2</VersionPrefix>
</PropertyGroup>

<PropertyGroup>
<Authors>Revo Framework</Authors>
<Copyright>Copyright (c) 2017-2024 Martin Zima</Copyright>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<LangVersion>11</LangVersion>
<LangVersion>12</LangVersion>
<PackageIcon>icon-128.png</PackageIcon>
<PackageIconUrl>https://raw.githubusercontent.com/revoframework/Revo/develop/res/icon-128.png</PackageIconUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
2 changes: 1 addition & 1 deletion Providers/EF6/Tests/Revo.EF6.Tests/Revo.EF6.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
6 changes: 6 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# RELEASE NOTES

## [1.35.2] - 2024-03-14

### Fixed

- fixed support for multiple registered IDatabaseMigrationProvider(s)

## [1.35.1] - 2024-01-18

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private async Task<IReadOnlyCollection<PendingModuleMigration>> SelectModuleMigr
.Distinct()
.ToArray();

var selectedMigrations = await migrationSelector.SelectMigrationsAsync(migratedModules, environmentTags);
var selectedMigrations = await migrationSelector.SelectMigrationsAsync(provider, migratedModules, environmentTags);

if (selectedMigrations.Count > 0 && selectedMigrations.SelectMany(x => x.Migrations)
.All(provider.SupportsMigration))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@ namespace Revo.Infrastructure.DataAccess.Migrations
public class DatabaseMigrationSelector : IDatabaseMigrationSelector
{
private readonly IDatabaseMigrationRegistry migrationRegistry;
private readonly IDatabaseMigrationProvider migrationProvider;
private readonly IDatabaseMigrationSelectorOptions selectorOptions;
private IReadOnlyCollection<IDatabaseMigrationRecord> history;

public DatabaseMigrationSelector(IDatabaseMigrationRegistry migrationRegistry, IDatabaseMigrationProvider migrationProvider,
public DatabaseMigrationSelector(IDatabaseMigrationRegistry migrationRegistry,
IDatabaseMigrationSelectorOptions selectorOptions)
{
this.migrationRegistry = migrationRegistry;
this.migrationProvider = migrationProvider;
this.selectorOptions = selectorOptions;
}

public async Task<IReadOnlyCollection<SelectedModuleMigrations>> SelectMigrationsAsync(DatabaseMigrationSpecifier[] modules, string[] tags)
public async Task<IReadOnlyCollection<SelectedModuleMigrations>> SelectMigrationsAsync(IDatabaseMigrationProvider migrationProvider,
DatabaseMigrationSpecifier[] modules, string[] tags)
{
try
{
Expand All @@ -33,7 +32,7 @@ public async Task<IReadOnlyCollection<SelectedModuleMigrations>> SelectMigration

foreach (var module in sortedModules)
{
var migrations = await DoSelectMigrationsAsync(module, tags, queuedMigrations);
var migrations = await DoSelectMigrationsAsync(module, tags, queuedMigrations, false);

if (migrations.Count > 0)
{
Expand All @@ -58,10 +57,10 @@ private bool IsRepeatableMigration(DatabaseMigrationSpecifier specifier)
}

private async Task<IReadOnlyCollection<IDatabaseMigration>> DoSelectMigrationsAsync(DatabaseMigrationSpecifier specifier, string[] tags,
List<DatabaseMigrationSpecifier> queuedMigrations)
List<DatabaseMigrationSpecifier> queuedMigrations, bool required)
{
var result = await SelectModuleMigrationsNoDependenciesAsync(specifier, tags, queuedMigrations);

var result = await SelectModuleMigrationsNoDependenciesAsync(specifier, tags, queuedMigrations, required);
foreach (var migration in result)
{
queuedMigrations.Add(new DatabaseMigrationSpecifier(migration.ModuleName, migration.Version));
Expand All @@ -81,7 +80,7 @@ private async Task AddRequiredDependenciesAsync(List<IDatabaseMigration> migrati
var dependencySpecs = await GetRequiredMigrationDependenciesAsync(migration, queuedMigrations, tags);
foreach (var dependencySpec in dependencySpecs)
{
var dependencyMigrations = await DoSelectMigrationsAsync(dependencySpec, tags, queuedMigrations);
var dependencyMigrations = await DoSelectMigrationsAsync(dependencySpec, tags, queuedMigrations, true);
migrations.InsertRange(i, dependencyMigrations);
queuedMigrations.AddRange(dependencyMigrations.Select(x => new DatabaseMigrationSpecifier(x.ModuleName, x.Version)));
i += dependencyMigrations.Count;
Expand All @@ -96,7 +95,7 @@ private async Task<List<DatabaseMigrationSpecifier>> GetRequiredMigrationDepende

foreach (var dependency in migration.Dependencies)
{
var dependencyMigrations = await SelectModuleMigrationsNoDependenciesAsync(dependency, tags, queuedMigrations);
var dependencyMigrations = await SelectModuleMigrationsNoDependenciesAsync(dependency, tags, queuedMigrations, true);
if (dependencyMigrations.Count > 0)
{
dependencies.Add(new DatabaseMigrationSpecifier(
Expand All @@ -109,18 +108,19 @@ private async Task<List<DatabaseMigrationSpecifier>> GetRequiredMigrationDepende
}

private async Task<List<IDatabaseMigration>> SelectModuleMigrationsNoDependenciesAsync(DatabaseMigrationSpecifier specifier,
string[] tags, List<DatabaseMigrationSpecifier> queuedMigrations)
string[] tags, List<DatabaseMigrationSpecifier> queuedMigrations, bool required)
{
var moduleMigrations = migrationRegistry.Migrations
.Where(x => string.Equals(x.ModuleName, specifier.ModuleName, StringComparison.InvariantCultureIgnoreCase))
.Where(x => string.Equals(x.ModuleName, specifier.ModuleName, StringComparison.InvariantCultureIgnoreCase));
var providerModuleMigrations = moduleMigrations
.Where(x => x.Tags.All(tagGroup => tags.Any(tagGroup.Contains)));

if (specifier.Version != null)
{
moduleMigrations = moduleMigrations.Where(x => x.Version.CompareTo(specifier.Version) <= 0);
providerModuleMigrations = providerModuleMigrations.Where(x => x.Version.CompareTo(specifier.Version) <= 0);
}

moduleMigrations = moduleMigrations
providerModuleMigrations = providerModuleMigrations
.OrderBy(x => x.Version)
.ToArray();

Expand All @@ -131,14 +131,14 @@ private async Task<List<IDatabaseMigration>> SelectModuleMigrationsNoDependencie

if (specifier.Version != null)
{
if (moduleMigrations.Any() && moduleMigrations.Last().IsRepeatable)
if (providerModuleMigrations.Any() && providerModuleMigrations.Last().IsRepeatable)
{
throw new DatabaseMigrationException($"Cannot select database migrations for module {specifier} because it is a repeatable migration module, which means it is versioned only by checksums");
}
}
else if (!moduleMigrations.Any())
else if (!providerModuleMigrations.Any())
{
if (!historyMigrations.Any())
if (!historyMigrations.Any() && (required || !moduleMigrations.Any()))
{
// TODO maybe return without errors if there are migrations for this module with different tags?
throw new DatabaseMigrationException($"Cannot select database migrations for module {specifier}: no migrations for specified module were found");
Expand All @@ -147,10 +147,10 @@ private async Task<List<IDatabaseMigration>> SelectModuleMigrationsNoDependencie
return new List<IDatabaseMigration>();
}

if (historyMigrations.Any() && moduleMigrations.Any())
if (historyMigrations.Any() && providerModuleMigrations.Any())
{
bool wasRepeatable = historyMigrations.First().Version == null;
bool isRepeatable = moduleMigrations.First().IsRepeatable;
bool isRepeatable = providerModuleMigrations.First().IsRepeatable;

if (wasRepeatable != isRepeatable)
{
Expand All @@ -166,7 +166,7 @@ private async Task<List<IDatabaseMigration>> SelectModuleMigrationsNoDependencie
}

// repeatable-migration modules
if (moduleMigrations.Any() && moduleMigrations.First().IsRepeatable)
if (providerModuleMigrations.Any() && providerModuleMigrations.First().IsRepeatable)
{
if (moduleQueuedMigrations.Any())
{
Expand All @@ -177,7 +177,7 @@ private async Task<List<IDatabaseMigration>> SelectModuleMigrationsNoDependencie
.OrderByDescending(x => x.TimeApplied)
.FirstOrDefault();

var migration = moduleMigrations.SingleOrDefault()
var migration = providerModuleMigrations.SingleOrDefault()
?? throw new DatabaseMigrationException($"Cannot select database migrations for repeatable module {specifier}: multiple migrations found");

// return if same and no dependencies got updated
Expand Down Expand Up @@ -214,21 +214,21 @@ private async Task<List<IDatabaseMigration>> SelectModuleMigrationsNoDependencie

if (version == null)
{
var baseline = moduleMigrations.FirstOrDefault(x => x.IsBaseline);
var baseline = providerModuleMigrations.FirstOrDefault(x => x.IsBaseline);
if (baseline != null)
{
result.Add(baseline);
result.AddRange(moduleMigrations
result.AddRange(providerModuleMigrations
.Where(x => x.Version.CompareTo(baseline.Version) > 0));
}
else
{
result.AddRange(moduleMigrations);
result.AddRange(providerModuleMigrations);
}
}
else
{
result.AddRange(moduleMigrations
result.AddRange(providerModuleMigrations
.Where(x => !x.IsBaseline && x.Version.CompareTo(version) > 0));
}

Expand All @@ -242,7 +242,7 @@ private async Task<List<IDatabaseMigration>> SelectModuleMigrationsNoDependencie
}
else
{
var maxVersion = moduleMigrations.Select(x => x.Version).Max();
var maxVersion = providerModuleMigrations.Select(x => x.Version).Max();

if ((!result.Any() && (version == null || version.CompareTo(maxVersion) < 0))
|| (result.Any() && !result.Last().Version.Equals(maxVersion)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Revo.Infrastructure.DataAccess.Migrations
{
public abstract class FileSqlDatabaseMigration : SqlDatabaseMigration
{
public static readonly Regex DefaultFileNameRegex = new Regex(@"^(?<module>[a-z0-9\-]+)(?:_(?<baseline>baseline))?(?:_(?<repeatable>repeatable))?(?:_(?<version>\d+(?:\.\d+)*))?(?:_(?<tag>[a-z0-9\-]+)(?:,(?<tag>[a-z0-9\-]+))*)?\.sql$",
public static readonly Regex DefaultFileNameRegex = new(@"^(?<module>[a-z0-9\-]+)(?:_(?<baseline>baseline))?(?:_(?<repeatable>repeatable))?(?:_(?<version>\d+(?:\.\d+)*))?(?:_(?<tag>[a-z0-9\-]+)(?:,(?<tag>[a-z0-9\-]+))*)?\.sql$",
RegexOptions.Compiled | RegexOptions.IgnoreCase);

private string moduleName;
Expand All @@ -16,9 +16,9 @@ public abstract class FileSqlDatabaseMigration : SqlDatabaseMigration
public DatabaseMigrationTransactionMode transactionMode = DatabaseMigrationTransactionMode.Default;
private bool isBaseline;
private bool isRepeatable;
private string[] sqlCommands;
private List<string> sqlCommands;
private string description;
private List<DatabaseMigrationSpecifier> dependencies = new List<DatabaseMigrationSpecifier>();
private List<DatabaseMigrationSpecifier> dependencies = new();
private bool hasParsedFile;

protected FileSqlDatabaseMigration(string fileName, Regex fileNameRegex = null)
Expand Down Expand Up @@ -82,7 +82,6 @@ public override DatabaseVersion Version
public override bool IsRepeatable => isRepeatable;

public override string Description

{
get
{
Expand Down Expand Up @@ -123,7 +122,7 @@ public override IReadOnlyCollection<DatabaseMigrationSpecifier> Dependencies
}


public override string[] SqlCommands
public override IReadOnlyCollection<string> SqlCommands
{
get
{
Expand Down Expand Up @@ -153,7 +152,7 @@ public override string ToString(bool includeClassName)
protected void ParseFile()
{
string contents = ReadSqlFileContents();
sqlCommands = new[] {contents};
sqlCommands = new() { contents };

int i = 0;
while (i < contents.Length)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Revo.Infrastructure.DataAccess.Migrations
{
public interface IDatabaseMigrationSelector
{
Task<IReadOnlyCollection<SelectedModuleMigrations>> SelectMigrationsAsync(DatabaseMigrationSpecifier[] modules, string[] tags);
Task<IReadOnlyCollection<SelectedModuleMigrations>> SelectMigrationsAsync(IDatabaseMigrationProvider migrationProvider,
DatabaseMigrationSpecifier[] modules, string[] tags);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace Revo.Infrastructure.DataAccess.Migrations
using System.Collections.Generic;

namespace Revo.Infrastructure.DataAccess.Migrations
{
public interface ISqlDatabaseMigration : IDatabaseMigration
{
string[] SqlCommands { get; }
IReadOnlyCollection<string> SqlCommands { get; }
}
}
Loading

0 comments on commit c063aca

Please sign in to comment.