add information about match players to match API object

This commit is contained in:
Ilion Beyst 2022-03-11 00:41:18 +01:00
parent 523de3ba06
commit 63695c299c
3 changed files with 74 additions and 17 deletions

View file

@ -1,9 +1,14 @@
pub use crate::db_types::MatchState; pub use crate::db_types::MatchState;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{BelongingToDsl, ExpressionMethods, QueryDsl, RunQueryDsl}; use diesel::associations::BelongsTo;
use diesel::{
BelongingToDsl, ExpressionMethods, JoinOnDsl, NullableExpressionMethods, QueryDsl, RunQueryDsl,
};
use diesel::{Connection, GroupedBy, PgConnection, QueryResult}; use diesel::{Connection, GroupedBy, PgConnection, QueryResult};
use crate::schema::{match_players, matches}; use crate::schema::{bots, code_bundles, match_players, matches};
use super::bots::{Bot, CodeBundle};
#[derive(Insertable)] #[derive(Insertable)]
#[table_name = "matches"] #[table_name = "matches"]
@ -32,7 +37,7 @@ pub struct MatchBase {
pub created_at: NaiveDateTime, pub created_at: NaiveDateTime,
} }
#[derive(Queryable, Identifiable, Associations)] #[derive(Queryable, Identifiable, Associations, Clone)]
#[primary_key(match_id, player_id)] #[primary_key(match_id, player_id)]
#[belongs_to(MatchBase, foreign_key = "match_id")] #[belongs_to(MatchBase, foreign_key = "match_id")]
pub struct MatchPlayer { pub struct MatchPlayer {
@ -81,18 +86,20 @@ pub struct MatchData {
pub match_players: Vec<MatchPlayer>, pub match_players: Vec<MatchPlayer>,
} }
pub fn list_matches(conn: &PgConnection) -> QueryResult<Vec<MatchData>> { pub fn list_matches(conn: &PgConnection) -> QueryResult<Vec<FullMatchData>> {
conn.transaction(|| { conn.transaction(|| {
let matches = matches::table.get_results::<MatchBase>(conn)?; let matches = matches::table.get_results::<MatchBase>(conn)?;
let match_players = MatchPlayer::belonging_to(&matches) let match_players = MatchPlayer::belonging_to(&matches)
.load::<MatchPlayer>(conn)? .inner_join(code_bundles::table)
.left_join(bots::table.on(code_bundles::bot_id.eq(bots::id.nullable())))
.load::<FullMatchPlayerData>(conn)?
.grouped_by(&matches); .grouped_by(&matches);
let res = matches let res = matches
.into_iter() .into_iter()
.zip(match_players.into_iter()) .zip(match_players.into_iter())
.map(|(base, players)| MatchData { .map(|(base, players)| FullMatchData {
base, base,
match_players: players.into_iter().collect(), match_players: players.into_iter().collect(),
}) })
@ -102,13 +109,43 @@ pub fn list_matches(conn: &PgConnection) -> QueryResult<Vec<MatchData>> {
}) })
} }
pub fn find_match(id: i32, conn: &PgConnection) -> QueryResult<MatchData> { // TODO: maybe unify this with matchdata?
pub struct FullMatchData {
pub base: MatchBase,
pub match_players: Vec<FullMatchPlayerData>,
}
#[derive(Queryable)]
// #[primary_key(base.match_id, base::player_id)]
pub struct FullMatchPlayerData {
pub base: MatchPlayer,
pub code_bundle: CodeBundle,
pub bot: Option<Bot>,
}
impl BelongsTo<MatchBase> for FullMatchPlayerData {
type ForeignKey = i32;
type ForeignKeyColumn = match_players::match_id;
fn foreign_key(&self) -> Option<&Self::ForeignKey> {
Some(&self.base.match_id)
}
fn foreign_key_column() -> Self::ForeignKeyColumn {
match_players::match_id
}
}
pub fn find_match(id: i32, conn: &PgConnection) -> QueryResult<FullMatchData> {
conn.transaction(|| { conn.transaction(|| {
let match_base = matches::table.find(id).get_result::<MatchBase>(conn)?; let match_base = matches::table.find(id).get_result::<MatchBase>(conn)?;
let match_players = MatchPlayer::belonging_to(&match_base).load::<MatchPlayer>(conn)?; let match_players = MatchPlayer::belonging_to(&match_base)
.inner_join(code_bundles::table)
.left_join(bots::table.on(code_bundles::bot_id.eq(bots::id.nullable())))
.load::<FullMatchPlayerData>(conn)?;
let res = MatchData { let res = FullMatchData {
base: match_base, base: match_base,
match_players, match_players,
}; };

View file

@ -1,5 +1,5 @@
use crate::db; use crate::db;
use crate::db::matches::{MatchPlayerData, MatchState}; use crate::db::matches::{FullMatchData, FullMatchPlayerData, MatchPlayerData, MatchState};
use crate::modules::bots::save_code_bundle; use crate::modules::bots::save_code_bundle;
use crate::util::gen_alphanumeric; use crate::util::gen_alphanumeric;
use crate::{ConnectionPool, BOTS_DIR, MAPS_DIR, MATCHES_DIR}; use crate::{ConnectionPool, BOTS_DIR, MAPS_DIR, MATCHES_DIR};
@ -92,7 +92,6 @@ pub async fn submit_bot(
code_bundle_id: opponent_code_bundle.id, code_bundle_id: opponent_code_bundle.id,
}, },
]; ];
// TODO: set match players
let match_data = db::matches::create_match(&new_match_data, &new_match_players, &conn) let match_data = db::matches::create_match(&new_match_data, &new_match_players, &conn)
.expect("failed to create match"); .expect("failed to create match");
@ -102,7 +101,24 @@ pub async fn submit_bot(
pool.clone(), pool.clone(),
)); ));
let api_match = super::matches::match_data_to_api(match_data); // TODO: avoid clones
let full_match_data = FullMatchData {
base: match_data.base,
match_players: vec![
FullMatchPlayerData {
base: match_data.match_players[0].clone(),
code_bundle: player_code_bundle,
bot: None,
},
FullMatchPlayerData {
base: match_data.match_players[1].clone(),
code_bundle: opponent_code_bundle,
bot: Some(opponent),
},
],
};
let api_match = super::matches::match_data_to_api(full_match_data);
Ok(Json(SubmitBotResponse { Ok(Json(SubmitBotResponse {
match_data: api_match, match_data: api_match,
})) }))

View file

@ -109,9 +109,9 @@ pub struct ApiMatch {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct ApiMatchPlayer { pub struct ApiMatchPlayer {
// TODO! code_bundle_id: i32,
// bot_id: i32, bot_id: Option<i32>,
// code_bundle_id: i32 bot_name: Option<String>,
} }
pub async fn list_matches(conn: DatabaseConnection) -> Result<Json<Vec<ApiMatch>>, StatusCode> { pub async fn list_matches(conn: DatabaseConnection) -> Result<Json<Vec<ApiMatch>>, StatusCode> {
@ -120,7 +120,7 @@ pub async fn list_matches(conn: DatabaseConnection) -> Result<Json<Vec<ApiMatch>
.map(|matches| Json(matches.into_iter().map(match_data_to_api).collect())) .map(|matches| Json(matches.into_iter().map(match_data_to_api).collect()))
} }
pub fn match_data_to_api(data: matches::MatchData) -> ApiMatch { pub fn match_data_to_api(data: matches::FullMatchData) -> ApiMatch {
ApiMatch { ApiMatch {
id: data.base.id, id: data.base.id,
timestamp: data.base.created_at, timestamp: data.base.created_at,
@ -128,7 +128,11 @@ pub fn match_data_to_api(data: matches::MatchData) -> ApiMatch {
players: data players: data
.match_players .match_players
.iter() .iter()
.map(|_p| ApiMatchPlayer {}) .map(|_p| ApiMatchPlayer {
code_bundle_id: _p.code_bundle.id,
bot_id: _p.bot.as_ref().map(|b| b.id),
bot_name: _p.bot.as_ref().map(|b| b.name.clone()),
})
.collect(), .collect(),
} }
} }