Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 1 | package db |
| 2 | |
| 3 | import ( |
| 4 | "database/sql" |
Philipp Schrader | 30005e4 | 2022-03-06 13:53:58 -0800 | [diff] [blame^] | 5 | "errors" |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 6 | "fmt" |
| 7 | |
| 8 | _ "github.com/mattn/go-sqlite3" |
| 9 | ) |
| 10 | |
| 11 | type Database struct { |
| 12 | *sql.DB |
| 13 | } |
| 14 | |
| 15 | type Match struct { |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 16 | MatchNumber, Round int32 |
Philipp Schrader | 1e6c0a9 | 2022-02-27 23:30:57 -0800 | [diff] [blame] | 17 | CompLevel string |
Philipp Schrader | cbf5c6a | 2022-02-27 23:25:19 -0800 | [diff] [blame] | 18 | R1, R2, R3, B1, B2, B3 int32 |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 19 | // Each of these variables holds the matchID of the corresponding Stats row |
| 20 | r1ID, r2ID, r3ID, b1ID, b2ID, b3ID int |
| 21 | } |
| 22 | |
| 23 | type Stats struct { |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 24 | TeamNumber, MatchNumber int32 |
| 25 | ShotsMissed, UpperGoalShots, LowerGoalShots int32 |
| 26 | ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, PlayedDefense int32 |
| 27 | Climbing int32 |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 28 | } |
| 29 | |
Philipp Schrader | 4953cc3 | 2022-02-25 18:09:02 -0800 | [diff] [blame] | 30 | // Opens a database at the specified path. If the path refers to a non-existent |
| 31 | // file, the database will be created and initialized with empty tables. |
| 32 | func NewDatabase(path string) (*Database, error) { |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 33 | database := new(Database) |
Philipp Schrader | 4953cc3 | 2022-02-25 18:09:02 -0800 | [diff] [blame] | 34 | database.DB, _ = sql.Open("sqlite3", path) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 35 | statement, error_ := database.Prepare("CREATE TABLE IF NOT EXISTS matches " + |
Philipp Schrader | 1e6c0a9 | 2022-02-27 23:30:57 -0800 | [diff] [blame] | 36 | "(id INTEGER PRIMARY KEY, MatchNumber INTEGER, Round INTEGER, CompLevel INTEGER, R1 INTEGER, R2 INTEGER, R3 INTEGER, B1 INTEGER, B2 INTEGER, B3 INTEGER, r1ID INTEGER, r2ID INTEGER, r3ID INTEGER, b1ID INTEGER, b2ID INTEGER, b3ID INTEGER)") |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 37 | defer statement.Close() |
| 38 | if error_ != nil { |
| 39 | fmt.Println(error_) |
| 40 | return nil, error_ |
| 41 | } |
| 42 | _, error_ = statement.Exec() |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 43 | statement, error_ = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (id INTEGER PRIMARY KEY, TeamNumber INTEGER, MatchNumber DOUBLE, ShotsMissed INTEGER, UpperGoalShots INTEGER, LowerGoalShots INTEGER, ShotsMissedAuto INTEGER, UpperGoalAuto INTEGER, LowerGoalAuto INTEGER, PlayedDefense INTEGER, Climbing INTEGER)") |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 44 | defer statement.Close() |
| 45 | if error_ != nil { |
| 46 | fmt.Println(error_) |
| 47 | return nil, error_ |
| 48 | } |
| 49 | _, error_ = statement.Exec() |
| 50 | return database, nil |
| 51 | } |
| 52 | |
| 53 | func (database *Database) Delete() error { |
| 54 | statement, error_ := database.Prepare("DROP TABLE IF EXISTS matches") |
| 55 | if error_ != nil { |
| 56 | fmt.Println(error_) |
| 57 | return (error_) |
| 58 | } |
| 59 | _, error_ = statement.Exec() |
| 60 | statement, error_ = database.Prepare("DROP TABLE IF EXISTS team_match_stats") |
| 61 | if error_ != nil { |
| 62 | fmt.Println(error_) |
| 63 | return (error_) |
| 64 | } |
| 65 | _, error_ = statement.Exec() |
| 66 | return nil |
| 67 | } |
| 68 | |
| 69 | // This function will also populate the Stats table with six empty rows every time a match is added |
| 70 | func (database *Database) AddToMatch(m Match) error { |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 71 | statement, error_ := database.Prepare("INSERT INTO team_match_stats(TeamNumber, MatchNumber, ShotsMissed, UpperGoalShots, LowerGoalShots, ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, PlayedDefense, Climbing) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 72 | defer statement.Close() |
| 73 | if error_ != nil { |
| 74 | fmt.Println("failed to prepare stats database:", error_) |
| 75 | return (error_) |
| 76 | } |
| 77 | var rowIds [6]int64 |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 78 | for i, TeamNumber := range []int32{m.R1, m.R2, m.R3, m.B1, m.B2, m.B3} { |
| 79 | result, error_ := statement.Exec(TeamNumber, m.MatchNumber, 0, 0, 0, 0, 0, 0, 0, 0) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 80 | if error_ != nil { |
| 81 | fmt.Println("failed to execute statement 2:", error_) |
| 82 | return (error_) |
| 83 | } |
| 84 | rowIds[i], error_ = result.LastInsertId() |
| 85 | } |
Philipp Schrader | 1e6c0a9 | 2022-02-27 23:30:57 -0800 | [diff] [blame] | 86 | statement, error_ = database.Prepare("INSERT INTO matches(MatchNumber, Round, CompLevel, R1, R2, R3, B1, B2, B3, r1ID, r2ID, r3ID, b1ID, b2ID, b3ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 87 | defer statement.Close() |
| 88 | if error_ != nil { |
| 89 | fmt.Println("failed to prepare match database:", error_) |
| 90 | return (error_) |
| 91 | } |
Philipp Schrader | 1e6c0a9 | 2022-02-27 23:30:57 -0800 | [diff] [blame] | 92 | _, error_ = statement.Exec(m.MatchNumber, m.Round, m.CompLevel, m.R1, m.R2, m.R3, m.B1, m.B2, m.B3, rowIds[0], rowIds[1], rowIds[2], rowIds[3], rowIds[4], rowIds[5]) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 93 | if error_ != nil { |
| 94 | fmt.Println(error_) |
| 95 | return (error_) |
| 96 | } |
| 97 | return nil |
| 98 | } |
| 99 | |
| 100 | func (database *Database) AddToStats(s Stats) error { |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 101 | statement, error_ := database.Prepare("UPDATE team_match_stats SET TeamNumber = ?, MatchNumber = ?, ShotsMissed = ?, UpperGoalShots = ?, LowerGoalShots = ?, ShotsMissedAuto = ?, UpperGoalAuto = ?, LowerGoalAuto = ?, PlayedDefense = ?, Climbing = ? WHERE MatchNumber = ? AND TeamNumber = ?") |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 102 | if error_ != nil { |
| 103 | fmt.Println(error_) |
| 104 | return (error_) |
| 105 | } |
Philipp Schrader | 30005e4 | 2022-03-06 13:53:58 -0800 | [diff] [blame^] | 106 | result, error_ := statement.Exec(s.TeamNumber, s.MatchNumber, s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots, s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto, s.PlayedDefense, s.Climbing, s.MatchNumber, s.TeamNumber) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 107 | if error_ != nil { |
| 108 | fmt.Println(error_) |
| 109 | return (error_) |
| 110 | } |
Philipp Schrader | 30005e4 | 2022-03-06 13:53:58 -0800 | [diff] [blame^] | 111 | numRowsAffected, error_ := result.RowsAffected() |
| 112 | if error_ != nil { |
| 113 | return errors.New(fmt.Sprint("Failed to query rows affected: ", error_)) |
| 114 | } |
| 115 | if numRowsAffected == 0 { |
| 116 | return errors.New(fmt.Sprint( |
| 117 | "Failed to find team ", s.TeamNumber, |
| 118 | " in match ", s.MatchNumber, " in the schedule.")) |
| 119 | } |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 120 | return nil |
| 121 | } |
| 122 | |
| 123 | func (database *Database) ReturnMatches() ([]Match, error) { |
| 124 | matches := make([]Match, 0) |
| 125 | rows, _ := database.Query("SELECT * FROM matches") |
| 126 | defer rows.Close() |
| 127 | for rows.Next() { |
| 128 | var match Match |
| 129 | var id int |
Philipp Schrader | 1e6c0a9 | 2022-02-27 23:30:57 -0800 | [diff] [blame] | 130 | error_ := rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel, &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3, &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 131 | if error_ != nil { |
| 132 | fmt.Println(nil, error_) |
| 133 | return nil, error_ |
| 134 | } |
| 135 | matches = append(matches, match) |
| 136 | } |
| 137 | return matches, nil |
| 138 | } |
| 139 | |
| 140 | func (database *Database) ReturnStats() ([]Stats, error) { |
Philipp Schrader | 30005e4 | 2022-03-06 13:53:58 -0800 | [diff] [blame^] | 141 | rows, error_ := database.Query("SELECT * FROM team_match_stats") |
| 142 | if error_ != nil { |
| 143 | return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", error_)) |
| 144 | } |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 145 | defer rows.Close() |
| 146 | teams := make([]Stats, 0) |
| 147 | var id int |
| 148 | for rows.Next() { |
| 149 | var team Stats |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 150 | error_ := rows.Scan(&id, &team.TeamNumber, &team.MatchNumber, &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots, &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto, &team.PlayedDefense, &team.Climbing) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 151 | if error_ != nil { |
| 152 | fmt.Println(error_) |
| 153 | return nil, error_ |
| 154 | } |
| 155 | teams = append(teams, team) |
| 156 | } |
| 157 | return teams, nil |
| 158 | } |
| 159 | |
Philipp Schrader | d1c4bef | 2022-02-28 22:51:30 -0800 | [diff] [blame] | 160 | func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) { |
Philipp Schrader | 1e6c0a9 | 2022-02-27 23:30:57 -0800 | [diff] [blame] | 161 | rows, error_ := database.Query("SELECT * FROM matches WHERE R1 = ? OR R2 = ? OR R3 = ? OR B1 = ? OR B2 = ? OR B3 = ?", teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 162 | if error_ != nil { |
| 163 | fmt.Println("failed to execute statement 1:", error_) |
| 164 | return nil, error_ |
| 165 | } |
| 166 | defer rows.Close() |
| 167 | var matches []Match |
| 168 | var id int |
| 169 | for rows.Next() { |
| 170 | var match Match |
Philipp Schrader | 1e6c0a9 | 2022-02-27 23:30:57 -0800 | [diff] [blame] | 171 | rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel, &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3, &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 172 | matches = append(matches, match) |
| 173 | } |
| 174 | return matches, nil |
| 175 | } |
| 176 | |
| 177 | func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) { |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 178 | rows, error_ := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = ?", teamNumber_) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 179 | if error_ != nil { |
| 180 | fmt.Println("failed to execute statement 3:", error_) |
| 181 | return nil, error_ |
| 182 | } |
| 183 | defer rows.Close() |
| 184 | var teams []Stats |
| 185 | for rows.Next() { |
| 186 | var team Stats |
| 187 | var id int |
Philipp Schrader | 80ccb66 | 2022-03-01 21:47:30 -0800 | [diff] [blame] | 188 | error_ = rows.Scan(&id, &team.TeamNumber, &team.MatchNumber, &team.ShotsMissed, |
| 189 | &team.UpperGoalShots, &team.LowerGoalShots, &team.ShotsMissedAuto, &team.UpperGoalAuto, |
| 190 | &team.LowerGoalAuto, &team.PlayedDefense, &team.Climbing) |
Sabina Leaver | c5fd277 | 2022-01-29 17:00:23 -0800 | [diff] [blame] | 191 | teams = append(teams, team) |
| 192 | } |
| 193 | if error_ != nil { |
| 194 | fmt.Println("failed to execute statement 3:", error_) |
| 195 | return nil, error_ |
| 196 | } |
| 197 | return teams, nil |
| 198 | } |