diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 39402da..648fa69 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -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" diff --git a/Mongo.Migration.Tests/Migrations/Locators/TypeMigrationLocator_when_locate.cs b/Mongo.Migration.Tests/Migrations/Locators/TypeMigrationLocator_when_locate.cs index aed02e3..3c5669f 100644 --- a/Mongo.Migration.Tests/Migrations/Locators/TypeMigrationLocator_when_locate.cs +++ b/Mongo.Migration.Tests/Migrations/Locators/TypeMigrationLocator_when_locate.cs @@ -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; @@ -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.Instance); + _serviceProvider = new ServiceCollection().BuildServiceProvider(); + _locator = new TypeMigrationLocator(NullLogger.Instance, _serviceProvider); } [Test] @@ -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()); } + + public void Dispose() + { + _serviceProvider.Dispose(); + GC.SuppressFinalize(this); + } } \ No newline at end of file diff --git a/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_1.cs b/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_1.cs index 9fa2b76..efe02d9 100644 --- a/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_1.cs +++ b/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_1.cs @@ -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; diff --git a/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_2.cs b/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_2.cs index f4a5b8e..7471e05 100644 --- a/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_2.cs +++ b/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_2.cs @@ -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; diff --git a/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_3.cs b/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_3.cs index c295fc3..441b2e1 100644 --- a/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_3.cs +++ b/Mongo.Migration.Tests/TestDoubles/Database/TestDatabaseMigration_0_0_3.cs @@ -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; diff --git a/Mongo.Migration.sln b/Mongo.Migration.sln index 2477102..b4a4326 100644 --- a/Mongo.Migration.sln +++ b/Mongo.Migration.sln @@ -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}" diff --git a/Mongo.Migration/Documents/Locators/AbstractLocator.cs b/Mongo.Migration/Documents/Locators/AbstractLocator.cs index fdd9c80..b00d04c 100644 --- a/Mongo.Migration/Documents/Locators/AbstractLocator.cs +++ b/Mongo.Migration/Documents/Locators/AbstractLocator.cs @@ -1,38 +1,43 @@ +using System.Collections.Frozen; using System.Reflection; namespace Mongo.Migration.Documents.Locators; -public abstract class AbstractLocator : ILocator +public abstract class AbstractLocator : ILocator where TReturnType : struct - where TTypeIdentifier : class + where TAttributeType : Attribute { - private IDictionary? _locatesDictionary; + private readonly Lazy> _lazyLocateDictionary; - protected IDictionary LocatesDictionary + protected AbstractLocator() { - get - { - if (_locatesDictionary == null) - { - Locate(); - } + _lazyLocateDictionary = new Lazy>( + LoadLocateDictionary, + LazyThreadSafetyMode.PublicationOnly); + } - return _locatesDictionary!; - } + protected abstract TReturnType GetAttributeValue(TAttributeType attribute); - set => _locatesDictionary = value; - } + protected IDictionary 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() where TAttribute : Attribute + private FrozenDictionary LoadLocateDictionary() { return AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetExportedTypes()) - .Select(t => (t, t.GetCustomAttributes(true).FirstOrDefault())) - .Where(tuple => tuple.Item2 is not null) - .Cast<(Type, TAttribute)>(); + .Select(t => (t, t.GetCustomAttribute())) + .Where(t => t.Item2 is not null) + .ToFrozenDictionary( + pair => pair.t, + pair => GetAttributeValue(pair.Item2!)); } } \ No newline at end of file diff --git a/Mongo.Migration/Documents/Locators/CollectionLocator.cs b/Mongo.Migration/Documents/Locators/CollectionLocator.cs index ae5632f..52c3b47 100644 --- a/Mongo.Migration/Documents/Locators/CollectionLocator.cs +++ b/Mongo.Migration/Documents/Locators/CollectionLocator.cs @@ -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, ICollectionLocator +public class CollectionLocator : AbstractLocator, ICollectionLocator { + protected override CollectionLocationInformation GetAttributeValue(CollectionLocationAttribute attribute) + { + return attribute.CollectionInformation; + } + public override CollectionLocationInformation? GetLocateOrNull(Type identifier) { if (!LocatesDictionary.ContainsKey(identifier)) @@ -20,17 +20,6 @@ public class CollectionLocator : AbstractLocator() -#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 GetLocatesOrEmpty() { return LocatesDictionary; diff --git a/Mongo.Migration/Documents/Locators/ILocator.cs b/Mongo.Migration/Documents/Locators/ILocator.cs index afc587c..c79677a 100644 --- a/Mongo.Migration/Documents/Locators/ILocator.cs +++ b/Mongo.Migration/Documents/Locators/ILocator.cs @@ -5,6 +5,4 @@ public interface ILocator where TTypeIdentifier : class { TReturnType? GetLocateOrNull(TTypeIdentifier identifier); - - void Locate(); } \ No newline at end of file diff --git a/Mongo.Migration/Documents/Locators/RuntimeVersionLocator.cs b/Mongo.Migration/Documents/Locators/RuntimeVersionLocator.cs index 47ea10e..47785e0 100644 --- a/Mongo.Migration/Documents/Locators/RuntimeVersionLocator.cs +++ b/Mongo.Migration/Documents/Locators/RuntimeVersionLocator.cs @@ -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, IRuntimeVersionLocator +internal class RuntimeVersionLocator : AbstractLocator, IRuntimeVersionLocator { -#if NET8_0_OR_GREATER private readonly FrozenDictionary _codeDefinedDictionary; -#else - private readonly ImmutableDictionary _codeDefinedDictionary; -#endif internal RuntimeVersionLocator(IEnumerable> 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) @@ -31,21 +24,6 @@ internal RuntimeVersionLocator(IEnumerable> return version; } - if (LocatesDictionary.TryGetValue(identifier, out version)) - { - return version; - } - - return null; - } - - public override void Locate() - { - LocatesDictionary = LocateAttributes() -#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); } } \ No newline at end of file diff --git a/Mongo.Migration/Documents/Locators/StartUpVersionLocator.cs b/Mongo.Migration/Documents/Locators/StartUpVersionLocator.cs index cb889ad..5ef96c4 100644 --- a/Mongo.Migration/Documents/Locators/StartUpVersionLocator.cs +++ b/Mongo.Migration/Documents/Locators/StartUpVersionLocator.cs @@ -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, IStartUpVersionLocator +internal class StartUpVersionLocator : AbstractLocator, 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() -#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; } } \ No newline at end of file diff --git a/Mongo.Migration/Extensions/EnumerableExtensions.cs b/Mongo.Migration/Extensions/EnumerableExtensions.cs index e331d8d..ea936f1 100644 --- a/Mongo.Migration/Extensions/EnumerableExtensions.cs +++ b/Mongo.Migration/Extensions/EnumerableExtensions.cs @@ -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; @@ -23,29 +25,16 @@ private static IEnumerable CheckForDuplicates(th } } - internal static IDictionary> ToMigrationDictionary( + internal static IDictionary> ToMigrationDictionary( this IEnumerable migrations) where TMigrationType : IMigration { - var dictionary = new Dictionary>(); - 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()); } } \ No newline at end of file diff --git a/Mongo.Migration/Migrations/Document/DocumentMigration.cs b/Mongo.Migration/Migrations/Document/DocumentMigration.cs index 1985305..31f8392 100644 --- a/Mongo.Migration/Migrations/Document/DocumentMigration.cs +++ b/Mongo.Migration/Migrations/Document/DocumentMigration.cs @@ -5,14 +5,17 @@ namespace Mongo.Migration.Migrations.Document; public abstract class DocumentMigration : IDocumentMigration { - protected DocumentMigration(string version) + protected DocumentMigration(DocumentVersion version) { - Version = DocumentVersion.Parse(version.AsSpan()); + Version = version; } + protected DocumentMigration(ReadOnlySpan 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); diff --git a/Mongo.Migration/Migrations/Locators/DatabaseTypeMigrationDependencyLocator.cs b/Mongo.Migration/Migrations/Locators/DatabaseTypeMigrationDependencyLocator.cs index 6185ee9..e9a8c01 100644 --- a/Mongo.Migration/Migrations/Locators/DatabaseTypeMigrationDependencyLocator.cs +++ b/Mongo.Migration/Migrations/Locators/DatabaseTypeMigrationDependencyLocator.cs @@ -5,23 +5,6 @@ namespace Mongo.Migration.Migrations.Locators; internal class DatabaseTypeMigrationDependencyLocator : TypeMigrationDependencyLocator, IDatabaseTypeMigrationDependencyLocator { - private IDictionary>? _migrations; public DatabaseTypeMigrationDependencyLocator(ILogger logger, IServiceProvider serviceProvider) : base(logger, serviceProvider) { } - - protected override IDictionary> Migrations - { - get - { - if (_migrations == null) - { - Locate(); - } - - return _migrations!; - } - set => _migrations = value; - } - - } \ No newline at end of file diff --git a/Mongo.Migration/Migrations/Locators/IDatabaseTypeMigrationDependencyLocator.cs b/Mongo.Migration/Migrations/Locators/IDatabaseTypeMigrationDependencyLocator.cs index 8cd8dca..3b9f22d 100644 --- a/Mongo.Migration/Migrations/Locators/IDatabaseTypeMigrationDependencyLocator.cs +++ b/Mongo.Migration/Migrations/Locators/IDatabaseTypeMigrationDependencyLocator.cs @@ -2,6 +2,4 @@ namespace Mongo.Migration.Migrations.Locators; -internal interface IDatabaseTypeMigrationDependencyLocator : IMigrationLocator -{ -} \ No newline at end of file +internal interface IDatabaseTypeMigrationDependencyLocator : IMigrationLocator; \ No newline at end of file diff --git a/Mongo.Migration/Migrations/Locators/IMigrationLocator.cs b/Mongo.Migration/Migrations/Locators/IMigrationLocator.cs index ee0a8e8..6b45799 100644 --- a/Mongo.Migration/Migrations/Locators/IMigrationLocator.cs +++ b/Mongo.Migration/Migrations/Locators/IMigrationLocator.cs @@ -13,5 +13,5 @@ public interface IMigrationLocator DocumentVersion GetLatestVersion(Type type); - void Locate(); + void Initialize(); } \ No newline at end of file diff --git a/Mongo.Migration/Migrations/Locators/MigrationLocator.cs b/Mongo.Migration/Migrations/Locators/MigrationLocator.cs index ba45a6f..f5b5700 100644 --- a/Mongo.Migration/Migrations/Locators/MigrationLocator.cs +++ b/Mongo.Migration/Migrations/Locators/MigrationLocator.cs @@ -1,7 +1,9 @@ -using System.Collections.Immutable; +using System.Collections.ObjectModel; using System.Reflection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Mongo.Migration.Documents; +using Mongo.Migration.Extensions; namespace Mongo.Migration.Migrations.Locators; @@ -10,36 +12,21 @@ public abstract class MigrationLocator : IMigrationLocator> _logger; - private readonly List _assemblies; + private readonly IServiceProvider _serviceProvider; - private IDictionary>? _migrations; + private readonly Lazy>> _lazyMigrations; - protected MigrationLocator(ILogger> logger) + protected MigrationLocator(ILogger> logger, IServiceProvider serviceProvider) { _logger = logger; - _assemblies = GetAssemblies(); + _serviceProvider = serviceProvider; + _lazyMigrations = new Lazy>>( + LoadMigrations, + LazyThreadSafetyMode.PublicationOnly); } - protected IEnumerable Assemblies => _assemblies; - - protected virtual IDictionary> Migrations - { - get - { - if (_migrations is null) - { - Locate(); - } - - if (_migrations is null || _migrations.Count <= 0) - { - _logger.LogWarning("No migration found"); - } - - return _migrations ?? ImmutableDictionary>.Empty; - } - set => _migrations = value; - } + protected virtual IDictionary> Migrations + => _lazyMigrations.Value; public IReadOnlyCollection GetMigrations(Type type) { @@ -73,7 +60,32 @@ public DocumentVersion GetLatestVersion(Type type) : DocumentVersion.Default; } - public abstract void Locate(); + public void Initialize() + { + if (!_lazyMigrations.IsValueCreated) + { + var migrations = _lazyMigrations.Value; + _logger.LogDebug("Migration locator initialized and loaded {Count} migrations", migrations.Count); + } + } + + private IDictionary> LoadMigrations() + { + Type migrationType = typeof(TMigrationType); + + List assemblies = GetAssemblies(); + + var migrationTypes = assemblies + .SelectMany(a => a.GetExportedTypes()) + .Where(type => !type.IsAbstract && migrationType.IsAssignableFrom(type)) + .DistinctBy(t => t.AssemblyQualifiedName) + .Select(GetMigrationInstance) + .ToMigrationDictionary(); + + _logger.LogDebug("{Count} {MigrationType} migrations found", migrationTypes.Count, migrationType.Name); + + return migrationTypes; + } private static List GetAssemblies() { @@ -92,4 +104,24 @@ private static List GetAssemblies() return assemblies; } + + private TMigrationType GetMigrationInstance(Type type) + { + ConstructorInfo[] constructors = type.GetConstructors(); + + if (constructors.Length > 0) + { + var args = constructors + .First() + .GetParameters() + .Select(parameterInfo => _serviceProvider.GetRequiredService(parameterInfo.ParameterType)) + .ToArray(); + + return Activator.CreateInstance(type, args) as TMigrationType + ?? throw new InvalidOperationException($"Cannot create {type} migration"); + } + + return Activator.CreateInstance(type) as TMigrationType + ?? throw new InvalidOperationException($"Cannot create {type} migration"); + } } \ No newline at end of file diff --git a/Mongo.Migration/Migrations/Locators/TypeMigrationDependencyLocator.cs b/Mongo.Migration/Migrations/Locators/TypeMigrationDependencyLocator.cs index c628fcc..967ea5c 100644 --- a/Mongo.Migration/Migrations/Locators/TypeMigrationDependencyLocator.cs +++ b/Mongo.Migration/Migrations/Locators/TypeMigrationDependencyLocator.cs @@ -1,63 +1,10 @@ -using System.Reflection; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Mongo.Migration.Extensions; +using Microsoft.Extensions.Logging; namespace Mongo.Migration.Migrations.Locators; internal class TypeMigrationDependencyLocator : MigrationLocator where TMigrationType : class, IMigration { - private readonly IServiceProvider _serviceProvider; - public TypeMigrationDependencyLocator(ILogger> logger, IServiceProvider serviceProvider) - : base(logger) - { - _serviceProvider = serviceProvider; - } - - public override void Locate() - { - var migrationTypes = - (from assembly in Assemblies - from type in assembly.GetTypes() - where typeof(TMigrationType).IsAssignableFrom(type) && !type.IsAbstract - select type).Distinct(new TypeComparer()); - - Migrations = migrationTypes.Select(GetMigrationInstance).ToMigrationDictionary(); - } - - private TMigrationType GetMigrationInstance(Type type) - { - ConstructorInfo[] constructors = type.GetConstructors(); - - if (constructors.Length > 0) - { - var args = constructors - .First() - .GetParameters() - .Select(parameterInfo => _serviceProvider.GetRequiredService(parameterInfo.ParameterType)) - .ToArray(); - - return Activator.CreateInstance(type, args) as TMigrationType - ?? throw new InvalidOperationException($"Cannot create {type} migration"); - } - - return Activator.CreateInstance(type) as TMigrationType - ?? throw new InvalidOperationException($"Cannot create {type} migration"); - } - - private class TypeComparer : IEqualityComparer - { - public bool Equals(Type? x, Type? y) - { - return x?.AssemblyQualifiedName == y?.AssemblyQualifiedName; - } - - public int GetHashCode(Type obj) - { - return obj.AssemblyQualifiedName?.GetHashCode() - ?? throw new InvalidOperationException($"Cannot get AssemblyQualifiedName from {obj}"); - } - } + : base(logger, serviceProvider) { } } \ No newline at end of file diff --git a/Mongo.Migration/Migrations/Locators/TypeMigrationLocator.cs b/Mongo.Migration/Migrations/Locators/TypeMigrationLocator.cs index 2b0d495..4caf514 100644 --- a/Mongo.Migration/Migrations/Locators/TypeMigrationLocator.cs +++ b/Mongo.Migration/Migrations/Locators/TypeMigrationLocator.cs @@ -1,25 +1,9 @@ using Microsoft.Extensions.Logging; -using Mongo.Migration.Extensions; using Mongo.Migration.Migrations.Document; namespace Mongo.Migration.Migrations.Locators; internal class TypeMigrationLocator : MigrationLocator { - public TypeMigrationLocator(ILogger logger) : base(logger) { } - - public override void Locate() - { - var migrationTypes = - (from assembly in Assemblies - from type in assembly.GetTypes() - where typeof(IDocumentMigration).IsAssignableFrom(type) && !type.IsAbstract - select type).Distinct(); - - Migrations = migrationTypes - .Select(t => - Activator.CreateInstance(t) as IDocumentMigration - ?? throw new InvalidOperationException($"Cannot create {t} document migration")) - .ToMigrationDictionary(); - } + public TypeMigrationLocator(ILogger logger, IServiceProvider serviceProvider) : base(logger, serviceProvider) { } } \ No newline at end of file diff --git a/Mongo.Migration/Mongo.Migration.csproj b/Mongo.Migration/Mongo.Migration.csproj index 75f2b21..e16246d 100644 --- a/Mongo.Migration/Mongo.Migration.csproj +++ b/Mongo.Migration/Mongo.Migration.csproj @@ -1,11 +1,10 @@  - net7.0;net8.0;net9.0 + net8.0;net9.0 13.0 enable enable - op-icon.png embedded true true @@ -15,10 +14,10 @@ - Mongo.Migration + Mongo.RuntimeMigration git https://github.com/rpallares/Mongo.Migration - SRoddis;delepster;pleveille333;etiennelepagel;rpallares + rpallares Mongo.Migration is designed for the MongoDB.Driver to migrate documents easily and on-the-fly mongo, library, migration MIT @@ -28,7 +27,6 @@ - diff --git a/Mongo.Migration/Services/MigrationService.cs b/Mongo.Migration/Services/MigrationService.cs index c4f04f7..104d717 100644 --- a/Mongo.Migration/Services/MigrationService.cs +++ b/Mongo.Migration/Services/MigrationService.cs @@ -6,6 +6,7 @@ using Mongo.Migration.Documents.Serializers; using Mongo.Migration.Migrations.Database; using Mongo.Migration.Migrations.Document; +using Mongo.Migration.Migrations.Locators; using Mongo.Migration.Startup; using MongoDB.Bson.Serialization; using MongoDB.Driver; @@ -40,6 +41,9 @@ public void RegisterBsonStatics() { MigrationBsonSerializerProvider migrationSerializerProvider = _provider.GetRequiredService(); BsonSerializer.RegisterSerializationProvider(migrationSerializerProvider); + + var documentMigrationLocator = _provider.GetRequiredService>(); + documentMigrationLocator.Initialize(); } } diff --git a/README.md b/README.md index 35e318a..112c9be 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ ![GitHub License](https://img.shields.io/github/license/rpallares/Mongo.Migration) -![NuGet Downloads](https://img.shields.io/nuget/dt/Mongo.Migration) -![NuGet](https://img.shields.io/nuget/v/Mongo.Migration) +![NuGet Downloads](https://img.shields.io/nuget/dt/Mongo.RuntimeMigration) +![NuGet](https://img.shields.io/nuget/v/Mongo.RuntimeMigration) ![GitHub last commit](https://img.shields.io/github/last-commit/rpallares/Mongo.Migration) -# Mongo.Migration +# Mongo.RuntimeMigration ![](https://media.giphy.com/media/10tLOFXDFDjgQM/giphy.gif) -Mongo.Migration is designed for the [MongoDB C# Driver](https://github.com/mongodb/mongo-csharp-driver) to migrate your documents easily and on-the-fly. +Mongo.RuntimeMigration is designed for the [MongoDB C# Driver](https://github.com/mongodb/mongo-csharp-driver) to migrate your documents easily and on-the-fly. No more downtime for schema-migrations. Just write small and simple `migrations`. -Version 5.0.0 of Mongo.Migration is a code modernization and simplification release. It also has a strong focus on performance. +Version 5.0.0 of Mongo.RuntimeMigration is a code modernization and simplification release. It also has a strong focus on performance. The library is still based on the official [MongoDB.Driver](https://www.mongodb.com/docs/drivers/csharp/) (3.0.0+) and supports the following 3 types of migration: - **Runtime document migration:** @@ -28,11 +28,11 @@ A robust application will probably use two kind of migrations. # Installation -Install via nuget https://www.nuget.org/packages/Mongo.Migration +Install via nuget https://www.nuget.org/packages/Mongo.RuntimeMigration **Note:** The package isn't maintained since a while, so for now it's preferable to compile it locally ```shell -dotnet add package Mongo.Migration +dotnet add package Mongo.RuntimeMigration ``` # Register migration services @@ -114,7 +114,7 @@ You can still execute them at startup to migrate your database but this **is not } ``` 3`(Optional)` If you choose to put your migrations into an extra project, -add the suffix `".MongoMigrations"` to the name and make sure it is referenced in the main project. By convention Mongo.Migration collects all .dlls named like that in your bin folder. +add the suffix `".MongoMigrations"` to the name and make sure it is referenced in the main project. By convention Mongo.RuntimeMigration collects all .dlls named like that in your bin folder. Compile, run and enjoy! @@ -180,7 +180,7 @@ public class Car : IDocument { } ## CollectionLocation Add `CollectionLocation` attribute if you want to migrate your collections at startup with document migration. -This attribute tells Mongo.Migration where to find your Collections. +This attribute tells Mongo.RuntimeMigration where to find your Collections. ```csharp [CollectionLocation("Car")] @@ -202,11 +202,11 @@ Deploy the migrations in a separate artifact. Otherwise, you lose the ability to # Performance The performance is measured on every push to the repository with a small performance-test. -It measures the time MongoDB needs to insert and read `n documents` (5000) with and without Mongo.Migration. The difference is asserted and should be not higher than a given tolerance (150ms). +It measures the time MongoDB needs to insert and read `n documents` (5000) with and without Mongo.RuntimeMigration. The difference is asserted and should be not higher than a given tolerance (150ms). Example output of the automated test: ```bash -MongoDB: 21ms, Mongo.Migration: 210ms, Diff: 189ms (Tolerance: 600ms), Documents: 5000, Migrations per Document: 2 +MongoDB: 21ms, Mongo.RuntimeMigration: 210ms, Diff: 189ms (Tolerance: 600ms), Documents: 5000, Migrations per Document: 2 ``` After bigger changes the code is analyzed with profiling tools to check for performance or memory problems. @@ -240,7 +240,7 @@ This could be not 100% exhaustive but v5.0.0 did a lot of changes comparing to o Consider also there was a lot of changes between the last 3.1.4 officially published version and the source code. ### Updates -- .Net version update (.net7_0, .net8_0, .net9_0) +- .Net version update (.net8_0, .net9_0) - MongDB.Driver@3.0.0+ - Dependency updates - Remove Mongo2Go in favor of Testcontainers @@ -268,5 +268,8 @@ Consider also there was a lot of changes between the last 3.1.4 officially publi 2. Remove .net7_0 support # License +Mongo.RuntimeMigration is licensed under [MIT](http://www.opensource.org/licenses/mit-license.php "Read more about the MIT license form"). Refer to license.txt for more information. -Mongo.Migration is licensed under [MIT](http://www.opensource.org/licenses/mit-license.php "Read more about the MIT license form"). Refer to license.txt for more information. +It has been forked from [SRoddis/Mongo.Migration](https://github.com/SRoddis/Mongo.Migration) that is no longer maintained. +That's why the nuget name is `Mongo.RuntimeMigration` whereas namespace is still `Mongo.Migration`. +Thanks to SRoddis for that library.