feat: import messages from go version
This commit is contained in:
parent
b56a71e105
commit
a50a8567dd
15 changed files with 503 additions and 769 deletions
|
|
@ -25,6 +25,7 @@ public class DatabaseConnection(Guid id, ILogger logger, NpgsqlConnection inner)
|
|||
IDisposable
|
||||
{
|
||||
public Guid ConnectionId => id;
|
||||
public NpgsqlConnection Inner => inner;
|
||||
private readonly ILogger _logger = logger.ForContext<DatabaseConnection>();
|
||||
private readonly DateTimeOffset _openTime = DateTimeOffset.UtcNow;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ using NodaTime;
|
|||
|
||||
namespace Catalogger.Backend.Database;
|
||||
|
||||
/// <summary>
|
||||
/// Manages database migrations.
|
||||
/// </summary>
|
||||
public class DatabaseMigrator(ILogger logger, IClock clock, DatabaseConnection conn)
|
||||
: IDisposable,
|
||||
IAsyncDisposable
|
||||
|
|
@ -26,7 +29,10 @@ public class DatabaseMigrator(ILogger logger, IClock clock, DatabaseConnection c
|
|||
private const string RootPath = "Catalogger.Backend.Database";
|
||||
private static readonly int MigrationsPathLength = $"{RootPath}.Migrations.".Length;
|
||||
|
||||
public async Task Migrate()
|
||||
/// <summary>
|
||||
/// Migrates the database to the latest version.
|
||||
/// </summary>
|
||||
public async Task MigrateUp()
|
||||
{
|
||||
var migrations = GetMigrationNames().ToArray();
|
||||
logger.Debug("Getting current database migration");
|
||||
|
|
@ -65,6 +71,43 @@ public class DatabaseMigrator(ILogger logger, IClock clock, DatabaseConnection c
|
|||
await tx.CommitAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Migrates the database to a previous version.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of migrations to revert. If higher than the number of applied migrations,
|
||||
/// reverts the database to a clean slate.</param>
|
||||
public async Task MigrateDown(int count = 1)
|
||||
{
|
||||
await using var tx = await conn.BeginTransactionAsync();
|
||||
|
||||
var migrationCount = 0;
|
||||
var totalStartTime = clock.GetCurrentInstant();
|
||||
for (var i = count; i > 0; i--)
|
||||
{
|
||||
var migration = await GetCurrentMigration();
|
||||
if (migration == null)
|
||||
{
|
||||
logger.Information(
|
||||
"More down migrations requested than were in the database, finishing early"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
logger.Debug("Reverting migration {Migration}", migration);
|
||||
var startTime = clock.GetCurrentInstant();
|
||||
await ExecuteMigration(tx, migration.MigrationName, up: false);
|
||||
var took = clock.GetCurrentInstant() - startTime;
|
||||
logger.Debug("Reverted migration {Migration} in {Took}", migration, took);
|
||||
migrationCount++;
|
||||
}
|
||||
|
||||
var totalTook = clock.GetCurrentInstant() - totalStartTime;
|
||||
logger.Information("Reverted {Count} migrations in {Took}", migrationCount, totalTook);
|
||||
|
||||
// Finally, commit the transaction
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
|
||||
private async Task ExecuteMigration(DbTransaction tx, string migrationName, bool up = true)
|
||||
{
|
||||
var query = await GetResource(
|
||||
|
|
@ -73,11 +116,17 @@ public class DatabaseMigrator(ILogger logger, IClock clock, DatabaseConnection c
|
|||
|
||||
// Run the migration
|
||||
await conn.ExecuteAsync(query, transaction: tx);
|
||||
// Store that we ran the migration
|
||||
await conn.ExecuteAsync(
|
||||
"INSERT INTO migrations (migration_name, applied_at) VALUES (@MigrationName, @AppliedAt)",
|
||||
new { MigrationName = migrationName, AppliedAt = clock.GetCurrentInstant() }
|
||||
);
|
||||
// Store that we ran the migration (or reverted it)
|
||||
if (up)
|
||||
await conn.ExecuteAsync(
|
||||
"INSERT INTO migrations (migration_name, applied_at) VALUES (@MigrationName, now())",
|
||||
new { MigrationName = migrationName }
|
||||
);
|
||||
else
|
||||
await conn.ExecuteAsync(
|
||||
"DELETE FROM migrations WHERE migration_name = @MigrationName",
|
||||
new { MigrationName = migrationName }
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the current migration. If no migrations have been applied, returns null
|
||||
|
|
|
|||
|
|
@ -148,19 +148,17 @@ public class DatabasePool
|
|||
Array.ConvertAll((long[])value, i => (ulong)i);
|
||||
}
|
||||
|
||||
public class JsonTypeHandler<T> : SqlMapper.TypeHandler<T>
|
||||
private class JsonTypeHandler<T> : SqlMapper.TypeHandler<T>
|
||||
{
|
||||
public override T Parse(object value)
|
||||
{
|
||||
string json = (string)value;
|
||||
var json = (string)value;
|
||||
return JsonSerializer.Deserialize<T>(json)
|
||||
?? throw new CataloggerError("JsonTypeHandler<T> returned null");
|
||||
}
|
||||
|
||||
public override void SetValue(IDbDataParameter parameter, T? value)
|
||||
{
|
||||
public override void SetValue(IDbDataParameter parameter, T? value) =>
|
||||
parameter.Value = JsonSerializer.Serialize(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Catalogger.Backend.Extensions;
|
||||
using Catalogger.Backend.Services;
|
||||
using Remora.Rest.Core;
|
||||
|
|
@ -22,10 +21,8 @@ namespace Catalogger.Backend.Database.Models;
|
|||
|
||||
public class Guild
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public required ulong Id { get; init; }
|
||||
|
||||
[Column(TypeName = "jsonb")]
|
||||
public ChannelConfig Channels { get; init; } = new();
|
||||
public string[] BannedSystems { get; set; } = [];
|
||||
public ulong[] KeyRoles { get; set; } = [];
|
||||
|
|
|
|||
|
|
@ -13,13 +13,10 @@
|
|||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Catalogger.Backend.Database.Models;
|
||||
|
||||
public class Message
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public required ulong Id { get; init; }
|
||||
|
||||
public ulong? OriginalId { get; set; }
|
||||
|
|
@ -38,5 +35,3 @@ public class Message
|
|||
|
||||
public int AttachmentSize { get; set; } = 0;
|
||||
}
|
||||
|
||||
public record IgnoredMessage([property: DatabaseGenerated(DatabaseGeneratedOption.None)] ulong Id);
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ public static class StartupExtensions
|
|||
DatabasePool.ConfigureDapper();
|
||||
|
||||
await using var migrator = scope.ServiceProvider.GetRequiredService<DatabaseMigrator>();
|
||||
await migrator.Migrate();
|
||||
await migrator.MigrateUp();
|
||||
|
||||
var config = scope.ServiceProvider.GetRequiredService<Config>();
|
||||
var slashService = scope.ServiceProvider.GetRequiredService<SlashService>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue