Backend (.NET 10): - EventFlow CQRS/Event Sourcing with PostgreSQL - GraphQL.NET API with mutations and queries - Custom ReadModelSqlGenerator for snake_case PostgreSQL columns - Hangfire for background job processing - Integration tests with isolated test databases Frontend (React/Vite): - Initial project structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
43 lines
1.2 KiB
C#
43 lines
1.2 KiB
C#
using System.Reflection;
|
|
using Dapper;
|
|
using DbUp;
|
|
using Npgsql;
|
|
|
|
namespace Books.Api.EventFlow.Infrastructure;
|
|
|
|
public static class DatabaseMigrator
|
|
{
|
|
public static void Migrate(string connectionString)
|
|
{
|
|
EnsureDatabaseExists(connectionString);
|
|
|
|
var upgrader = DeployChanges.To
|
|
.PostgresqlDatabase(connectionString)
|
|
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly())
|
|
.LogToConsole()
|
|
.Build();
|
|
|
|
var result = upgrader.PerformUpgrade();
|
|
if (!result.Successful)
|
|
throw result.Error;
|
|
}
|
|
|
|
private static void EnsureDatabaseExists(string connectionString)
|
|
{
|
|
var builder = new NpgsqlConnectionStringBuilder(connectionString);
|
|
var database = builder.Database;
|
|
builder.Database = "postgres";
|
|
|
|
using var connection = new NpgsqlConnection(builder.ConnectionString);
|
|
connection.Open();
|
|
|
|
var exists = connection.ExecuteScalar<bool>(
|
|
"SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname = @db)",
|
|
new { db = database });
|
|
|
|
if (!exists)
|
|
{
|
|
connection.Execute($"CREATE DATABASE \"{database}\"");
|
|
}
|
|
}
|
|
}
|