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
38,228 changes: 24,444 additions & 13,784 deletions generated/schema.graphql

Large diffs are not rendered by default.

55,992 changes: 33,423 additions & 22,569 deletions generated/schema.ts

Large diffs are not rendered by default.

142,144 changes: 78,867 additions & 63,277 deletions generated/types.ts

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions hasura/enums/league-movement-types.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
SET check_function_bodies = false;

insert into e_league_movement_types ("value", "description") values
('Promote', 'Promoted to a higher division'),
('Relegate', 'Relegated to a lower division'),
('Stay', 'Stays in the same division'),
('Remove', 'Removed from the league'),
('DirectPromote', 'Promoted directly to a higher division'),
('RelegationUp', 'Plays a relegation playoff for a higher-division spot'),
('Hold', 'Holds its division'),
('RelegationDown', 'Plays a relegation playoff to keep its division'),
('DirectRelegate', 'Relegated directly to a lower division')
on conflict(value) do update set "description" = EXCLUDED."description"
10 changes: 10 additions & 0 deletions hasura/enums/league-proposal-statuses.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
SET check_function_bodies = false;

insert into e_league_proposal_statuses ("value", "description") values
('Pending', 'Pending response'),
('Accepted', 'Accepted'),
('Declined', 'Declined'),
('Countered', 'Countered with a new time'),
('Superseded', 'Superseded by another proposal'),
('Expired', 'Expired')
on conflict(value) do update set "description" = EXCLUDED."description"
9 changes: 9 additions & 0 deletions hasura/enums/league-registration-statuses.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
SET check_function_bodies = false;

insert into e_league_registration_statuses ("value", "description") values
('Pending', 'Pending review'),
('Approved', 'Approved'),
('Waitlisted', 'Waitlisted'),
('Declined', 'Declined'),
('Withdrawn', 'Withdrawn')
on conflict(value) do update set "description" = EXCLUDED."description"
11 changes: 11 additions & 0 deletions hasura/enums/league-season-statuses.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SET check_function_bodies = false;

