75 lines
2.8 KiB
C#
75 lines
2.8 KiB
C#
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Logging;
|
|
using MongoDB.Driver;
|
|
|
|
namespace StellaOps.Vexer.Storage.Mongo.Migrations;
|
|
|
|
internal sealed class VexMongoMigrationRunner
|
|
{
|
|
private readonly IMongoDatabase _database;
|
|
private readonly IReadOnlyList<IVexMongoMigration> _migrations;
|
|
private readonly ILogger<VexMongoMigrationRunner> _logger;
|
|
|
|
public VexMongoMigrationRunner(
|
|
IMongoDatabase database,
|
|
IEnumerable<IVexMongoMigration> migrations,
|
|
ILogger<VexMongoMigrationRunner> logger)
|
|
{
|
|
_database = database ?? throw new ArgumentNullException(nameof(database));
|
|
_migrations = (migrations ?? throw new ArgumentNullException(nameof(migrations)))
|
|
.OrderBy(migration => migration.Id, StringComparer.Ordinal)
|
|
.ToArray();
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
public async ValueTask RunAsync(CancellationToken cancellationToken)
|
|
{
|
|
if (_migrations.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var migrationsCollection = _database.GetCollection<VexMigrationRecord>(VexMongoCollectionNames.Migrations);
|
|
await EnsureMigrationsIndexAsync(migrationsCollection, cancellationToken).ConfigureAwait(false);
|
|
|
|
var applied = await LoadAppliedMigrationsAsync(migrationsCollection, cancellationToken).ConfigureAwait(false);
|
|
|
|
foreach (var migration in _migrations)
|
|
{
|
|
if (applied.Contains(migration.Id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
_logger.LogInformation("Applying Vexer Mongo migration {MigrationId}", migration.Id);
|
|
await migration.ExecuteAsync(_database, cancellationToken).ConfigureAwait(false);
|
|
|
|
var record = new VexMigrationRecord(migration.Id, DateTimeOffset.UtcNow);
|
|
await migrationsCollection.InsertOneAsync(record, cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
_logger.LogInformation("Completed Vexer Mongo migration {MigrationId}", migration.Id);
|
|
}
|
|
}
|
|
|
|
private static ValueTask EnsureMigrationsIndexAsync(
|
|
IMongoCollection<VexMigrationRecord> collection,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
// default _id index already enforces uniqueness
|
|
return ValueTask.CompletedTask;
|
|
}
|
|
|
|
private static async ValueTask<HashSet<string>> LoadAppliedMigrationsAsync(
|
|
IMongoCollection<VexMigrationRecord> collection,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var records = await collection.Find(FilterDefinition<VexMigrationRecord>.Empty)
|
|
.ToListAsync(cancellationToken)
|
|
.ConfigureAwait(false);
|
|
|
|
return records.Select(static record => record.Id)
|
|
.ToHashSet(StringComparer.Ordinal);
|
|
}
|
|
}
|