blob: d666f79c0e3b38ff37493992c67c4e5b988a2f77 [file] [log] [blame]
Sabina Leaverc5fd2772022-01-29 17:00:23 -08001package db
2
3import (
4 "database/sql"
Philipp Schrader30005e42022-03-06 13:53:58 -08005 "errors"
Sabina Leaverc5fd2772022-01-29 17:00:23 -08006 "fmt"
7
8 _ "github.com/mattn/go-sqlite3"
9)
10
11type Database struct {
12 *sql.DB
13}
14
15type Match struct {
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080016 MatchNumber, Round int32
Philipp Schrader1e6c0a92022-02-27 23:30:57 -080017 CompLevel string
Philipp Schradercbf5c6a2022-02-27 23:25:19 -080018 R1, R2, R3, B1, B2, B3 int32
Sabina Leaverc5fd2772022-01-29 17:00:23 -080019 // Each of these variables holds the matchID of the corresponding Stats row
20 r1ID, r2ID, r3ID, b1ID, b2ID, b3ID int
21}
22
23type Stats struct {
Philipp Schrader80ccb662022-03-01 21:47:30 -080024 TeamNumber, MatchNumber int32
25 ShotsMissed, UpperGoalShots, LowerGoalShots int32
26 ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, PlayedDefense int32
27 Climbing int32
Sabina Leaverc5fd2772022-01-29 17:00:23 -080028}
29
Philipp Schrader4953cc32022-02-25 18:09:02 -080030// 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.
32func NewDatabase(path string) (*Database, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -080033 var err error
Sabina Leaverc5fd2772022-01-29 17:00:23 -080034 database := new(Database)
Philipp Schrader83fc2722022-03-10 21:59:20 -080035 database.DB, err = sql.Open("sqlite3", path)
36 if err != nil {
37 return nil, errors.New(fmt.Sprint("Failed to create postgres db: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080038 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080039
40 statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
41 "id INTEGER PRIMARY KEY, " +
42 "MatchNumber INTEGER, " +
43 "Round INTEGER, " +
44 "CompLevel INTEGER, " +
45 "R1 INTEGER, " +
46 "R2 INTEGER, " +
47 "R3 INTEGER, " +
48 "B1 INTEGER, " +
49 "B2 INTEGER, " +
50 "B3 INTEGER, " +
51 "r1ID INTEGER, " +
52 "r2ID INTEGER, " +
53 "r3ID INTEGER, " +
54 "b1ID INTEGER, " +
55 "b2ID INTEGER, " +
56 "b3ID INTEGER)")
57 if err != nil {
58 return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080059 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080060 defer statement.Close()
61
62 _, err = statement.Exec()
63 if err != nil {
64 return nil, errors.New(fmt.Sprint("Failed to create matches table: ", err))
65 }
66
67 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
68 "id INTEGER PRIMARY KEY, " +
69 "TeamNumber INTEGER, " +
70 "MatchNumber INTEGER, " +
71 "ShotsMissed INTEGER, " +
72 "UpperGoalShots INTEGER, " +
73 "LowerGoalShots INTEGER, " +
74 "ShotsMissedAuto INTEGER, " +
75 "UpperGoalAuto INTEGER, " +
76 "LowerGoalAuto INTEGER, " +
77 "PlayedDefense INTEGER, " +
78 "Climbing INTEGER)")
79 if err != nil {
80 return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
81 }
82 defer statement.Close()
83
84 _, err = statement.Exec()
85 if err != nil {
86 return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
87 }
88
Sabina Leaverc5fd2772022-01-29 17:00:23 -080089 return database, nil
90}
91
92func (database *Database) Delete() error {
Philipp Schrader83fc2722022-03-10 21:59:20 -080093 statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
94 if err != nil {
95 return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080096 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080097 _, err = statement.Exec()
98 if err != nil {
99 return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800100 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800101
102 statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
103 if err != nil {
104 return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
105 }
106 _, err = statement.Exec()
107 if err != nil {
108 return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
109 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800110 return nil
111}
112
113// This function will also populate the Stats table with six empty rows every time a match is added
114func (database *Database) AddToMatch(m Match) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800115 statement, err := database.Prepare("INSERT INTO team_match_stats(" +
116 "TeamNumber, MatchNumber, " +
117 "ShotsMissed, UpperGoalShots, LowerGoalShots, " +
118 "ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
119 "PlayedDefense, Climbing) " +
120 "VALUES (" +
121 "?, ?, " +
122 "?, ?, ?, " +
123 "?, ?, ?, " +
124 "?, ?)")
125 if err != nil {
126 return errors.New(fmt.Sprint("Failed to prepare insertion into stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800127 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800128 defer statement.Close()
129
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800130 var rowIds [6]int64
Philipp Schrader80ccb662022-03-01 21:47:30 -0800131 for i, TeamNumber := range []int32{m.R1, m.R2, m.R3, m.B1, m.B2, m.B3} {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800132 result, err := statement.Exec(TeamNumber, m.MatchNumber, 0, 0, 0, 0, 0, 0, 0, 0)
133 if err != nil {
134 return errors.New(fmt.Sprint("Failed to insert stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800135 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800136 rowIds[i], err = result.LastInsertId()
137 if err != nil {
138 return errors.New(fmt.Sprint("Failed to get last insert ID: ", err))
139 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800140 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800141
142 statement, err = database.Prepare("INSERT INTO matches(" +
143 "MatchNumber, Round, CompLevel, " +
144 "R1, R2, R3, B1, B2, B3, " +
145 "r1ID, r2ID, r3ID, b1ID, b2ID, b3ID) " +
146 "VALUES (" +
147 "?, ?, ?, " +
148 "?, ?, ?, ?, ?, ?, " +
149 "?, ?, ?, ?, ?, ?)")
150 if err != nil {
151 return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
152 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800153 defer statement.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800154
155 _, err = statement.Exec(m.MatchNumber, m.Round, m.CompLevel,
156 m.R1, m.R2, m.R3, m.B1, m.B2, m.B3,
157 rowIds[0], rowIds[1], rowIds[2], rowIds[3], rowIds[4], rowIds[5])
158 if err != nil {
159 return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800160 }
161 return nil
162}
163
164func (database *Database) AddToStats(s Stats) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800165 statement, err := database.Prepare("UPDATE team_match_stats SET " +
166 "TeamNumber = ?, MatchNumber = ?, " +
167 "ShotsMissed = ?, UpperGoalShots = ?, LowerGoalShots = ?, " +
168 "ShotsMissedAuto = ?, UpperGoalAuto = ?, LowerGoalAuto = ?, " +
169 "PlayedDefense = ?, Climbing = ? " +
170 "WHERE MatchNumber = ? AND TeamNumber = ?")
171 if err != nil {
172 return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800173 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800174 defer statement.Close()
175
176 result, err := statement.Exec(s.TeamNumber, s.MatchNumber,
177 s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
178 s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
179 s.PlayedDefense, s.Climbing,
180 s.MatchNumber, s.TeamNumber)
181 if err != nil {
182 return errors.New(fmt.Sprint("Failed to update stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800183 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800184
185 numRowsAffected, err := result.RowsAffected()
186 if err != nil {
187 return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800188 }
189 if numRowsAffected == 0 {
190 return errors.New(fmt.Sprint(
191 "Failed to find team ", s.TeamNumber,
192 " in match ", s.MatchNumber, " in the schedule."))
193 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800194 return nil
195}
196
197func (database *Database) ReturnMatches() ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800198 rows, err := database.Query("SELECT * FROM matches")
199 if err != nil {
200 return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
201 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800202 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800203
204 matches := make([]Match, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800205 for rows.Next() {
206 var match Match
207 var id int
Philipp Schrader83fc2722022-03-10 21:59:20 -0800208 err := rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
209 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
210 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
211 if err != nil {
212 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800213 }
214 matches = append(matches, match)
215 }
216 return matches, nil
217}
218
219func (database *Database) ReturnStats() ([]Stats, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800220 rows, err := database.Query("SELECT * FROM team_match_stats")
221 if err != nil {
222 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800223 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800224 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800225
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800226 teams := make([]Stats, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800227 for rows.Next() {
228 var team Stats
Philipp Schrader83fc2722022-03-10 21:59:20 -0800229 var id int
230 err = rows.Scan(&id, &team.TeamNumber, &team.MatchNumber,
231 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
232 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
233 &team.PlayedDefense, &team.Climbing)
234 if err != nil {
235 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800236 }
237 teams = append(teams, team)
238 }
239 return teams, nil
240}
241
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800242func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800243 rows, err := database.Query("SELECT * FROM matches WHERE "+
244 "R1 = ? OR R2 = ? OR R3 = ? OR B1 = ? OR B2 = ? OR B3 = ?",
245 teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
246 if err != nil {
247 return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800248 }
249 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800250
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800251 var matches []Match
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800252 for rows.Next() {
253 var match Match
Philipp Schrader83fc2722022-03-10 21:59:20 -0800254 var id int
255 err = rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
256 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
257 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
258 if err != nil {
259 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
260 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800261 matches = append(matches, match)
262 }
263 return matches, nil
264}
265
266func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800267 rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = ?", teamNumber_)
268 if err != nil {
269 return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800270 }
271 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800272
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800273 var teams []Stats
274 for rows.Next() {
275 var team Stats
276 var id int
Philipp Schrader83fc2722022-03-10 21:59:20 -0800277 err = rows.Scan(&id, &team.TeamNumber, &team.MatchNumber,
278 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
279 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
280 &team.PlayedDefense, &team.Climbing)
281 if err != nil {
282 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
283 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800284 teams = append(teams, team)
285 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800286 return teams, nil
287}