feat(server): add database context and migrations

This commit is contained in:
Stevan Freeborn
2026-01-04 21:10:44 -06:00
parent 18b8dec374
commit 7ba17ea0e3
12 changed files with 383 additions and 0 deletions
@@ -0,0 +1,32 @@
using GroundsForSupport.Server.Payments;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace GroundsForSupport.Server.Data;
internal sealed class Context(
IOptions<ContextOptions> ctxOptions,
DbContextOptions<Context> options
) : DbContext(options)
{
private const string DataSourceKey = "Data Source=";
private readonly ContextOptions _ctxOptions = ctxOptions.Value;
public DbSet<Payment> Payments => Set<Payment>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var dbPath = _ctxOptions.GetFullyQualifiedDatabasePath();
var dbDirectory = Path.GetDirectoryName(dbPath) ?? throw new InvalidOperationException("Database directory path could not be determined.");
if (Directory.Exists(dbDirectory) is false)
{
Directory.CreateDirectory(dbDirectory);
}
var connectionString = $"{DataSourceKey}{dbPath}";
optionsBuilder.UseSqlite(connectionString);
}
}
@@ -0,0 +1,28 @@
using Microsoft.Extensions.Options;
namespace GroundsForSupport.Server.Data;
internal sealed record ContextOptions
{
public string DatabaseFilePath { get; init; } = string.Empty;
public string GetFullyQualifiedDatabasePath()
{
return Path.GetFullPath(DatabaseFilePath, AppContext.BaseDirectory);
}
}
internal sealed record ContextOptionsSetup : IConfigureOptions<ContextOptions>
{
private const string SectionName = nameof(ContextOptions);
private readonly IConfiguration _configuration;
public ContextOptionsSetup(IConfiguration configuration)
{
_configuration = configuration;
}
public void Configure(ContextOptions options)
{
_configuration.GetSection(SectionName).Bind(options);
}
}
@@ -0,0 +1,27 @@
using Microsoft.EntityFrameworkCore;
namespace GroundsForSupport.Server.Data;
internal sealed class MigrationService(
IServiceProvider serviceProvider,
ILogger<MigrationService> logger
) : IHostedService
{
private readonly IServiceProvider _serviceProvider = serviceProvider;
public async Task StartAsync(CancellationToken cancellationToken)
{
logger.LogInformation("Applying database migrations...");
using var scope = _serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<Context>();
await context.Database.MigrateAsync(cancellationToken);
logger.LogInformation("Database migrations applied.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}