insert into e_league_season_statuses ("value", "description") values
('Setup', 'Setup'),
('RegistrationOpen', 'Registration Open'),
('RegistrationClosed', 'Registration Closed'),
('Live', 'Live'),
('Playoffs', 'Playoffs'),
('Finished', 'Finished'),
('Canceled', 'Canceled')
on conflict(value) do update set "description" = EXCLUDED."description"
20 changes: 15 additions & 5 deletions hasura/enums/maps.sql
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,14 @@ WITH map_data AS (
('de_palacio', '3249860053', '/img/maps/screenshots/de_palacio.webp', '/img/maps/icons/de_palacio.svg', null),
('de_rooftop', '3536622725', '/img/maps/screenshots/de_rooftop.webp', '/img/maps/icons/de_rooftop.svg', null),
('de_transit', '3542662073', '/img/maps/screenshots/de_transit.webp', '/img/maps/icons/de_transit.svg', null),
('de_poseidon', null, '/img/maps/screenshots/de_poseidon.webp', '/img/maps/icons/de_poseidon.svg', null),
('de_sanctum', null, '/img/maps/screenshots/de_sanctum.webp', '/img/maps/icons/de_sanctum.svg', null),
('de_stronghold', null, '/img/maps/screenshots/de_stronghold.webp', '/img/maps/icons/de_stronghold.svg', null),
('de_warden', null, '/img/maps/screenshots/de_warden.webp', '/img/maps/icons/de_warden.svg', null)
('de_poseidon', '3522144043', '/img/maps/screenshots/de_poseidon.webp', '/img/maps/icons/de_poseidon.svg', null),
('de_sanctum', '3643331442', '/img/maps/screenshots/de_sanctum.webp', '/img/maps/icons/de_sanctum.svg', null),
('de_stronghold', '3076973469', '/img/maps/screenshots/de_stronghold.webp', '/img/maps/icons/de_stronghold.svg', null),
('de_warden', '3256988376', '/img/maps/screenshots/de_warden.webp', '/img/maps/icons/de_warden.svg', null),
('de_boulder', null, '/img/maps/screenshots/de_boulder.webp', '/img/maps/icons/de_boulder.svg', null),
('de_debris', null, '/img/maps/screenshots/de_debris.webp', '/img/maps/icons/de_debris.svg', null),
('de_eldorado', null, '/img/maps/screenshots/de_eldorado.webp', '/img/maps/icons/de_eldorado.svg', null),
('de_fachwerk', null, '/img/maps/screenshots/de_fachwerk.webp', '/img/maps/icons/de_fachwerk.svg', null)

) AS data(name, workshop_map_id, poster, patch, label)
),
Expand Down Expand Up @@ -87,6 +91,8 @@ map_type_config AS (
('de_palacio', 'Competitive', false),
('de_stronghold', 'Competitive', false),
('de_warden', 'Competitive', false),
('de_boulder', 'Competitive', false),
('de_fachwerk', 'Competitive', false),

-- Wingman maps
('de_inferno', 'Wingman', true),
Expand All @@ -103,6 +109,8 @@ map_type_config AS (
('de_transit', 'Wingman', false),
('de_poseidon', 'Wingman', true),
('de_sanctum', 'Wingman', true),
('de_debris', 'Competitive', false),
('de_eldorado', 'Competitive', false),

-- Duel maps
('de_inferno', 'Duel', true),
Expand All @@ -118,7 +126,9 @@ map_type_config AS (
('de_rooftop', 'Duel', false),
('de_transit', 'Duel', false),
('de_poseidon', 'Duel', true),
('de_sanctum', 'Duel', true)
('de_sanctum', 'Duel', true),
('de_debris', 'Duel', false),
('de_eldorado', 'Duel', false)

) AS data(name, type, active_pool)
),
Expand Down
8 changes: 7 additions & 1 deletion hasura/enums/notification-types.sql
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ INSERT INTO e_notification_types ("value", "description") VALUES
('ScrimAlertMatch', 'A team matching your scrim alert is available'),
('FormTeamSuggestion', 'You frequently play with these players'),
('EloRecompute', 'Player ELO recompute finished'),
('PlayerReindex', 'Player search reindex finished')
('PlayerReindex', 'Player search reindex finished'),
('LeagueProposalReceived', 'A league opponent proposed a match time'),
('LeagueProposalAccepted', 'Your league match time proposal was accepted'),
('LeagueProposalDeclined', 'Your league match time proposal was declined'),
('LeagueMatchUnscheduled', 'A league matchup is unscheduled and will default soon'),
('LeagueRegistrationDecision', 'Your league registration was reviewed'),
('LeagueRosterUndersized', 'Your league team no longer meets the minimum roster size')
ON CONFLICT("value") DO UPDATE
SET "description" = EXCLUDED."description";
117 changes: 117 additions & 0 deletions hasura/functions/leaderboard/get_league_season_leaderboard.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
-- League-season player leaderboard. Isolated from get_leaderboard (the global
-- leaderboard) on purpose: it reuses the same per-map HLTV / util math but
-- scopes strictly to the matches played inside a league season's division
-- tournaments, so nothing here can affect the sitewide leaderboard.
--
-- Dropped first because CREATE OR REPLACE cannot remove an overload.
DROP FUNCTION IF EXISTS public.get_league_season_leaderboard(UUID, TEXT, TEXT);

CREATE OR REPLACE FUNCTION public.get_league_season_leaderboard(
_league_season_id UUID,
_category TEXT,
_role TEXT DEFAULT NULL
)
RETURNS SETOF public.leaderboard_entries
LANGUAGE plpgsql STABLE
AS $$
BEGIN
-- rating / adr / kpr / kast come from the per-map HLTV view.
IF _category IN ('best_rating', 'best_adr', 'best_kpr', 'best_kast') THEN
RETURN QUERY
WITH league_matches AS (
SELECT DISTINCT tb.match_id
FROM tournament_brackets tb
JOIN tournament_stages ts ON ts.id = tb.tournament_stage_id
JOIN league_season_divisions lsd ON lsd.tournament_id = ts.tournament_id
WHERE lsd.league_season_id = _league_season_id
AND tb.match_id IS NOT NULL
),
agg AS (
SELECT
h.steam_id,
SUM(h.hltv_rating * h.rounds_played) / NULLIF(SUM(h.rounds_played), 0) AS rating,
SUM(h.adr * h.rounds_played) / NULLIF(SUM(h.rounds_played), 0) AS adr,
SUM(h.kpr * h.rounds_played) / NULLIF(SUM(h.rounds_played), 0) AS kpr,
SUM(h.dpr * h.rounds_played) / NULLIF(SUM(h.rounds_played), 0) AS dpr,
SUM(h.kast_pct * h.rounds_played) / NULLIF(SUM(h.rounds_played), 0) AS kast,
SUM(h.rounds_played) AS rounds,
COUNT(DISTINCT h.match_id)::int AS match_count
FROM v_player_match_map_hltv h
JOIN league_matches lm ON lm.match_id = h.match_id
LEFT JOIN v_player_match_map_roles r
ON _role IS NOT NULL
AND r.match_map_id = h.match_map_id
AND r.steam_id = h.steam_id
WHERE (_role IS NULL OR r.role = _role)
GROUP BY h.steam_id
HAVING SUM(h.rounds_played) >= 1
)
SELECT
a.steam_id::text AS player_steam_id,
p.name AS player_name,
p.avatar_url AS player_avatar_url,
p.country AS player_country,
(CASE _category
WHEN 'best_rating' THEN ROUND(a.rating::numeric, 2)
WHEN 'best_adr' THEN ROUND(a.adr::numeric, 1)
WHEN 'best_kpr' THEN ROUND(a.kpr::numeric, 2)
WHEN 'best_kast' THEN ROUND(a.kast::numeric, 1)
END)::float AS value,
(CASE _category
WHEN 'best_rating' THEN ROUND(a.adr::numeric, 1)
WHEN 'best_adr' THEN ROUND(a.rating::numeric, 2)
WHEN 'best_kpr' THEN ROUND(a.dpr::numeric, 2)
WHEN 'best_kast' THEN ROUND(a.rating::numeric, 2)
END)::float AS secondary_value,
a.rounds::float AS tertiary_value,
a.match_count AS matches_played
FROM agg a
JOIN players p ON p.steam_id = a.steam_id
ORDER BY value DESC NULLS LAST;

-- utility damage per round comes from raw per-map stats.
ELSIF _category = 'best_udr' THEN
RETURN QUERY
WITH league_matches AS (
SELECT DISTINCT tb.match_id
FROM tournament_brackets tb
JOIN tournament_stages ts ON ts.id = tb.tournament_stage_id
JOIN league_season_divisions lsd ON lsd.tournament_id = ts.tournament_id
WHERE lsd.league_season_id = _league_season_id
AND tb.match_id IS NOT NULL
),
agg AS (
SELECT
s.steam_id,
SUM(s.he_damage + s.molotov_damage) AS util_damage,
SUM(s.he_damage + s.molotov_damage)::numeric / NULLIF(SUM(s.rounds_played), 0) AS udr,
SUM(s.rounds_played) AS rounds,
COUNT(DISTINCT s.match_id)::int AS match_count
FROM player_match_map_stats s
JOIN league_matches lm ON lm.match_id = s.match_id
LEFT JOIN v_player_match_map_roles r
ON _role IS NOT NULL
AND r.match_map_id = s.match_map_id
AND r.steam_id = s.steam_id
WHERE (_role IS NULL OR r.role = _role)
GROUP BY s.steam_id
HAVING SUM(s.rounds_played) >= 1
)
SELECT
a.steam_id::text AS player_steam_id,
p.name AS player_name,
p.avatar_url AS player_avatar_url,
p.country AS player_country,
ROUND(a.udr, 1)::float AS value,
a.util_damage::float AS secondary_value,
a.rounds::float AS tertiary_value,
a.match_count AS matches_played
FROM agg a
JOIN players p ON p.steam_id = a.steam_id
ORDER BY value DESC NULLS LAST;

ELSE
RAISE EXCEPTION 'Invalid league leaderboard category: %. Must be one of: best_rating, best_adr, best_kpr, best_kast, best_udr', _category;
END IF;
END;
$$;
15 changes: 15 additions & 0 deletions hasura/functions/leagues/is_league_tournament.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- League tournaments must not be cancelled/reset/deleted directly; the league
-- season owns their lifecycle.
CREATE OR REPLACE FUNCTION public.is_league_tournament(_tournament_id uuid)
RETURNS boolean
LANGUAGE sql
STABLE
AS $$
SELECT EXISTS (
SELECT 1 FROM public.league_season_divisions
WHERE tournament_id = _tournament_id
) OR EXISTS (
SELECT 1 FROM public.league_relegation_playoffs
WHERE tournament_id = _tournament_id
);
$$;
26 changes: 26 additions & 0 deletions hasura/functions/leagues/league_divisions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-- Tier 1 is the top of the ladder. A single UPDATE permutes the tiers, relying
-- on the deferrable unique constraint to allow the swap.
CREATE OR REPLACE FUNCTION public.reorder_league_divisions(
_division_ids uuid[],
hasura_session json
)
RETURNS SETOF public.league_divisions
LANGUAGE plpgsql
AS $$
BEGIN
IF NOT public.is_league_admin_for_session(hasura_session) THEN
RAISE EXCEPTION 'Must be a league admin' USING ERRCODE = '22000';
END IF;

UPDATE public.league_divisions d
SET tier = pos.rn
FROM (
SELECT id, ordinality AS rn
FROM unnest(_division_ids) WITH ORDINALITY AS t(id, ordinality)
) pos
WHERE d.id = pos.id
AND d.tier <> pos.rn;

RETURN QUERY SELECT * FROM public.league_divisions ORDER BY tier;
END;
$$;
Loading
Loading