fixed migration scripts, moved migration code to dbservice

This commit is contained in:
Toastie 2025-01-25 19:53:36 +13:00
parent 211f610d28
commit 45b507bf79
Signed by: toastie_t0ast
GPG key ID: 0861BE54AD481DC7
4 changed files with 69 additions and 78 deletions

View file

@ -1,18 +1,22 @@
using LinqToDB.Common;
using LinqToDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using EllieBot.Migrations;
namespace EllieBot.Db;
public sealed class EllieDbService : DbService
public sealed class EllieDbService : DbService
{
private readonly IBotCredsProvider _creds;
// these are props because creds can change at runtime
private string DbType => _creds.GetCreds().Db.Type.ToLowerInvariant().Trim();
private string ConnString => _creds.GetCreds().Db.ConnectionString;
private string DbType
=> _creds.GetCreds().Db.Type.ToLowerInvariant().Trim();
private string ConnString
=> _creds.GetCreds().Db.ConnectionString;
public EllieDbService(IBotCredsProvider creds)
{
LinqToDBForEFTools.Initialize();
@ -28,14 +32,14 @@ public sealed class EllieDbService : DbService
await using var context = CreateRawDbContext(dbType, connString);
await MigrationRunner.RunMigration(context);
await RunMigration(context);
// make sure sqlite db is in wal journal mode
if (context is SqliteContext)
{
await context.Database.ExecuteSqlRawAsync("PRAGMA journal_mode=WAL");
}
// await context.Database.MigrateAsync();
}
@ -53,7 +57,7 @@ public sealed class EllieDbService : DbService
throw new NotSupportedException($"The database provide type of '{dbType}' is not supported.");
}
}
private EllieContext GetDbContextInternal()
{
var dbType = DbType;
@ -74,4 +78,52 @@ public sealed class EllieDbService : DbService
public override EllieContext GetDbContext()
=> GetDbContextInternal();
private static async Task RunMigration(DbContext ctx)
{
// if database doesn't exist, run the baseline migration
if (!await ctx.Database.CanConnectAsync())
{
Log.Information("Database does not exist. Creating a new database...");
await ctx.Database.MigrateAsync();
return;
}
// get the latest applied migration
var applied = await ctx.Database.GetAppliedMigrationsAsync();
// get all .sql file names from the migrations folder
var available = Directory.GetFiles("Migrations/Sqlite", "*_*.sql")
.Select(x => Path.GetFileNameWithoutExtension(x))
.OrderBy(x => x);
var lastApplied = applied.Last();
Log.Information("Last applied migration: {LastApplied}", lastApplied);
// apply all mirations with names greater than the last applied
foreach (var runnable in available)
{
if (string.Compare(lastApplied, runnable, StringComparison.Ordinal) < 0)
{
Log.Warning("Migration {MigrationName} has not been applied yet", runnable);
var query = await File.ReadAllTextAsync(GetMigrationPath(ctx.Database, runnable));
await ctx.Database.ExecuteSqlRawAsync(query);
}
}
// run all migrations that have not been applied yet
}
private static string GetMigrationPath(DatabaseFacade ctxDatabase, string runnable)
{
if (ctxDatabase.IsSqlite())
return $"Migrations/Sqlite/{runnable}.sql";
if (ctxDatabase.IsNpgsql())
return $"Migrations/PostgreSql/{runnable}.sql";
throw new NotSupportedException("This database type is not supported.");
}
}

View file

@ -1,54 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace EllieBot.Migrations;
public class MigrationRunner
{
public static async Task RunMigration(DbContext ctx)
{
// if database doesn't exist, run the baseline migration
if (!await ctx.Database.CanConnectAsync())
{
Log.Information("Database does not exist. Creating a new database...");
await ctx.Database.MigrateAsync();
}
// get the latest applied migration
var applied = await ctx.Database.GetAppliedMigrationsAsync();
// get all .sql file names from the migrations folder
var available = Directory.GetFiles("Migrations/Sqlite", "*_*.sql")
.Select(x => Path.GetFileNameWithoutExtension(x))
.OrderBy(x => x);
string lastApplied = applied.Last();
Log.Information("Last applied migration: {LastApplied}", lastApplied);
// apply all mirations with names greater than the last applied
foreach (var runnable in available)
{
if (string.Compare(lastApplied, runnable, StringComparison.Ordinal) < 0)
{
Log.Warning("Migration {MigrationName} has not been applied yet", runnable);
var query = await File.ReadAllTextAsync(GetMigrationPath(ctx.Database, runnable));
await ctx.Database.ExecuteSqlRawAsync(query);
}
}
// run all migrations that have not been applied yet
}
private static string GetMigrationPath(DatabaseFacade ctxDatabase, string runnable)
{
if (ctxDatabase.IsSqlite())
return $"Migrations/Sqlite/{runnable}.sql";
if (ctxDatabase.IsNpgsql())
return $"Migrations/PostgreSql/{runnable}.sql";
throw new NotSupportedException("This database type is not supported.");
}
}

View file

