blob: e21ca43d7b7c026a7f4c27ef99dad98839d2b186 [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
Philipp Schrader7365d322022-03-06 16:40:08 -08008 _ "github.com/jackc/pgx/stdlib"
Sabina Leaverc5fd2772022-01-29 17:00:23 -08009)
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}
20
21type Stats struct {
Philipp Schraderf117fae2022-04-08 20:14:57 -070022 TeamNumber, MatchNumber, Round int32
23 CompLevel string
24 StartingQuadrant int32
25 AutoBallPickedUp [5]bool
Philipp Schraderfee07e12022-03-17 22:19:47 -070026 // TODO(phil): Re-order auto and teleop fields so auto comes first.
Philipp Schraderfa45d742022-03-18 19:29:05 -070027 ShotsMissed, UpperGoalShots, LowerGoalShots int32
28 ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto int32
29 PlayedDefense, DefenseReceivedScore int32
Philipp Schrader36df73a2022-03-17 23:27:24 -070030 // Climbing level:
31 // 0 -> "NoAttempt"
32 // 1 -> "Failed"
33 // 2 -> "FailedWithPlentyOfTime"
34 // 3 -> "Low"
35 // 4 -> "Medium"
36 // 5 -> "High"
37 // 6 -> "Transversal"
38 Climbing int32
Philipp Schraderfa45d742022-03-18 19:29:05 -070039 // Some non-numerical data that the scout felt worth noting.
40 Comment string
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070041 // The username of the person who collected these statistics.
42 // "unknown" if submitted without logging in.
43 // Empty if the stats have not yet been collected.
44 CollectedBy string
Sabina Leaverc5fd2772022-01-29 17:00:23 -080045}
46
Alex Perry871eab92022-03-12 17:43:52 -080047type NotesData struct {
48 TeamNumber int32
49 Notes []string
50}
51
Yash Chainanibcd1bb32022-04-02 17:10:24 -070052type Ranking struct {
53 TeamNumber int
54 Losses, Wins, Ties int32
55 Rank, Dq int32
56}
57
Philipp Schrader7365d322022-03-06 16:40:08 -080058// Opens a database at the specified port on localhost. We currently don't
59// support connecting to databases on other hosts.
60func NewDatabase(user string, password string, port int) (*Database, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -080061 var err error
Sabina Leaverc5fd2772022-01-29 17:00:23 -080062 database := new(Database)
Philipp Schrader83fc2722022-03-10 21:59:20 -080063
Philipp Schrader7365d322022-03-06 16:40:08 -080064 psqlInfo := fmt.Sprintf("postgres://%s:%s@localhost:%d/postgres", user, password, port)
65 database.DB, err = sql.Open("pgx", psqlInfo)
66 if err != nil {
67 return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
68 }
Philipp Schrader36df73a2022-03-17 23:27:24 -070069
Philipp Schrader83fc2722022-03-10 21:59:20 -080070 statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
Philipp Schrader83fc2722022-03-10 21:59:20 -080071 "MatchNumber INTEGER, " +
72 "Round INTEGER, " +
Philipp Schrader7365d322022-03-06 16:40:08 -080073 "CompLevel VARCHAR, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080074 "R1 INTEGER, " +
75 "R2 INTEGER, " +
76 "R3 INTEGER, " +
77 "B1 INTEGER, " +
78 "B2 INTEGER, " +
Philipp Schrader45befdd2022-04-08 19:12:44 -070079 "B3 INTEGER, " +
80 "PRIMARY KEY (MatchNumber, Round, CompLevel))")
Philipp Schrader83fc2722022-03-10 21:59:20 -080081 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080082 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080083 return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080084 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080085 defer statement.Close()
86
87 _, err = statement.Exec()
88 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080089 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080090 return nil, errors.New(fmt.Sprint("Failed to create matches table: ", err))
91 }
92
93 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
Philipp Schrader83fc2722022-03-10 21:59:20 -080094 "TeamNumber INTEGER, " +
95 "MatchNumber INTEGER, " +
Philipp Schraderf117fae2022-04-08 20:14:57 -070096 "Round INTEGER, " +
97 "CompLevel VARCHAR, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -070098 "StartingQuadrant INTEGER, " +
99 "AutoBall1PickedUp BOOLEAN, " +
100 "AutoBall2PickedUp BOOLEAN, " +
101 "AutoBall3PickedUp BOOLEAN, " +
102 "AutoBall4PickedUp BOOLEAN, " +
103 "AutoBall5PickedUp BOOLEAN, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800104 "ShotsMissed INTEGER, " +
105 "UpperGoalShots INTEGER, " +
106 "LowerGoalShots INTEGER, " +
107 "ShotsMissedAuto INTEGER, " +
108 "UpperGoalAuto INTEGER, " +
109 "LowerGoalAuto INTEGER, " +
110 "PlayedDefense INTEGER, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700111 "DefenseReceivedScore INTEGER, " +
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700112 "Climbing INTEGER, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700113 "Comment VARCHAR, " +
Philipp Schraderf117fae2022-04-08 20:14:57 -0700114 "CollectedBy VARCHAR, " +
115 "PRIMARY KEY (TeamNumber, MatchNumber, Round, CompLevel))")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800116 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800117 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800118 return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
119 }
120 defer statement.Close()
121
122 _, err = statement.Exec()
123 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800124 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800125 return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
126 }
127
Alex Perry871eab92022-03-12 17:43:52 -0800128 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_notes (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800129 "id SERIAL PRIMARY KEY, " +
Alex Perry871eab92022-03-12 17:43:52 -0800130 "TeamNumber INTEGER, " +
131 "Notes TEXT)")
132 if err != nil {
133 return nil, errors.New(fmt.Sprint("Failed to prepare notes table creation: ", err))
134 }
135 defer statement.Close()
136
137 _, err = statement.Exec()
138 if err != nil {
139 return nil, errors.New(fmt.Sprint("Failed to create notes table: ", err))
140 }
141
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700142 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS rankings (" +
143 "id SERIAL PRIMARY KEY, " +
144 "Losses INTEGER, " +
145 "Wins INTEGER, " +
146 "Ties INTEGER, " +
147 "Rank INTEGER, " +
148 "Dq INTEGER, " +
149 "TeamNumber INTEGER)")
150 if err != nil {
151 return nil, errors.New(fmt.Sprint("Failed to prepare rankings table creation: ", err))
152 }
153 defer statement.Close()
154
155 _, err = statement.Exec()
156 if err != nil {
157 return nil, errors.New(fmt.Sprint("Failed to create rankings table: ", err))
158 }
159
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800160 return database, nil
161}
162
163func (database *Database) Delete() error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800164 statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
165 if err != nil {
166 return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800167 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800168 _, err = statement.Exec()
169 if err != nil {
170 return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800171 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800172
173 statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
174 if err != nil {
175 return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
176 }
177 _, err = statement.Exec()
178 if err != nil {
179 return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
180 }
Alex Perry871eab92022-03-12 17:43:52 -0800181
182 statement, err = database.Prepare("DROP TABLE IF EXISTS team_notes")
183 if err != nil {
184 return errors.New(fmt.Sprint("Failed to prepare dropping notes table: ", err))
185 }
186 _, err = statement.Exec()
187 if err != nil {
188 return errors.New(fmt.Sprint("Failed to drop notes table: ", err))
189 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800190 return nil
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700191
192 statement, err = database.Prepare("DROP TABLE IF EXISTS rankings")
193 if err != nil {
194 return errors.New(fmt.Sprint("Failed to prepare dropping rankings table: ", err))
195 }
196 _, err = statement.Exec()
197 if err != nil {
198 return errors.New(fmt.Sprint("Failed to drop rankings table: ", err))
199 }
200 return nil
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800201}
202
203// This function will also populate the Stats table with six empty rows every time a match is added
204func (database *Database) AddToMatch(m Match) error {
Philipp Schradercd12c952022-04-08 18:58:49 -0700205 statement, err := database.Prepare("INSERT INTO matches(" +
206 "MatchNumber, Round, CompLevel, " +
207 "R1, R2, R3, B1, B2, B3) " +
208 "VALUES (" +
209 "$1, $2, $3, " +
Philipp Schraderfe583842022-04-08 19:47:07 -0700210 "$4, $5, $6, $7, $8, $9) " +
211 "ON CONFLICT (MatchNumber, Round, CompLevel) DO UPDATE SET " +
212 "R1 = EXCLUDED.R1, R2 = EXCLUDED.R2, R3 = EXCLUDED.R3, " +
213 "B1 = EXCLUDED.B1, B2 = EXCLUDED.B2, B3 = EXCLUDED.B3")
Philipp Schradercd12c952022-04-08 18:58:49 -0700214 if err != nil {
215 return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
216 }
217 defer statement.Close()
218
219 _, err = statement.Exec(m.MatchNumber, m.Round, m.CompLevel,
220 m.R1, m.R2, m.R3, m.B1, m.B2, m.B3)
221 if err != nil {
222 return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
223 }
224 return nil
225}
226
227func (database *Database) AddToStats(s Stats) error {
228 matches, err := database.QueryMatches(s.TeamNumber)
229 if err != nil {
230 return err
231 }
232 foundMatch := false
233 for _, match := range matches {
234 if match.MatchNumber == s.MatchNumber {
235 foundMatch = true
236 break
237 }
238 }
239 if !foundMatch {
240 return errors.New(fmt.Sprint(
241 "Failed to find team ", s.TeamNumber,
242 " in match ", s.MatchNumber, " in the schedule."))
243 }
244
Philipp Schrader83fc2722022-03-10 21:59:20 -0800245 statement, err := database.Prepare("INSERT INTO team_match_stats(" +
Philipp Schraderf117fae2022-04-08 20:14:57 -0700246 "TeamNumber, MatchNumber, Round, CompLevel, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700247 "StartingQuadrant, " +
248 "AutoBall1PickedUp, AutoBall2PickedUp, AutoBall3PickedUp, " +
249 "AutoBall4PickedUp, AutoBall5PickedUp, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800250 "ShotsMissed, UpperGoalShots, LowerGoalShots, " +
251 "ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700252 "PlayedDefense, DefenseReceivedScore, Climbing, " +
253 "Comment, CollectedBy) " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800254 "VALUES (" +
Philipp Schraderf117fae2022-04-08 20:14:57 -0700255 "$1, $2, $3, $4, " +
256 "$5, " +
257 "$6, $7, $8, " +
258 "$9, $10, " +
259 "$11, $12, $13, " +
260 "$14, $15, $16, " +
261 "$17, $18, $19, " +
262 "$20, $21)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800263 if err != nil {
264 return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800265 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800266 defer statement.Close()
267
Philipp Schradercd12c952022-04-08 18:58:49 -0700268 _, err = statement.Exec(
Philipp Schraderf117fae2022-04-08 20:14:57 -0700269 s.TeamNumber, s.MatchNumber, s.Round, s.CompLevel,
Philipp Schraderfee07e12022-03-17 22:19:47 -0700270 s.StartingQuadrant,
271 s.AutoBallPickedUp[0], s.AutoBallPickedUp[1], s.AutoBallPickedUp[2],
272 s.AutoBallPickedUp[3], s.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800273 s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
274 s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700275 s.PlayedDefense, s.DefenseReceivedScore, s.Climbing,
Philipp Schradercd12c952022-04-08 18:58:49 -0700276 s.Comment, s.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800277 if err != nil {
278 return errors.New(fmt.Sprint("Failed to update stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800279 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800280
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800281 return nil
282}
283
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700284func (database *Database) AddOrUpdateRankings(r Ranking) error {
285 statement, err := database.Prepare("UPDATE rankings SET " +
286 "Losses = $1, Wins = $2, Ties = $3, " +
287 "Rank = $4, Dq = $5, TeamNumber = $6 " +
288 "WHERE TeamNumber = $6")
289 if err != nil {
290 return errors.New(fmt.Sprint("Failed to prepare rankings database update: ", err))
291 }
292 defer statement.Close()
293
294 result, err := statement.Exec(r.Losses, r.Wins, r.Ties,
295 r.Rank, r.Dq, r.TeamNumber)
296 if err != nil {
297 return errors.New(fmt.Sprint("Failed to update rankings database: ", err))
298 }
299
300 numRowsAffected, err := result.RowsAffected()
301 if err != nil {
302 return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
303 }
304 if numRowsAffected == 0 {
305 statement, err := database.Prepare("INSERT INTO rankings(" +
306 "Losses, Wins, Ties, " +
307 "Rank, Dq, TeamNumber) " +
308 "VALUES (" +
309 "$1, $2, $3, " +
310 "$4, $5, $6)")
311 if err != nil {
312 return errors.New(fmt.Sprint("Failed to prepare insertion into rankings database: ", err))
313 }
314 defer statement.Close()
315
316 _, err = statement.Exec(r.Losses, r.Wins, r.Ties,
317 r.Rank, r.Dq, r.TeamNumber)
318 if err != nil {
319 return errors.New(fmt.Sprint("Failed to insert into rankings database: ", err))
320 }
321 }
322
323 return nil
324}
325
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800326func (database *Database) ReturnMatches() ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800327 rows, err := database.Query("SELECT * FROM matches")
328 if err != nil {
329 return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
330 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800331 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800332
333 matches := make([]Match, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800334 for rows.Next() {
335 var match Match
Philipp Schrader45befdd2022-04-08 19:12:44 -0700336 err := rows.Scan(&match.MatchNumber, &match.Round, &match.CompLevel,
Philipp Schradercd12c952022-04-08 18:58:49 -0700337 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800338 if err != nil {
339 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800340 }
341 matches = append(matches, match)
342 }
343 return matches, nil
344}
345
346func (database *Database) ReturnStats() ([]Stats, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800347 rows, err := database.Query("SELECT * FROM team_match_stats")
348 if err != nil {
349 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800350 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800351 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800352
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800353 teams := make([]Stats, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800354 for rows.Next() {
355 var team Stats
Philipp Schraderf117fae2022-04-08 20:14:57 -0700356 err = rows.Scan(
357 &team.TeamNumber, &team.MatchNumber, &team.Round, &team.CompLevel,
Philipp Schraderfee07e12022-03-17 22:19:47 -0700358 &team.StartingQuadrant,
359 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
360 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800361 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
362 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700363 &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
364 &team.Comment, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800365 if err != nil {
366 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800367 }
368 teams = append(teams, team)
369 }
370 return teams, nil
371}
372
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700373func (database *Database) ReturnRankings() ([]Ranking, error) {
374 rows, err := database.Query("SELECT * FROM rankings")
375 if err != nil {
376 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM rankings: ", err))
377 }
378 defer rows.Close()
379
380 all_rankings := make([]Ranking, 0)
381 for rows.Next() {
382 var ranking Ranking
383 var id int
384 err = rows.Scan(&id,
385 &ranking.Losses, &ranking.Wins, &ranking.Ties,
386 &ranking.Rank, &ranking.Dq, &ranking.TeamNumber)
387 if err != nil {
388 return nil, errors.New(fmt.Sprint("Failed to scan from rankings: ", err))
389 }
390 all_rankings = append(all_rankings, ranking)
391 }
392 return all_rankings, nil
393}
394
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800395func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800396 rows, err := database.Query("SELECT * FROM matches WHERE "+
Philipp Schrader7365d322022-03-06 16:40:08 -0800397 "R1 = $1 OR R2 = $2 OR R3 = $3 OR B1 = $4 OR B2 = $5 OR B3 = $6",
Philipp Schrader83fc2722022-03-10 21:59:20 -0800398 teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
399 if err != nil {
400 return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800401 }
402 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800403
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800404 var matches []Match
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800405 for rows.Next() {
406 var match Match
Philipp Schrader45befdd2022-04-08 19:12:44 -0700407 err = rows.Scan(&match.MatchNumber, &match.Round, &match.CompLevel,
Philipp Schradercd12c952022-04-08 18:58:49 -0700408 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800409 if err != nil {
410 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
411 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800412 matches = append(matches, match)
413 }
414 return matches, nil
415}
416
417func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800418 rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = $1", teamNumber_)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800419 if err != nil {
420 return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800421 }
422 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800423
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800424 var teams []Stats
425 for rows.Next() {
426 var team Stats
Philipp Schraderf117fae2022-04-08 20:14:57 -0700427 err = rows.Scan(
428 &team.TeamNumber, &team.MatchNumber, &team.Round, &team.CompLevel,
Philipp Schraderfee07e12022-03-17 22:19:47 -0700429 &team.StartingQuadrant,
430 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
431 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800432 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
433 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700434 &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
435 &team.Comment, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800436 if err != nil {
437 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
438 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800439 teams = append(teams, team)
440 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800441 return teams, nil
442}
Alex Perry871eab92022-03-12 17:43:52 -0800443
444func (database *Database) QueryNotes(TeamNumber int32) (NotesData, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800445 rows, err := database.Query("SELECT * FROM team_notes WHERE TeamNumber = $1", TeamNumber)
Alex Perry871eab92022-03-12 17:43:52 -0800446 if err != nil {
447 return NotesData{}, errors.New(fmt.Sprint("Failed to select from notes: ", err))
448 }
449 defer rows.Close()
450
451 var notes []string
452 for rows.Next() {
453 var id int32
454 var data string
455 err = rows.Scan(&id, &TeamNumber, &data)
456 if err != nil {
457 return NotesData{}, errors.New(fmt.Sprint("Failed to scan from notes: ", err))
458 }
459 notes = append(notes, data)
460 }
461 return NotesData{TeamNumber, notes}, nil
462}
463
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700464func (database *Database) QueryRankings(TeamNumber int) ([]Ranking, error) {
465 rows, err := database.Query("SELECT * FROM rankings WHERE TeamNumber = $1", TeamNumber)
466 if err != nil {
467 return nil, errors.New(fmt.Sprint("Failed to select from rankings: ", err))
468 }
469 defer rows.Close()
470
471 all_rankings := make([]Ranking, 0)
472 for rows.Next() {
473 var ranking Ranking
474 var id int
475 err = rows.Scan(&id,
476 &ranking.Losses, &ranking.Wins, &ranking.Ties,
477 &ranking.Rank, &ranking.Dq, &ranking.TeamNumber)
478 if err != nil {
479 return nil, errors.New(fmt.Sprint("Failed to scan from rankings: ", err))
480 }
481 all_rankings = append(all_rankings, ranking)
482 }
483 return all_rankings, nil
484}
485
Alex Perry871eab92022-03-12 17:43:52 -0800486func (database *Database) AddNotes(data NotesData) error {
487 if len(data.Notes) > 1 {
488 return errors.New("Can only insert one row of notes at a time")
489 }
490 statement, err := database.Prepare("INSERT INTO " +
491 "team_notes(TeamNumber, Notes)" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800492 "VALUES ($1, $2)")
Alex Perry871eab92022-03-12 17:43:52 -0800493 if err != nil {
494 return errors.New(fmt.Sprint("Failed to prepare insertion into notes table: ", err))
495 }
496 defer statement.Close()
497
498 _, err = statement.Exec(data.TeamNumber, data.Notes[0])
499 if err != nil {
500 return errors.New(fmt.Sprint("Failed to insert into Notes database: ", err))
501 }
502 return nil
503}