blob: 1f182b18a178c740bbedbbb28d94a39b86c6a9f3 [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
Milo Lina72e2002022-04-06 20:31:13 -070021type Shift struct {
22 MatchNumber int32
23 R1scouter, R2scouter, R3scouter, B1scouter, B2scouter, B3scouter string
24}
25
Sabina Leaverc5fd2772022-01-29 17:00:23 -080026type Stats struct {
Philipp Schraderf117fae2022-04-08 20:14:57 -070027 TeamNumber, MatchNumber, Round int32
28 CompLevel string
29 StartingQuadrant int32
30 AutoBallPickedUp [5]bool
Philipp Schraderfee07e12022-03-17 22:19:47 -070031 // TODO(phil): Re-order auto and teleop fields so auto comes first.
Philipp Schraderfa45d742022-03-18 19:29:05 -070032 ShotsMissed, UpperGoalShots, LowerGoalShots int32
33 ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto int32
34 PlayedDefense, DefenseReceivedScore int32
Philipp Schrader36df73a2022-03-17 23:27:24 -070035 // Climbing level:
36 // 0 -> "NoAttempt"
37 // 1 -> "Failed"
38 // 2 -> "FailedWithPlentyOfTime"
39 // 3 -> "Low"
40 // 4 -> "Medium"
41 // 5 -> "High"
42 // 6 -> "Transversal"
43 Climbing int32
Philipp Schraderfa45d742022-03-18 19:29:05 -070044 // Some non-numerical data that the scout felt worth noting.
45 Comment string
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070046 // The username of the person who collected these statistics.
47 // "unknown" if submitted without logging in.
48 // Empty if the stats have not yet been collected.
49 CollectedBy string
Sabina Leaverc5fd2772022-01-29 17:00:23 -080050}
51
Alex Perry871eab92022-03-12 17:43:52 -080052type NotesData struct {
53 TeamNumber int32
54 Notes []string
55}
56
Yash Chainanibcd1bb32022-04-02 17:10:24 -070057type Ranking struct {
58 TeamNumber int
59 Losses, Wins, Ties int32
60 Rank, Dq int32
61}
62
Philipp Schrader7365d322022-03-06 16:40:08 -080063// Opens a database at the specified port on localhost. We currently don't
64// support connecting to databases on other hosts.
65func NewDatabase(user string, password string, port int) (*Database, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -080066 var err error
Sabina Leaverc5fd2772022-01-29 17:00:23 -080067 database := new(Database)
Philipp Schrader83fc2722022-03-10 21:59:20 -080068
Philipp Schrader7365d322022-03-06 16:40:08 -080069 psqlInfo := fmt.Sprintf("postgres://%s:%s@localhost:%d/postgres", user, password, port)
70 database.DB, err = sql.Open("pgx", psqlInfo)
71 if err != nil {
72 return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
73 }
Philipp Schrader36df73a2022-03-17 23:27:24 -070074
Philipp Schrader83fc2722022-03-10 21:59:20 -080075 statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
Philipp Schrader83fc2722022-03-10 21:59:20 -080076 "MatchNumber INTEGER, " +
77 "Round INTEGER, " +
Philipp Schrader7365d322022-03-06 16:40:08 -080078 "CompLevel VARCHAR, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080079 "R1 INTEGER, " +
80 "R2 INTEGER, " +
81 "R3 INTEGER, " +
82 "B1 INTEGER, " +
83 "B2 INTEGER, " +
Philipp Schrader45befdd2022-04-08 19:12:44 -070084 "B3 INTEGER, " +
85 "PRIMARY KEY (MatchNumber, Round, CompLevel))")
Philipp Schrader83fc2722022-03-10 21:59:20 -080086 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080087 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080088 return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080089 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080090 defer statement.Close()
91
92 _, err = statement.Exec()
93 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080094 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080095 return nil, errors.New(fmt.Sprint("Failed to create matches table: ", err))
96 }
97
Milo Lina72e2002022-04-06 20:31:13 -070098 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS shift_schedule (" +
99 "id SERIAL PRIMARY KEY, " +
100 "MatchNumber INTEGER, " +
101 "R1Scouter VARCHAR, " +
102 "R2Scouter VARCHAR, " +
103 "R3Scouter VARCHAR, " +
104 "B1Scouter VARCHAR, " +
105 "B2Scouter VARCHAR, " +
106 "B3scouter VARCHAR)")
107 if err != nil {
108 database.Close()
109 return nil, errors.New(fmt.Sprint("Failed to prepare shift schedule table creation: ", err))
110 }
111 defer statement.Close()
112
113 _, err = statement.Exec()
114 if err != nil {
115 database.Close()
116 return nil, errors.New(fmt.Sprint("Failed to create shift schedule table: ", err))
117 }
118
Philipp Schrader83fc2722022-03-10 21:59:20 -0800119 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800120 "TeamNumber INTEGER, " +
121 "MatchNumber INTEGER, " +
Philipp Schraderf117fae2022-04-08 20:14:57 -0700122 "Round INTEGER, " +
123 "CompLevel VARCHAR, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700124 "StartingQuadrant INTEGER, " +
125 "AutoBall1PickedUp BOOLEAN, " +
126 "AutoBall2PickedUp BOOLEAN, " +
127 "AutoBall3PickedUp BOOLEAN, " +
128 "AutoBall4PickedUp BOOLEAN, " +
129 "AutoBall5PickedUp BOOLEAN, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800130 "ShotsMissed INTEGER, " +
131 "UpperGoalShots INTEGER, " +
132 "LowerGoalShots INTEGER, " +
133 "ShotsMissedAuto INTEGER, " +
134 "UpperGoalAuto INTEGER, " +
135 "LowerGoalAuto INTEGER, " +
136 "PlayedDefense INTEGER, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700137 "DefenseReceivedScore INTEGER, " +
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700138 "Climbing INTEGER, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700139 "Comment VARCHAR, " +
Philipp Schraderf117fae2022-04-08 20:14:57 -0700140 "CollectedBy VARCHAR, " +
141 "PRIMARY KEY (TeamNumber, MatchNumber, Round, CompLevel))")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800142 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800143 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800144 return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
145 }
146 defer statement.Close()
147
148 _, err = statement.Exec()
149 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800150 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800151 return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
152 }
153
Alex Perry871eab92022-03-12 17:43:52 -0800154 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_notes (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800155 "id SERIAL PRIMARY KEY, " +
Alex Perry871eab92022-03-12 17:43:52 -0800156 "TeamNumber INTEGER, " +
157 "Notes TEXT)")
158 if err != nil {
159 return nil, errors.New(fmt.Sprint("Failed to prepare notes table creation: ", err))
160 }
161 defer statement.Close()
162
163 _, err = statement.Exec()
164 if err != nil {
165 return nil, errors.New(fmt.Sprint("Failed to create notes table: ", err))
166 }
167
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700168 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS rankings (" +
169 "id SERIAL PRIMARY KEY, " +
170 "Losses INTEGER, " +
171 "Wins INTEGER, " +
172 "Ties INTEGER, " +
173 "Rank INTEGER, " +
174 "Dq INTEGER, " +
175 "TeamNumber INTEGER)")
176 if err != nil {
177 return nil, errors.New(fmt.Sprint("Failed to prepare rankings table creation: ", err))
178 }
179 defer statement.Close()
180
181 _, err = statement.Exec()
182 if err != nil {
183 return nil, errors.New(fmt.Sprint("Failed to create rankings table: ", err))
184 }
185
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800186 return database, nil
187}
188
189func (database *Database) Delete() error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800190 statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
191 if err != nil {
192 return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800193 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800194 _, err = statement.Exec()
195 if err != nil {
196 return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800197 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800198
Milo Lina72e2002022-04-06 20:31:13 -0700199 statement, err = database.Prepare("DROP TABLE IF EXISTS shift_schedule")
200 if err != nil {
201 return errors.New(fmt.Sprint("Failed to prepare dropping shifts table: ", err))
202 }
203 _, err = statement.Exec()
204 if err != nil {
205 return errors.New(fmt.Sprint("Failed to drop shifts table: ", err))
206 }
207
Philipp Schrader83fc2722022-03-10 21:59:20 -0800208 statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
209 if err != nil {
210 return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
211 }
212 _, err = statement.Exec()
213 if err != nil {
214 return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
215 }
Alex Perry871eab92022-03-12 17:43:52 -0800216
217 statement, err = database.Prepare("DROP TABLE IF EXISTS team_notes")
218 if err != nil {
219 return errors.New(fmt.Sprint("Failed to prepare dropping notes table: ", err))
220 }
221 _, err = statement.Exec()
222 if err != nil {
223 return errors.New(fmt.Sprint("Failed to drop notes table: ", err))
224 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800225 return nil
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700226
227 statement, err = database.Prepare("DROP TABLE IF EXISTS rankings")
228 if err != nil {
229 return errors.New(fmt.Sprint("Failed to prepare dropping rankings table: ", err))
230 }
231 _, err = statement.Exec()
232 if err != nil {
233 return errors.New(fmt.Sprint("Failed to drop rankings table: ", err))
234 }
235 return nil
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800236}
237
238// This function will also populate the Stats table with six empty rows every time a match is added
239func (database *Database) AddToMatch(m Match) error {
Philipp Schradercd12c952022-04-08 18:58:49 -0700240 statement, err := database.Prepare("INSERT INTO matches(" +
241 "MatchNumber, Round, CompLevel, " +
242 "R1, R2, R3, B1, B2, B3) " +
243 "VALUES (" +
244 "$1, $2, $3, " +
Philipp Schraderfe583842022-04-08 19:47:07 -0700245 "$4, $5, $6, $7, $8, $9) " +
246 "ON CONFLICT (MatchNumber, Round, CompLevel) DO UPDATE SET " +
247 "R1 = EXCLUDED.R1, R2 = EXCLUDED.R2, R3 = EXCLUDED.R3, " +
248 "B1 = EXCLUDED.B1, B2 = EXCLUDED.B2, B3 = EXCLUDED.B3")
Philipp Schradercd12c952022-04-08 18:58:49 -0700249 if err != nil {
250 return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
251 }
252 defer statement.Close()
253
254 _, err = statement.Exec(m.MatchNumber, m.Round, m.CompLevel,
255 m.R1, m.R2, m.R3, m.B1, m.B2, m.B3)
256 if err != nil {
257 return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
258 }
259 return nil
260}
261
Milo Lina72e2002022-04-06 20:31:13 -0700262func (database *Database) AddToShift(sh Shift) error {
263 statement, err := database.Prepare("INSERT INTO shift_schedule(" +
264 "MatchNumber, " +
265 "R1scouter, R2scouter, R3scouter, B1scouter, B2scouter, B3scouter) " +
266 "VALUES (" +
267 "$1, " +
268 "$2, $3, $4, $5, $6, $7)")
269 if err != nil {
270 return errors.New(fmt.Sprint("Failed to prepare insertion into shift database: ", err))
271 }
272 defer statement.Close()
273
274 _, err = statement.Exec(sh.MatchNumber,
275 sh.R1scouter, sh.R2scouter, sh.R3scouter, sh.B1scouter, sh.B2scouter, sh.B3scouter)
276 if err != nil {
277 return errors.New(fmt.Sprint("Failed to insert into shift database: ", err))
278 }
279 return nil
280}
281
Philipp Schradercd12c952022-04-08 18:58:49 -0700282func (database *Database) AddToStats(s Stats) error {
283 matches, err := database.QueryMatches(s.TeamNumber)
284 if err != nil {
285 return err
286 }
287 foundMatch := false
288 for _, match := range matches {
289 if match.MatchNumber == s.MatchNumber {
290 foundMatch = true
291 break
292 }
293 }
294 if !foundMatch {
295 return errors.New(fmt.Sprint(
296 "Failed to find team ", s.TeamNumber,
297 " in match ", s.MatchNumber, " in the schedule."))
298 }
299
Philipp Schrader83fc2722022-03-10 21:59:20 -0800300 statement, err := database.Prepare("INSERT INTO team_match_stats(" +
Philipp Schraderf117fae2022-04-08 20:14:57 -0700301 "TeamNumber, MatchNumber, Round, CompLevel, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700302 "StartingQuadrant, " +
303 "AutoBall1PickedUp, AutoBall2PickedUp, AutoBall3PickedUp, " +
304 "AutoBall4PickedUp, AutoBall5PickedUp, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800305 "ShotsMissed, UpperGoalShots, LowerGoalShots, " +
306 "ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700307 "PlayedDefense, DefenseReceivedScore, Climbing, " +
308 "Comment, CollectedBy) " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800309 "VALUES (" +
Philipp Schraderf117fae2022-04-08 20:14:57 -0700310 "$1, $2, $3, $4, " +
311 "$5, " +
312 "$6, $7, $8, " +
313 "$9, $10, " +
314 "$11, $12, $13, " +
315 "$14, $15, $16, " +
316 "$17, $18, $19, " +
317 "$20, $21)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800318 if err != nil {
319 return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800320 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800321 defer statement.Close()
322
Philipp Schradercd12c952022-04-08 18:58:49 -0700323 _, err = statement.Exec(
Philipp Schraderf117fae2022-04-08 20:14:57 -0700324 s.TeamNumber, s.MatchNumber, s.Round, s.CompLevel,
Philipp Schraderfee07e12022-03-17 22:19:47 -0700325 s.StartingQuadrant,
326 s.AutoBallPickedUp[0], s.AutoBallPickedUp[1], s.AutoBallPickedUp[2],
327 s.AutoBallPickedUp[3], s.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800328 s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
329 s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700330 s.PlayedDefense, s.DefenseReceivedScore, s.Climbing,
Philipp Schradercd12c952022-04-08 18:58:49 -0700331 s.Comment, s.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800332 if err != nil {
333 return errors.New(fmt.Sprint("Failed to update stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800334 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800335
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800336 return nil
337}
338
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700339func (database *Database) AddOrUpdateRankings(r Ranking) error {
340 statement, err := database.Prepare("UPDATE rankings SET " +
341 "Losses = $1, Wins = $2, Ties = $3, " +
342 "Rank = $4, Dq = $5, TeamNumber = $6 " +
343 "WHERE TeamNumber = $6")
344 if err != nil {
345 return errors.New(fmt.Sprint("Failed to prepare rankings database update: ", err))
346 }
347 defer statement.Close()
348
349 result, err := statement.Exec(r.Losses, r.Wins, r.Ties,
350 r.Rank, r.Dq, r.TeamNumber)
351 if err != nil {
352 return errors.New(fmt.Sprint("Failed to update rankings database: ", err))
353 }
354
355 numRowsAffected, err := result.RowsAffected()
356 if err != nil {
357 return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
358 }
359 if numRowsAffected == 0 {
360 statement, err := database.Prepare("INSERT INTO rankings(" +
361 "Losses, Wins, Ties, " +
362 "Rank, Dq, TeamNumber) " +
363 "VALUES (" +
364 "$1, $2, $3, " +
365 "$4, $5, $6)")
366 if err != nil {
367 return errors.New(fmt.Sprint("Failed to prepare insertion into rankings database: ", err))
368 }
369 defer statement.Close()
370
371 _, err = statement.Exec(r.Losses, r.Wins, r.Ties,
372 r.Rank, r.Dq, r.TeamNumber)
373 if err != nil {
374 return errors.New(fmt.Sprint("Failed to insert into rankings database: ", err))
375 }
376 }
377
378 return nil
379}
380
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800381func (database *Database) ReturnMatches() ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800382 rows, err := database.Query("SELECT * FROM matches")
383 if err != nil {
384 return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
385 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800386 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800387
388 matches := make([]Match, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800389 for rows.Next() {
390 var match Match
Philipp Schrader45befdd2022-04-08 19:12:44 -0700391 err := rows.Scan(&match.MatchNumber, &match.Round, &match.CompLevel,
Philipp Schradercd12c952022-04-08 18:58:49 -0700392 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800393 if err != nil {
394 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800395 }
396 matches = append(matches, match)
397 }
398 return matches, nil
399}
400
Milo Lina72e2002022-04-06 20:31:13 -0700401func (database *Database) ReturnAllShifts() ([]Shift, error) {
402 rows, err := database.Query("SELECT * FROM shift_schedule")
403 if err != nil {
404 return nil, errors.New(fmt.Sprint("Failed to select from shift: ", err))
405 }
406 defer rows.Close()
407
408 shifts := make([]Shift, 0)
409 for rows.Next() {
410 var shift Shift
411 var id int
412 err := rows.Scan(&id, &shift.MatchNumber,
413 &shift.R1scouter, &shift.R2scouter, &shift.R3scouter, &shift.B1scouter, &shift.B2scouter, &shift.B3scouter)
414 if err != nil {
415 return nil, errors.New(fmt.Sprint("Failed to scan from shift: ", err))
416 }
417 shifts = append(shifts, shift)
418 }
419 return shifts, nil
420}
421
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800422func (database *Database) ReturnStats() ([]Stats, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800423 rows, err := database.Query("SELECT * FROM team_match_stats")
424 if err != nil {
425 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800426 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800427 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800428
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800429 teams := make([]Stats, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800430 for rows.Next() {
431 var team Stats
Philipp Schraderf117fae2022-04-08 20:14:57 -0700432 err = rows.Scan(
433 &team.TeamNumber, &team.MatchNumber, &team.Round, &team.CompLevel,
Philipp Schraderfee07e12022-03-17 22:19:47 -0700434 &team.StartingQuadrant,
435 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
436 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800437 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
438 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700439 &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
440 &team.Comment, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800441 if err != nil {
442 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800443 }
444 teams = append(teams, team)
445 }
446 return teams, nil
447}
448
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700449func (database *Database) ReturnRankings() ([]Ranking, error) {
450 rows, err := database.Query("SELECT * FROM rankings")
451 if err != nil {
452 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM rankings: ", err))
453 }
454 defer rows.Close()
455
456 all_rankings := make([]Ranking, 0)
457 for rows.Next() {
458 var ranking Ranking
459 var id int
460 err = rows.Scan(&id,
461 &ranking.Losses, &ranking.Wins, &ranking.Ties,
462 &ranking.Rank, &ranking.Dq, &ranking.TeamNumber)
463 if err != nil {
464 return nil, errors.New(fmt.Sprint("Failed to scan from rankings: ", err))
465 }
466 all_rankings = append(all_rankings, ranking)
467 }
468 return all_rankings, nil
469}
470
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800471func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800472 rows, err := database.Query("SELECT * FROM matches WHERE "+
Philipp Schrader7365d322022-03-06 16:40:08 -0800473 "R1 = $1 OR R2 = $2 OR R3 = $3 OR B1 = $4 OR B2 = $5 OR B3 = $6",
Philipp Schrader83fc2722022-03-10 21:59:20 -0800474 teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
475 if err != nil {
476 return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800477 }
478 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800479
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800480 var matches []Match
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800481 for rows.Next() {
482 var match Match
Philipp Schrader45befdd2022-04-08 19:12:44 -0700483 err = rows.Scan(&match.MatchNumber, &match.Round, &match.CompLevel,
Philipp Schradercd12c952022-04-08 18:58:49 -0700484 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800485 if err != nil {
486 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
487 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800488 matches = append(matches, match)
489 }
490 return matches, nil
491}
492
Milo Lina72e2002022-04-06 20:31:13 -0700493func (database *Database) QueryAllShifts(matchNumber_ int) ([]Shift, error) {
494 rows, err := database.Query("SELECT * FROM shift_schedule WHERE MatchNumber = $1", matchNumber_)
495 if err != nil {
496 return nil, errors.New(fmt.Sprint("Failed to select from shift for team: ", err))
497 }
498 defer rows.Close()
499
500 var shifts []Shift
501 for rows.Next() {
502 var shift Shift
503 var id int
504 err = rows.Scan(&id, &shift.MatchNumber,
505 &shift.R1scouter, &shift.R2scouter, &shift.R3scouter, &shift.B1scouter, &shift.B2scouter, &shift.B3scouter)
506 if err != nil {
507 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
508 }
509 shifts = append(shifts, shift)
510 }
511 return shifts, nil
512}
513
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800514func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800515 rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = $1", teamNumber_)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800516 if err != nil {
517 return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800518 }
519 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800520
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800521 var teams []Stats
522 for rows.Next() {
523 var team Stats
Philipp Schraderf117fae2022-04-08 20:14:57 -0700524 err = rows.Scan(
525 &team.TeamNumber, &team.MatchNumber, &team.Round, &team.CompLevel,
Philipp Schraderfee07e12022-03-17 22:19:47 -0700526 &team.StartingQuadrant,
527 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
528 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800529 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
530 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700531 &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
532 &team.Comment, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800533 if err != nil {
534 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
535 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800536 teams = append(teams, team)
537 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800538 return teams, nil
539}
Alex Perry871eab92022-03-12 17:43:52 -0800540
541func (database *Database) QueryNotes(TeamNumber int32) (NotesData, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800542 rows, err := database.Query("SELECT * FROM team_notes WHERE TeamNumber = $1", TeamNumber)
Alex Perry871eab92022-03-12 17:43:52 -0800543 if err != nil {
544 return NotesData{}, errors.New(fmt.Sprint("Failed to select from notes: ", err))
545 }
546 defer rows.Close()
547
548 var notes []string
549 for rows.Next() {
550 var id int32
551 var data string
552 err = rows.Scan(&id, &TeamNumber, &data)
553 if err != nil {
554 return NotesData{}, errors.New(fmt.Sprint("Failed to scan from notes: ", err))
555 }
556 notes = append(notes, data)
557 }
558 return NotesData{TeamNumber, notes}, nil
559}
560
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700561func (database *Database) QueryRankings(TeamNumber int) ([]Ranking, error) {
562 rows, err := database.Query("SELECT * FROM rankings WHERE TeamNumber = $1", TeamNumber)
563 if err != nil {
564 return nil, errors.New(fmt.Sprint("Failed to select from rankings: ", err))
565 }
566 defer rows.Close()
567
568 all_rankings := make([]Ranking, 0)
569 for rows.Next() {
570 var ranking Ranking
571 var id int
572 err = rows.Scan(&id,
573 &ranking.Losses, &ranking.Wins, &ranking.Ties,
574 &ranking.Rank, &ranking.Dq, &ranking.TeamNumber)
575 if err != nil {
576 return nil, errors.New(fmt.Sprint("Failed to scan from rankings: ", err))
577 }
578 all_rankings = append(all_rankings, ranking)
579 }
580 return all_rankings, nil
581}
582
Alex Perry871eab92022-03-12 17:43:52 -0800583func (database *Database) AddNotes(data NotesData) error {
584 if len(data.Notes) > 1 {
585 return errors.New("Can only insert one row of notes at a time")
586 }
587 statement, err := database.Prepare("INSERT INTO " +
588 "team_notes(TeamNumber, Notes)" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800589 "VALUES ($1, $2)")
Alex Perry871eab92022-03-12 17:43:52 -0800590 if err != nil {
591 return errors.New(fmt.Sprint("Failed to prepare insertion into notes table: ", err))
592 }
593 defer statement.Close()
594
595 _, err = statement.Exec(data.TeamNumber, data.Notes[0])
596 if err != nil {
597 return errors.New(fmt.Sprint("Failed to insert into Notes database: ", err))
598 }
599 return nil
600}