Skip to content

Commit 1775e1f

Browse files
committed
fix: correct bye resolution, slot assignment, and LB bye cascade
- seed_stage: fix bye marking bug using column names instead of stale local variables, restrict to WB path only - advance_byes_for_tournament: mark bye brackets as finished so downstream resolve_bracket_bye knows no loser will arrive - resolve_bracket_bye: replace total_feeders >= 2 guard with pending (unfinished) feeders check, allowing LB brackets to correctly resolve as byes when a WB feeder was a bye - assign_team_to_bracket_slot: use deterministic slot assignment based on feeder ordering instead of first-empty-slot heuristic - update_tournament_bracket: pass source bracket ID for correct slot
1 parent 7e963f4 commit 1775e1f

5 files changed

Lines changed: 56 additions & 26 deletions

File tree

hasura/functions/tournaments/advance_byes_for_tournament.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ BEGIN
4646
WHERE id = v_parent_bracket_id;
4747
END IF;
4848

49+
-- Mark the bye bracket as finished so downstream bye resolution
50+
-- (e.g. LB R1 brackets) can detect that no loser will arrive
51+
UPDATE tournament_brackets
52+
SET finished = true
53+
WHERE id = bracket.id;
54+
4955
RAISE NOTICE ' Advanced team % from bracket % to parent %', winner_id, bracket.id, v_parent_bracket_id;
5056
END LOOP;
5157

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
CREATE OR REPLACE FUNCTION public.assign_team_to_bracket_slot(
22
_target_bracket_id uuid,
3-
_team_id uuid
3+
_team_id uuid,
4+
_source_bracket_id uuid DEFAULT NULL
45
) RETURNS VOID
56
LANGUAGE plpgsql
67
AS $$
78
DECLARE
89
target_bracket tournament_brackets%ROWTYPE;
10+
slot_position int;
911
BEGIN
1012
SELECT * INTO target_bracket
1113
FROM tournament_brackets
@@ -16,14 +18,48 @@ BEGIN
1618
RETURN;
1719
END IF;
1820

19-
IF target_bracket.tournament_team_id_1 IS NULL THEN
21+
-- Determine the correct slot from feeder ordering:
22+
-- 1. Loser drops (loser_parent_bracket_id) come before winner feeds (parent_bracket_id)
23+
-- 2. Within same type, order by round then match_number
24+
-- This matches the bracket generation layout.
25+
IF _source_bracket_id IS NOT NULL THEN
26+
SELECT pos INTO slot_position
27+
FROM (
28+
SELECT f.id,
29+
row_number() OVER (
30+
ORDER BY
31+
CASE WHEN f.loser_parent_bracket_id = _target_bracket_id THEN 0 ELSE 1 END,
32+
f.round,
33+
f.match_number
34+
) AS pos
35+
FROM tournament_brackets f
36+
WHERE f.parent_bracket_id = _target_bracket_id
37+
OR f.loser_parent_bracket_id = _target_bracket_id
38+
) ranked
39+
WHERE ranked.id = _source_bracket_id;
40+
END IF;
41+
42+
IF slot_position = 1 THEN
2043
UPDATE tournament_brackets
2144
SET tournament_team_id_1 = _team_id
22-
WHERE id = _target_bracket_id;
23-
ELSIF target_bracket.tournament_team_id_2 IS NULL THEN
45+
WHERE id = _target_bracket_id
46+
AND tournament_team_id_1 IS NULL;
47+
ELSIF slot_position = 2 THEN
2448
UPDATE tournament_brackets
2549
SET tournament_team_id_2 = _team_id
26-
WHERE id = _target_bracket_id;
50+
WHERE id = _target_bracket_id
51+
AND tournament_team_id_2 IS NULL;
52+
ELSE
53+
-- Fallback: first empty slot (for callers without source bracket)
54+
IF target_bracket.tournament_team_id_1 IS NULL THEN
55+
UPDATE tournament_brackets
56+
SET tournament_team_id_1 = _team_id
57+
WHERE id = _target_bracket_id;
58+
ELSIF target_bracket.tournament_team_id_2 IS NULL THEN
59+
UPDATE tournament_brackets
60+
SET tournament_team_id_2 = _team_id
61+
WHERE id = _target_bracket_id;
62+
END IF;
2763
END IF;
2864
END;
2965
$$;

