blob: 85395e11319f6f0620dd8e0c615ea61c7cff2c6b [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 // 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 Schraderfee07e12022-03-17 22:19:47 -070024 TeamNumber, MatchNumber int32
25 StartingQuadrant int32
26 AutoBallPickedUp [5]bool
27 // TODO(phil): Re-order auto and teleop fields so auto comes first.
Philipp Schraderfa45d742022-03-18 19:29:05 -070028 ShotsMissed, UpperGoalShots, LowerGoalShots int32
29 ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto int32
30 PlayedDefense, DefenseReceivedScore int32
Philipp Schrader36df73a2022-03-17 23:27:24 -070031 // Climbing level:
32 // 0 -> "NoAttempt"
33 // 1 -> "Failed"
34 // 2 -> "FailedWithPlentyOfTime"
35 // 3 -> "Low"
36 // 4 -> "Medium"
37 // 5 -> "High"
38 // 6 -> "Transversal"
39 Climbing int32
Philipp Schraderfa45d742022-03-18 19:29:05 -070040 // Some non-numerical data that the scout felt worth noting.
41 Comment string
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070042 // The username of the person who collected these statistics.
43 // "unknown" if submitted without logging in.
44 // Empty if the stats have not yet been collected.
45 CollectedBy string
Sabina Leaverc5fd2772022-01-29 17:00:23 -080046}
47
Alex Perry871eab92022-03-12 17:43:52 -080048type NotesData struct {
49 TeamNumber int32
50 Notes []string
51}
52
Philipp Schrader7365d322022-03-06 16:40:08 -080053// Opens a database at the specified port on localhost. We currently don't
54// support connecting to databases on other hosts.
55func NewDatabase(user string, password string, port int) (*Database, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -080056 var err error
Sabina Leaverc5fd2772022-01-29 17:00:23 -080057 database := new(Database)
Philipp Schrader83fc2722022-03-10 21:59:20 -080058
Philipp Schrader7365d322022-03-06 16:40:08 -080059 psqlInfo := fmt.Sprintf("postgres://%s:%s@localhost:%d/postgres", user, password, port)
60 database.DB, err = sql.Open("pgx", psqlInfo)
61 if err != nil {
62 return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
63 }
Philipp Schrader36df73a2022-03-17 23:27:24 -070064
Philipp Schrader83fc2722022-03-10 21:59:20 -080065 statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
Philipp Schrader7365d322022-03-06 16:40:08 -080066 "id SERIAL PRIMARY KEY, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080067 "MatchNumber INTEGER, " +
68 "Round INTEGER, " +
Philipp Schrader7365d322022-03-06 16:40:08 -080069 "CompLevel VARCHAR, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080070 "R1 INTEGER, " +
71 "R2 INTEGER, " +
72 "R3 INTEGER, " +
73 "B1 INTEGER, " +
74 "B2 INTEGER, " +
75 "B3 INTEGER, " +
76 "r1ID INTEGER, " +
77 "r2ID INTEGER, " +
78 "r3ID INTEGER, " +
79 "b1ID INTEGER, " +
80 "b2ID INTEGER, " +
81 "b3ID INTEGER)")
82 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080083 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080084 return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080085 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080086 defer statement.Close()
87
88 _, err = statement.Exec()
89 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080090 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080091 return nil, errors.New(fmt.Sprint("Failed to create matches table: ", err))
92 }
93
94 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
Philipp Schrader7365d322022-03-06 16:40:08 -080095 "id SERIAL PRIMARY KEY, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080096 "TeamNumber INTEGER, " +
97 "MatchNumber INTEGER, " +
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 Schraderfae8a7e2022-03-13 22:51:54 -0700114 "CollectedBy VARCHAR)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800115 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800116 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800117 return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
118 }
119 defer statement.Close()
120
121 _, err = statement.Exec()
122 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800123 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800124 return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
125 }
126
Alex Perry871eab92022-03-12 17:43:52 -0800127 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_notes (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800128 "id SERIAL PRIMARY KEY, " +
Alex Perry871eab92022-03-12 17:43:52 -0800129 "TeamNumber INTEGER, " +
130 "Notes TEXT)")
131 if err != nil {
132 return nil, errors.New(fmt.Sprint("Failed to prepare notes table creation: ", err))
133 }
134 defer statement.Close()
135
136 _, err = statement.Exec()
137 if err != nil {
138 return nil, errors.New(fmt.Sprint("Failed to create notes table: ", err))
139 }
140
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800141 return database, nil
142}
143
144func (database *Database) Delete() error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800145 statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
146 if err != nil {
147 return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800148 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800149 _, err = statement.Exec()
150 if err != nil {
151 return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800152 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800153
154 statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
155 if err != nil {
156 return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
157 }
158 _, err = statement.Exec()
159 if err != nil {
160 return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
161 }
Alex Perry871eab92022-03-12 17:43:52 -0800162
163 statement, err = database.Prepare("DROP TABLE IF EXISTS team_notes")
164 if err != nil {
165 return errors.New(fmt.Sprint("Failed to prepare dropping notes table: ", err))
166 }
167 _, err = statement.Exec()
168 if err != nil {
169 return errors.New(fmt.Sprint("Failed to drop notes table: ", err))
170 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800171 return nil
172}
173
174// This function will also populate the Stats table with six empty rows every time a match is added
175func (database *Database) AddToMatch(m Match) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800176 statement, err := database.Prepare("INSERT INTO team_match_stats(" +
177 "TeamNumber, MatchNumber, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700178 "StartingQuadrant, " +
179 "AutoBall1PickedUp, AutoBall2PickedUp, AutoBall3PickedUp, " +
180 "AutoBall4PickedUp, AutoBall5PickedUp, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800181 "ShotsMissed, UpperGoalShots, LowerGoalShots, " +
182 "ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700183 "PlayedDefense, DefenseReceivedScore, Climbing, " +
184 "Comment, CollectedBy) " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800185 "VALUES (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800186 "$1, $2, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700187 "$3, " +
188 "$4, $5, $6, " +
189 "$7, $8, " +
190 "$9, $10, $11, " +
191 "$12, $13, $14, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700192 "$15, $16, $17, " +
193 "$18, $19) " +
Philipp Schrader7365d322022-03-06 16:40:08 -0800194 "RETURNING id")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800195 if err != nil {
196 return errors.New(fmt.Sprint("Failed to prepare insertion into stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800197 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800198 defer statement.Close()
199
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800200 var rowIds [6]int64
Philipp Schrader80ccb662022-03-01 21:47:30 -0800201 for i, TeamNumber := range []int32{m.R1, m.R2, m.R3, m.B1, m.B2, m.B3} {
Philipp Schraderfee07e12022-03-17 22:19:47 -0700202 row := statement.QueryRow(
203 TeamNumber, m.MatchNumber,
204 0,
205 false, false, false,
206 false, false,
207 0, 0, 0,
208 0, 0, 0,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700209 0, 0, 0,
210 "", "")
Philipp Schrader7365d322022-03-06 16:40:08 -0800211 err = row.Scan(&rowIds[i])
Philipp Schrader83fc2722022-03-10 21:59:20 -0800212 if err != nil {
213 return errors.New(fmt.Sprint("Failed to insert stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800214 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800215 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800216
217 statement, err = database.Prepare("INSERT INTO matches(" +
218 "MatchNumber, Round, CompLevel, " +
219 "R1, R2, R3, B1, B2, B3, " +
220 "r1ID, r2ID, r3ID, b1ID, b2ID, b3ID) " +
221 "VALUES (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800222 "$1, $2, $3, " +
223 "$4, $5, $6, $7, $8, $9, " +
224 "$10, $11, $12, $13, $14, $15)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800225 if err != nil {
226 return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
227 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800228 defer statement.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800229
230 _, err = statement.Exec(m.MatchNumber, m.Round, m.CompLevel,
231 m.R1, m.R2, m.R3, m.B1, m.B2, m.B3,
232 rowIds[0], rowIds[1], rowIds[2], rowIds[3], rowIds[4], rowIds[5])
233 if err != nil {
234 return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800235 }
236 return nil
237}
238
239func (database *Database) AddToStats(s Stats) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800240 statement, err := database.Prepare("UPDATE team_match_stats SET " +
Philipp Schrader7365d322022-03-06 16:40:08 -0800241 "TeamNumber = $1, MatchNumber = $2, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700242 "StartingQuadrant = $3, " +
243 "AutoBall1PickedUp = $4, AutoBall2PickedUp = $5, AutoBall3PickedUp = $6, " +
244 "AutoBall4PickedUp = $7, AutoBall5PickedUp = $8, " +
245 "ShotsMissed = $9, UpperGoalShots = $10, LowerGoalShots = $11, " +
246 "ShotsMissedAuto = $12, UpperGoalAuto = $13, LowerGoalAuto = $14, " +
Philipp Schraderfa45d742022-03-18 19:29:05 -0700247 "PlayedDefense = $15, DefenseReceivedScore = $16, Climbing = $17, " +
248 "Comment = $18, CollectedBy = $19 " +
249 "WHERE MatchNumber = $20 AND TeamNumber = $21")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800250 if err != nil {
251 return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800252 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800253 defer statement.Close()
254
Philipp Schraderfee07e12022-03-17 22:19:47 -0700255 result, err := statement.Exec(
256 s.TeamNumber, s.MatchNumber,
257 s.StartingQuadrant,
258 s.AutoBallPickedUp[0], s.AutoBallPickedUp[1], s.AutoBallPickedUp[2],
259 s.AutoBallPickedUp[3], s.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800260 s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
261 s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700262 s.PlayedDefense, s.DefenseReceivedScore, s.Climbing,
263 s.Comment, s.CollectedBy,
Philipp Schrader83fc2722022-03-10 21:59:20 -0800264 s.MatchNumber, s.TeamNumber)
265 if err != nil {
266 return errors.New(fmt.Sprint("Failed to update stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800267 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800268
269 numRowsAffected, err := result.RowsAffected()
270 if err != nil {
271 return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800272 }
273 if numRowsAffected == 0 {
274 return errors.New(fmt.Sprint(
275 "Failed to find team ", s.TeamNumber,
276 " in match ", s.MatchNumber, " in the schedule."))
277 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800278 return nil
279}
280
281func (database *Database) ReturnMatches() ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800282 rows, err := database.Query("SELECT * FROM matches")
283 if err != nil {
284 return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
285 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800286 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800287
288 matches := make([]Match, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800289 for rows.Next() {
290 var match Match
291 var id int
Philipp Schrader83fc2722022-03-10 21:59:20 -0800292 err := rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
293 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
294 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
295 if err != nil {
296 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800297 }
298 matches = append(matches, match)
299 }
300 return matches, nil
301}
302
303func (database *Database) ReturnStats() ([]Stats, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800304 rows, err := database.Query("SELECT * FROM team_match_stats")
305 if err != nil {
306 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800307 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800308 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800309
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800310 teams := make([]Stats, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800311 for rows.Next() {
312 var team Stats
Philipp Schrader83fc2722022-03-10 21:59:20 -0800313 var id int
Philipp Schraderfee07e12022-03-17 22:19:47 -0700314 err = rows.Scan(&id,
315 &team.TeamNumber, &team.MatchNumber,
316 &team.StartingQuadrant,
317 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
318 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800319 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
320 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700321 &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
322 &team.Comment, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800323 if err != nil {
324 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800325 }
326 teams = append(teams, team)
327 }
328 return teams, nil
329}
330
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800331func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800332 rows, err := database.Query("SELECT * FROM matches WHERE "+
Philipp Schrader7365d322022-03-06 16:40:08 -0800333 "R1 = $1 OR R2 = $2 OR R3 = $3 OR B1 = $4 OR B2 = $5 OR B3 = $6",
Philipp Schrader83fc2722022-03-10 21:59:20 -0800334 teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
335 if err != nil {
336 return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800337 }
338 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800339
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800340 var matches []Match
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800341 for rows.Next() {
342 var match Match
Philipp Schrader83fc2722022-03-10 21:59:20 -0800343 var id int
344 err = rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
345 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
346 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
347 if err != nil {
348 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
349 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800350 matches = append(matches, match)
351 }
352 return matches, nil
353}
354
355func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800356 rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = $1", teamNumber_)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800357 if err != nil {
358 return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800359 }
360 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800361
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800362 var teams []Stats
363 for rows.Next() {
364 var team Stats
365 var id int
Philipp Schraderfee07e12022-03-17 22:19:47 -0700366 err = rows.Scan(&id,
367 &team.TeamNumber, &team.MatchNumber,
368 &team.StartingQuadrant,
369 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
370 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800371 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
372 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfa45d742022-03-18 19:29:05 -0700373 &team.PlayedDefense, &team.DefenseReceivedScore, &team.Climbing,
374 &team.Comment, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800375 if err != nil {
376 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
377 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800378 teams = append(teams, team)
379 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800380 return teams, nil
381}
Alex Perry871eab92022-03-12 17:43:52 -0800382
383func (database *Database) QueryNotes(TeamNumber int32) (NotesData, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800384 rows, err := database.Query("SELECT * FROM team_notes WHERE TeamNumber = $1", TeamNumber)
Alex Perry871eab92022-03-12 17:43:52 -0800385 if err != nil {
386 return NotesData{}, errors.New(fmt.Sprint("Failed to select from notes: ", err))
387 }
388 defer rows.Close()
389
390 var notes []string
391 for rows.Next() {
392 var id int32
393 var data string
394 err = rows.Scan(&id, &TeamNumber, &data)
395 if err != nil {
396 return NotesData{}, errors.New(fmt.Sprint("Failed to scan from notes: ", err))
397 }
398 notes = append(notes, data)
399 }
400 return NotesData{TeamNumber, notes}, nil
401}
402
403func (database *Database) AddNotes(data NotesData) error {
404 if len(data.Notes) > 1 {
405 return errors.New("Can only insert one row of notes at a time")
406 }
407 statement, err := database.Prepare("INSERT INTO " +
408 "team_notes(TeamNumber, Notes)" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800409 "VALUES ($1, $2)")
Alex Perry871eab92022-03-12 17:43:52 -0800410 if err != nil {
411 return errors.New(fmt.Sprint("Failed to prepare insertion into notes table: ", err))
412 }
413 defer statement.Close()
414
415 _, err = statement.Exec(data.TeamNumber, data.Notes[0])
416 if err != nil {
417 return errors.New(fmt.Sprint("Failed to insert into Notes database: ", err))
418 }
419 return nil
420}