aboutsummaryrefslogtreecommitdiff
path: root/planetwars-server/src/db/matches.rs
blob: 6444bf6a67b06315fd1441b036cb347fae9410ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
pub use crate::db_types::MatchState;
use chrono::NaiveDateTime;
use diesel::{BelongingToDsl, ExpressionMethods, QueryDsl, RunQueryDsl};
use diesel::{Connection, GroupedBy, PgConnection, QueryResult};

use crate::schema::{match_players, matches};

#[derive(Insertable)]
#[table_name = "matches"]
pub struct NewMatch<'a> {
    pub state: MatchState,
    pub log_path: &'a str,
}

#[derive(Insertable)]
#[table_name = "match_players"]
pub struct NewMatchPlayer {
    /// id of the match this player is in
    pub match_id: i32,
    /// id of the bot behind this player
    pub bot_id: i32,
    /// player id within the match
    pub player_id: i32,
}

#[derive(Queryable, Identifiable)]
#[table_name = "matches"]
pub struct MatchBase {
    pub id: i32,
    pub state: MatchState,
    pub log_path: String,
    pub created_at: NaiveDateTime,
}

#[derive(Queryable, Identifiable, Associations)]
#[primary_key(match_id, player_id)]
#[belongs_to(MatchBase, foreign_key = "match_id")]
pub struct MatchPlayer {
    pub match_id: i32,
    pub bot_id: i32,
    pub player_id: i32,
}

pub struct MatchPlayerData {
    pub bot_id: i32,
}

pub fn create_match(
    new_match_base: &NewMatch,
    new_match_players: &[MatchPlayerData],
    conn: &PgConnection,
) -> QueryResult<MatchData> {
    conn.transaction(|| {
        let match_base = diesel::insert_into(matches::table)
            .values(new_match_base)
            .get_result::<MatchBase>(conn)?;

        let new_match_players = new_match_players
            .iter()
            .enumerate()
            .map(|(num, player_data)| NewMatchPlayer {
                match_id: match_base.id,
                bot_id: player_data.bot_id,
                player_id: num as i32,
            })
            .collect::<Vec<_>>();

        let match_players = diesel::insert_into(match_players::table)
            .values(&new_match_players)
            .get_results::<MatchPlayer>(conn)?;

        Ok(MatchData {
            base: match_base,
            match_players,
        })
    })
}

pub struct MatchData {
    pub base: MatchBase,
    pub match_players: Vec<MatchPlayer>,
}

pub fn list_matches(conn: &PgConnection) -> QueryResult<Vec<MatchData>> {
    conn.transaction(|| {
        let matches = matches::table.get_results::<MatchBase>(conn)?;

        let match_players = MatchPlayer::belonging_to(&matches)
            .load::<MatchPlayer>(conn)?
            .grouped_by(&matches);

        let res = matches
            .into_iter()
            .zip(match_players.into_iter())
            .map(|(base, players)| MatchData {
                base,
                match_players: players.into_iter().collect(),
            })
            .collect();

        Ok(res)
    })
}

pub fn find_match(id: i32, conn: &PgConnection) -> QueryResult<MatchData> {
    conn.transaction(|| {
        let match_base = matches::table.find(id).get_result::<MatchBase>(conn)?;

        let match_players = MatchPlayer::belonging_to(&match_base).load::<MatchPlayer>(conn)?;

        let res = MatchData {
            base: match_base,
            match_players,
        };

        Ok(res)
    })
}

pub fn find_mach_base(id: i32, conn: &PgConnection) -> QueryResult<MatchBase> {
    matches::table.find(id).get_result::<MatchBase>(conn)
}

pub fn set_match_state(id: i32, match_state: MatchState, conn: &PgConnection) -> QueryResult<()> {
    diesel::update(matches::table.find(id))
        .set(matches::state.eq(match_state))
        .execute(conn)?;
    Ok(())
}