blob: 4b40dbcbd6a59735b00eafea1541dce9d3ccb52e [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 Schrader80ccb662022-03-01 21:47:30 -080028 ShotsMissed, UpperGoalShots, LowerGoalShots int32
29 ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, PlayedDefense 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 Schraderfae8a7e2022-03-13 22:51:54 -070039 // The username of the person who collected these statistics.
40 // "unknown" if submitted without logging in.
41 // Empty if the stats have not yet been collected.
42 CollectedBy string
Sabina Leaverc5fd2772022-01-29 17:00:23 -080043}
44
Alex Perry871eab92022-03-12 17:43:52 -080045type NotesData struct {
46 TeamNumber int32
47 Notes []string
48}
49
Philipp Schrader7365d322022-03-06 16:40:08 -080050// Opens a database at the specified port on localhost. We currently don't
51// support connecting to databases on other hosts.
52func NewDatabase(user string, password string, port int) (*Database, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -080053 var err error
Sabina Leaverc5fd2772022-01-29 17:00:23 -080054 database := new(Database)
Philipp Schrader83fc2722022-03-10 21:59:20 -080055
Philipp Schrader7365d322022-03-06 16:40:08 -080056 psqlInfo := fmt.Sprintf("postgres://%s:%s@localhost:%d/postgres", user, password, port)
57 database.DB, err = sql.Open("pgx", psqlInfo)
58 if err != nil {
59 return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
60 }
Philipp Schrader36df73a2022-03-17 23:27:24 -070061
Philipp Schrader83fc2722022-03-10 21:59:20 -080062 statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
Philipp Schrader7365d322022-03-06 16:40:08 -080063 "id SERIAL PRIMARY KEY, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080064 "MatchNumber INTEGER, " +
65 "Round INTEGER, " +
Philipp Schrader7365d322022-03-06 16:40:08 -080066 "CompLevel VARCHAR, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080067 "R1 INTEGER, " +
68 "R2 INTEGER, " +
69 "R3 INTEGER, " +
70 "B1 INTEGER, " +
71 "B2 INTEGER, " +
72 "B3 INTEGER, " +
73 "r1ID INTEGER, " +
74 "r2ID INTEGER, " +
75 "r3ID INTEGER, " +
76 "b1ID INTEGER, " +
77 "b2ID INTEGER, " +
78 "b3ID INTEGER)")
79 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080080 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080081 return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080082 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080083 defer statement.Close()
84
85 _, err = statement.Exec()
86 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 create matches table: ", err))
89 }
90
91 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
Philipp Schrader7365d322022-03-06 16:40:08 -080092 "id SERIAL PRIMARY KEY, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080093 "TeamNumber INTEGER, " +
94 "MatchNumber INTEGER, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -070095 "StartingQuadrant INTEGER, " +
96 "AutoBall1PickedUp BOOLEAN, " +
97 "AutoBall2PickedUp BOOLEAN, " +
98 "AutoBall3PickedUp BOOLEAN, " +
99 "AutoBall4PickedUp BOOLEAN, " +
100 "AutoBall5PickedUp BOOLEAN, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800101 "ShotsMissed INTEGER, " +
102 "UpperGoalShots INTEGER, " +
103 "LowerGoalShots INTEGER, " +
104 "ShotsMissedAuto INTEGER, " +
105 "UpperGoalAuto INTEGER, " +
106 "LowerGoalAuto INTEGER, " +
107 "PlayedDefense INTEGER, " +
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700108 "Climbing INTEGER, " +
109 "CollectedBy VARCHAR)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800110 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800111 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800112 return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
113 }
114 defer statement.Close()
115
116 _, err = statement.Exec()
117 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800118 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800119 return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
120 }
121
Alex Perry871eab92022-03-12 17:43:52 -0800122 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_notes (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800123 "id SERIAL PRIMARY KEY, " +
Alex Perry871eab92022-03-12 17:43:52 -0800124 "TeamNumber INTEGER, " +
125 "Notes TEXT)")
126 if err != nil {
127 return nil, errors.New(fmt.Sprint("Failed to prepare notes table creation: ", err))
128 }
129 defer statement.Close()
130
131 _, err = statement.Exec()
132 if err != nil {
133 return nil, errors.New(fmt.Sprint("Failed to create notes table: ", err))
134 }
135
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800136 return database, nil
137}
138
139func (database *Database) Delete() error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800140 statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
141 if err != nil {
142 return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800143 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800144 _, err = statement.Exec()
145 if err != nil {
146 return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800147 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800148
149 statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
150 if err != nil {
151 return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
152 }
153 _, err = statement.Exec()
154 if err != nil {
155 return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
156 }
Alex Perry871eab92022-03-12 17:43:52 -0800157
158 statement, err = database.Prepare("DROP TABLE IF EXISTS team_notes")
159 if err != nil {
160 return errors.New(fmt.Sprint("Failed to prepare dropping notes table: ", err))
161 }
162 _, err = statement.Exec()
163 if err != nil {
164 return errors.New(fmt.Sprint("Failed to drop notes table: ", err))
165 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800166 return nil
167}
168
169// This function will also populate the Stats table with six empty rows every time a match is added
170func (database *Database) AddToMatch(m Match) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800171 statement, err := database.Prepare("INSERT INTO team_match_stats(" +
172 "TeamNumber, MatchNumber, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700173 "StartingQuadrant, " +
174 "AutoBall1PickedUp, AutoBall2PickedUp, AutoBall3PickedUp, " +
175 "AutoBall4PickedUp, AutoBall5PickedUp, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800176 "ShotsMissed, UpperGoalShots, LowerGoalShots, " +
177 "ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700178 "PlayedDefense, Climbing, CollectedBy) " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800179 "VALUES (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800180 "$1, $2, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700181 "$3, " +
182 "$4, $5, $6, " +
183 "$7, $8, " +
184 "$9, $10, $11, " +
185 "$12, $13, $14, " +
186 "$15, $16, $17) " +
Philipp Schrader7365d322022-03-06 16:40:08 -0800187 "RETURNING id")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800188 if err != nil {
189 return errors.New(fmt.Sprint("Failed to prepare insertion into stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800190 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800191 defer statement.Close()
192
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800193 var rowIds [6]int64
Philipp Schrader80ccb662022-03-01 21:47:30 -0800194 for i, TeamNumber := range []int32{m.R1, m.R2, m.R3, m.B1, m.B2, m.B3} {
Philipp Schraderfee07e12022-03-17 22:19:47 -0700195 row := statement.QueryRow(
196 TeamNumber, m.MatchNumber,
197 0,
198 false, false, false,
199 false, false,
200 0, 0, 0,
201 0, 0, 0,
202 0, 0, "")
Philipp Schrader7365d322022-03-06 16:40:08 -0800203 err = row.Scan(&rowIds[i])
Philipp Schrader83fc2722022-03-10 21:59:20 -0800204 if err != nil {
205 return errors.New(fmt.Sprint("Failed to insert stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800206 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800207 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800208
209 statement, err = database.Prepare("INSERT INTO matches(" +
210 "MatchNumber, Round, CompLevel, " +
211 "R1, R2, R3, B1, B2, B3, " +
212 "r1ID, r2ID, r3ID, b1ID, b2ID, b3ID) " +
213 "VALUES (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800214 "$1, $2, $3, " +
215 "$4, $5, $6, $7, $8, $9, " +
216 "$10, $11, $12, $13, $14, $15)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800217 if err != nil {
218 return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
219 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800220 defer statement.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800221
222 _, err = statement.Exec(m.MatchNumber, m.Round, m.CompLevel,
223 m.R1, m.R2, m.R3, m.B1, m.B2, m.B3,
224 rowIds[0], rowIds[1], rowIds[2], rowIds[3], rowIds[4], rowIds[5])
225 if err != nil {
226 return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800227 }
228 return nil
229}
230
231func (database *Database) AddToStats(s Stats) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800232 statement, err := database.Prepare("UPDATE team_match_stats SET " +
Philipp Schrader7365d322022-03-06 16:40:08 -0800233 "TeamNumber = $1, MatchNumber = $2, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700234 "StartingQuadrant = $3, " +
235 "AutoBall1PickedUp = $4, AutoBall2PickedUp = $5, AutoBall3PickedUp = $6, " +
236 "AutoBall4PickedUp = $7, AutoBall5PickedUp = $8, " +
237 "ShotsMissed = $9, UpperGoalShots = $10, LowerGoalShots = $11, " +
238 "ShotsMissedAuto = $12, UpperGoalAuto = $13, LowerGoalAuto = $14, " +
239 "PlayedDefense = $15, Climbing = $16, CollectedBy = $17 " +
240 "WHERE MatchNumber = $18 AND TeamNumber = $19")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800241 if err != nil {
242 return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800243 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800244 defer statement.Close()
245
Philipp Schraderfee07e12022-03-17 22:19:47 -0700246 result, err := statement.Exec(
247 s.TeamNumber, s.MatchNumber,
248 s.StartingQuadrant,
249 s.AutoBallPickedUp[0], s.AutoBallPickedUp[1], s.AutoBallPickedUp[2],
250 s.AutoBallPickedUp[3], s.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800251 s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
252 s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700253 s.PlayedDefense, s.Climbing, s.CollectedBy,
Philipp Schrader83fc2722022-03-10 21:59:20 -0800254 s.MatchNumber, s.TeamNumber)
255 if err != nil {
256 return errors.New(fmt.Sprint("Failed to update stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800257 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800258
259 numRowsAffected, err := result.RowsAffected()
260 if err != nil {
261 return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800262 }
263 if numRowsAffected == 0 {
264 return errors.New(fmt.Sprint(
265 "Failed to find team ", s.TeamNumber,
266 " in match ", s.MatchNumber, " in the schedule."))
267 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800268 return nil
269}
270
271func (database *Database) ReturnMatches() ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800272 rows, err := database.Query("SELECT * FROM matches")
273 if err != nil {
274 return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
275 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800276 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800277
278 matches := make([]Match, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800279 for rows.Next() {
280 var match Match
281 var id int
Philipp Schrader83fc2722022-03-10 21:59:20 -0800282 err := rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
283 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
284 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
285 if err != nil {
286 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800287 }
288 matches = append(matches, match)
289 }
290 return matches, nil
291}
292
293func (database *Database) ReturnStats() ([]Stats, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800294 rows, err := database.Query("SELECT * FROM team_match_stats")
295 if err != nil {
296 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800297 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800298 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800299
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800300 teams := make([]Stats, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800301 for rows.Next() {
302 var team Stats
Philipp Schrader83fc2722022-03-10 21:59:20 -0800303 var id int
Philipp Schraderfee07e12022-03-17 22:19:47 -0700304 err = rows.Scan(&id,
305 &team.TeamNumber, &team.MatchNumber,
306 &team.StartingQuadrant,
307 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
308 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800309 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
310 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700311 &team.PlayedDefense, &team.Climbing, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800312 if err != nil {
313 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800314 }
315 teams = append(teams, team)
316 }
317 return teams, nil
318}
319
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800320func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800321 rows, err := database.Query("SELECT * FROM matches WHERE "+
Philipp Schrader7365d322022-03-06 16:40:08 -0800322 "R1 = $1 OR R2 = $2 OR R3 = $3 OR B1 = $4 OR B2 = $5 OR B3 = $6",
Philipp Schrader83fc2722022-03-10 21:59:20 -0800323 teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
324 if err != nil {
325 return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800326 }
327 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800328
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800329 var matches []Match
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800330 for rows.Next() {
331 var match Match
Philipp Schrader83fc2722022-03-10 21:59:20 -0800332 var id int
333 err = rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
334 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
335 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
336 if err != nil {
337 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
338 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800339 matches = append(matches, match)
340 }
341 return matches, nil
342}
343
344func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800345 rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = $1", teamNumber_)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800346 if err != nil {
347 return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800348 }
349 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800350
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800351 var teams []Stats
352 for rows.Next() {
353 var team Stats
354 var id int
Philipp Schraderfee07e12022-03-17 22:19:47 -0700355 err = rows.Scan(&id,
356 &team.TeamNumber, &team.MatchNumber,
357 &team.StartingQuadrant,
358 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
359 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800360 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
361 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700362 &team.PlayedDefense, &team.Climbing, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800363 if err != nil {
364 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
365 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800366 teams = append(teams, team)
367 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800368 return teams, nil
369}
Alex Perry871eab92022-03-12 17:43:52 -0800370
371func (database *Database) QueryNotes(TeamNumber int32) (NotesData, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800372 rows, err := database.Query("SELECT * FROM team_notes WHERE TeamNumber = $1", TeamNumber)
Alex Perry871eab92022-03-12 17:43:52 -0800373 if err != nil {
374 return NotesData{}, errors.New(fmt.Sprint("Failed to select from notes: ", err))
375 }
376 defer rows.Close()
377
378 var notes []string
379 for rows.Next() {
380 var id int32
381 var data string
382 err = rows.Scan(&id, &TeamNumber, &data)
383 if err != nil {
384 return NotesData{}, errors.New(fmt.Sprint("Failed to scan from notes: ", err))
385 }
386 notes = append(notes, data)
387 }
388 return NotesData{TeamNumber, notes}, nil
389}
390
391func (database *Database) AddNotes(data NotesData) error {
392 if len(data.Notes) > 1 {
393 return errors.New("Can only insert one row of notes at a time")
394 }
395 statement, err := database.Prepare("INSERT INTO " +
396 "team_notes(TeamNumber, Notes)" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800397 "VALUES ($1, $2)")
Alex Perry871eab92022-03-12 17:43:52 -0800398 if err != nil {
399 return errors.New(fmt.Sprint("Failed to prepare insertion into notes table: ", err))
400 }
401 defer statement.Close()
402
403 _, err = statement.Exec(data.TeamNumber, data.Notes[0])
404 if err != nil {
405 return errors.New(fmt.Sprint("Failed to insert into Notes database: ", err))
406 }
407 return nil
408}