Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ jobs:
env:
NUGET_SOURCE: ${{ vars.NUGET_SOURCE }}
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: dotnet nuget push Mongo.Migration.${VERSION}.nupkg --source $NUGET_SOURCE --api-key "$NUGET_API_KEY"
run: dotnet nuget push Mongo.RuntimeMigration.${VERSION}.nupkg --source $NUGET_SOURCE --api-key "$NUGET_API_KEY"
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Mongo.Migration.Documents;
using Mongo.Migration.Migrations.Locators;
using Mongo.Migration.Tests.TestDoubles;
Expand All @@ -7,15 +8,15 @@
namespace Mongo.Migration.Tests.Migrations.Locators;

[TestFixture]
public class TypeMigrationLocatorWhenLocate
public class TypeMigrationLocatorWhenLocate : IDisposable
{
private TypeMigrationLocator _locator;
private readonly TypeMigrationLocator _locator;
private readonly ServiceProvider _serviceProvider;

[OneTimeSetUp]
public void OneTimeSetUp()
public TypeMigrationLocatorWhenLocate()
{
// Arrange
_locator = new TypeMigrationLocator(NullLogger<TypeMigrationLocator>.Instance);
_serviceProvider = new ServiceCollection().BuildServiceProvider();
_locator = new TypeMigrationLocator(NullLogger<TypeMigrationLocator>.Instance, _serviceProvider);
}

[Test]
Expand Down Expand Up @@ -71,4 +72,10 @@ public void When_get_migrations_from_to_down()
Assert.That(result, Has.Count.EqualTo(1));
Assert.That(result[0], Is.TypeOf<TestDocumentWithTwoMigration002>());
}

