Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions hasura/functions/players/get_player_live_lineup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- Starts from the few Live matches, never from the player's history. Each
-- lineup is probed on both columns of its unique key, so any index the planner
-- picks reads a single entry; an index on steam_id alone would read the
-- player's whole history instead, which is why match_lineup_players has none.
-- Practice sessions are Live matches the matches permissions hide, so they are
-- left out here too.
CREATE OR REPLACE FUNCTION public.get_player_live_lineup(player public.players)
RETURNS SETOF public.match_lineup_players
LANGUAGE sql
STABLE
AS $$
SELECT mlp.*
FROM matches m
CROSS JOIN LATERAL (
SELECT *
FROM match_lineup_players mlp
WHERE mlp.match_lineup_id = m.lineup_1_id
AND mlp.steam_id = player.steam_id
UNION ALL
SELECT *
FROM match_lineup_players mlp
WHERE mlp.match_lineup_id = m.lineup_2_id
AND mlp.steam_id = player.steam_id
LIMIT 1
) mlp
WHERE m.status = 'Live'
AND m.source <> 'practice';
$$;
37 changes: 30 additions & 7 deletions hasura/functions/players/is_in_another_match.sql
Original file line number Diff line number Diff line change
@@ -1,19 +1,42 @@
-- Starts from the few active matches, never from the player's history.
-- idx_matches_active_schedule answers the active statuses and the Scheduled
-- cut-off as two index ranges, so matches scheduled further out are never read.
-- Each lineup is probed on both columns of its unique key, so any index the
-- planner picks reads a single entry; an index on steam_id alone would read the
-- player's whole history instead, which is why match_lineup_players has none.
-- The CTE keeps match_series_decided to the player's own matches.
CREATE OR REPLACE FUNCTION public.is_in_another_match(player public.players)
RETURNS boolean
LANGUAGE sql
STABLE
AS $$
WITH mine AS MATERIALIZED (
SELECT m.id, m.status, m.scheduled_at
FROM matches m
CROSS JOIN LATERAL (
SELECT 1
FROM match_lineup_players mlp
WHERE mlp.match_lineup_id = m.lineup_1_id
AND mlp.steam_id = player.steam_id
UNION ALL
SELECT 1
FROM match_lineup_players mlp
WHERE mlp.match_lineup_id = m.lineup_2_id
AND mlp.steam_id = player.steam_id
LIMIT 1
) member
WHERE m.source <> 'practice'
AND (
m.status IN ('Veto', 'WaitingForCheckIn', 'WaitingForServer', 'Live')
OR (m.status = 'Scheduled' AND m.scheduled_at <= NOW() + INTERVAL '1 hour')
)
)
SELECT EXISTS (
SELECT 1
FROM get_player_matches(player) AS pm
-- A utility practice server is a Live match row seating its host, and
-- the host can leave it whenever they like.
WHERE pm.source <> 'practice'
AND (
FROM mine pm
WHERE (
pm.status IN ('Veto', 'WaitingForCheckIn', 'WaitingForServer')
OR (pm.status = 'Live' AND NOT match_series_decided(pm.id))
-- A scheduled match only ties the player up once it's within an hour
-- of kickoff; before that they're free to play other matches.
OR (
pm.status = 'Scheduled'
AND pm.scheduled_at IS NOT NULL
Expand Down
5 changes: 5 additions & 0 deletions hasura/metadata/databases/default/tables/public_players.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,11 @@ computed_fields:
function:
name: is_muted
schema: public
- name: live_lineup
definition:
function:
name: get_player_live_lineup
schema: public
- name: losses
definition:
function:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CREATE INDEX IF NOT EXISTS idx_match_lineup_players_steam_id
ON public.match_lineup_players (steam_id);
DROP INDEX IF EXISTS public.idx_matches_active_schedule;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- is_in_another_match and get_player_live_lineup start from the active
-- matches: the active statuses, plus Scheduled matches by start time so the
-- ones further out are never read.
CREATE INDEX IF NOT EXISTS idx_matches_active_schedule
ON public.matches (status, scheduled_at)
INCLUDE (id, lineup_1_id, lineup_2_id, source)
WHERE status IN ('Veto', 'WaitingForCheckIn', 'WaitingForServer', 'Live', 'Scheduled');

-- Both functions probe a lineup on (match_lineup_id, steam_id). An index on
-- steam_id alone costs the same to the planner, and when it wins that tie the
-- probe reads the player's whole history once per active match.
-- idx_match_lineup_players_steam_id_lineup_id still serves steam_id lookups.
DROP INDEX IF EXISTS public.idx_match_lineup_players_steam_id;
Loading
Loading