using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using SurrealDb.Net; using TarninaHub.Application.Abstractions; using TarninaHub.Infrastructure.Settings; namespace TarninaHub.Infrastructure.Persistence; public sealed class MigrationRunner : IMigrationRunner { private readonly ISurrealDbClient _client; private readonly SurrealDbSettings _settings; private readonly ILogger _logger; public MigrationRunner( ISurrealDbClient client, IOptions settings, ILogger logger) { _client = client; _settings = settings.Value; _logger = logger; } public async Task ApplyAsync(CancellationToken cancellationToken) { await EnsureNamespaceAsync(cancellationToken); var migrationsPath = Path.Combine(AppContext.BaseDirectory, _settings.MigrationsDirectory); if (!Directory.Exists(migrationsPath)) { _logger.LogWarning( "Migrations directory '{MigrationsPath}' was not found; skipping migrations.", migrationsPath); return; } var files = Directory.GetFiles(migrationsPath, "*.surql") .OrderBy(file => file, StringComparer.Ordinal); foreach (var file in files) { var sql = await File.ReadAllTextAsync(file, cancellationToken); await _client.RawQuery(sql, cancellationToken: cancellationToken); _logger.LogInformation("Applied migration {Migration}.", Path.GetFileName(file)); } } private async Task EnsureNamespaceAsync(CancellationToken cancellationToken) { var sql = $"DEFINE NAMESPACE IF NOT EXISTS {_settings.Namespace}; " + $"USE NS {_settings.Namespace}; " + $"DEFINE DATABASE IF NOT EXISTS {_settings.Database}; " + $"USE DB {_settings.Database};"; await _client.RawQuery(sql, cancellationToken: cancellationToken); } }