Update migrations, move translations from xml to JSON

master
Tait Hoyem 1 year ago
parent 1ea919c954
commit 4019823dd7

@ -1 +1 @@
export DATABASE_URL="postgresql://ibihf2:ibihf@localhost/ibihf" export DATABASE_URL="postgresql://ibihf:ibihf@localhost/ibihf"

@ -0,0 +1,10 @@
# IBIHF Statistics System
This is the official system of the International Blind Ice Hockey Federation,
and their stats website can be found live at [stats.ibihf.org](https://stats.ibihf.org/).
## Database Inforamtion
All migrations can be applied in order of the UNIX timestamp identifier before the name of the migrations.
These `*.sql` files are valid for the Postgres database.

@ -1 +1,2 @@
DELETE FROM period_types; DELETE FROM period_types
WHERE id BETWEEN 1 AND 13;

@ -1,2 +1,3 @@
-- Add down migration script here -- Add down migration script here
DELETE FROM game_players; DELETE FROM game_players
WHERE id BETWEEN 1 AND 116;

@ -1,8 +1,9 @@
-- Add up migration script here -- Add up migration script here
INSERT INTO game_players INSERT INTO game_players
(team, player, position, player_number, game) (id, team, player, position, player_number, game)
VALUES VALUES
( (
1,
1, 1,
31, 31,
1, 1,
@ -10,6 +11,7 @@ VALUES
1 1
), ),
( (
2,
1, 1,
1, 1,
3, 3,
@ -17,6 +19,7 @@ VALUES
1 1
), ),
( (
3,
1, 1,
2, 2,
4, 4,
@ -24,6 +27,7 @@ VALUES
1 1
), ),
( (
4,
1, 1,
3, 3,
5, 5,
@ -31,6 +35,7 @@ VALUES
1 1
), ),
( (
5,
1, 1,
4, 4,
2, 2,
@ -38,6 +43,7 @@ VALUES
1 1
), ),
( (
6,
1, 1,
5, 5,
4, 4,
@ -45,6 +51,7 @@ VALUES
1 1
), ),
( (
7,
1, 1,
7, 7,
1, 1,
@ -52,6 +59,7 @@ VALUES
1 1
), ),
( (
8,
1, 1,
8, 8,
4, 4,
@ -59,6 +67,7 @@ VALUES
1 1
), ),
( (
9,
1, 1,
9, 9,
3, 3,
@ -66,6 +75,7 @@ VALUES
1 1
), ),
( (
10,
1, 1,
10, 10,
1, 1,
@ -73,6 +83,7 @@ VALUES
1 1
), ),
( (
11,
1, 1,
11, 11,
2, 2,
@ -80,6 +91,7 @@ VALUES
1 1
), ),
( (
12,
2, 2,
12, 12,
5, 5,
@ -87,6 +99,7 @@ VALUES
1 1
), ),
( (
13,
2, 2,
13, 13,
5, 5,
@ -94,6 +107,7 @@ VALUES
1 1
), ),
( (
14,
2, 2,
14, 14,
1, 1,
@ -101,6 +115,7 @@ VALUES
1 1
), ),
( (
15,
2, 2,
15, 15,
2, 2,
@ -108,6 +123,7 @@ VALUES
1 1
), ),
( (
16,
2, 2,
16, 16,
1, 1,
@ -115,6 +131,7 @@ VALUES
1 1
), ),
( (
17,
2, 2,
17, 17,
2, 2,
@ -122,6 +139,7 @@ VALUES
1 1
), ),
( (
18,
2, 2,
18, 18,
4, 4,
@ -129,6 +147,7 @@ VALUES
1 1
), ),
( (
19,
2, 2,
19, 19,
4, 4,
@ -136,6 +155,7 @@ VALUES
1 1
), ),
( (
20,
2, 2,
21, 21,
4, 4,
@ -143,6 +163,7 @@ VALUES
1 1
), ),
( (
21,
2, 2,
22, 22,
4, 4,
@ -150,6 +171,7 @@ VALUES
1 1
), ),
( (
22,
2, 2,
23, 23,
2, 2,
@ -157,6 +179,7 @@ VALUES
1 1
), ),
( (
23,
2, 2,
24, 24,
7, 7,
@ -164,6 +187,7 @@ VALUES
1 1
), ),
( (
24,
2, 2,
25, 25,
7, 7,
@ -171,6 +195,7 @@ VALUES
1 1
), ),
( (
25,
2, 2,
26, 26,
7, 7,
@ -178,6 +203,7 @@ VALUES
1 1
), ),
( (
26,
1, 1,
27, 27,
7, 7,
@ -185,6 +211,7 @@ VALUES
1 1
), ),
( (
27,
1, 1,
28, 28,
7, 7,
@ -192,6 +219,7 @@ VALUES
1 1
), ),
( (
28,
1, 1,
29, 29,
7, 7,
@ -199,6 +227,7 @@ VALUES
1 1
), ),
( (
29,
1, 1,
30, 30,
7, 7,
@ -206,6 +235,7 @@ VALUES
1 1
), ),
( (
30,
1, 1,
31, 31,
1, 1,
@ -213,6 +243,7 @@ VALUES
2 2
), ),
( (
31,
1, 1,
1, 1,
3, 3,
@ -220,6 +251,7 @@ VALUES
2 2
), ),
( (
32,
1, 1,
2, 2,
4, 4,
@ -227,6 +259,7 @@ VALUES
2 2
), ),
( (
33,
1, 1,
3, 3,
5, 5,
@ -234,6 +267,7 @@ VALUES
2 2
), ),
( (
34,
1, 1,
4, 4,
2, 2,
@ -241,6 +275,7 @@ VALUES
2 2
), ),
( (
35,
1, 1,
5, 5,
4, 4,
@ -248,6 +283,7 @@ VALUES
2 2
), ),
( (
36,
1, 1,
7, 7,
1, 1,
@ -255,6 +291,7 @@ VALUES
2 2
), ),
( (
37,
1, 1,
8, 8,
4, 4,
@ -262,6 +299,7 @@ VALUES
2 2
), ),
( (
38,
1, 1,
9, 9,
3, 3,
@ -269,6 +307,7 @@ VALUES
2 2
), ),
( (
39,
1, 1,
10, 10,
1, 1,
@ -276,6 +315,7 @@ VALUES
2 2
), ),
( (
40,
1, 1,
11, 11,
2, 2,
@ -283,6 +323,7 @@ VALUES
2 2
), ),
( (
41,
2, 2,
12, 12,
5, 5,
@ -290,6 +331,7 @@ VALUES
2 2
), ),
( (
42,
2, 2,
13, 13,
5, 5,
@ -297,6 +339,7 @@ VALUES
2 2
), ),
( (
43,
2, 2,
14, 14,
1, 1,
@ -304,6 +347,7 @@ VALUES
2 2
), ),
( (
44,
2, 2,
15, 15,
2, 2,
@ -311,6 +355,7 @@ VALUES
2 2
), ),
( (
45,
2, 2,
16, 16,
1, 1,
@ -318,6 +363,7 @@ VALUES
2 2
), ),
( (
46,
2, 2,
17, 17,
2, 2,
@ -325,6 +371,7 @@ VALUES
2 2
), ),
( (
47,
2, 2,
18, 18,
4, 4,
@ -332,6 +379,7 @@ VALUES
2 2
), ),
( (
48,
2, 2,
19, 19,
4, 4,
@ -339,6 +387,7 @@ VALUES
2 2
), ),
( (
49,
2, 2,
21, 21,
4, 4,
@ -346,6 +395,7 @@ VALUES
2 2
), ),
( (
50,
2, 2,
22, 22,
4, 4,
@ -353,6 +403,7 @@ VALUES
2 2
), ),
( (
51,
2, 2,
23, 23,
2, 2,
@ -360,6 +411,7 @@ VALUES
2 2
), ),
( (
52,
2, 2,
24, 24,
7, 7,
@ -367,6 +419,7 @@ VALUES
2 2
), ),
( (
53,
2, 2,
25, 25,
7, 7,
@ -374,6 +427,7 @@ VALUES
2 2
), ),
( (
54,
2, 2,
26, 26,
7, 7,
@ -381,6 +435,7 @@ VALUES
2 2
), ),
( (
55,
1, 1,
27, 27,
7, 7,
@ -388,6 +443,7 @@ VALUES
2 2
), ),
( (
56,
1, 1,
28, 28,
7, 7,
@ -395,6 +451,7 @@ VALUES
2 2
), ),
( (
57,
1, 1,
29, 29,
7, 7,
@ -402,6 +459,7 @@ VALUES
2 2
), ),
( (
58,
1, 1,
30, 30,
7, 7,
@ -409,6 +467,7 @@ VALUES
2 2
), ),
( (
59,
1, 1,
31, 31,
1, 1,
@ -416,6 +475,7 @@ VALUES
3 3
), ),
( (
60,
1, 1,
1, 1,
3, 3,
@ -423,6 +483,7 @@ VALUES
3 3
), ),
( (
61,
1, 1,
2, 2,
4, 4,
@ -430,6 +491,7 @@ VALUES
3 3
), ),
( (
62,
1, 1,
3, 3,
5, 5,
@ -437,6 +499,7 @@ VALUES
3 3
), ),
( (
63,
1, 1,
4, 4,
2, 2,
@ -444,6 +507,7 @@ VALUES
3 3
), ),
( (
64,
1, 1,
5, 5,
4, 4,
@ -451,6 +515,7 @@ VALUES
3 3
), ),
( (
65,
1, 1,
7, 7,
1, 1,
@ -458,6 +523,7 @@ VALUES
3 3
), ),
( (
66,
1, 1,
8, 8,
4, 4,
@ -465,6 +531,7 @@ VALUES
3 3
), ),
( (
67,
1, 1,
9, 9,
3, 3,
@ -472,6 +539,7 @@ VALUES
3 3
), ),
( (
68,
1, 1,
10, 10,
1, 1,
@ -479,6 +547,7 @@ VALUES
3 3
), ),
( (
69,
1, 1,
11, 11,
2, 2,
@ -486,6 +555,7 @@ VALUES
3 3
), ),
( (
70,
2, 2,
12, 12,
5, 5,
@ -493,6 +563,7 @@ VALUES
3 3
), ),
( (
71,
2, 2,
13, 13,
5, 5,
@ -500,6 +571,7 @@ VALUES
3 3
), ),
( (
72,
2, 2,
14, 14,
1, 1,
@ -507,6 +579,7 @@ VALUES
3 3
), ),
( (
73,
2, 2,
15, 15,
2, 2,
@ -514,6 +587,7 @@ VALUES
3 3
), ),
( (
74,
2, 2,
16, 16,
1, 1,
@ -521,6 +595,7 @@ VALUES
3 3
), ),
( (
75,
2, 2,
17, 17,
2, 2,
@ -528,6 +603,7 @@ VALUES
3 3
), ),
( (
76,
2, 2,
18, 18,
4, 4,
@ -535,6 +611,7 @@ VALUES
3 3
), ),
( (
77,
2, 2,
19, 19,
4, 4,
@ -542,6 +619,7 @@ VALUES
3 3
), ),
( (
78,
2, 2,
21, 21,
4, 4,
@ -549,6 +627,7 @@ VALUES
3 3
), ),
( (
79,
2, 2,
22, 22,
4, 4,
@ -556,6 +635,7 @@ VALUES
3 3
), ),
( (
80,
2, 2,
23, 23,
2, 2,
@ -563,6 +643,7 @@ VALUES
3 3
), ),
( (
81,
2, 2,
24, 24,
7, 7,
@ -570,6 +651,7 @@ VALUES
3 3
), ),
( (
82,
2, 2,
25, 25,
7, 7,
@ -577,6 +659,7 @@ VALUES
3 3
), ),
( (
83,
2, 2,
26, 26,
7, 7,
@ -584,6 +667,7 @@ VALUES
3 3
), ),
( (
84,
1, 1,
27, 27,
7, 7,
@ -591,6 +675,7 @@ VALUES
3 3
), ),
( (
85,
1, 1,
28, 28,
7, 7,
@ -598,6 +683,7 @@ VALUES
3 3
), ),
( (
86,
1, 1,
29, 29,
7, 7,
@ -605,6 +691,7 @@ VALUES
3 3
), ),
( (
87,
1, 1,
30, 30,
7, 7,
@ -612,6 +699,7 @@ VALUES
3 3
), ),
( (
88,
1, 1,
31, 31,
1, 1,
@ -619,6 +707,7 @@ VALUES
4 4
), ),
( (
89,
1, 1,
1, 1,
3, 3,
@ -626,6 +715,7 @@ VALUES
4 4
), ),
( (
90,
1, 1,
2, 2,
4, 4,
@ -633,6 +723,7 @@ VALUES
4 4
), ),
( (
91,
1, 1,
3, 3,
5, 5,
@ -640,6 +731,7 @@ VALUES
4 4
), ),
( (
92,
1, 1,
4, 4,
2, 2,
@ -647,6 +739,7 @@ VALUES
4 4
), ),
( (
93,
1, 1,
5, 5,
4, 4,
@ -654,6 +747,7 @@ VALUES
4 4
), ),
( (
94,
1, 1,
7, 7,
1, 1,
@ -661,6 +755,7 @@ VALUES
4 4
), ),
( (
95,
1, 1,
8, 8,
4, 4,
@ -668,6 +763,7 @@ VALUES
4 4
), ),
( (
96,
1, 1,
9, 9,
3, 3,
@ -675,6 +771,7 @@ VALUES
4 4
), ),
( (
97,
1, 1,
10, 10,
1, 1,
@ -682,6 +779,7 @@ VALUES
4 4
), ),
( (
98,
1, 1,
11, 11,
2, 2,
@ -689,6 +787,7 @@ VALUES
4 4
), ),
( (
99,
2, 2,
12, 12,
5, 5,
@ -696,6 +795,7 @@ VALUES
4 4
), ),
( (
100,
2, 2,
13, 13,
5, 5,
@ -703,6 +803,7 @@ VALUES
4 4
), ),
( (
101,
2, 2,
14, 14,
1, 1,
@ -710,6 +811,7 @@ VALUES
4 4
), ),
( (
102,
2, 2,
15, 15,
2, 2,
@ -717,6 +819,7 @@ VALUES
4 4
), ),
( (
103,
2, 2,
16, 16,
1, 1,
@ -724,6 +827,7 @@ VALUES
4 4
), ),
( (
104,
2, 2,
17, 17,
2, 2,
@ -731,6 +835,7 @@ VALUES
4 4
), ),
( (
105,
2, 2,
18, 18,
4, 4,
@ -738,6 +843,7 @@ VALUES
4 4
), ),
( (
106,
2, 2,
19, 19,
4, 4,
@ -745,6 +851,7 @@ VALUES
4 4
), ),
( (
107,
2, 2,
21, 21,
4, 4,
@ -752,6 +859,7 @@ VALUES
4 4
), ),
( (
108,
2, 2,
22, 22,
4, 4,
@ -759,6 +867,7 @@ VALUES
4 4
), ),
( (
109,
2, 2,
23, 23,
2, 2,
@ -766,6 +875,7 @@ VALUES
4 4
), ),
( (
110,
2, 2,
24, 24,
7, 7,
@ -773,6 +883,7 @@ VALUES
4 4
), ),
( (
111,
2, 2,
25, 25,
7, 7,
@ -780,6 +891,7 @@ VALUES
4 4
), ),
( (
112,
2, 2,
26, 26,
7, 7,
@ -787,6 +899,7 @@ VALUES
4 4
), ),
( (
113,
1, 1,
27, 27,
7, 7,
@ -794,6 +907,7 @@ VALUES
4 4
), ),
( (
114,
1, 1,
28, 28,
7, 7,
@ -801,6 +915,7 @@ VALUES
4 4
), ),
( (
115,
1, 1,
29, 29,
7, 7,
@ -808,6 +923,7 @@ VALUES
4 4
), ),
( (
116,
1, 1,
30, 30,
7, 7,

@ -1 +1,2 @@
DELETE FROM periods; DELETE FROM periods
WHERE id BETWEEN 1 AND 12;

@ -1,62 +1,74 @@
INSERT INTO periods INSERT INTO periods
(game, period_type, period_length) (id, game, period_type, period_length)
VALUES VALUES
( (
1,
1, 1,
1, 1,
1200 1200
), ),
( (
2,
1, 1,
2, 2,
900 900
), ),
( (
3,
1, 1,
3, 3,
900 900
), ),
( (
4,
2, 2,
1, 1,
1200 1200
), ),
( (
5,
2, 2,
2, 2,
1200 1200
), ),
( (
6,
2, 2,
3, 3,
1200 1200
), ),
( (
7,
3, 3,
1, 1,
720 720
), ),
( (
8,
3, 3,
2, 2,
720 720
), ),
( (
9,
3, 3,
3, 3,
1200 1200
), ),
( (
10,
4, 4,
1, 1,
1200 1200
), ),
( (
11,
4, 4,
2, 2,
1200 1200
), ),
( (
12,
4, 4,
3, 3,
1200 1200

@ -0,0 +1,6 @@
CREATE FUNCTION periods(game_id INTEGER)
RETURNS INTEGER AS $$
BEGIN
RETURN (SELECT COUNT(id) FROM periods WHERE periods.game=game_id);
END;
$$ LANGUAGE plpgsql;

@ -0,0 +1,2 @@
-- Add down migration script here
--DROP FUNCTION game_results(INTEGER, INTEGER);

@ -0,0 +1,99 @@
-- Add up migration script here
--CREATE FUNCTION periods(game_id INTEGER)
--RETURNS INTEGER AS $$
--BEGIN
-- RETURN (SELECT COUNT(id) FROM periods WHERE periods.game=game_id);
--END;
--$$ LANGUAGE plpgsql;
--
--CREATE FUNCTION goals(game_id INTEGER, team_id INTEGER)
--RETURNS INTEGER AS $$
--DECLARE
-- goals INTEGER;
--BEGIN
-- IF NOT EXISTS (SELECT * FROM games WHERE games.id=game_id) THEN
-- RAISE EXCEPTION 'The game does not exist.';
-- END IF;
-- IF NOT EXISTS (SELECT * FROM teams WHERE teams.id=team_id) THEN
-- RAISE EXCEPTION 'The team does not exist.';
-- END IF;
-- IF NOT EXISTS (SELECT * FROM games JOIN teams ON teams.id=games.team_home OR teams.id=team_away WHERE games.id=game_id) THEN
-- RAISE EXCEPTION 'The team specified did not play this game.';
-- END IF;
--
-- SELECT
-- COUNT(shots.id)
-- INTO
-- goals
-- FROM shots
-- JOIN game_players
-- ON game_players.id=shots.shooter
-- JOIN periods
-- ON periods.id=shots.period
-- WHERE shots.goal=true
-- AND game_players.team=team_id
-- AND periods.game=game_id;
-- -- return 0 if not goals are found given the team and the game
-- RETURN COALESCE(goals, 0);
--END;
--$$ LANGUAGE plpgsql;
--
--CREATE OR REPLACE FUNCTION calculate_iihf_stats(game_id INT, team_id INT)
--RETURNS TABLE (
-- reg_win INT,
-- reg_loss INT,
-- ot_win INT,
-- ot_loss INT,
-- tie INT,
-- game INT,
-- team INT
--) AS $$
--DECLARE
-- opponent_team_id INTEGER;
--BEGIN
-- IF NOT EXISTS (SELECT * FROM games WHERE games.id=game_id) THEN
-- RAISE EXCEPTION 'The game does not exist.';
-- END IF;
-- IF NOT EXISTS (SELECT * FROM teams WHERE teams.id=team_id) THEN
-- RAISE EXCEPTION 'The team does not exist.';
-- END IF;
-- IF NOT EXISTS (SELECT * FROM games JOIN teams ON teams.id=games.team_home OR teams.id=team_away WHERE games.id=game_id) THEN
-- RAISE EXCEPTION 'The team specified did not play this game.';
-- END IF;
--
-- SELECT
-- teams.id
-- INTO
-- opponent_team_id
-- FROM games
-- JOIN teams
-- ON (teams.id=games.team_home
-- OR teams.id=games.team_away)
-- WHERE games.id=game_id
-- AND teams.id!=team_id;
--
-- RETURN QUERY
-- SELECT
-- (CASE WHEN goals(game_id, team_id) > goals(game_id, opponent_team_id) AND periods(game_id) <= 3 THEN 1 ELSE 0 END) AS reg_win,
-- (CASE WHEN goals(game_id, team_id) < goals(game_id, opponent_team_id) AND periods(game_id) <= 3 THEN 1 ELSE 0 END) AS reg_loss,
-- (CASE WHEN goals(game_id, team_id) > goals(game_id, opponent_team_id) AND periods(game_id) > 3 THEN 1 ELSE 0 END) AS ot_win,
-- (CASE WHEN goals(game_id, team_id) < goals(game_id, opponent_team_id) AND periods(game_id) > 3 THEN 1 ELSE 0 END) AS ot_loss,
-- (CASE WHEN goals(game_id, team_id) = goals(game_id, opponent_team_id) THEN 1 ELSE 0 END) AS tie,
-- game_id AS game,
-- team_id AS team;
--END;
--$$ LANGUAGE plpgsql;
--
--CREATE OR REPLACE FUNCTION calculate_iihf_points(game_id INT, team_id INT)
--RETURNS INTEGER AS $$
--BEGIN
-- RETURN (
-- SELECT
-- (iihs_stats.reg_win * 3) +
-- (iihs_stats.reg_loss * 0) +
-- (iihs_stats.ot_win * 2) +
-- (iihs_stats.ot_loss * 1) +
-- (iihs_stats.tie * 2) AS points
-- FROM calculate_iihs_stats_stats(game_id, team_id) iihs_stats);
--END;
--$$ LANGUAGE plpgsql;

@ -0,0 +1,2 @@
-- Add down migration script here
DROP FUNCTION goals(INTEGER, INTEGER);

@ -0,0 +1,32 @@
-- Add up migration script here
CREATE FUNCTION goals(game_id INTEGER, team_id INTEGER)
RETURNS INTEGER AS $$
DECLARE
goals INTEGER;
BEGIN
IF NOT EXISTS (SELECT * FROM games WHERE games.id=game_id) THEN
RAISE EXCEPTION 'The game does not exist.';
END IF;
IF NOT EXISTS (SELECT * FROM teams WHERE teams.id=team_id) THEN
RAISE EXCEPTION 'The team does not exist.';
END IF;
IF NOT EXISTS (SELECT * FROM games JOIN teams ON teams.id=games.team_home OR teams.id=team_away WHERE games.id=game_id) THEN
RAISE EXCEPTION 'The team specified did not play this game.';
END IF;
SELECT
COUNT(shots.id)
INTO
goals
FROM shots
JOIN game_players
ON game_players.id=shots.shooter
JOIN periods
ON periods.id=shots.period
WHERE shots.goal=true
AND game_players.team=team_id
AND periods.game=game_id;
-- return 0 if not goals are found given the team and the game
RETURN COALESCE(goals, 0);
END;
$$ LANGUAGE plpgsql;

@ -0,0 +1,2 @@
-- Add down migration script here
DROP FUNCTION iihf_stats(INTEGER, INTEGER);

@ -0,0 +1,46 @@
-- Add up migration script here
CREATE OR REPLACE FUNCTION iihf_stats(game_id INT, team_id INT)
RETURNS TABLE (
reg_win INT,
reg_loss INT,
ot_win INT,
ot_loss INT,
tie INT,
game INT,
team INT
) AS $$
DECLARE
opponent_team_id INTEGER;
BEGIN
IF NOT EXISTS (SELECT * FROM games WHERE games.id=game_id) THEN
RAISE EXCEPTION 'The game does not exist.';
END IF;
IF NOT EXISTS (SELECT * FROM teams WHERE teams.id=team_id) THEN
RAISE EXCEPTION 'The team does not exist.';
END IF;
IF NOT EXISTS (SELECT * FROM games JOIN teams ON teams.id=games.team_home OR teams.id=team_away WHERE games.id=game_id) THEN
RAISE EXCEPTION 'The team specified did not play this game.';
END IF;
SELECT
teams.id
INTO
opponent_team_id
FROM games
JOIN teams
ON (teams.id=games.team_home
OR teams.id=games.team_away)
WHERE games.id=game_id
AND teams.id!=team_id;
RETURN QUERY
SELECT
(CASE WHEN goals(game_id, team_id) > goals(game_id, opponent_team_id) AND periods(game_id) <= 3 THEN 1 ELSE 0 END) AS reg_win,
(CASE WHEN goals(game_id, team_id) < goals(game_id, opponent_team_id) AND periods(game_id) <= 3 THEN 1 ELSE 0 END) AS reg_loss,
(CASE WHEN goals(game_id, team_id) > goals(game_id, opponent_team_id) AND periods(game_id) > 3 THEN 1 ELSE 0 END) AS ot_win,
(CASE WHEN goals(game_id, team_id) < goals(game_id, opponent_team_id) AND periods(game_id) > 3 THEN 1 ELSE 0 END) AS ot_loss,
(CASE WHEN goals(game_id, team_id) = goals(game_id, opponent_team_id) THEN 1 ELSE 0 END) AS tie,
game_id AS game,
team_id AS team;
END;
$$ LANGUAGE plpgsql;

@ -0,0 +1,2 @@
-- Add down migration script here
DROP FUNCTION iihf_points(INTEGER, INTEGER);

@ -0,0 +1,14 @@
-- Add up migration script here
CREATE OR REPLACE FUNCTION iihf_points(game_id INT, team_id INT)
RETURNS INTEGER AS $$
BEGIN
RETURN (
SELECT
(iihs_stats.reg_win * 3) +
(iihs_stats.reg_loss * 0) +
(iihs_stats.ot_win * 2) +
(iihs_stats.ot_loss * 1) +
(iihs_stats.tie * 2) AS points
FROM calculate_iihs_stats_stats(game_id, team_id) iihs_stats);
END;
$$ LANGUAGE plpgsql;

@ -4,6 +4,6 @@ use sqlx::postgres::PgPoolOptions;
pub async fn connect() -> Pool<Postgres> { pub async fn connect() -> Pool<Postgres> {
PgPoolOptions::new() PgPoolOptions::new()
.max_connections(8) .max_connections(8)
.connect("postgres://ibihf2:ibihf@localhost/ibihf").await .connect("postgres://ibihf:ibihf@localhost/ibihf").await
.unwrap() .unwrap()
} }

@ -20,7 +20,7 @@ pub struct TeamStats {
pub struct IihfGameStats { pub struct IihfGameStats {
pub team_name: String, pub team_name: String,
pub team_id: i32, pub team_id: i32,
pub points: i64, pub points: i32,
} }
#[derive(FromRow, Deserialize, Serialize, Debug)] #[derive(FromRow, Deserialize, Serialize, Debug)]
@ -109,20 +109,106 @@ impl Game {
.fetch_all(pool) .fetch_all(pool)
.await .await
} }
pub async fn iihf_stats(pool: &PgPool, game_id: i32) -> Result<Vec<IihfGameStats>, sqlx::Error> {
let query = r#"
SELECT
(CASE WHEN
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id=teams.id
THEN shots.id
END) >
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id!=teams.id
THEN shots.id
END)
AND (SELECT COUNT(id) FROM periods WHERE periods.game=games.id) <= 3
THEN 1
ELSE 0
END) AS reg_wins,
(CASE WHEN
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id=teams.id
THEN shots.id
END) <
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id!=teams.id
THEN shots.id
END)
AND (SELECT COUNT(id) FROM periods WHERE periods.game=games.id) <= 3
THEN 1
ELSE 0
END) AS reg_losses,
(CASE WHEN
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id=teams.id
THEN shots.id
END) >
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id!=teams.id
THEN shots.id
END)
AND (SELECT COUNT(id) FROM periods WHERE periods.game=games.id) > 3
THEN 1
ELSE 0
END) AS ot_wins,
(CASE WHEN
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id=teams.id
THEN shots.id
END) <
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id!=teams.id
THEN shots.id
END)
AND (SELECT COUNT(id) FROM periods WHERE periods.game=games.id) > 3
THEN 1
ELSE 0
END) AS ot_losses,
(CASE WHEN
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id=teams.id
THEN shots.id
END) =
COUNT(CASE WHEN shots.goal=true
AND scoring_team.id!=teams.id
THEN shots.id
END)
THEN 1
ELSE 0
END) AS ties
FROM games
JOIN periods ON periods.game=games.id
JOIN shots ON shots.period=periods.id
JOIN game_players ON game_players.id=shots.shooter
JOIN teams scoring_team
ON scoring_team.id=game_players.team
JOIN teams
ON teams.id=games.team_home
OR teams.id=games.team_away
WHERE games.id=4
GROUP BY teams.id,games.id;
"#;
sqlx::query_as::<_, IihfGameStats>(query)
.bind(game_id)
.fetch_all(pool)
.await
}
/// Returns the number of points using IIHF scoring rules for each team. /// Returns the number of points using IIHF scoring rules for each team.
/// NOTE: The algorithm used here requires that a 4th period is the "overtime";
/// it does not check if there was only two periods, followed by an overtime.
/// This should be sufficient for most.
pub async fn iihf_score(pool: &PgPool, game_id: i32) -> Result<Vec<IihfGameStats>, sqlx::Error> { pub async fn iihf_score(pool: &PgPool, game_id: i32) -> Result<Vec<IihfGameStats>, sqlx::Error> {
let query = r#" let query = r#"
SELECT SELECT
COUNT(CASE WHEN shots.goal = true THEN shots.id END) AS points, calculate_iihf_points(games.id, teams.id) AS points,
teams.id AS team_id, teams.name AS team_name,
teams.name AS team_name teams.id AS team_id
FROM games FROM games
JOIN periods ON periods.game=games.id JOIN teams
JOIN shots ON shots.period=periods.id ON teams.id=games.team_home
JOIN game_players ON game_players.id=shots.shooter OR teams.id=games.team_away
JOIN teams ON teams.id=game_players.team
WHERE games.id=$1 WHERE games.id=$1
GROUP BY teams.id; ORDER BY points;
"#; "#;
sqlx::query_as::<_, IihfGameStats>(query) sqlx::query_as::<_, IihfGameStats>(query)
.bind(game_id) .bind(game_id)
@ -493,14 +579,15 @@ mod tests {
fn check_iihf_score() { fn check_iihf_score() {
tokio_test::block_on(async move{ tokio_test::block_on(async move{
let pool = db_connect().await; let pool = db_connect().await;
let game = Game::get(&pool, 1) let game = Game::get(&pool, 4)
.await .await
.unwrap(); .unwrap();
let score = Game::iihf_score(&pool, game.id) let score = Game::iihf_score(&pool, game.id)
.await .await
.unwrap(); .unwrap();
assert_eq!(score.get(0).unwrap().points, 3); assert_eq!(score.get(0).unwrap().points, 2);
assert_eq!(score.get(0).unwrap().team_name, "Bullseye"); assert_eq!(score.get(0).unwrap().team_name, "Bullseye");
assert_eq!(score.get(1).unwrap().points, 2);
}) })
} }

@ -1,6 +1,12 @@
{% extends "master.html" %}
{% block title %}Divisions{% endblock %}
{% block content %}
<h1 id="first-heading">Divisions for the {{ league.name }}</h1> <h1 id="first-heading">Divisions for the {{ league.name }}</h1>
<ul aria-labelledby="first-heading"> <ul aria-labelledby="first-heading">
{% for division in divisions %} {% for division in divisions %}
<li><a href="/en/division/{{ division.id }}/">{{ division.name }}</a></li> <li><a href="/en/division/{{ division.id }}/">{{ division.name }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endblock %}

@ -1,10 +1,16 @@
<h1 id="games">Games for {{ division.name }}</h1> {% extends "master.html" %}
{% if games.len() > 0 %}
<ol aria-labelledby="games"> {% block title %}Games{% endblock %}
{% for game in games %}
<li><a href="/en/game/{{ game.id }}/">{{ game.name }}</a></li> {% block content %}
{% endfor %} <h1 id="games">Games for {{ division.name }}</h1>
</ol> {% if games.len() > 0 %}
{% else %} <ol aria-labelledby="games">
<p>No games have been recorded.</p> {% for game in games %}
{% endif %} <li><a href="/en/game/{{ game.id }}/">{{ game.name }}</a></li>
{% endfor %}
</ol>
{% else %}
<p>No games have been recorded.</p>
{% endif %}
{% endblock %}

@ -1,3 +1,8 @@
{% extends "master.html" %}
{% block title %}{{ game.name }}{% endblock %}
{% block content %}
<h1>{{ game.name }} of the {{ division.name }}</h1> <h1>{{ game.name }} of the {{ division.name }}</h1>
<h2>Team</h2> <h2>Team</h2>
{{ team_stats|safe }} {{ team_stats|safe }}
@ -7,3 +12,4 @@
{{ box_score|safe }} {{ box_score|safe }}
<h2>Play-by-Play</h2> <h2>Play-by-Play</h2>
{{ play_by_play|safe }} {{ play_by_play|safe }}
{% endblock %}

@ -1,6 +1,12 @@
{% extends "master.html" %}
{% block title %}Leagues{% endblock %}
{% block content %}
<h1 id="leagues">{{ heading }}</h1> <h1 id="leagues">{{ heading }}</h1>
<ol aria-labelledby="leagues"> <ol aria-labelledby="leagues">
{% for league in leagues %} {% for league in leagues %}
<li><a href="/{{ lang }}/league/{{ league.id }}/">{{ league.name }}</a></li> <li><a href="/{{ lang }}/league/{{ league.id }}/">{{ league.name }}</a></li>
{% endfor %} {% endfor %}
</ol> </ol>
{% endblock %}

@ -0,0 +1,16 @@
<!DOCTYPE html>
<!-- TODO: auto-generate page language. -->
<html lang="en">
<head>
<!-- TODO: auto-generate IBIHF string to some other languages -->
<title>{% block title %}{% endblock %} | IBIHF Stats</title>
{% block head %}{% endblock %}
</head>
<body>
<header></header>
<main>
{% block content %}{% endblock %}
</main>
<footer></footer>
</body>
</html>

@ -0,0 +1,11 @@
{
"phrases": {
"urlGame": "game",
"urlDivision": "division",
"urlLeague": "league",
"ibihfLeagues": "IBIHF Leagues",
"goals": "Goals",
"assists": "Assists",
"period": "Period"
}
}

@ -0,0 +1,11 @@
{
"phrases": {
"urlGame": "match",
"urlDivision": "division",
"urlLeague": "league",
"ibihfLeagues": "Leagues de FIDHS",
"goals": "But",
"assists": "Assisté",
"period": "Période"
}
}
Loading…
Cancel
Save