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>
|
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<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.Http.Resilience" Version="10.10.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" 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.Exporter.OpenTelemetryProtocol" Version="1.20.1" />
|
||||||
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.20.1" />
|
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.20.1" />
|
||||||
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.20.1" />
|
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.20.1" />
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/Commons/">
|
<Folder Name="/Commons/">
|
||||||
<Project Path="Commons/Hearth.Commons/Hearth.Commons.csproj" />
|
<Project Path="Commons/Hearth.Commons/Hearth.Commons.csproj" />
|
||||||
|
<Project Path="Commons/Hearth.Database/Hearth.Database.csproj" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/Characters/">
|
<Folder Name="/Characters/">
|
||||||
<Project Path="Characters/Hearth.Characters/Hearth.Characters.csproj" />
|
<Project Path="Characters/Hearth.Characters/Hearth.Characters.csproj" />
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
var builder = DistributedApplication.CreateBuilder(args);
|
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();
|
builder.Build().Run();
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
<UserSecretsId>388fbdf7-df04-4c75-858e-1bdc720d2a91</UserSecretsId>
|
<UserSecretsId>388fbdf7-df04-4c75-858e-1bdc720d2a91</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Aspire.Hosting.PostgreSQL" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Hearth.Api\Hearth.Api.csproj" />
|
<ProjectReference Include="..\Hearth.Api\Hearth.Api.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
Reference in new issue
Block a user