using Ludarium.Application; using Ludarium.Domain; namespace Ludarium.Infrastructure; public sealed partial class PostgresStore { public async Task> ListFirmwareAssetsAsync(CancellationToken ct) => await ListJsonAsync("SELECT data FROM firmware_assets ORDER BY platform,slot,created_at DESC", ct); public Task GetFirmwareAssetAsync(Guid id, CancellationToken ct) => SingleJsonAsync("SELECT data FROM firmware_assets WHERE id=$1", ct, id); public Task GetSelectedFirmwareAssetAsync(string platform, string slot, CancellationToken ct) => SingleJsonAsync("SELECT data FROM firmware_assets WHERE platform=$1 AND slot=$2 AND selected=true", ct, platform.ToLowerInvariant(), slot.ToLowerInvariant()); public async Task SaveFirmwareAssetAsync(FirmwareAsset asset, string actor, CancellationToken ct) { var audit = new AuditEvent(Guid.NewGuid(), actor, "FirmwareUploaded", "FirmwareAsset", asset.Id, null, System.Text.Json.JsonSerializer.Serialize(new { asset.Platform, asset.Slot, asset.Kind, asset.FileName, asset.Length, Sha256Prefix = asset.Sha256[..12] }), Guid.NewGuid(), asset.CreatedAt); await ExecuteTransactionAsync(ct, ("UPDATE firmware_assets SET selected=false,data=jsonb_set(data,'{selected}','false'::jsonb,true),updated_at=$3 WHERE platform=$1 AND slot=$2 AND selected=true", [asset.Platform, asset.Slot, asset.CreatedAt]), ("INSERT INTO firmware_assets(id,platform,slot,selected,version,data,created_at,updated_at) VALUES($1,$2,$3,true,1,$4,$5,$5)", [asset.Id, asset.Platform, asset.Slot, Json(asset), asset.CreatedAt]), ("INSERT INTO audit_events(id,data,created_at) VALUES($1,$2,$3)", [audit.Id, Json(audit), audit.CreatedAt])); } public async Task> DeleteFirmwareAssetAsync(Guid id, long expectedVersion, string actor, CancellationToken ct) { var current = await GetFirmwareAssetAsync(id, ct) ?? throw new KeyNotFoundException("Firmware asset was not found."); if (current.Version != expectedVersion) throw new ConcurrencyException("Firmware changed since it was loaded."); var audit = new AuditEvent(Guid.NewGuid(), actor, "FirmwareDeleted", "FirmwareAsset", id, System.Text.Json.JsonSerializer.Serialize(new { current.Platform, current.Slot, current.Kind, current.FileName, current.Length, Sha256Prefix = current.Sha256[..12] }), null, Guid.NewGuid(), DateTimeOffset.UtcNow); await ExecuteTransactionAsync(ct, ("DELETE FROM firmware_assets WHERE id=$1 AND version=$2", [id, expectedVersion]), ("INSERT INTO audit_events(id,data,created_at) VALUES($1,$2,$3)", [audit.Id, Json(audit), audit.CreatedAt])); return [current]; } }