feat: promote accepted proposals from API

This commit is contained in:
Josh Creek
2026-09-01 10:29:41 +01:00
parent e0ba6c6ead
commit 03ff8e485e
16 changed files with 270 additions and 49 deletions
+38
View File
@@ -63,6 +63,44 @@ const AcceptedMatchParticipantInsertSQL = `INSERT INTO match_participants
(match_id, player_id, ticket_id, slot, team)
VALUES ($1, $2, $3, $4, $5)`
const StoredProposalMatchPlanSQL = `SELECT match_region, match_protocol
FROM proposals
WHERE proposal_id = $1 AND state = 'ACCEPTED'`
const StoredProposalMatchPlayersSQL = `SELECT player_id, team, slot
FROM proposal_participants
WHERE proposal_id = $1 AND response = 'ACCEPTED'
ORDER BY player_id`
// PromoteStoredAcceptedProposal materializes the exact topology persisted by
// the matcher once every player has accepted. The deterministic match ID makes
// a request retry converge after an API/worker interruption.
func PromoteStoredAcceptedProposal(ctx context.Context, db *sql.DB, proposalID string, now time.Time) error {
if db == nil || proposalID == "" || now.IsZero() {
return fmt.Errorf("invalid stored proposal promotion arguments")
}
plan := AcceptedMatchPlan{MatchID: "match-" + proposalID, ProposalID: proposalID}
if err := db.QueryRowContext(ctx, StoredProposalMatchPlanSQL, proposalID).Scan(&plan.Region, &plan.Protocol); err != nil {
return err
}
rows, err := db.QueryContext(ctx, StoredProposalMatchPlayersSQL, proposalID)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var player MatchPlayer
if err := rows.Scan(&player.PlayerID, &player.Team, &player.Slot); err != nil {
return err
}
plan.Players = append(plan.Players, player)
}
if err := rows.Err(); err != nil {
return err
}
return CreateMatchFromAcceptedProposal(ctx, db, plan, now)
}
// CreateMatchFromAcceptedProposal atomically promotes the exact accepted
// roster into an ALLOCATING match. An existing match ID is an idempotent retry
// only if every durable field and participant assignment matches the request.