using Dapper; using Galaeth.Core.Exceptions; using Galaeth.Core.Infrastructure; using Injectio.Attributes; using Microsoft.Extensions.Logging; namespace Galaeth.DAL.Infrastructure; /// [RegisterScoped] public class DatabaseMigrator : IDatabaseMigrator { private readonly IDbConnectionProvider _dbConnectionProvider; private readonly ITransactionProvider _transactionProvider; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Instance of . /// Instance of . /// Instance of . public DatabaseMigrator( IDbConnectionProvider dbConnectionProvider, ITransactionProvider transactionProvider, ILogger logger) { _dbConnectionProvider = dbConnectionProvider; _transactionProvider = transactionProvider; _logger = logger; } /// public async Task MigrateDatabaseAsync(string migrationsPath) { var connection = await _dbConnectionProvider.OpenConnectionAsync(); _logger.LogInformation("Beginning database migrations"); using var transaction = await _transactionProvider.BeginTransactionAsync(); await connection.ExecuteAsync(""" CREATE TABLE IF NOT EXISTS migrations ( date_added TIMESTAMP NOT NULL, filename VARCHAR(128) NOT NULL, CONSTRAINT migrations_filename_pk PRIMARY KEY (filename) ); """); var appliedMigrationsEnumerable = await connection.QueryAsync("SELECT filename FROM migrations ORDER BY date_added;"); // Prevent multiple enumeration. var appliedMigrations = appliedMigrationsEnumerable.ToList(); var files = Directory.GetFiles(migrationsPath, "*.sql").ToList(); files.Sort(); foreach (var filename in files) { var file = filename.Replace(migrationsPath, string.Empty).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); if (appliedMigrations.Contains(file)) { _logger.LogInformation("Already applied: {file}", file); continue; } _logger.LogInformation("Applying {file}...", file); try { var sql = await File.ReadAllTextAsync(filename); await connection.ExecuteAsync(sql); await connection.ExecuteAsync( "INSERT INTO migrations (date_added, filename) SELECT CURRENT_TIMESTAMP, @pFilename ;", new { pFilename = file, }); } catch (Exception e) { throw new MigrationException(file, e.Message); } } transaction.Commit(); _logger.LogInformation("Database migrations complete"); } }