@ -8,10 +8,6 @@ Write-Output "Creating new migration..."
# Step 1: Create initial migrations
dotnet build
# Get previous migration IDs
$firstMigrationIdSqlite = (dotnet ef migrations list --context SqliteContext --no-build --no-connect | Select-Object -Last 2 | Select-Object -First 1) -split ' ' | Select-Object -First 1
$firstMigrationIdPostgresql = (dotnet ef migrations list --context PostgresqlContext --no-build --no-connect | Select-Object -Last 2 | Select-Object -First 1) -split ' ' | Select-Object -First 1
dotnet ef migrations add $MigrationName --context SqliteContext --output-dir "Migrations/Sqlite" --no-build
dotnet ef migrations add $MigrationName --context PostgresqlContext --output-dir "Migrations/PostgreSql" --no-build
@ -28,8 +24,8 @@ Write-Output "Generating diff SQL scripts..."
$newMigrationIdSqlite = (dotnet ef migrations list --context SqliteContext --no-build --no-connect | Select-Object -Last 2 | Select-Object -First 1) -split ' ' | Select-Object -First 1
$newMigrationIdPostgresql = (dotnet ef migrations list --context PostgresqlContext --no-build --no-connect | Select-Object -Last 2 | Select-Object -First 1) -split ' ' | Select-Object -First 1
dotnet ef migrations script ($firstMigrationIdSqlite -replace '^.*_', '') $MigrationName --context SqliteContext -o "Migrations/Sqlite/$newMigrationIdSqlite.sql" --no-build
dotnet ef migrations script ($firstMigrationIdPostgresql -replace '^.*_', '') $MigrationName --context PostgresqlContext -o "Migrations/Postgresql/$newMigrationIdPostgresql.sql" --no-build
dotnet ef migrations script init $MigrationName --context SqliteContext -o "Migrations/Sqlite/$newMigrationIdSqlite.sql" --no-build
dotnet ef migrations script init $MigrationName --context PostgresqlContext -o "Migrations/Postgresql/$newMigrationIdPostgresql.sql" --no-build
if ($LASTEXITCODE -ne 0) {
Write-Error "Error: Failed to generate SQL script"
@ -53,5 +49,5 @@ dotnet build
# Step 4: Create new initial migrations
Write-Output "Creating new initial migration..."
dotnet ef migrations add $MigrationName --context SqliteContext --output-dir "Migrations/Sqlite" --no-build
dotnet ef migrations add $MigrationName --context PostgresqlContext --output-dir "Migrations/PostgreSql" --no-build
dotnet ef migrations add init --context SqliteContext --output-dir "Migrations/Sqlite" --no-build
dotnet ef migrations add init --context PostgresqlContext --output-dir "Migrations/PostgreSql" --no-build

View file

@ -15,9 +15,6 @@ echo "Creating new migration..."
dotnet build
# Getting previous migration names in order to generate SQL scripts
FIRST_MIGRATION_ID_SQLITE=$(dotnet ef migrations list --context SqliteContext --no-build --no-connect | tail -2 | head -1 | cut -d' ' -f1)
FIRST_MIGRATION_ID_POSTGRESQL=$(dotnet ef migrations list --context PostgresqlContext --no-build --no-connect | tail -2 | head -1 | cut -d' ' -f1)
dotnet ef migrations add "${MIGRATION_NAME}" --context SqliteContext --output-dir "Migrations/Sqlite" --no-build
dotnet ef migrations add "${MIGRATION_NAME}" --context PostgresqlContext --output-dir "Migrations/PostgreSql" --no-build
@ -35,8 +32,8 @@ echo "Generating diff SQL scripts..."
NEW_MIGRATION_ID_SQLITE=$(dotnet ef migrations list --context SqliteContext --no-build --no-connect | tail -2 | head -1 | cut -d' ' -f1)
NEW_MIGRATION_ID_POSTGRESQL=$(dotnet ef migrations list --context PostgresqlContext --no-build --no-connect | tail -2 | head -1 | cut -d' ' -f1)
dotnet ef migrations script "${FIRST_MIGRATION_ID_SQLITE#*_}" $MIGRATION_NAME --context SqliteContext -o "Migrations/Sqlite/${NEW_MIGRATION_ID_SQLITE}.sql" --no-build
dotnet ef migrations script "${FIRST_MIGRATION_ID_POSTGRESQL#*_}" $MIGRATION_NAME --context PostgresqlContext -o "Migrations/Postgresql/${NEW_MIGRATION_ID_POSTGRESQL}.sql" --no-build
dotnet ef migrations script init $MIGRATION_NAME --context SqliteContext -o "Migrations/Sqlite/${NEW_MIGRATION_ID_SQLITE}.sql" --no-build
dotnet ef migrations script init $MIGRATION_NAME --context PostgresqlContext -o "Migrations/Postgresql/${NEW_MIGRATION_ID_POSTGRESQL}.sql" --no-build
if [ $? -ne 0 ]; then
@ -78,8 +75,8 @@ for file in "Migrations/Postgresql"/*; do
done
# Step 4: Adding new initial migration
echo "Creating new initial migration..."
dotnet build
echo "Creating new initial migration..."
dotnet ef migrations add "${MIGRATION_NAME}" --context SqliteContext --output-dir "Migrations/Sqlite" --no-build
dotnet ef migrations add "${MIGRATION_NAME}" --context PostgresqlContext --output-dir "Migrations/PostgreSql" --no-build
dotnet ef migrations add init --context SqliteContext --output-dir "Migrations/Sqlite" --no-build
dotnet ef migrations add init --context PostgresqlContext --output-dir "Migrations/PostgreSql" --no-build