hasura/functions/tournaments/resolve_bracket_bye.sql

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ CREATE OR REPLACE FUNCTION public.resolve_bracket_bye(
1111
AS $$
1212
DECLARE
1313
current_bracket tournament_brackets%ROWTYPE;
14-
total_feeders int;
1514
pending_feeders int;
1615
lone_team_id uuid;
1716
tournament_id uuid;
@@ -38,25 +37,14 @@ BEGIN
3837
RETURN false;
3938
END IF;
4039

41-
-- A bracket with 2+ total feeders is designed to receive 2 teams through
42-
-- normal match play (e.g. LB R1 fed by two WB R1 matches). It should
43-
-- never be a bye — the second team will arrive when the other feeder finishes.
44-
SELECT COUNT(*) INTO total_feeders
45-
FROM tournament_brackets child
46-
WHERE child.parent_bracket_id = current_bracket.id
47-
OR child.loser_parent_bracket_id = current_bracket.id;
48-
49-
IF total_feeders >= 2 THEN
50-
RETURN false;
51-
END IF;
52-
53-
-- For brackets with 0-1 feeders, check if any are still pending
40+
-- Check if any feeders can still provide a team.
41+
-- A finished bye feeder via loser_parent_bracket_id will never send a loser,
42+
-- so it doesn't count as pending. Only unfinished feeders are pending.
5443
SELECT COUNT(*) INTO pending_feeders
5544
FROM tournament_brackets child
5645
WHERE (child.parent_bracket_id = current_bracket.id
5746
OR child.loser_parent_bracket_id = current_bracket.id)
58-
AND child.finished = false
59-
AND child.bye = false;
47+
AND child.finished = false;
6048

6149
IF pending_feeders > 0 THEN
6250
RETURN false;
@@ -75,7 +63,7 @@ BEGIN
7563

7664
-- Advance the lone team to the parent bracket
7765
IF current_bracket.parent_bracket_id IS NOT NULL THEN
78-
PERFORM public.assign_team_to_bracket_slot(current_bracket.parent_bracket_id, lone_team_id);
66+
PERFORM public.assign_team_to_bracket_slot(current_bracket.parent_bracket_id, lone_team_id, current_bracket.id);
7967
ELSE
8068
RAISE WARNING 'resolve_bracket_bye: bracket % has no parent, team % cannot advance',
8169
current_bracket.id, lone_team_id;

hasura/functions/tournaments/seed_stage.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ BEGIN
166166
team_2_seed_val, team_2_id;
167167
END LOOP;
168168

169-
update tournament_brackets set bye = (team_1_id IS NULL OR team_2_id IS NULL)
170-
where tournament_stage_id = stage.id and round = 1;
169+
update tournament_brackets set bye = (tournament_team_id_1 IS NULL OR tournament_team_id_2 IS NULL)
170+
where tournament_stage_id = stage.id and round = 1 and COALESCE(path, 'WB') = 'WB';
171171
END IF;
172172

173173
IF stage.type != 'RoundRobin' THEN

hasura/functions/tournaments/update_tournament_bracket.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ BEGIN
3434
WHERE id = bracket.id;
3535

3636
IF bracket.parent_bracket_id IS NOT NULL THEN
37-
PERFORM public.assign_team_to_bracket_slot(bracket.parent_bracket_id, winning_team_id);
37+
PERFORM public.assign_team_to_bracket_slot(bracket.parent_bracket_id, winning_team_id, bracket.id);
3838
END IF;
3939

4040
IF bracket.loser_parent_bracket_id IS NOT NULL THEN
41-
PERFORM public.assign_team_to_bracket_slot(bracket.loser_parent_bracket_id, losing_team_id);
41+
PERFORM public.assign_team_to_bracket_slot(bracket.loser_parent_bracket_id, losing_team_id, bracket.id);
4242
END IF;
4343

4444
SELECT ts.tournament_id, ts.type INTO tournament_id, stage_type

0 commit comments

Comments
 (0)