adding
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using LCU.API.Internal.DocumentLib.Utilities;
|
||||
using MongoDB.Driver;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration;
|
||||
|
||||
public class AttributeMigration<T> : IAttributeMigration
|
||||
{
|
||||
private readonly IDocumentFilterFactory _filterFactory;
|
||||
private readonly IMongoCollectionFactory _collectionFactory;
|
||||
private readonly string _attributeName;
|
||||
private readonly IValueParsingStrategy<T> _valueParsingStrategy;
|
||||
private readonly string _destinationProperty;
|
||||
private readonly IObserver<DocumentInformation> _observer;
|
||||
|
||||
public AttributeMigration
|
||||
(
|
||||
IMongoCollectionFactory collectionFactory,
|
||||
string attributeName,
|
||||
IValueParsingStrategy<T> valueParsingStrategy,
|
||||
string destinationProperty,
|
||||
IObserver<DocumentInformation> observer,
|
||||
IDocumentFilterFactory filterFactory
|
||||
)
|
||||
{
|
||||
_attributeName = attributeName;
|
||||
_valueParsingStrategy = valueParsingStrategy;
|
||||
_destinationProperty = destinationProperty;
|
||||
_observer = observer;
|
||||
_collectionFactory = collectionFactory;
|
||||
_filterFactory = filterFactory;
|
||||
}
|
||||
|
||||
public async Task Migrate(CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return;
|
||||
|
||||
try
|
||||
{
|
||||
if (typeof(DocumentInformation).GetProperty(_destinationProperty) is null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var hasAttribute = _filterFactory.AppliesForMigrationFilterFactory(_attributeName, _destinationProperty);
|
||||
var collection = _collectionFactory.GetCollection<DocumentInformation>();
|
||||
var documents = await RetryOnTooManyRequests(async () => await collection.FindAsync(hasAttribute, cancellationToken: cancellationToken), cancellationToken);
|
||||
|
||||
var done = false;
|
||||
while (!done)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested && await documents.MoveNextAsync(cancellationToken))
|
||||
{
|
||||
foreach (var document in documents.Current)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) break;
|
||||
|
||||
_observer.OnNext(document);
|
||||
|
||||
var value = _valueParsingStrategy.Parse(document.Attributes[_attributeName]);
|
||||
await RetryOnTooManyRequests(async () => await collection.FindOneAndUpdateAsync
|
||||
(
|
||||
d => d.DocumentId == document.DocumentId,
|
||||
Builders<DocumentInformation>.Update.Set(_destinationProperty, value),
|
||||
cancellationToken: cancellationToken
|
||||
), cancellationToken);
|
||||
|
||||
_observer.OnCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
done = true;
|
||||
}
|
||||
catch (MongoCursorNotFoundException e)
|
||||
{
|
||||
_observer.OnError(e);
|
||||
|
||||
documents = await RetryOnTooManyRequests(async () => await collection.FindAsync(hasAttribute, cancellationToken: cancellationToken), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_observer.OnError(e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<TU> RetryOnTooManyRequests<TU>(Func<Task<TU>> action, CancellationToken cancellationToken)
|
||||
where TU : class
|
||||
{
|
||||
TU? result = null;
|
||||
while (result is null)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = await action();
|
||||
}
|
||||
catch (MongoCommandException e)
|
||||
{
|
||||
if (e.Code == 16500)
|
||||
{
|
||||
_observer.OnError(e);
|
||||
|
||||
var wait = int.Parse(Regex.Match(e.Result.GetValue("errmsg").AsString, "\\bRetryAfterMs=(\\d+)\\b").Groups[1].ValueSpan);
|
||||
await Task.Delay(wait, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace OwnerNumberMigration;
|
||||
|
||||
public class DocumentFilterFactory : IDocumentFilterFactory
|
||||
{
|
||||
public FilterDefinition<DocumentInformation> AppliesForMigrationFilterFactory(string attributeName, string destinationAttributeName)
|
||||
{
|
||||
return Builders<DocumentInformation>.Filter.Exists($"Attributes.{attributeName}")
|
||||
& !Builders<DocumentInformation>.Filter.Exists(destinationAttributeName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration;
|
||||
|
||||
public delegate IAttributeMigration AttributeMigrationFactory<in T>
|
||||
(
|
||||
string attributeName,
|
||||
IValueParsingStrategy<T> valueParsingStrategy,
|
||||
string destinationProperty
|
||||
);
|
||||
|
||||
public interface IAttributeMigration
|
||||
{
|
||||
Task Migrate(CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace OwnerNumberMigration;
|
||||
|
||||
public interface IDocumentFilterFactory
|
||||
{
|
||||
FilterDefinition<DocumentInformation> AppliesForMigrationFilterFactory(string attributeName, string destinationAttributeName);
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using LCU.API.Internal.DocumentLib.Utilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace OwnerNumberMigration.Logging;
|
||||
|
||||
public delegate IAttributeMigration AttributeMigrationLoggingDecoratorFactory
|
||||
(
|
||||
IAttributeMigration migration,
|
||||
string attributeName,
|
||||
string destinationAttributeName
|
||||
);
|
||||
|
||||
public class AttributeMigrationLoggingDecorator : IAttributeMigration
|
||||
{
|
||||
private readonly IAttributeMigration _migration;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IMongoCollection<DocumentInformation> _documents;
|
||||
private readonly string _attributeName;
|
||||
private readonly string _destinationAttributeName;
|
||||
private readonly IDocumentFilterFactory _filterFactory;
|
||||
|
||||
public AttributeMigrationLoggingDecorator
|
||||
(
|
||||
IAttributeMigration migration,
|
||||
ILogger logger,
|
||||
IMongoCollectionFactory collectionFactory,
|
||||
string attributeName,
|
||||
string destinationAttributeName,
|
||||
IDocumentFilterFactory filterFactory
|
||||
)
|
||||
{
|
||||
_migration = migration;
|
||||
_logger = logger;
|
||||
_documents = collectionFactory.GetCollection<DocumentInformation>();
|
||||
_attributeName = attributeName;
|
||||
_destinationAttributeName = destinationAttributeName;
|
||||
_filterFactory = filterFactory;
|
||||
}
|
||||
|
||||
public async Task Migrate(CancellationToken cancellationToken)
|
||||
{
|
||||
var countToMigration = await _documents.CountDocumentsAsync
|
||||
(
|
||||
_filterFactory.AppliesForMigrationFilterFactory(_attributeName, _destinationAttributeName),
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
_logger.LogInformation
|
||||
(
|
||||
"starting to migration {attribute} with {count} documents",
|
||||
_attributeName,
|
||||
countToMigration
|
||||
);
|
||||
var start = DateTime.Now;
|
||||
|
||||
await _migration.Migrate(cancellationToken);
|
||||
|
||||
var duration = DateTime.Now - start;
|
||||
_logger.LogInformation("finished migration for {attribute} in {elapsed}", _attributeName, duration);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace OwnerNumberMigration.Logging;
|
||||
|
||||
public delegate IObserver<DocumentInformation> AttributeMigrationLoggingObserverFactory(string attributeName);
|
||||
|
||||
public class AttributeMigrationLoggingObserver : IObserver<DocumentInformation>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly string _attributeName;
|
||||
|
||||
public AttributeMigrationLoggingObserver(ILogger logger, string attributeName)
|
||||
{
|
||||
_logger = logger;
|
||||
_attributeName = attributeName;
|
||||
}
|
||||
|
||||
public void OnCompleted()
|
||||
{
|
||||
_logger.LogInformation("completed one migration for {attribute}", _attributeName);
|
||||
}
|
||||
|
||||
public void OnError(Exception error)
|
||||
{
|
||||
_logger.LogError("migration error {error} in migration for {attribute}", error, _attributeName);
|
||||
}
|
||||
|
||||
public void OnNext(DocumentInformation value)
|
||||
{
|
||||
_logger.LogInformation("starting one migration for {attribute} on {documentId}", _attributeName, value.DocumentId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public class AccountNumberMigration : AttributeMigrationTask<string>
|
||||
{
|
||||
public AccountNumberMigration
|
||||
(
|
||||
AttributeMigrationFactory<string> factory,
|
||||
IParsingStrategyFactory strategyFactory,
|
||||
IMigrationManager manager
|
||||
)
|
||||
: base
|
||||
(
|
||||
"AccountNumber",
|
||||
nameof(DocumentInformation.AccountNumber),
|
||||
factory,
|
||||
strategyFactory,
|
||||
manager
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public abstract class AttributeMigrationTask<T> : IHostedService
|
||||
{
|
||||
private readonly IAttributeMigration _migration;
|
||||
private readonly CancellationTokenSource _cancellation = new();
|
||||
private readonly IMigrationManager _manager;
|
||||
|
||||
private Task? _runningMigration;
|
||||
|
||||
protected AttributeMigrationTask
|
||||
(
|
||||
string sourceAttribute,
|
||||
string destinationAttribute,
|
||||
AttributeMigrationFactory<T> factory,
|
||||
IParsingStrategyFactory strategyFactory,
|
||||
IMigrationManager manager
|
||||
)
|
||||
{
|
||||
_manager = manager;
|
||||
_migration = factory
|
||||
(
|
||||
sourceAttribute,
|
||||
strategyFactory.CreateParsingStrategy<T>(sourceAttribute),
|
||||
destinationAttribute
|
||||
);
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return Task.CompletedTask;
|
||||
|
||||
_manager.Start(_runningMigration = _migration.Migrate(_cancellation.Token));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_runningMigration is not null)
|
||||
{
|
||||
if (!_runningMigration.IsCompleted)
|
||||
{
|
||||
_cancellation.Cancel();
|
||||
try
|
||||
{
|
||||
await _runningMigration;
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
_runningMigration.Dispose();
|
||||
}
|
||||
|
||||
_cancellation.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public interface IMigrationManager
|
||||
{
|
||||
public void Start(Task migrationTask);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public class MigrationManager : IMigrationManager
|
||||
{
|
||||
private readonly IHostApplicationLifetime _appLifetime;
|
||||
private readonly IList<Task> _migrationTasks = new List<Task>();
|
||||
|
||||
private static readonly IReadOnlySet<TaskStatus> CompletedStatuses = new HashSet<TaskStatus>
|
||||
{
|
||||
TaskStatus.Faulted,
|
||||
TaskStatus.Canceled,
|
||||
TaskStatus.RanToCompletion
|
||||
};
|
||||
|
||||
public MigrationManager(IHostApplicationLifetime appLifetime)
|
||||
{
|
||||
_appLifetime = appLifetime;
|
||||
}
|
||||
|
||||
public void Start(Task migrationTask)
|
||||
{
|
||||
_migrationTasks.Add(migrationTask);
|
||||
|
||||
migrationTask.ContinueWith(_ =>
|
||||
{
|
||||
lock (_migrationTasks)
|
||||
{
|
||||
if (_migrationTasks.All(t => CompletedStatuses.Contains(t.Status)))
|
||||
{
|
||||
_appLifetime.StopApplication();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public class OrganizationNumberMigration : AttributeMigrationTask<string[]>
|
||||
{
|
||||
public OrganizationNumberMigration
|
||||
(
|
||||
AttributeMigrationFactory<string[]> factory,
|
||||
IParsingStrategyFactory strategyFactory,
|
||||
IMigrationManager manager
|
||||
)
|
||||
: base
|
||||
(
|
||||
"OrganizationNumber",
|
||||
nameof(DocumentInformation.OrganizationNumbers),
|
||||
factory,
|
||||
strategyFactory,
|
||||
manager
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public class OrganizationNumbersMigration : AttributeMigrationTask<string[]>
|
||||
{
|
||||
public OrganizationNumbersMigration
|
||||
(
|
||||
AttributeMigrationFactory<string[]> factory,
|
||||
IParsingStrategyFactory strategyFactory,
|
||||
IMigrationManager manager
|
||||
)
|
||||
: base
|
||||
(
|
||||
"OrganizationNumbers",
|
||||
nameof(DocumentInformation.OrganizationNumbers),
|
||||
factory,
|
||||
strategyFactory,
|
||||
manager
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public class PersonNumberMigration : AttributeMigrationTask<string[]>
|
||||
{
|
||||
public PersonNumberMigration
|
||||
(
|
||||
AttributeMigrationFactory<string[]> factory,
|
||||
IParsingStrategyFactory strategyFactory,
|
||||
IMigrationManager manager
|
||||
)
|
||||
: base
|
||||
(
|
||||
"PersonNumber",
|
||||
nameof(DocumentInformation.PersonNumbers),
|
||||
factory,
|
||||
strategyFactory,
|
||||
manager
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
|
||||
namespace OwnerNumberMigration.Migrations;
|
||||
|
||||
public class PersonNumbersMigration : AttributeMigrationTask<string[]>
|
||||
{
|
||||
public PersonNumbersMigration
|
||||
(
|
||||
AttributeMigrationFactory<string[]> factory,
|
||||
IParsingStrategyFactory strategyFactory,
|
||||
IMigrationManager manager
|
||||
)
|
||||
: base
|
||||
(
|
||||
"PersonNumbers",
|
||||
nameof(DocumentInformation.PersonNumbers),
|
||||
factory,
|
||||
strategyFactory,
|
||||
manager
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\LCU.API.Internal.Document\appsettings.json" Link="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LCU.Library.Internal.Configuration" Version="1.0.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LCU.API.Internal.DocumentLib\LCU.API.Internal.DocumentLib.csproj" />
|
||||
<ProjectReference Include="..\LCU.API.Internal.Document\LCU.API.Internal.Document.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Logging\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties /></VisualStudio></ProjectExtensions>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,137 @@
|
||||
using LCU.API.Internal.DocumentLib.Configurations;
|
||||
using LCU.API.Internal.DocumentLib.Utilities;
|
||||
using LCU.Library.Internal.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using OwnerNumberMigration;
|
||||
using OwnerNumberMigration.Logging;
|
||||
using OwnerNumberMigration.Migrations;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
using Azure.Identity;
|
||||
using LCU.API.Internal.DocumentLib.Containers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OwnerNumberMigration.ValueParsing;
|
||||
using Serilog;
|
||||
using LCU.Library.Internal.Logging.Models;
|
||||
using LCU.Library.Internal.Logging;
|
||||
|
||||
await Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration((host, configuration) =>
|
||||
{
|
||||
var vaultConfiguration = configuration.Build();
|
||||
var clientSecretCredentials = new ClientSecretCredential
|
||||
(
|
||||
vaultConfiguration["TenantId"],
|
||||
vaultConfiguration["ClientId"],
|
||||
vaultConfiguration["ClientSecret"]
|
||||
);
|
||||
var vaultLocation = new Uri($"https://{vaultConfiguration["AzureKeyVaultUrl"]}.vault.azure.net/");
|
||||
|
||||
configuration.AddAzureKeyVault(vaultLocation, clientSecretCredentials);
|
||||
})
|
||||
/* remove for local */
|
||||
.UseSerilog()
|
||||
/* to here */
|
||||
/* local:
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging
|
||||
.AddConsole()
|
||||
.AddFile("Logs/OwnerMigration-{Date}.log", isJson: true)
|
||||
.SetMinimumLevel(LogLevel.Information);
|
||||
})
|
||||
*/
|
||||
.ConfigureServices((host, services) =>
|
||||
{
|
||||
services.RegisterOwnerMigrationServices();
|
||||
|
||||
host.Configuration.Bind<DatabaseConfiguration>(services, "MongoDatabase");
|
||||
host.Configuration.Bind<NotificationApiConfiguration>(services, "NotificationApiConfiguration");
|
||||
|
||||
/* remove for local */
|
||||
var loggingConfiguration = host.Configuration.GetSection("Primary");
|
||||
var loggerConfiguration = new LoggingConfiguration
|
||||
(
|
||||
loggingConfiguration["AppName"],
|
||||
loggingConfiguration["SeqUrl"],
|
||||
loggingConfiguration["SeqApiKey"]
|
||||
);
|
||||
var lcuLogging = new LcuLogging(loggerConfiguration);
|
||||
lcuLogging.UseLcuLogging();
|
||||
/* to here */
|
||||
})
|
||||
.RunConsoleAsync();
|
||||
|
||||
public static class ServiceRegistrationExtension
|
||||
{
|
||||
public static IServiceCollection RegisterOwnerMigrationServices(this IServiceCollection services)
|
||||
{
|
||||
ServiceRegistrations.AddDocumentRepositories(services);
|
||||
services.AddTransient<ILogger>(p => p.GetRequiredService<ILogger<DocumentInformation>>());
|
||||
services.AddTransient<SingleValueStrategy>();
|
||||
services.AddTransient<SingleValueArrayStrategy>();
|
||||
services.AddTransient<CommaStringArrayStrategy>();
|
||||
services.AddTransient<IParsingStrategyFactory, ParsingStrategyFactory>();
|
||||
services.AddTransient<IDocumentFilterFactory, DocumentFilterFactory>();
|
||||
services.AddTransient<AttributeMigrationLoggingDecoratorFactory>(p => (migration, name, destination) =>
|
||||
new AttributeMigrationLoggingDecorator
|
||||
(
|
||||
migration,
|
||||
p.GetRequiredService<ILogger>(),
|
||||
p.GetRequiredService<IMongoCollectionFactory>(),
|
||||
name,
|
||||
destination,
|
||||
p.GetRequiredService<IDocumentFilterFactory>()
|
||||
)
|
||||
);
|
||||
services.AddTransient<AttributeMigrationLoggingObserverFactory>(p => name =>
|
||||
new AttributeMigrationLoggingObserver
|
||||
(
|
||||
p.GetRequiredService<ILogger>(),
|
||||
name
|
||||
)
|
||||
);
|
||||
services.AddTransient<AttributeMigrationFactory<string>>(p => (name, strategy, property) =>
|
||||
p.GetRequiredService<AttributeMigrationLoggingDecoratorFactory>()
|
||||
(
|
||||
new AttributeMigration<string>
|
||||
(
|
||||
p.GetRequiredService<IMongoCollectionFactory>(),
|
||||
name,
|
||||
strategy,
|
||||
property,
|
||||
p.GetRequiredService<AttributeMigrationLoggingObserverFactory>()(name),
|
||||
p.GetRequiredService<IDocumentFilterFactory>()
|
||||
),
|
||||
name,
|
||||
property
|
||||
)
|
||||
);
|
||||
services.AddTransient<AttributeMigrationFactory<string[]>>(p => (name, strategy, property) =>
|
||||
p.GetRequiredService<AttributeMigrationLoggingDecoratorFactory>()
|
||||
(
|
||||
new AttributeMigration<string[]>
|
||||
(
|
||||
p.GetRequiredService<IMongoCollectionFactory>(),
|
||||
name,
|
||||
strategy,
|
||||
property,
|
||||
p.GetRequiredService<AttributeMigrationLoggingObserverFactory>()(name),
|
||||
p.GetRequiredService<IDocumentFilterFactory>()
|
||||
),
|
||||
name,
|
||||
property
|
||||
)
|
||||
);
|
||||
|
||||
services.AddSingleton<IMigrationManager, MigrationManager>();
|
||||
services.AddHostedService<PersonNumberMigration>();
|
||||
services.AddHostedService<PersonNumbersMigration>();
|
||||
services.AddHostedService<OrganizationNumberMigration>();
|
||||
services.AddHostedService<OrganizationNumbersMigration>();
|
||||
services.AddHostedService<AccountNumberMigration>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"profiles": {
|
||||
"OwnerNumberMigration": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
namespace OwnerNumberMigration.ValueParsing;
|
||||
|
||||
public class CommaStringArrayStrategy : IValueParsingStrategy<string[]>
|
||||
{
|
||||
public string[] Parse(string value) => value.Split(",");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OwnerNumberMigration.ValueParsing;
|
||||
|
||||
public interface IParsingStrategyFactory
|
||||
{
|
||||
IValueParsingStrategy<T> CreateParsingStrategy<T>(string attribute);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OwnerNumberMigration.ValueParsing;
|
||||
|
||||
public interface IValueParsingStrategy<out T>
|
||||
{
|
||||
T Parse(string value);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace OwnerNumberMigration.ValueParsing;
|
||||
|
||||
public class ParsingStrategyFactory : IParsingStrategyFactory
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public ParsingStrategyFactory(IServiceProvider services)
|
||||
{
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public IValueParsingStrategy<T> CreateParsingStrategy<T>(string attribute) => attribute switch
|
||||
{
|
||||
"PersonNumber" => (IValueParsingStrategy<T>)_services.GetRequiredService<SingleValueArrayStrategy>(),
|
||||
"PersonNumbers" => (IValueParsingStrategy<T>)_services.GetRequiredService<CommaStringArrayStrategy>(),
|
||||
"OrganizationNumber" => (IValueParsingStrategy<T>)_services.GetRequiredService<SingleValueArrayStrategy>(),
|
||||
"OrganizationNumbers" => (IValueParsingStrategy<T>)_services.GetRequiredService<CommaStringArrayStrategy>(),
|
||||
"AccountNumber" => (IValueParsingStrategy<T>)_services.GetRequiredService<SingleValueStrategy>(),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
namespace OwnerNumberMigration.ValueParsing;
|
||||
|
||||
public class SingleValueArrayStrategy : IValueParsingStrategy<string[]>
|
||||
{
|
||||
public string[] Parse(string value) => new[] { value };
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace OwnerNumberMigration.ValueParsing;
|
||||
|
||||
public class SingleValueStrategy : IValueParsingStrategy<string>
|
||||
{
|
||||
public string Parse(string value) => value;
|
||||
}
|
||||
Reference in New Issue
Block a user