feat: added database
This commit is contained in:
1 parent
4c517788fe
commit
91ae771ca2
7 files changed
+107
-1
No files matched your search
@@ -0,0 +1,43 @@
|
||||
using System.Reflection;
|
||||
using DbUp;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Npgsql;
|
||||
|
||||
namespace Hearth.Database;
|
||||
|
||||
// A hosted service so building the app (e.g. a schema export in CI) needs no database.
|
||||
// Not safe for two processes upgrading the same schema at once; Hearth.Api runs one replica with Recreate until the worker split.
|
||||
internal sealed class DatabaseUpgrade(
|
||||
string connectionString,
|
||||
string schema,
|
||||
Assembly scripts
|
||||
) : IHostedService
|
||||
{
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using (var connection = new NpgsqlConnection(connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
using var command = new NpgsqlCommand($"CREATE SCHEMA IF NOT EXISTS {schema}", connection);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
var result = DeployChanges.To
|
||||
.PostgresqlDatabase(connectionString)
|
||||
.JournalToPostgresqlTable(schema, "schema_versions")
|
||||
.WithScriptsEmbeddedInAssembly(scripts)
|
||||
.WithTransactionPerScript()
|
||||
.LogToConsole()
|
||||
.Build()
|
||||
.PerformUpgrade();
|
||||
|
||||
if (!result.Successful)
|
||||
{
|
||||
throw new InvalidOperationException($"Database upgrade of schema '{schema}' failed.", result.Error);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hearth.Database.Extensions;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
private const string ConnectionStringName = "Postgres";
|
||||
|
||||
// Registers a module's DbContext and upgrades its schema at startup with the SQL scripts embedded in the context's assembly.
|
||||
public static IServiceCollection AddHearthDatabase<TContext>(this IServiceCollection services, string schema)
|
||||
where TContext : DbContext
|
||||
{
|
||||
services.AddPooledDbContextFactory<TContext>((provider, options) => options
|
||||
.UseNpgsql(ConnectionString(provider)));
|
||||
services.AddScoped(provider => provider
|
||||
.GetRequiredService<IDbContextFactory<TContext>>()
|
||||
.CreateDbContext());
|
||||
|
||||
services.AddHostedService(provider => new DatabaseUpgrade(
|
||||
ConnectionString(provider),
|
||||
schema,
|
||||
typeof(TContext).Assembly
|
||||
));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static string ConnectionString(IServiceProvider provider) =>
|
||||
provider
|
||||
.GetRequiredService<IConfiguration>()
|
||||
.GetConnectionString(ConnectionStringName)
|
||||
?? throw new InvalidOperationException($"ConnectionStrings:{ConnectionStringName} is not configured.");
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="dbup-postgresql" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -4,8 +4,12 @@
|
||||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="13.6.4" />
|
||||
<PackageVersion Include="dbup-postgresql" Version="7.0.1" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.13" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.10.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.10.0" />
|
||||
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.3" />
|
||||
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.20.1" />
|
||||
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.20.1" />
|
||||
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.20.1" />
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</Folder>
|
||||
<Folder Name="/Commons/">
|
||||
<Project Path="Commons/Hearth.Commons/Hearth.Commons.csproj" />
|
||||
<Project Path="Commons/Hearth.Database/Hearth.Database.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/Characters/">
|
||||
<Project Path="Characters/Hearth.Characters/Hearth.Characters.csproj" />
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
var builder = DistributedApplication.CreateBuilder(args);
|
||||
|
||||
builder.AddProject<Projects.Hearth_Api>("api");
|
||||
var postgres = builder
|
||||
.AddPostgres("postgres")
|
||||
.WithDataVolume()
|
||||
.WithLifetime(ContainerLifetime.Persistent);
|
||||
|
||||
var database = postgres.AddDatabase("hearth");
|
||||
|
||||
builder
|
||||
.AddProject<Projects.Hearth_Api>("api")
|
||||
.WithReference(database, "Postgres")
|
||||
.WaitFor(database);
|
||||
|
||||
builder.Build().Run();
|
||||
@@ -6,6 +6,10 @@
|
||||
<UserSecretsId>388fbdf7-df04-4c75-858e-1bdc720d2a91</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.PostgreSQL" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Hearth.Api\Hearth.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in new issue
Block a user