align backend with TSS schema: drop SRE-specific fields, fix cross-tournament queries
- Remove teams_points, clanrating, tag/short/long name, description, region, guild_id, clan_id — none of these exist in the TSS DB schema - Rename long_name → name throughout (TSS teams have one name, not long+short) - Cross-tournament stat queries now use team_name (string) from player_games_hist instead of team_id, since team_id is assigned per-tournament by Spectra - Leaderboard deduplicates teams_data by name with GROUP BY, MAX(team_id) for roster ref - team_members roster still uses team_id (correct within a single tournament) - Fix player_teams_for: was grouping by non-existent team_tag column, now team_id - Fix games_for: winning_team/losing_team → winning_slot/losing_slot; add mission_name - Remove joined_unix, points, sqb_points from PlayerSummary; nick resolved from battles_db - Remove rating_hourly from HistoryResponse (teams_points never existed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+85
-195
@@ -105,51 +105,34 @@ struct SearchResponse {
|
||||
#[derive(Serialize)]
|
||||
struct ResolveResponse {
|
||||
team_id: i64,
|
||||
long_name: String,
|
||||
tag_name: Option<String>,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TeamSearchRow {
|
||||
team_id: i64,
|
||||
long_name: String,
|
||||
tag_name: Option<String>,
|
||||
name: String,
|
||||
members: i64,
|
||||
clanrating: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TeamLeaderboardRow {
|
||||
team_id: i64,
|
||||
clan_id: i64,
|
||||
long_name: String,
|
||||
tag_name: Option<String>,
|
||||
short_name: Option<String>,
|
||||
name: String,
|
||||
player_count: i64,
|
||||
total_battles: i64,
|
||||
wins: i64,
|
||||
losses: i64,
|
||||
win_rate: f64,
|
||||
total_kills: i64,
|
||||
points: Points,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TeamDetail {
|
||||
team_id: i64,
|
||||
clan_id: i64,
|
||||
long_name: String,
|
||||
tag_name: Option<String>,
|
||||
short_name: Option<String>,
|
||||
description: Option<String>,
|
||||
region: Option<String>,
|
||||
name: String,
|
||||
members: i64,
|
||||
captain_uid: Option<String>,
|
||||
guild_id: Option<String>,
|
||||
created_unix: Option<i64>,
|
||||
updated_unix: Option<i64>,
|
||||
clanrating: Option<i64>,
|
||||
data_set: &'static str,
|
||||
team_summary: TeamSummary,
|
||||
players: Vec<PlayerSummary>,
|
||||
@@ -164,12 +147,6 @@ struct TeamSummary {
|
||||
win_rate: f64,
|
||||
kdr: f64,
|
||||
total_kills: i64,
|
||||
points: Points,
|
||||
total_points: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Points {
|
||||
total_points: i64,
|
||||
}
|
||||
|
||||
@@ -178,9 +155,6 @@ struct PlayerSummary {
|
||||
uid: String,
|
||||
nick: Option<String>,
|
||||
role: String,
|
||||
joined_unix: Option<i64>,
|
||||
points: i64,
|
||||
sqb_points: i64,
|
||||
total_battles: i64,
|
||||
wins: i64,
|
||||
losses: i64,
|
||||
@@ -196,10 +170,8 @@ struct PlayerSummary {
|
||||
#[derive(Serialize)]
|
||||
struct HistoryResponse {
|
||||
team_id: i64,
|
||||
long_name: String,
|
||||
tag_name: Option<String>,
|
||||
name: String,
|
||||
history: Vec<PeriodHistory>,
|
||||
rating_hourly: Vec<RatingPoint>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -211,17 +183,10 @@ struct PeriodHistory {
|
||||
win_rate: f64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct RatingPoint {
|
||||
timestamp: i64,
|
||||
rating: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GamesResponse {
|
||||
team_id: i64,
|
||||
long_name: String,
|
||||
tag_name: Option<String>,
|
||||
name: String,
|
||||
games: Vec<GameRow>,
|
||||
}
|
||||
|
||||
@@ -290,7 +255,6 @@ struct PlayerCareer {
|
||||
#[derive(Serialize)]
|
||||
struct PlayerTeamRef {
|
||||
team_id: Option<i64>,
|
||||
team_tag: Option<String>,
|
||||
team_name: Option<String>,
|
||||
games: i64,
|
||||
last_seen: i64,
|
||||
@@ -298,16 +262,9 @@ struct PlayerTeamRef {
|
||||
|
||||
struct TeamRecord {
|
||||
team_id: i64,
|
||||
long_name: String,
|
||||
tag_name: Option<String>,
|
||||
description: Option<String>,
|
||||
region: Option<String>,
|
||||
name: String,
|
||||
members: i64,
|
||||
captain_uid: Option<String>,
|
||||
guild_id: Option<String>,
|
||||
created_unix: Option<i64>,
|
||||
updated_unix: Option<i64>,
|
||||
clanrating: Option<i64>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -411,12 +368,14 @@ async fn leaderboard(
|
||||
let limit = i64::from(query.limit.unwrap_or(100).clamp(1, 100));
|
||||
let teams_conn = open_db(&state.teams_db)?;
|
||||
let battles_conn = open_db(&state.battles_db)?;
|
||||
// Deduplicate teams by name across tournaments — pick the highest team_id
|
||||
// (most recent) per name for the roster count, but stats come from team_name.
|
||||
let mut stmt = teams_conn
|
||||
.prepare(
|
||||
"SELECT team_id, long_name, tag_name, description, region, members, captain_uid, guild_id,
|
||||
created_unix, updated_unix, clanrating
|
||||
"SELECT MAX(team_id), name, MAX(members), MAX(captain_uid)
|
||||
FROM teams_data
|
||||
ORDER BY COALESCE(clanrating, 0) DESC, members DESC, long_name COLLATE NOCASE ASC
|
||||
GROUP BY name COLLATE NOCASE
|
||||
ORDER BY MAX(members) DESC, name COLLATE NOCASE ASC
|
||||
LIMIT ?1",
|
||||
)
|
||||
.map_err(db_error)?;
|
||||
@@ -429,22 +388,16 @@ async fn leaderboard(
|
||||
|
||||
let mut rows = Vec::with_capacity(teams.len());
|
||||
for team in teams {
|
||||
let summary = team_summary_for(&battles_conn, team.team_id)?;
|
||||
let summary = team_summary_for(&battles_conn, &team.name)?;
|
||||
rows.push(TeamLeaderboardRow {
|
||||
team_id: team.team_id,
|
||||
clan_id: team.team_id,
|
||||
long_name: team.long_name.clone(),
|
||||
tag_name: team.tag_name.clone(),
|
||||
short_name: team.tag_name.clone(),
|
||||
name: team.name,
|
||||
player_count: team.members,
|
||||
total_battles: summary.total_battles,
|
||||
wins: summary.wins,
|
||||
losses: summary.losses,
|
||||
win_rate: summary.win_rate,
|
||||
total_kills: summary.total_kills,
|
||||
points: Points {
|
||||
total_points: team.clanrating.unwrap_or(summary.total_points),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -460,9 +413,7 @@ async fn resolve_team(
|
||||
let team = find_team(&conn, name)?.ok_or_else(|| ApiError::not_found("Team not found"))?;
|
||||
Ok(Json(ResolveResponse {
|
||||
team_id: team.team_id,
|
||||
long_name: team.long_name.clone(),
|
||||
tag_name: team.tag_name.clone(),
|
||||
name: team.tag_name.clone().unwrap_or(team.long_name),
|
||||
name: team.name,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -477,17 +428,13 @@ async fn search_teams(
|
||||
let conn = open_db(&state.teams_db)?;
|
||||
let mut stmt = conn
|
||||
.prepare(
|
||||
"SELECT team_id, long_name, tag_name, members, clanrating
|
||||
"SELECT team_id, name, members
|
||||
FROM teams_data
|
||||
WHERE long_name LIKE ?1 ESCAPE '\\' OR tag_name LIKE ?1 ESCAPE '\\'
|
||||
WHERE name LIKE ?1 ESCAPE '\\'
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN tag_name = ?2 COLLATE NOCASE THEN 0
|
||||
WHEN long_name = ?2 COLLATE NOCASE THEN 1
|
||||
ELSE 2
|
||||
END,
|
||||
COALESCE(clanrating, 0) DESC,
|
||||
long_name COLLATE NOCASE ASC
|
||||
CASE WHEN name = ?2 COLLATE NOCASE THEN 0 ELSE 1 END,
|
||||
members DESC,
|
||||
name COLLATE NOCASE ASC
|
||||
LIMIT ?3",
|
||||
)
|
||||
.map_err(db_error)?;
|
||||
@@ -496,10 +443,8 @@ async fn search_teams(
|
||||
.query_map(params![like, name, limit], |row| {
|
||||
Ok(TeamSearchRow {
|
||||
team_id: row.get(0)?,
|
||||
long_name: row.get(1)?,
|
||||
tag_name: row.get(2)?,
|
||||
members: row.get(3)?,
|
||||
clanrating: row.get(4)?,
|
||||
name: row.get(1)?,
|
||||
members: row.get(2)?,
|
||||
})
|
||||
})
|
||||
.map_err(db_error)?
|
||||
@@ -518,23 +463,15 @@ async fn team_detail(
|
||||
let battles_conn = open_db(&state.battles_db)?;
|
||||
let team =
|
||||
find_team(&teams_conn, &decoded)?.ok_or_else(|| ApiError::not_found("Team not found"))?;
|
||||
let summary = team_summary_for(&battles_conn, team.team_id)?;
|
||||
let players = player_summaries_for(&teams_conn, &battles_conn, team.team_id)?;
|
||||
let summary = team_summary_for(&battles_conn, &team.name)?;
|
||||
// team_id is the most recent tournament entry — used only for the roster lookup.
|
||||
let players = player_summaries_for(&teams_conn, &battles_conn, team.team_id, &team.name)?;
|
||||
|
||||
Ok(Json(TeamDetail {
|
||||
team_id: team.team_id,
|
||||
clan_id: team.team_id,
|
||||
long_name: team.long_name,
|
||||
tag_name: team.tag_name.clone(),
|
||||
short_name: team.tag_name,
|
||||
description: team.description,
|
||||
region: team.region,
|
||||
name: team.name,
|
||||
members: team.members,
|
||||
captain_uid: team.captain_uid,
|
||||
guild_id: team.guild_id,
|
||||
created_unix: team.created_unix,
|
||||
updated_unix: team.updated_unix,
|
||||
clanrating: team.clanrating,
|
||||
data_set: "tss",
|
||||
team_summary: summary,
|
||||
players,
|
||||
@@ -551,15 +488,12 @@ async fn team_history(
|
||||
let team =
|
||||
find_team(&teams_conn, &decoded)?.ok_or_else(|| ApiError::not_found("Team not found"))?;
|
||||
|
||||
let history = period_history_for(&battles_conn, team.team_id)?;
|
||||
let rating_hourly = rating_history_for(&teams_conn, team.team_id)?;
|
||||
let history = period_history_for(&battles_conn, &team.name)?;
|
||||
|
||||
Ok(Json(HistoryResponse {
|
||||
team_id: team.team_id,
|
||||
long_name: team.long_name,
|
||||
tag_name: team.tag_name,
|
||||
name: team.name,
|
||||
history,
|
||||
rating_hourly,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -572,12 +506,11 @@ async fn team_games(
|
||||
let battles_conn = open_db(&state.battles_db)?;
|
||||
let team =
|
||||
find_team(&teams_conn, &decoded)?.ok_or_else(|| ApiError::not_found("Team not found"))?;
|
||||
let games = games_for(&battles_conn, team.team_id)?;
|
||||
let games = games_for(&battles_conn, &team.name)?;
|
||||
|
||||
Ok(Json(GamesResponse {
|
||||
team_id: team.team_id,
|
||||
long_name: team.long_name,
|
||||
tag_name: team.tag_name,
|
||||
name: team.name,
|
||||
games,
|
||||
}))
|
||||
}
|
||||
@@ -639,33 +572,19 @@ fn db_error(error: rusqlite::Error) -> ApiError {
|
||||
fn read_team_record(row: &rusqlite::Row<'_>) -> rusqlite::Result<TeamRecord> {
|
||||
Ok(TeamRecord {
|
||||
team_id: row.get(0)?,
|
||||
long_name: row.get(1)?,
|
||||
tag_name: row.get(2)?,
|
||||
description: row.get(3)?,
|
||||
region: row.get(4)?,
|
||||
members: row.get(5)?,
|
||||
captain_uid: row.get(6)?,
|
||||
guild_id: row.get(7)?,
|
||||
created_unix: row.get(8)?,
|
||||
updated_unix: row.get(9)?,
|
||||
clanrating: row.get(10)?,
|
||||
name: row.get(1)?,
|
||||
members: row.get(2)?,
|
||||
captain_uid: row.get(3)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn find_team(conn: &Connection, name: &str) -> Result<Option<TeamRecord>, ApiError> {
|
||||
// Return the most recent tournament entry for this team (highest team_id).
|
||||
conn.query_row(
|
||||
"SELECT team_id, long_name, tag_name, description, region, members, captain_uid, guild_id,
|
||||
created_unix, updated_unix, clanrating
|
||||
"SELECT team_id, name, members, captain_uid
|
||||
FROM teams_data
|
||||
WHERE team_id = ?1
|
||||
OR long_name = ?2 COLLATE NOCASE
|
||||
OR tag_name = ?2 COLLATE NOCASE
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN tag_name = ?2 COLLATE NOCASE THEN 0
|
||||
WHEN long_name = ?2 COLLATE NOCASE THEN 1
|
||||
ELSE 2
|
||||
END
|
||||
WHERE name = ?2 COLLATE NOCASE OR team_id = ?1
|
||||
ORDER BY team_id DESC
|
||||
LIMIT 1",
|
||||
params![name.parse::<i64>().ok(), name],
|
||||
read_team_record,
|
||||
@@ -674,7 +593,7 @@ fn find_team(conn: &Connection, name: &str) -> Result<Option<TeamRecord>, ApiErr
|
||||
.map_err(db_error)
|
||||
}
|
||||
|
||||
fn team_summary_for(conn: &Connection, team_id: i64) -> Result<TeamSummary, ApiError> {
|
||||
fn team_summary_for(conn: &Connection, team_name: &str) -> Result<TeamSummary, ApiError> {
|
||||
conn.query_row(
|
||||
"SELECT
|
||||
COUNT(DISTINCT session_id),
|
||||
@@ -687,8 +606,8 @@ fn team_summary_for(conn: &Connection, team_id: i64) -> Result<TeamSummary, ApiE
|
||||
COALESCE(SUM(score), 0),
|
||||
COUNT(DISTINCT UID)
|
||||
FROM player_games_hist
|
||||
WHERE team_id = ?1",
|
||||
params![team_id],
|
||||
WHERE team_name = ?1 COLLATE NOCASE",
|
||||
params![team_name],
|
||||
|row| {
|
||||
let battles: i64 = row.get(0)?;
|
||||
let wins: i64 = row.get(1)?;
|
||||
@@ -708,9 +627,6 @@ fn team_summary_for(conn: &Connection, team_id: i64) -> Result<TeamSummary, ApiE
|
||||
win_rate: percent(wins, battles),
|
||||
kdr: ratio(total_kills, deaths),
|
||||
total_kills,
|
||||
points: Points {
|
||||
total_points: score + assists + total_kills,
|
||||
},
|
||||
total_points: score + assists + total_kills,
|
||||
})
|
||||
},
|
||||
@@ -721,24 +637,24 @@ fn team_summary_for(conn: &Connection, team_id: i64) -> Result<TeamSummary, ApiE
|
||||
fn player_summaries_for(
|
||||
teams_conn: &Connection,
|
||||
battles_conn: &Connection,
|
||||
// team_id: roster for this specific tournament entry only
|
||||
team_id: i64,
|
||||
// team_name: cross-tournament stats key
|
||||
team_name: &str,
|
||||
) -> Result<Vec<PlayerSummary>, ApiError> {
|
||||
let mut stmt = teams_conn
|
||||
.prepare(
|
||||
"SELECT uid, nick, role, joined_unix, points
|
||||
"SELECT uid, role
|
||||
FROM team_members
|
||||
WHERE team_id = ?1
|
||||
ORDER BY points DESC, nick COLLATE NOCASE ASC",
|
||||
ORDER BY uid",
|
||||
)
|
||||
.map_err(db_error)?;
|
||||
let members = stmt
|
||||
.query_map(params![team_id], |row| {
|
||||
Ok((
|
||||
row.get::<_, String>(0)?,
|
||||
row.get::<_, Option<String>>(1)?,
|
||||
row.get::<_, String>(2)?,
|
||||
row.get::<_, Option<i64>>(3)?,
|
||||
row.get::<_, i64>(4)?,
|
||||
row.get::<_, String>(1)?,
|
||||
))
|
||||
})
|
||||
.map_err(db_error)?
|
||||
@@ -756,15 +672,17 @@ fn player_summaries_for(
|
||||
COALESCE(SUM(air_kills), 0),
|
||||
COALESCE(SUM(assists), 0),
|
||||
COALESCE(SUM(deaths), 0),
|
||||
COALESCE(SUM(score), 0)
|
||||
(SELECT nick FROM player_games_hist
|
||||
WHERE UID = ?2 AND nick IS NOT NULL
|
||||
ORDER BY endtime_unix DESC LIMIT 1)
|
||||
FROM player_games_hist
|
||||
WHERE team_id = ?1 AND UID = ?2",
|
||||
WHERE team_name = ?1 COLLATE NOCASE AND UID = ?2",
|
||||
)
|
||||
.map_err(db_error)?;
|
||||
|
||||
for (uid, nick, role, joined_unix, points) in members {
|
||||
for (uid, role) in members {
|
||||
let summary = stats_stmt
|
||||
.query_row(params![team_id, uid], |row| {
|
||||
.query_row(params![team_name, uid], |row| {
|
||||
let battles: i64 = row.get(0)?;
|
||||
let wins: i64 = row.get(1)?;
|
||||
let losses: i64 = row.get(2)?;
|
||||
@@ -772,19 +690,12 @@ fn player_summaries_for(
|
||||
let air: i64 = row.get(4)?;
|
||||
let assists: i64 = row.get(5)?;
|
||||
let deaths: i64 = row.get(6)?;
|
||||
let score: i64 = row.get(7)?;
|
||||
let nick: Option<String> = row.get(7)?;
|
||||
let total_kills = ground + air;
|
||||
Ok(PlayerSummary {
|
||||
uid: uid.clone(),
|
||||
nick: nick.clone(),
|
||||
nick,
|
||||
role: role.clone(),
|
||||
joined_unix,
|
||||
points,
|
||||
sqb_points: if points == 0 {
|
||||
score + assists + total_kills
|
||||
} else {
|
||||
points
|
||||
},
|
||||
total_battles: battles,
|
||||
wins,
|
||||
losses,
|
||||
@@ -801,6 +712,7 @@ fn player_summaries_for(
|
||||
out.push(summary);
|
||||
}
|
||||
|
||||
out.sort_by(|a, b| b.total_battles.cmp(&a.total_battles));
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
@@ -931,22 +843,21 @@ fn player_career_for(conn: &Connection, uid: &str) -> Result<Option<PlayerCareer
|
||||
fn player_teams_for(conn: &Connection, uid: &str) -> Result<Vec<PlayerTeamRef>, ApiError> {
|
||||
let mut stmt = conn
|
||||
.prepare(
|
||||
"SELECT team_tag, MAX(team_name) AS team_name, team_id,
|
||||
"SELECT team_id, MAX(team_name) AS team_name,
|
||||
COUNT(DISTINCT session_id) AS games, MAX(endtime_unix) AS last_seen
|
||||
FROM player_games_hist
|
||||
WHERE UID = ?1
|
||||
GROUP BY team_tag
|
||||
WHERE UID = ?1 AND team_id IS NOT NULL
|
||||
GROUP BY team_id
|
||||
ORDER BY last_seen DESC",
|
||||
)
|
||||
.map_err(db_error)?;
|
||||
let teams = stmt
|
||||
.query_map(params![uid], |row| {
|
||||
Ok(PlayerTeamRef {
|
||||
team_tag: row.get(0)?,
|
||||
team_id: row.get(0)?,
|
||||
team_name: row.get(1)?,
|
||||
team_id: row.get(2)?,
|
||||
games: row.get(3)?,
|
||||
last_seen: row.get(4)?,
|
||||
games: row.get(2)?,
|
||||
last_seen: row.get(3)?,
|
||||
})
|
||||
})
|
||||
.map_err(db_error)?
|
||||
@@ -955,7 +866,7 @@ fn player_teams_for(conn: &Connection, uid: &str) -> Result<Vec<PlayerTeamRef>,
|
||||
Ok(teams)
|
||||
}
|
||||
|
||||
fn period_history_for(conn: &Connection, team_id: i64) -> Result<Vec<PeriodHistory>, ApiError> {
|
||||
fn period_history_for(conn: &Connection, team_name: &str) -> Result<Vec<PeriodHistory>, ApiError> {
|
||||
let mut stmt = conn
|
||||
.prepare(
|
||||
"SELECT
|
||||
@@ -964,14 +875,14 @@ fn period_history_for(conn: &Connection, team_id: i64) -> Result<Vec<PeriodHisto
|
||||
SUM(CASE WHEN victor_bool = 'Win' THEN 1 ELSE 0 END),
|
||||
SUM(CASE WHEN victor_bool != 'Win' THEN 1 ELSE 0 END)
|
||||
FROM player_games_hist
|
||||
WHERE team_id = ?1 AND endtime_unix > 0
|
||||
WHERE team_name = ?1 COLLATE NOCASE AND endtime_unix > 0
|
||||
GROUP BY period
|
||||
ORDER BY period ASC",
|
||||
)
|
||||
.map_err(db_error)?;
|
||||
|
||||
let rows = stmt
|
||||
.query_map(params![team_id], |row| {
|
||||
.query_map(params![team_name], |row| {
|
||||
let period: String = row.get(0)?;
|
||||
let battles: i64 = row.get(1)?;
|
||||
let wins: i64 = row.get(2)?;
|
||||
@@ -990,35 +901,13 @@ fn period_history_for(conn: &Connection, team_id: i64) -> Result<Vec<PeriodHisto
|
||||
Ok(rows)
|
||||
}
|
||||
|
||||
fn rating_history_for(conn: &Connection, team_id: i64) -> Result<Vec<RatingPoint>, ApiError> {
|
||||
let mut stmt = conn
|
||||
.prepare(
|
||||
"SELECT unix_time, COALESCE(total_score, 0)
|
||||
FROM teams_points
|
||||
WHERE team_id = ?1
|
||||
ORDER BY unix_time ASC",
|
||||
)
|
||||
.map_err(db_error)?;
|
||||
|
||||
let rows = stmt
|
||||
.query_map(params![team_id], |row| {
|
||||
Ok(RatingPoint {
|
||||
timestamp: row.get(0)?,
|
||||
rating: row.get(1)?,
|
||||
})
|
||||
})
|
||||
.map_err(db_error)?
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(db_error)?;
|
||||
Ok(rows)
|
||||
}
|
||||
|
||||
fn games_for(conn: &Connection, team_id: i64) -> Result<Vec<GameRow>, ApiError> {
|
||||
fn games_for(conn: &Connection, team_name: &str) -> Result<Vec<GameRow>, ApiError> {
|
||||
let mut stmt = conn
|
||||
.prepare(
|
||||
"SELECT
|
||||
p.session_id,
|
||||
COALESCE(m.endtime_unix, MAX(p.endtime_unix), 0) AS timestamp,
|
||||
m.mission_name,
|
||||
m.mission_mode,
|
||||
CASE
|
||||
WHEN MAX(CASE WHEN p.victor_bool = 'Win' THEN 1 ELSE 0 END) = 1 THEN 'Win'
|
||||
@@ -1034,11 +923,11 @@ fn games_for(conn: &Connection, team_id: i64) -> Result<Vec<GameRow>, ApiError>
|
||||
COALESCE(SUM(p.missile_evades), 0),
|
||||
COALESCE(SUM(p.shell_interceptions), 0),
|
||||
COALESCE(SUM(p.team_kills_stat), 0),
|
||||
m.winning_team,
|
||||
m.losing_team
|
||||
m.winning_slot,
|
||||
m.losing_slot
|
||||
FROM player_games_hist p
|
||||
LEFT JOIN match_summary m ON m.session_id = p.session_id
|
||||
WHERE p.team_id = ?1
|
||||
WHERE p.team_name = ?1 COLLATE NOCASE
|
||||
GROUP BY p.session_id
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT 100",
|
||||
@@ -1046,30 +935,31 @@ fn games_for(conn: &Connection, team_id: i64) -> Result<Vec<GameRow>, ApiError>
|
||||
.map_err(db_error)?;
|
||||
|
||||
let rows = stmt
|
||||
.query_map(params![team_id], |row| {
|
||||
.query_map(params![team_name], |row| {
|
||||
let session_id: String = row.get(0)?;
|
||||
let timestamp: i64 = row.get(1)?;
|
||||
let mission_mode: Option<String> = row.get(2)?;
|
||||
let map_name: Option<String> = row.get(2)?;
|
||||
let mission_mode: Option<String> = row.get(3)?;
|
||||
Ok(GameRow {
|
||||
session_id,
|
||||
timestamp,
|
||||
endtime_unix: timestamp,
|
||||
map_name: mission_mode.clone(),
|
||||
map_name,
|
||||
mission_mode,
|
||||
result: row.get(3)?,
|
||||
player_count: row.get(4)?,
|
||||
winning_team: row.get(14)?,
|
||||
losing_team: row.get(15)?,
|
||||
result: row.get(4)?,
|
||||
player_count: row.get(5)?,
|
||||
winning_team: row.get(15)?,
|
||||
losing_team: row.get(16)?,
|
||||
stats: GameStats {
|
||||
ground_kills: row.get(5)?,
|
||||
air_kills: row.get(6)?,
|
||||
assists: row.get(7)?,
|
||||
captures: row.get(8)?,
|
||||
deaths: row.get(9)?,
|
||||
score: row.get(10)?,
|
||||
missile_evades: row.get(11)?,
|
||||
shell_interceptions: row.get(12)?,
|
||||
team_kills_stat: row.get(13)?,
|
||||
ground_kills: row.get(6)?,
|
||||
air_kills: row.get(7)?,
|
||||
assists: row.get(8)?,
|
||||
captures: row.get(9)?,
|
||||
deaths: row.get(10)?,
|
||||
score: row.get(11)?,
|
||||
missile_evades: row.get(12)?,
|
||||
shell_interceptions: row.get(13)?,
|
||||
team_kills_stat: row.get(14)?,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user