using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NDB.Infrastructure.DatabaseMigration.Models; using NDB.Infrastructure.DatabaseMigration.Repositories; using NDB.Infrastructure.DatabaseMigration.Services.Abstractions; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; namespace NDB.Infrastructure.DatabaseMigration.Services { internal class MigrationService : IMigrationService { private readonly ILogger _logger; private readonly IServiceProvider _serviceProvider; private readonly ServiceConfiguration _configuration; private readonly IMetadataLocationService _metadataLocationService; private readonly IMigrationSignaturesService _migrationSignaturesService; public MigrationService(ILogger logger, IServiceProvider serviceProvider, ServiceConfiguration configuration, IMetadataLocationService metadataLocationService, IMigrationSignaturesService migrationSignaturesService) { _logger = logger; _serviceProvider = serviceProvider; _configuration = configuration; _metadataLocationService = metadataLocationService; _migrationSignaturesService = migrationSignaturesService; } public void Execute() => ExecuteAsync().GetAwaiter().GetResult(); private async Task ExecuteAsync() { _logger.LogInformation("Starting migration..."); await _metadataLocationService.Check(); var lastSignature = await _migrationSignaturesService.GetLastMigrationSignature(); var lastInstalledVersion = lastSignature?.LastVersion ?? "0.0.0"; var targetVersion = new Version(lastInstalledVersion); var scriptPacks = GetScriptPacks(); var packsToInstall = scriptPacks.Where(p => p.Version > targetVersion); if (!packsToInstall.Any()) { _logger.LogInformation("Nothing to migrate."); return; } var signature = new MigrationSignature() { MachineName = System.Environment.MachineName, MigrationDate = DateTime.Now }; var migratedVersions = new List(); foreach (var pack in packsToInstall.OrderBy(p => p.Version)) { var scripts = Directory.GetFiles(pack.Path); if (!scripts.Any()) continue; _logger.LogInformation($"Running script pack '{pack.Version}' with {scripts.Length} scripts:"); foreach (var script in scripts) await RunScript(script); var migratedVersion = new MigratedVersion() { Version = pack.Version.ToString(), Scripts = scripts.Select(z => Path.GetFileName(z)).ToArray() }; migratedVersions.Add(migratedVersion); } signature.MigratedVersions = migratedVersions.ToArray(); signature.LastVersion = packsToInstall.OrderByDescending(z => z.Version).First().Version.ToString(); await _migrationSignaturesService.SaveMigrationSignature(signature); } private ScriptPack[] GetScriptPacks() { var scripts = Directory.GetDirectories(_configuration.ScriptsDirectory); var packs = scripts.Select(z => new ScriptPack() { Path = z, Version = new Version(new DirectoryInfo(z).Name) }); return packs.ToArray(); } private async Task RunScript(string path) { _logger.LogInformation($"Running sql script: '{path}'"); var sqlContent = File.ReadAllText(path); if (string.IsNullOrEmpty(sqlContent)) return; using (var scope = _serviceProvider.CreateScope()) { var _repository = scope.ServiceProvider.GetRequiredService(); await _repository.ExecuteSqlRaw(sqlContent); } } } }