public void Dispose()
{
_serviceProvider.Dispose();
GC.SuppressFinalize(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@

namespace Mongo.Migration.Tests.TestDoubles.Database;

internal class TestDatabaseMigration001 : DatabaseMigration
public class TestDatabaseMigration001 : DatabaseMigration
{
public TestDatabaseMigration001()
: base("0.0.1")
{
}
public TestDatabaseMigration001() : base("0.0.1") { }

public override Task UpAsync(IMongoDatabase db, CancellationToken cancellationToken) => Task.CompletedTask;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@

namespace Mongo.Migration.Tests.TestDoubles.Database;

internal class TestDatabaseMigration002 : DatabaseMigration
public class TestDatabaseMigration002 : DatabaseMigration
{
public TestDatabaseMigration002()
: base("0.0.2")
{
}
public TestDatabaseMigration002() : base("0.0.2") { }

public override Task UpAsync(IMongoDatabase db, CancellationToken cancellationToken) => Task.CompletedTask;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@

namespace Mongo.Migration.Tests.TestDoubles.Database;

internal class TestDatabaseMigration003 : DatabaseMigration
public class TestDatabaseMigration003 : DatabaseMigration
{
public TestDatabaseMigration003()
: base("0.0.3")
{
}
public TestDatabaseMigration003() : base("0.0.3") { }

public override Task UpAsync(IMongoDatabase db, CancellationToken cancellationToken) => Task.CompletedTask;

Expand Down
6 changes: 6 additions & 0 deletions Mongo.Migration.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Git", "Git", "{CB26356F-6A6
Readme.md = Readme.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{E7B1F839-44B5-46BE-9CAB-AEBC376EB100}"
ProjectSection(SolutionItems) = preProject
.github\workflows\build.yaml = .github\workflows\build.yaml
.github\workflows\publish.yaml = .github\workflows\publish.yaml
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mongo.Migration", "Mongo.Migration\Mongo.Migration.csproj", "{8DFFD615-1E1A-4BED-8A96-CAF4C3637E81}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mongo.Migration.Tests", "Mongo.Migration.Tests\Mongo.Migration.Tests.csproj", "{1EEC8464-61D1-4FA3-97D4-21A35A45F3FE}"
Expand Down
45 changes: 25 additions & 20 deletions Mongo.Migration/Documents/Locators/AbstractLocator.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
using System.Collections.Frozen;
using System.Reflection;

namespace Mongo.Migration.Documents.Locators;

public abstract class AbstractLocator<TReturnType, TTypeIdentifier> : ILocator<TReturnType, TTypeIdentifier>
public abstract class AbstractLocator<TReturnType, TAttributeType> : ILocator<TReturnType, Type>
where TReturnType : struct
where TTypeIdentifier : class
where TAttributeType : Attribute
{
private IDictionary<TTypeIdentifier, TReturnType>? _locatesDictionary;
private readonly Lazy<IDictionary<Type, TReturnType>> _lazyLocateDictionary;

protected IDictionary<TTypeIdentifier, TReturnType> LocatesDictionary
protected AbstractLocator()
{
get
{
if (_locatesDictionary == null)
{
Locate();
}
_lazyLocateDictionary = new Lazy<IDictionary<Type, TReturnType>>(
LoadLocateDictionary,
LazyThreadSafetyMode.PublicationOnly);
}

return _locatesDictionary!;
}
protected abstract TReturnType GetAttributeValue(TAttributeType attribute);

set => _locatesDictionary = value;
}
protected IDictionary<Type, TReturnType> LocatesDictionary => _lazyLocateDictionary.Value;

public abstract TReturnType? GetLocateOrNull(TTypeIdentifier identifier);
public virtual TReturnType? GetLocateOrNull(Type identifier)
{
if (LocatesDictionary.TryGetValue(identifier, out TReturnType returnType))
{
return returnType;
}

public abstract void Locate();
return null;
}

protected IEnumerable<(Type, TAttribute)> LocateAttributes<TAttribute>() where TAttribute : Attribute
private FrozenDictionary<Type, TReturnType> LoadLocateDictionary()
{
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetExportedTypes())
.Select(t => (t, t.GetCustomAttributes<TAttribute>(true).FirstOrDefault()))
.Where(tuple => tuple.Item2 is not null)
.Cast<(Type, TAttribute)>();
.Select(t => (t, t.GetCustomAttribute<TAttributeType>()))
.Where(t => t.Item2 is not null)
.ToFrozenDictionary(
pair => pair.t,
pair => GetAttributeValue(pair.Item2!));
}
}
23 changes: 6 additions & 17 deletions Mongo.Migration/Documents/Locators/CollectionLocator.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using Mongo.Migration.Documents.Attributes;
#if NET8_0_OR_GREATER
using System.Collections.Frozen;
#else
using System.Collections.Immutable;
#endif

namespace Mongo.Migration.Documents.Locators;

public class CollectionLocator : AbstractLocator<CollectionLocationInformation, Type>, ICollectionLocator
public class CollectionLocator : AbstractLocator<CollectionLocationInformation, CollectionLocationAttribute>, ICollectionLocator
{
protected override CollectionLocationInformation GetAttributeValue(CollectionLocationAttribute attribute)
{
return attribute.CollectionInformation;
}

public override CollectionLocationInformation? GetLocateOrNull(Type identifier)
{
if (!LocatesDictionary.ContainsKey(identifier))
Expand All @@ -20,17 +20,6 @@ public class CollectionLocator : AbstractLocator<CollectionLocationInformation,
return value;
}

public override void Locate()
{
LocatesDictionary = LocateAttributes<CollectionLocationAttribute>()
#if NET8_0_OR_GREATER
.ToFrozenDictionary(pair => pair.Item1, pair => pair.Item2.CollectionInformation);
#else
.ToImmutableDictionary(pair => pair.Item1, pair => pair.Item2.CollectionInformation);
#endif

}

public IDictionary<Type, CollectionLocationInformation> GetLocatesOrEmpty()
{
return LocatesDictionary;
Expand Down
2 changes: 0 additions & 2 deletions Mongo.Migration/Documents/Locators/ILocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@ public interface ILocator<TReturnType, in TTypeIdentifier>
where TTypeIdentifier : class
{
TReturnType? GetLocateOrNull(TTypeIdentifier identifier);

void Locate();
}
38 changes: 8 additions & 30 deletions Mongo.Migration/Documents/Locators/RuntimeVersionLocator.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
#if NET8_0_OR_GREATER
using System.Collections.Frozen;
#else
using System.Collections.Immutable;
#endif
using System.Collections.Frozen;
using Mongo.Migration.Documents.Attributes;

namespace Mongo.Migration.Documents.Locators;

internal class RuntimeVersionLocator : AbstractLocator<DocumentVersion, Type>, IRuntimeVersionLocator
internal class RuntimeVersionLocator : AbstractLocator<DocumentVersion, RuntimeVersionAttribute>, IRuntimeVersionLocator
{
#if NET8_0_OR_GREATER
private readonly FrozenDictionary<Type, DocumentVersion> _codeDefinedDictionary;
#else
private readonly ImmutableDictionary<Type, DocumentVersion> _codeDefinedDictionary;
#endif

internal RuntimeVersionLocator(IEnumerable<KeyValuePair<Type, DocumentVersion>> alreadyDefinedRuntimeVersions)
{
#if NET8_0_OR_GREATER
_codeDefinedDictionary = alreadyDefinedRuntimeVersions.ToFrozenDictionary();
#else
_codeDefinedDictionary = alreadyDefinedRuntimeVersions.ToImmutableDictionary();
#endif
}

protected override DocumentVersion GetAttributeValue(RuntimeVersionAttribute attribute)
{
return attribute.Version;
}

public override DocumentVersion? GetLocateOrNull(Type identifier)
Expand All @@ -31,21 +24,6 @@ internal RuntimeVersionLocator(IEnumerable<KeyValuePair<Type, DocumentVersion>>
return version;
}

if (LocatesDictionary.TryGetValue(identifier, out version))
{
return version;
}

return null;
}

public override void Locate()
{
LocatesDictionary = LocateAttributes<RuntimeVersionAttribute>()
#if NET8_0_OR_GREATER
.ToFrozenDictionary(pair => pair.Item1, pair => pair.Item2.Version);
#else
.ToImmutableDictionary(pair => pair.Item1, pair => pair.Item2.Version);
#endif
return base.GetLocateOrNull(identifier);
}
}
29 changes: 4 additions & 25 deletions Mongo.Migration/Documents/Locators/StartUpVersionLocator.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,11 @@
#if NET8_0_OR_GREATER
using System.Collections.Frozen;
#else
using System.Collections.Immutable;
#endif
using Mongo.Migration.Documents.Attributes;
using Mongo.Migration.Documents.Attributes;

namespace Mongo.Migration.Documents.Locators;

internal class StartUpVersionLocator : AbstractLocator<DocumentVersion, Type>, IStartUpVersionLocator
internal class StartUpVersionLocator : AbstractLocator<DocumentVersion, StartUpVersionAttribute>, IStartUpVersionLocator
{
public override DocumentVersion? GetLocateOrNull(Type identifier)
protected override DocumentVersion GetAttributeValue(StartUpVersionAttribute attribute)
{
if (!LocatesDictionary.ContainsKey(identifier))
{
return null;
}

LocatesDictionary.TryGetValue(identifier, out var value);
return value;
}

public override void Locate()
{
LocatesDictionary = LocateAttributes<StartUpVersionAttribute>()
#if NET8_0_OR_GREATER
.ToFrozenDictionary(pair => pair.Item1, pair => pair.Item2.Version);
#else
.ToImmutableDictionary(pair => pair.Item1, pair => pair.Item2.Version);
#endif
return attribute.Version;
}
}
33 changes: 11 additions & 22 deletions Mongo.Migration/Extensions/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Mongo.Migration.Documents;
using System.Collections.Frozen;
using System.Collections.ObjectModel;
using Mongo.Migration.Documents;
using Mongo.Migration.Exceptions;
using Mongo.Migration.Migrations;

Expand All @@ -23,29 +25,16 @@ private static IEnumerable<TMigrationType> CheckForDuplicates<TMigrationType>(th
}
}

internal static IDictionary<Type, IReadOnlyCollection<TMigrationType>> ToMigrationDictionary<TMigrationType>(
internal static IDictionary<Type, ReadOnlyCollection<TMigrationType>> ToMigrationDictionary<TMigrationType>(
this IEnumerable<TMigrationType> migrations)
where TMigrationType : IMigration
{
var dictionary = new Dictionary<Type, IReadOnlyCollection<TMigrationType>>();
var list = migrations.ToList();
var types = (from m in list select m.Type).Distinct();

foreach (var type in types)
{
if (dictionary.ContainsKey(type))
{
continue;
}

var uniqueMigrations = list
.Where(m => m.Type == type)
.CheckForDuplicates()
.OrderBy(m => m.Version)
.ToList();
dictionary.Add(type, uniqueMigrations);
}

return dictionary;
return migrations
.GroupBy(m => m.Type)
.ToFrozenDictionary(
g => g.Key,
g => g
.CheckForDuplicates()
.OrderBy(m => m.Version).ToList().AsReadOnly());
}
}
9 changes: 6 additions & 3 deletions Mongo.Migration/Migrations/Document/DocumentMigration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ namespace Mongo.Migration.Migrations.Document;

public abstract class DocumentMigration<TClass> : IDocumentMigration
{
protected DocumentMigration(string version)
protected DocumentMigration(DocumentVersion version)
{
Version = DocumentVersion.Parse(version.AsSpan());
Version = version;
}

protected DocumentMigration(ReadOnlySpan<char> span)
: this(DocumentVersion.Parse(span)) { }

public DocumentVersion Version { get; }

public Type Type => typeof(TClass);
public Type Type { get; } = typeof(TClass);

public abstract void Up(BsonDocument document);

Expand Down
Loading