|
|
|
@ -15,7 +15,7 @@ pub struct TeamStats {
|
|
|
|
|
|
|
|
|
|
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
|
|
|
|
pub struct IihfStats {
|
|
|
|
|
pub team_name: String,
|
|
|
|
|
pub team_name: Option<String>,
|
|
|
|
|
pub team_id: i32,
|
|
|
|
|
pub reg_wins: i32,
|
|
|
|
|
pub reg_losses: i32,
|
|
|
|
@ -26,7 +26,7 @@ pub struct IihfStats {
|
|
|
|
|
}
|
|
|
|
|
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
|
|
|
|
pub struct IihfStatsI64 {
|
|
|
|
|
pub team_name: String,
|
|
|
|
|
pub team_name: Option<String>,
|
|
|
|
|
pub team_id: i32,
|
|
|
|
|
pub reg_wins: i64,
|
|
|
|
|
pub reg_losses: i64,
|
|
|
|
@ -59,7 +59,8 @@ pub struct IihfPoints {
|
|
|
|
|
|
|
|
|
|
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
|
|
|
|
pub struct Notification {
|
|
|
|
|
pub scorer_name: String,
|
|
|
|
|
pub scorer_first_names: String,
|
|
|
|
|
pub scorer_last_name: String,
|
|
|
|
|
pub scorer_number: i32,
|
|
|
|
|
pub position: String,
|
|
|
|
|
pub scorer_team_name: String,
|
|
|
|
@ -69,7 +70,8 @@ pub struct Notification {
|
|
|
|
|
|
|
|
|
|
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
|
|
|
|
pub struct PlayerStats {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub first_names: String,
|
|
|
|
|
pub last_name: String,
|
|
|
|
|
pub goals: i64,
|
|
|
|
|
pub assists: i64,
|
|
|
|
|
pub points: i64,
|
|
|
|
@ -81,7 +83,8 @@ SELECT
|
|
|
|
|
COUNT(shots.id) AS points,
|
|
|
|
|
COUNT(CASE WHEN shots.shooter = game_players.id THEN shots.id END) AS goals,
|
|
|
|
|
COUNT(CASE WHEN shots.assistant = game_players.id OR shots.assistant_second = game_players.id THEN shots.id END) AS assists,
|
|
|
|
|
players.name
|
|
|
|
|
players.first_names,
|
|
|
|
|
players.last_name
|
|
|
|
|
FROM game_players
|
|
|
|
|
JOIN players
|
|
|
|
|
ON game_players.player = players.id
|
|
|
|
@ -93,7 +96,8 @@ LEFT JOIN shots
|
|
|
|
|
WHERE game_players.game=$1
|
|
|
|
|
GROUP BY
|
|
|
|
|
game_players.id,
|
|
|
|
|
players.name
|
|
|
|
|
players.last_name,
|
|
|
|
|
players.first_names
|
|
|
|
|
HAVING COUNT(shots.id) > 0
|
|
|
|
|
ORDER BY
|
|
|
|
|
points DESC,
|
|
|
|
@ -104,20 +108,23 @@ ORDER BY
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
pub async fn game_goals(pool: &PgPool, game_id: i32) -> Result<Vec<GoalDetails>, sqlx::Error> {
|
|
|
|
|
pub async fn game_goals(pool: &PgPool, game_id: i32, lang: i32) -> Result<Vec<GoalDetails>, sqlx::Error> {
|
|
|
|
|
sqlx::query_as::<_, GoalDetails>(
|
|
|
|
|
r#"
|
|
|
|
|
SELECT
|
|
|
|
|
shots.shooter AS player_id,
|
|
|
|
|
shots.assistant AS first_assist_id,
|
|
|
|
|
shots.assistant_second AS second_assist_id,
|
|
|
|
|
players.name AS player_name,
|
|
|
|
|
p_assist.name AS first_assist_name,
|
|
|
|
|
p_assist_second.name AS second_assist_name,
|
|
|
|
|
players.first_names AS player_first_names,
|
|
|
|
|
players.last_name AS player_last_name,
|
|
|
|
|
p_assist.first_names AS first_assist_first_names,
|
|
|
|
|
p_assist.last_name AS first_assist_last_name,
|
|
|
|
|
p_assist_second.first_names AS second_assist_first_names,
|
|
|
|
|
p_assist_second.last_name AS second_assist_last_name,
|
|
|
|
|
game_players.player_number AS player_number,
|
|
|
|
|
gp_assist.player_number AS first_assist_number,
|
|
|
|
|
gp_assist_second.player_number AS second_assist_number,
|
|
|
|
|
teams.name AS team_name,
|
|
|
|
|
team_name(teams.id, $1) AS team_name,
|
|
|
|
|
teams.id AS team_id,
|
|
|
|
|
shots.period_time AS time_remaining,
|
|
|
|
|
period_types.id AS period_id,
|
|
|
|
@ -141,14 +148,15 @@ pub async fn game_goals(pool: &PgPool, game_id: i32) -> Result<Vec<GoalDetails>,
|
|
|
|
|
"#,
|
|
|
|
|
)
|
|
|
|
|
.bind(game_id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
pub async fn game_iihf_stats(pool: &PgPool, game_id: i32) -> Result<Vec<IihfStats>, sqlx::Error> {
|
|
|
|
|
pub async fn game_iihf_stats(pool: &PgPool, game_id: i32, lang: i32) -> Result<Vec<IihfStats>, sqlx::Error> {
|
|
|
|
|
let query = r#"
|
|
|
|
|
SELECT
|
|
|
|
|
teams.id AS team_id,
|
|
|
|
|
teams.name AS team_name,
|
|
|
|
|
team_name(teams.id, $2) AS team_name,
|
|
|
|
|
reg_win(games.id, teams.id) AS reg_wins,
|
|
|
|
|
reg_loss(games.id, teams.id) AS reg_losses,
|
|
|
|
|
ot_win(games.id, teams.id) AS ot_wins,
|
|
|
|
@ -169,6 +177,7 @@ pub async fn game_iihf_stats(pool: &PgPool, game_id: i32) -> Result<Vec<IihfStat
|
|
|
|
|
"#;
|
|
|
|
|
sqlx::query_as::<_, IihfStats>(query)
|
|
|
|
|
.bind(game_id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
@ -176,11 +185,11 @@ pub async fn game_iihf_stats(pool: &PgPool, game_id: i32) -> Result<Vec<IihfStat
|
|
|
|
|
/// 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 game_iihf_points(pool: &PgPool, game_id: i32) -> Result<Vec<IihfPoints>, sqlx::Error> {
|
|
|
|
|
pub async fn game_iihf_points(pool: &PgPool, game_id: i32, lang: i32) -> Result<Vec<IihfPoints>, sqlx::Error> {
|
|
|
|
|
let query = r#"
|
|
|
|
|
SELECT
|
|
|
|
|
iihf_points(games.id, teams.id) AS points,
|
|
|
|
|
teams.name AS team_name,
|
|
|
|
|
team_name(teams.id, $1) AS team_name,
|
|
|
|
|
teams.id AS team_id
|
|
|
|
|
FROM games
|
|
|
|
|
JOIN teams
|
|
|
|
@ -191,16 +200,17 @@ pub async fn game_iihf_points(pool: &PgPool, game_id: i32) -> Result<Vec<IihfPoi
|
|
|
|
|
"#;
|
|
|
|
|
sqlx::query_as::<_, IihfPoints>(query)
|
|
|
|
|
.bind(game_id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
/// Returns the number of shots and goals for each team in the game.
|
|
|
|
|
pub async fn game_score(pool: &PgPool, game_id: i32) -> Result<Vec<TeamStats>, sqlx::Error> {
|
|
|
|
|
pub async fn game_score(pool: &PgPool, game_id: i32, lang: i32) -> Result<Vec<TeamStats>, sqlx::Error> {
|
|
|
|
|
let query = r#"
|
|
|
|
|
SELECT
|
|
|
|
|
COUNT(CASE WHEN shots.goal = true THEN shots.id END) AS goals,
|
|
|
|
|
COUNT(shots.id) AS shots,
|
|
|
|
|
teams.name AS name
|
|
|
|
|
team_name(teams.id, $2) AS name
|
|
|
|
|
FROM games
|
|
|
|
|
JOIN periods ON periods.game=games.id
|
|
|
|
|
JOIN shots ON shots.period=periods.id
|
|
|
|
@ -211,12 +221,14 @@ pub async fn game_score(pool: &PgPool, game_id: i32) -> Result<Vec<TeamStats>, s
|
|
|
|
|
"#;
|
|
|
|
|
sqlx::query_as::<_, TeamStats>(query)
|
|
|
|
|
.bind(game_id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
pub async fn game_play_by_play(
|
|
|
|
|
pool: &PgPool,
|
|
|
|
|
game_id: i32,
|
|
|
|
|
lang: i32,
|
|
|
|
|
) -> Result<Vec<ShotDetails>, sqlx::Error> {
|
|
|
|
|
sqlx::query_as::<_, ShotDetails>(
|
|
|
|
|
r#"
|
|
|
|
@ -225,13 +237,16 @@ SELECT
|
|
|
|
|
shots.assistant AS first_assist_id,
|
|
|
|
|
shots.assistant_second AS second_assist_id,
|
|
|
|
|
shots.goal AS is_goal,
|
|
|
|
|
players.name AS player_name,
|
|
|
|
|
p_assistant.name AS first_assist_name,
|
|
|
|
|
p_assistant_second.name AS second_assist_name,
|
|
|
|
|
players.first_names AS player_first_names,
|
|
|
|
|
players.last_name AS player_last_name,
|
|
|
|
|
p_assistant.first_names AS first_assist_first_names,
|
|
|
|
|
p_assistant.last_name AS first_assist_last_name,
|
|
|
|
|
p_assistant_second.first_names AS second_assist_first_names,
|
|
|
|
|
p_assistant_second.last_name AS second_assist_last_name,
|
|
|
|
|
game_players.player_number AS player_number,
|
|
|
|
|
gp_assistant.player_number AS first_assist_number,
|
|
|
|
|
gp_assistant_second.player_number AS second_assist_number,
|
|
|
|
|
teams.name AS team_name,
|
|
|
|
|
team_name(teams.id, $2) AS team_name,
|
|
|
|
|
teams.id AS team_id,
|
|
|
|
|
shots.period_time AS time_remaining,
|
|
|
|
|
period_types.id AS period_id,
|
|
|
|
@ -253,79 +268,93 @@ ORDER BY
|
|
|
|
|
"#,
|
|
|
|
|
)
|
|
|
|
|
.bind(game_id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Game {
|
|
|
|
|
pub async fn score(&self, pool: &PgPool) -> Result<Vec<TeamStats>, sqlx::Error> {
|
|
|
|
|
game_score(pool, self.id).await
|
|
|
|
|
pub async fn score(&self, pool: &PgPool, lang: i32) -> Result<Vec<TeamStats>, sqlx::Error> {
|
|
|
|
|
game_score(pool, self.id, lang).await
|
|
|
|
|
}
|
|
|
|
|
pub async fn box_score(&self, pool: &PgPool) -> Result<Vec<PlayerStats>, sqlx::Error> {
|
|
|
|
|
game_box_score(pool, self.id).await
|
|
|
|
|
}
|
|
|
|
|
pub async fn iihf_points(&self, pool: &PgPool) -> Result<Vec<IihfPoints>, sqlx::Error> {
|
|
|
|
|
game_iihf_points(pool, self.id).await
|
|
|
|
|
pub async fn iihf_points(&self, pool: &PgPool, lang: i32) -> Result<Vec<IihfPoints>, sqlx::Error> {
|
|
|
|
|
game_iihf_points(pool, self.id, lang).await
|
|
|
|
|
}
|
|
|
|
|
pub async fn iihf_stats(&self, pool: &PgPool) -> Result<Vec<IihfStats>, sqlx::Error> {
|
|
|
|
|
game_iihf_stats(pool, self.id).await
|
|
|
|
|
pub async fn iihf_stats(&self, pool: &PgPool, lang: i32) -> Result<Vec<IihfStats>, sqlx::Error> {
|
|
|
|
|
game_iihf_stats(pool, self.id, lang).await
|
|
|
|
|
}
|
|
|
|
|
pub async fn goals(&self, pool: &PgPool) -> Result<Vec<GoalDetails>, sqlx::Error> {
|
|
|
|
|
game_goals(pool, self.id).await
|
|
|
|
|
pub async fn goals(&self, pool: &PgPool, lang: i32) -> Result<Vec<GoalDetails>, sqlx::Error> {
|
|
|
|
|
game_goals(pool, self.id, lang).await
|
|
|
|
|
}
|
|
|
|
|
pub async fn play_by_play(&self, pool: &PgPool) -> Result<Vec<ShotDetails>, sqlx::Error> {
|
|
|
|
|
game_play_by_play(pool, self.id).await
|
|
|
|
|
pub async fn play_by_play(&self, pool: &PgPool, lang: i32) -> Result<Vec<ShotDetails>, sqlx::Error> {
|
|
|
|
|
game_play_by_play(pool, self.id, lang).await
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn division_iihf_stats(
|
|
|
|
|
pool: &PgPool,
|
|
|
|
|
division_id: i32,
|
|
|
|
|
lang: SupportedLanguage,
|
|
|
|
|
lang: i32,
|
|
|
|
|
) -> Result<Vec<IihfStatsI64>, sqlx::Error> {
|
|
|
|
|
sqlx::query_as::<_, IihfStatsI64>(
|
|
|
|
|
sqlx::query_as!(
|
|
|
|
|
IihfStatsI64,
|
|
|
|
|
r#"
|
|
|
|
|
WITH team_name AS (
|
|
|
|
|
SELECT
|
|
|
|
|
teams.id AS team_id,
|
|
|
|
|
-- max will get the first matching string; technically it will always get the string that that has the maximum value based on the locale, ignoring nulls.
|
|
|
|
|
COALESCE(
|
|
|
|
|
MAX(localized_name.name),
|
|
|
|
|
MAX(default_name.name),
|
|
|
|
|
MAX(any_name.name)
|
|
|
|
|
) AS team_name,
|
|
|
|
|
-- this is to get the language id of the team name; although not strictly necessary, since we use MIN(...), then ORDER BY it later on, we prioritize languages that have been added earlier, making this table deterministic
|
|
|
|
|
COALESCE(
|
|
|
|
|
MIN(localized_name.language),
|
|
|
|
|
MIN(default_name.language),
|
|
|
|
|
MIN(any_name.language)
|
|
|
|
|
) AS name_language
|
|
|
|
|
FROM teams
|
|
|
|
|
LEFT JOIN team_names localized_name ON localized_name.team = teams.id AND localized_name.language = $2
|
|
|
|
|
LEFT JOIN team_names default_name ON default_name.team = teams.id AND default_name.language = 1
|
|
|
|
|
LEFT JOIN team_names any_name ON any_name.team = teams.id
|
|
|
|
|
GROUP BY teams.id
|
|
|
|
|
ORDER BY name_language
|
|
|
|
|
)
|
|
|
|
|
SELECT
|
|
|
|
|
SUM(reg_win(games.id, teams.id)) AS reg_wins,
|
|
|
|
|
SUM(reg_loss(games.id, teams.id)) AS reg_losses,
|
|
|
|
|
SUM(ot_win(games.id, teams.id)) AS ot_wins,
|
|
|
|
|
SUM(ot_loss(games.id, teams.id)) AS ot_losses,
|
|
|
|
|
SUM(tie(games.id, teams.id)) AS ties,
|
|
|
|
|
SUM(iihf_points(games.id, teams.id)) AS points,
|
|
|
|
|
teams.id AS team_id,
|
|
|
|
|
team_name.team_name
|
|
|
|
|
FROM
|
|
|
|
|
games
|
|
|
|
|
JOIN teams ON teams.id=games.team_home OR teams.id=games.team_away
|
|
|
|
|
JOIN team_name ON team_name.team_id=teams.id
|
|
|
|
|
WHERE games.division=$1
|
|
|
|
|
GROUP BY
|
|
|
|
|
teams.id,
|
|
|
|
|
team_name.team_name
|
|
|
|
|
ORDER BY
|
|
|
|
|
points DESC;
|
|
|
|
|
SUM(points) AS "points!",
|
|
|
|
|
SUM(reg_wins) AS "reg_wins!",
|
|
|
|
|
SUM(reg_losses) AS "reg_losses!",
|
|
|
|
|
SUM(ot_wins) AS "ot_wins!",
|
|
|
|
|
SUM(ot_losses) AS "ot_losses!",
|
|
|
|
|
SUM(ties) AS "ties!",
|
|
|
|
|
team_name(team_id, $2) AS team_name,
|
|
|
|
|
team_id AS "team_id!"
|
|
|
|
|
FROM team_points_view
|
|
|
|
|
WHERE division_id=$1
|
|
|
|
|
GROUP BY team_id;
|
|
|
|
|
--WITH team_name AS (
|
|
|
|
|
-- SELECT
|
|
|
|
|
-- teams.id AS team_id,
|
|
|
|
|
-- -- max will get the first matching string; technically it will always get the string that that has the maximum value based on the locale, ignoring nulls.
|
|
|
|
|
-- COALESCE(
|
|
|
|
|
-- MAX(localized_name.name),
|
|
|
|
|
-- MAX(default_name.name),
|
|
|
|
|
-- MAX(any_name.name)
|
|
|
|
|
-- ) AS team_name,
|
|
|
|
|
-- -- this is to get the language id of the team name; although not strictly necessary, since we use MIN(...), then ORDER BY it later on, we prioritize languages that have been added earlier, making this table deterministic
|
|
|
|
|
-- COALESCE(
|
|
|
|
|
-- MIN(localized_name.language),
|
|
|
|
|
-- MIN(default_name.language),
|
|
|
|
|
-- MIN(any_name.language)
|
|
|
|
|
-- ) AS name_language
|
|
|
|
|
-- FROM teams
|
|
|
|
|
-- LEFT JOIN team_names localized_name ON localized_name.team = teams.id AND localized_name.language = $2
|
|
|
|
|
-- LEFT JOIN team_names default_name ON default_name.team = teams.id AND default_name.language = 1
|
|
|
|
|
-- LEFT JOIN team_names any_name ON any_name.team = teams.id
|
|
|
|
|
-- GROUP BY teams.id
|
|
|
|
|
-- ORDER BY name_language
|
|
|
|
|
--)
|
|
|
|
|
--SELECT
|
|
|
|
|
-- SUM(reg_win(games.id, teams.id)) AS reg_wins,
|
|
|
|
|
-- SUM(reg_loss(games.id, teams.id)) AS reg_losses,
|
|
|
|
|
-- SUM(ot_win(games.id, teams.id)) AS ot_wins,
|
|
|
|
|
-- SUM(ot_loss(games.id, teams.id)) AS ot_losses,
|
|
|
|
|
-- SUM(tie(games.id, teams.id)) AS ties,
|
|
|
|
|
-- SUM(iihf_points(games.id, teams.id)) AS points,
|
|
|
|
|
-- teams.id AS team_id,
|
|
|
|
|
-- team_name.team_name
|
|
|
|
|
--FROM
|
|
|
|
|
-- games
|
|
|
|
|
--JOIN teams ON teams.id=games.team_home OR teams.id=games.team_away
|
|
|
|
|
--JOIN team_name ON team_name.team_id=teams.id
|
|
|
|
|
--WHERE games.division=$1
|
|
|
|
|
--GROUP BY
|
|
|
|
|
-- teams.id,
|
|
|
|
|
-- team_name.team_name
|
|
|
|
|
--ORDER BY
|
|
|
|
|
-- points DESC;
|
|
|
|
|
|
|
|
|
|
--SELECT DISTINCT ON (teams.id)
|
|
|
|
|
-- SUM(reg_win(games.id, teams.id)) AS reg_wins,
|
|
|
|
@ -361,23 +390,22 @@ ORDER BY
|
|
|
|
|
-- teams.id,
|
|
|
|
|
-- points DESC;
|
|
|
|
|
"#,
|
|
|
|
|
division_id, lang
|
|
|
|
|
)
|
|
|
|
|
.bind(division_id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Division {
|
|
|
|
|
pub async fn iihf_stats(&self, pool: &PgPool, lang: SupportedLanguage) -> Result<Vec<IihfStatsI64>, sqlx::Error> {
|
|
|
|
|
pub async fn iihf_stats(&self, pool: &PgPool, lang: i32) -> Result<Vec<IihfStatsI64>, sqlx::Error> {
|
|
|
|
|
division_iihf_stats(pool, self.id, lang).await
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Player {
|
|
|
|
|
pub async fn latest_league(pool: &PgPool, id: i32) -> Result<Option<League>, sqlx::Error> {
|
|
|
|
|
pub async fn latest_league(pool: &PgPool, id: i32, lang: i32) -> Result<Option<League>, sqlx::Error> {
|
|
|
|
|
let query = r#"
|
|
|
|
|
SELECT leagues.*
|
|
|
|
|
SELECT leagues.*,team_name(teams.id, $2) AS name
|
|
|
|
|
FROM players
|
|
|
|
|
JOIN game_players ON game_players.player=players.id
|
|
|
|
|
JOIN games ON games.id=game_players.game
|
|
|
|
@ -390,22 +418,26 @@ impl Player {
|
|
|
|
|
"#;
|
|
|
|
|
sqlx::query_as::<_, League>(query)
|
|
|
|
|
.bind(id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_optional(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
pub async fn latest_stats(pool: &PgPool, id: i32) -> Result<Vec<GoalDetails>, sqlx::Error> {
|
|
|
|
|
pub async fn latest_stats(pool: &PgPool, id: i32, lang: i32) -> Result<Vec<GoalDetails>, sqlx::Error> {
|
|
|
|
|
let query = r#"
|
|
|
|
|
SELECT
|
|
|
|
|
players.id AS player_id,
|
|
|
|
|
p_assist.id AS first_assist_id,
|
|
|
|
|
p_assist_second.id AS second_assist_id,
|
|
|
|
|
players.name AS player_name,
|
|
|
|
|
p_assist.name AS first_assist_name,
|
|
|
|
|
p_assist_second.name AS second_assist_name,
|
|
|
|
|
players.first_names AS player_first_names,
|
|
|
|
|
players.last_name AS player_last_name,
|
|
|
|
|
p_assist.first_names AS first_assist_first_names,
|
|
|
|
|
p_assist.last_name AS first_assist_last_name,
|
|
|
|
|
p_assist_second.first_names AS second_assist_first_names,
|
|
|
|
|
p_assist_second.last_name AS second_assist_last_name,
|
|
|
|
|
game_players.player_number AS player_number,
|
|
|
|
|
gp_assist.player_number AS first_assist_number,
|
|
|
|
|
gp_assist_second.player_number AS second_assist_number,
|
|
|
|
|
teams.name AS team_name,
|
|
|
|
|
team_name(teams.id, $2) AS team_name,
|
|
|
|
|
teams.id AS team_id,
|
|
|
|
|
shots.period_time AS time_remaining,
|
|
|
|
|
period_types.id AS period_id,
|
|
|
|
@ -429,6 +461,7 @@ impl Player {
|
|
|
|
|
"#;
|
|
|
|
|
sqlx::query_as::<_, GoalDetails>(&query)
|
|
|
|
|
.bind(id)
|
|
|
|
|
.bind(lang)
|
|
|
|
|
.fetch_all(pool)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
@ -438,7 +471,8 @@ impl Player {
|
|
|
|
|
COUNT(goals) AS goals,
|
|
|
|
|
COUNT(assists) AS assists,
|
|
|
|
|
COUNT(points) AS points,
|
|
|
|
|
players.name AS name
|
|
|
|
|
players.first_names AS first_names,
|
|
|
|
|
players.last_name AS last_name
|
|
|
|
|
FROM players
|
|
|
|
|
JOIN game_players ON game_players.player=players.id
|
|
|
|
|
LEFT JOIN shots points
|
|
|
|
@ -468,7 +502,8 @@ SELECT
|
|
|
|
|
COUNT(shots.id) AS points,
|
|
|
|
|
COUNT(CASE WHEN shots.shooter = game_players.id THEN shots.id END) AS goals,
|
|
|
|
|
COUNT(CASE WHEN shots.assistant = game_players.id OR shots.assistant_second = game_players.id THEN shots.id END) AS assists,
|
|
|
|
|
players.name
|
|
|
|
|
players.first_names AS first_names,
|
|
|
|
|
players.last_name AS last_name
|
|
|
|
|
FROM game_players
|
|
|
|
|
JOIN players ON game_players.player = players.id
|
|
|
|
|
LEFT JOIN shots
|
|
|
|
@ -478,7 +513,8 @@ LEFT JOIN shots
|
|
|
|
|
OR shots.assistant_second=game_players.id)
|
|
|
|
|
GROUP BY
|
|
|
|
|
game_players.id,
|
|
|
|
|
players.name
|
|
|
|
|
players.first_names,
|
|
|
|
|
players.last_name
|
|
|
|
|
ORDER BY
|
|
|
|
|
points DESC,
|
|
|
|
|
goals DESC;
|
|
|
|
@ -499,7 +535,8 @@ impl League {
|
|
|
|
|
COUNT(goals.id) AS goals,
|
|
|
|
|
COUNT(assists.id) AS assists,
|
|
|
|
|
COUNT(points.id) AS points,
|
|
|
|
|
players.name AS name
|
|
|
|
|
players.first_names AS first_names,
|
|
|
|
|
players.last_name AS last_name
|
|
|
|
|
FROM players
|
|
|
|
|
JOIN game_players ON game_players.player=players.id
|
|
|
|
|
LEFT JOIN shots goals
|
|
|
|
@ -532,17 +569,20 @@ impl League {
|
|
|
|
|
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
|
|
|
|
pub struct GoalDetails {
|
|
|
|
|
pub player_id: i32,
|
|
|
|
|
pub player_name: String,
|
|
|
|
|
pub player_first_names: String,
|
|
|
|
|
pub player_last_name: String,
|
|
|
|
|
pub player_number: i32,
|
|
|
|
|
pub team_name: String,
|
|
|
|
|
pub team_id: i32,
|
|
|
|
|
pub time_remaining: i32,
|
|
|
|
|
pub period_id: i32,
|
|
|
|
|
pub period_short_name: String,
|
|
|
|
|
pub first_assist_name: Option<String>,
|
|
|
|
|
pub first_assist_first_names: Option<String>,
|
|
|
|
|
pub first_assist_last_name: Option<String>,
|
|
|
|
|
pub first_assist_number: Option<i32>,
|
|
|
|
|
pub first_assist_id: Option<i32>,
|
|
|
|
|
pub second_assist_name: Option<String>,
|
|
|
|
|
pub second_assist_first_names: Option<String>,
|
|
|
|
|
pub second_assist_last_name: Option<String>,
|
|
|
|
|
pub second_assist_id: Option<i32>,
|
|
|
|
|
pub second_assist_number: Option<i32>,
|
|
|
|
|
}
|
|
|
|
@ -550,17 +590,20 @@ pub struct GoalDetails {
|
|
|
|
|
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
|
|
|
|
pub struct ShotDetails {
|
|
|
|
|
pub player_id: i32,
|
|
|
|
|
pub player_name: String,
|
|
|
|
|
pub player_first_names: String,
|
|
|
|
|
pub player_last_name: String,
|
|
|
|
|
pub player_number: i32,
|
|
|
|
|
pub team_name: String,
|
|
|
|
|
pub team_id: i32,
|
|
|
|
|
pub is_goal: bool,
|
|
|
|
|
pub time_remaining: i32,
|
|
|
|
|
pub period_short_name: String,
|
|
|
|
|
pub first_assist_name: Option<String>,
|
|
|
|
|
pub first_assist_first_names: Option<String>,
|
|
|
|
|
pub first_assist_last_name: Option<String>,
|
|
|
|
|
pub first_assist_number: Option<i32>,
|
|
|
|
|
pub first_assist_id: Option<i32>,
|
|
|
|
|
pub second_assist_name: Option<String>,
|
|
|
|
|
pub second_assist_first_names: Option<String>,
|
|
|
|
|
pub second_assist_last_name: Option<String>,
|
|
|
|
|
pub second_assist_id: Option<i32>,
|
|
|
|
|
pub second_assist_number: Option<i32>,
|
|
|
|
|
}
|
|
|
|
@ -580,7 +623,7 @@ mod tests {
|
|
|
|
|
fn check_play_by_play() {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let pbp = game_play_by_play(&pool, 3).await.unwrap();
|
|
|
|
|
let pbp = game_play_by_play(&pool, 3, SupportedLanguage::English.into()).await.unwrap();
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -589,7 +632,7 @@ mod tests {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let player = Player::get(&pool, 2).await.unwrap();
|
|
|
|
|
let latest = Player::latest_stats(&pool, player.id).await.unwrap();
|
|
|
|
|
let latest = Player::latest_stats(&pool, player.id, SupportedLanguage::English.into()).await.unwrap();
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -597,12 +640,12 @@ mod tests {
|
|
|
|
|
fn check_league_player_stats() {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let league = League::get(&pool, 1, SupportedLanguage::English).await.unwrap().unwrap();
|
|
|
|
|
let league = League::get(&pool, 1, SupportedLanguage::English.into()).await.unwrap().unwrap();
|
|
|
|
|
let player = Player::get(&pool, 2).await.unwrap();
|
|
|
|
|
let stats = League::player_stats(&pool, player.id, league.id)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(stats.name, "Hillary Scanlon");
|
|
|
|
|
assert_eq!(stats.last_name, "Scanlon");
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -611,7 +654,7 @@ mod tests {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let player = Player::get(&pool, 5).await.unwrap();
|
|
|
|
|
let league = Player::latest_league(&pool, player.id)
|
|
|
|
|
let league = Player::latest_league(&pool, player.id, SupportedLanguage::English.into())
|
|
|
|
|
.await
|
|
|
|
|
.unwrap()
|
|
|
|
|
.unwrap();
|
|
|
|
@ -623,7 +666,7 @@ mod tests {
|
|
|
|
|
fn check_score_details_from_game() {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let scores = game_goals(&pool, 3).await.unwrap();
|
|
|
|
|
let scores = game_goals(&pool, 3, SupportedLanguage::English.into()).await.unwrap();
|
|
|
|
|
println!("{scores:?}");
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
@ -635,7 +678,7 @@ mod tests {
|
|
|
|
|
let scores = game_box_score(&pool, 4).await.unwrap();
|
|
|
|
|
println!("{scores:?}");
|
|
|
|
|
let second_top_scorer = scores.get(1).unwrap();
|
|
|
|
|
assert_eq!(second_top_scorer.name, "Allyssa Foulds");
|
|
|
|
|
assert_eq!(second_top_scorer.last_name, "Foulds");
|
|
|
|
|
assert_eq!(second_top_scorer.goals, 1, "Allysa should have 1 goal..");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
second_top_scorer.assists, 2,
|
|
|
|
@ -654,14 +697,16 @@ mod tests {
|
|
|
|
|
fn check_division_iihf_stats() {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let score = division_iihf_stats(&pool, 1, SupportedLanguage::English).await.unwrap();
|
|
|
|
|
let score = division_iihf_stats(&pool, 1, SupportedLanguage::English.into()).await.unwrap();
|
|
|
|
|
let team_1 = score.get(0).unwrap();
|
|
|
|
|
let team_2 = score.get(1).unwrap();
|
|
|
|
|
assert_eq!(score.len(), 2, "Too many teams selected.");
|
|
|
|
|
assert_eq!(score.get(0).unwrap().points, 10, "Top team should have 10 points");
|
|
|
|
|
assert_eq!(score.get(0).unwrap().team_name, "Bullseye", "Top team should be bullseye");
|
|
|
|
|
assert_eq!(score.get(0).unwrap().reg_losses, 0, "The bullseye should have no regulation losses");
|
|
|
|
|
assert_eq!(score.get(0).unwrap().ties, 2, "There should be two ties for the bullsye");
|
|
|
|
|
assert_eq!(score.get(1).unwrap().team_name, "See Cats", "The second-place team should be the see cats");
|
|
|
|
|
assert_eq!(score.get(1).unwrap().points, 4, "The second-place team should have four points");
|
|
|
|
|
assert_eq!(team_1.points, 10, "Top team should have 10 points");
|
|
|
|
|
assert_eq!(team_1.team_name.as_ref().unwrap(), "Bullseye", "Top team should be bullseye");
|
|
|
|
|
assert_eq!(team_1.reg_losses, 0, "The bullseye should have no regulation losses");
|
|
|
|
|
assert_eq!(team_1.ties, 2, "There should be two ties for the bullsye");
|
|
|
|
|
assert_eq!(team_2.team_name.as_ref().unwrap(), "See Cats", "The second-place team should be the see cats");
|
|
|
|
|
assert_eq!(team_2.points, 4, "The second-place team should have four points");
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -669,11 +714,12 @@ mod tests {
|
|
|
|
|
fn check_iihf_stats() {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let score = game_iihf_stats(&pool, 4).await.unwrap();
|
|
|
|
|
assert_eq!(score.get(0).unwrap().points, 2);
|
|
|
|
|
assert_eq!(score.get(0).unwrap().team_name, "Bullseye");
|
|
|
|
|
assert_eq!(score.get(0).unwrap().reg_losses, 0);
|
|
|
|
|
assert_eq!(score.get(0).unwrap().ties, 1);
|
|
|
|
|
let score = game_iihf_stats(&pool, 4, SupportedLanguage::English.into()).await.unwrap();
|
|
|
|
|
let team_1 = score.get(0).unwrap();
|
|
|
|
|
assert_eq!(team_1.points, 2);
|
|
|
|
|
assert_eq!(team_1.team_name.as_ref().unwrap(), "Bullseye");
|
|
|
|
|
assert_eq!(team_1.reg_losses, 0);
|
|
|
|
|
assert_eq!(team_1.ties, 1);
|
|
|
|
|
assert_eq!(score.get(1).unwrap().points, 2);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
@ -682,7 +728,7 @@ mod tests {
|
|
|
|
|
fn check_iihf_points() {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let score = game_iihf_points(&pool, 4).await.unwrap();
|
|
|
|
|
let score = game_iihf_points(&pool, 4, SupportedLanguage::English.into()).await.unwrap();
|
|
|
|
|
assert_eq!(score.get(0).unwrap().points, 2);
|
|
|
|
|
assert_eq!(score.get(0).unwrap().team_name, "Bullseye");
|
|
|
|
|
assert_eq!(score.get(1).unwrap().points, 2);
|
|
|
|
@ -693,7 +739,7 @@ mod tests {
|
|
|
|
|
fn check_game_score() {
|
|
|
|
|
tokio_test::block_on(async move {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let score = game_score(&pool, 1).await.unwrap();
|
|
|
|
|
let score = game_score(&pool, 1, SupportedLanguage::English.into()).await.unwrap();
|
|
|
|
|
assert_eq!(score.get(0).unwrap().goals, 1);
|
|
|
|
|
assert_eq!(score.get(1).unwrap().goals, 1);
|
|
|
|
|
})
|
|
|
|
@ -724,8 +770,9 @@ mod tests {
|
|
|
|
|
let pool = db_connect().await;
|
|
|
|
|
let query = r#"
|
|
|
|
|
SELECT
|
|
|
|
|
teams.name AS scorer_team_name,
|
|
|
|
|
players.name AS scorer_name,
|
|
|
|
|
team_name(teams.id, $1) AS scorer_team_name,
|
|
|
|
|
players.first_names AS scorer_first_names,
|
|
|
|
|
players.last_name AS scorer_last_name,
|
|
|
|
|
positions.name AS position,
|
|
|
|
|
game_players.player_number AS scorer_number,
|
|
|
|
|
shots.period_time AS period_time_left,
|
|
|
|
@ -740,6 +787,7 @@ JOIN period_types ON period_types.id=periods.period_type
|
|
|
|
|
JOIN positions ON positions.id=game_players.position;
|
|
|
|
|
"#;
|
|
|
|
|
let result = sqlx::query_as::<_, Notification>(query)
|
|
|
|
|
.bind(1)
|
|
|
|
|
.fetch_one(&pool)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
@ -749,7 +797,7 @@ JOIN positions ON positions.id=game_players.position;
|
|
|
|
|
"{0} {1} player #{3} {2} has scored! Time of the goal: {4}:{5} in the {6}",
|
|
|
|
|
result.scorer_team_name,
|
|
|
|
|
result.position,
|
|
|
|
|
result.scorer_name,
|
|
|
|
|
result.scorer_last_name,
|
|
|
|
|
result.scorer_number,
|
|
|
|
|
minutes,
|
|
|
|
|
seconds,
|
|
|
|
|