using Dapper; using KArtSell.BuildingBlocks.Data; using KArtSell.BuildingBlocks.Time; namespace KArtSell.Modules.ModelOperations.Features.ApproveModel; public sealed class Handler(IDbConnectionFactory connectionFactory, IClock clock) { public async Task HandleAsync(Request request, Guid approverUserId, CancellationToken ct) { await using var connection = await connectionFactory.OpenAsync(ct); // Verify approval exists and is Pending var existing = await connection.QuerySingleOrDefaultAsync<(Guid Id, string Status)?>(""" SELECT id, status FROM model_operations.approval_queue WHERE run_id = @RunId """, new { request.RunId }); if (!existing.HasValue) throw new InvalidOperationException($"Approval not found for run {request.RunId}"); if (existing.Value.Status != "Pending") throw new InvalidOperationException($"Approval status is {existing.Value.Status}, not Pending"); // Update approval status (trigger will set approved_at) var now = MarketTime.SeoulDateTime(clock.UtcNow); await connection.ExecuteAsync(""" UPDATE model_operations.approval_queue SET status = 'Approved', approved_by = @ApprovedBy, approval_reason = @ApprovalReason, approved_at = @ApprovedAt WHERE run_id = @RunId """, new { request.RunId, ApprovedBy = approverUserId, request.ApprovalReason, ApprovedAt = now }); return new Response( existing.Value.Id, request.RunId, "Approved", now); } }