91 lines
3.3 KiB
C#
91 lines
3.3 KiB
C#
using Dapper;
|
|
using Galaeth.Core.Exceptions;
|
|
using Galaeth.Core.Infrastructure;
|
|
using Injectio.Attributes;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Galaeth.DAL.Infrastructure;
|
|
|
|
/// <inheritdoc />
|
|
[RegisterScoped]
|
|
public class DatabaseMigrator : IDatabaseMigrator
|
|
{
|
|
private readonly IDbConnectionProvider _dbConnectionProvider;
|
|
private readonly ITransactionProvider _transactionProvider;
|
|
private readonly ILogger<DatabaseMigrator> _logger;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="DatabaseMigrator"/> class.
|
|
/// </summary>
|
|
/// <param name="dbConnectionProvider">Instance of <see cref="IDbConnectionProvider"/>.</param>
|
|
/// <param name="transactionProvider">Instance of <see cref="ITransactionProvider"/>.</param>
|
|
/// <param name="logger">Instance of <see cref="ILogger"/>.</param>
|
|
public DatabaseMigrator(
|
|
IDbConnectionProvider dbConnectionProvider,
|
|
ITransactionProvider transactionProvider,
|
|
ILogger<DatabaseMigrator> logger)
|
|
{
|
|
_dbConnectionProvider = dbConnectionProvider;
|
|
_transactionProvider = transactionProvider;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
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<string>("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");
|
|
}
|
|
}
|