blob: d9bebc920b2b44fdbf5345edcc4cb46b1b880daf [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
30 Climbing int32
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070031 // The username of the person who collected these statistics.
32 // "unknown" if submitted without logging in.
33 // Empty if the stats have not yet been collected.
34 CollectedBy string
Sabina Leaverc5fd2772022-01-29 17:00:23 -080035}
36
Alex Perry871eab92022-03-12 17:43:52 -080037type NotesData struct {
38 TeamNumber int32
39 Notes []string
40}
41
Philipp Schrader7365d322022-03-06 16:40:08 -080042// Opens a database at the specified port on localhost. We currently don't
43// support connecting to databases on other hosts.
44func NewDatabase(user string, password string, port int) (*Database, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -080045 var err error
Sabina Leaverc5fd2772022-01-29 17:00:23 -080046 database := new(Database)
Philipp Schrader83fc2722022-03-10 21:59:20 -080047
Philipp Schrader7365d322022-03-06 16:40:08 -080048 psqlInfo := fmt.Sprintf("postgres://%s:%s@localhost:%d/postgres", user, password, port)
49 database.DB, err = sql.Open("pgx", psqlInfo)
50 if err != nil {
51 return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
52 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080053 statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
Philipp Schrader7365d322022-03-06 16:40:08 -080054 "id SERIAL PRIMARY KEY, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080055 "MatchNumber INTEGER, " +
56 "Round INTEGER, " +
Philipp Schrader7365d322022-03-06 16:40:08 -080057 "CompLevel VARCHAR, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080058 "R1 INTEGER, " +
59 "R2 INTEGER, " +
60 "R3 INTEGER, " +
61 "B1 INTEGER, " +
62 "B2 INTEGER, " +
63 "B3 INTEGER, " +
64 "r1ID INTEGER, " +
65 "r2ID INTEGER, " +
66 "r3ID INTEGER, " +
67 "b1ID INTEGER, " +
68 "b2ID INTEGER, " +
69 "b3ID INTEGER)")
70 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080071 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080072 return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -080073 }
Philipp Schrader83fc2722022-03-10 21:59:20 -080074 defer statement.Close()
75
76 _, err = statement.Exec()
77 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -080078 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -080079 return nil, errors.New(fmt.Sprint("Failed to create matches table: ", err))
80 }
81
82 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
Philipp Schrader7365d322022-03-06 16:40:08 -080083 "id SERIAL PRIMARY KEY, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080084 "TeamNumber INTEGER, " +
85 "MatchNumber INTEGER, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -070086 "StartingQuadrant INTEGER, " +
87 "AutoBall1PickedUp BOOLEAN, " +
88 "AutoBall2PickedUp BOOLEAN, " +
89 "AutoBall3PickedUp BOOLEAN, " +
90 "AutoBall4PickedUp BOOLEAN, " +
91 "AutoBall5PickedUp BOOLEAN, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -080092 "ShotsMissed INTEGER, " +
93 "UpperGoalShots INTEGER, " +
94 "LowerGoalShots INTEGER, " +
95 "ShotsMissedAuto INTEGER, " +
96 "UpperGoalAuto INTEGER, " +
97 "LowerGoalAuto INTEGER, " +
98 "PlayedDefense INTEGER, " +
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070099 "Climbing INTEGER, " +
100 "CollectedBy VARCHAR)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800101 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800102 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800103 return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
104 }
105 defer statement.Close()
106
107 _, err = statement.Exec()
108 if err != nil {
Philipp Schrader7365d322022-03-06 16:40:08 -0800109 database.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800110 return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
111 }
112
Alex Perry871eab92022-03-12 17:43:52 -0800113 statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_notes (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800114 "id SERIAL PRIMARY KEY, " +
Alex Perry871eab92022-03-12 17:43:52 -0800115 "TeamNumber INTEGER, " +
116 "Notes TEXT)")
117 if err != nil {
118 return nil, errors.New(fmt.Sprint("Failed to prepare notes table creation: ", err))
119 }
120 defer statement.Close()
121
122 _, err = statement.Exec()
123 if err != nil {
124 return nil, errors.New(fmt.Sprint("Failed to create notes table: ", err))
125 }
126
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800127 return database, nil
128}
129
130func (database *Database) Delete() error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800131 statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
132 if err != nil {
133 return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800134 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800135 _, err = statement.Exec()
136 if err != nil {
137 return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800138 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800139
140 statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
141 if err != nil {
142 return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
143 }
144 _, err = statement.Exec()
145 if err != nil {
146 return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
147 }
Alex Perry871eab92022-03-12 17:43:52 -0800148
149 statement, err = database.Prepare("DROP TABLE IF EXISTS team_notes")
150 if err != nil {
151 return errors.New(fmt.Sprint("Failed to prepare dropping notes table: ", err))
152 }
153 _, err = statement.Exec()
154 if err != nil {
155 return errors.New(fmt.Sprint("Failed to drop notes table: ", err))
156 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800157 return nil
158}
159
160// This function will also populate the Stats table with six empty rows every time a match is added
161func (database *Database) AddToMatch(m Match) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800162 statement, err := database.Prepare("INSERT INTO team_match_stats(" +
163 "TeamNumber, MatchNumber, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700164 "StartingQuadrant, " +
165 "AutoBall1PickedUp, AutoBall2PickedUp, AutoBall3PickedUp, " +
166 "AutoBall4PickedUp, AutoBall5PickedUp, " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800167 "ShotsMissed, UpperGoalShots, LowerGoalShots, " +
168 "ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700169 "PlayedDefense, Climbing, CollectedBy) " +
Philipp Schrader83fc2722022-03-10 21:59:20 -0800170 "VALUES (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800171 "$1, $2, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700172 "$3, " +
173 "$4, $5, $6, " +
174 "$7, $8, " +
175 "$9, $10, $11, " +
176 "$12, $13, $14, " +
177 "$15, $16, $17) " +
Philipp Schrader7365d322022-03-06 16:40:08 -0800178 "RETURNING id")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800179 if err != nil {
180 return errors.New(fmt.Sprint("Failed to prepare insertion into stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800181 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800182 defer statement.Close()
183
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800184 var rowIds [6]int64
Philipp Schrader80ccb662022-03-01 21:47:30 -0800185 for i, TeamNumber := range []int32{m.R1, m.R2, m.R3, m.B1, m.B2, m.B3} {
Philipp Schraderfee07e12022-03-17 22:19:47 -0700186 row := statement.QueryRow(
187 TeamNumber, m.MatchNumber,
188 0,
189 false, false, false,
190 false, false,
191 0, 0, 0,
192 0, 0, 0,
193 0, 0, "")
Philipp Schrader7365d322022-03-06 16:40:08 -0800194 err = row.Scan(&rowIds[i])
Philipp Schrader83fc2722022-03-10 21:59:20 -0800195 if err != nil {
196 return errors.New(fmt.Sprint("Failed to insert stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800197 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800198 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800199
200 statement, err = database.Prepare("INSERT INTO matches(" +
201 "MatchNumber, Round, CompLevel, " +
202 "R1, R2, R3, B1, B2, B3, " +
203 "r1ID, r2ID, r3ID, b1ID, b2ID, b3ID) " +
204 "VALUES (" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800205 "$1, $2, $3, " +
206 "$4, $5, $6, $7, $8, $9, " +
207 "$10, $11, $12, $13, $14, $15)")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800208 if err != nil {
209 return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
210 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800211 defer statement.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800212
213 _, err = statement.Exec(m.MatchNumber, m.Round, m.CompLevel,
214 m.R1, m.R2, m.R3, m.B1, m.B2, m.B3,
215 rowIds[0], rowIds[1], rowIds[2], rowIds[3], rowIds[4], rowIds[5])
216 if err != nil {
217 return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800218 }
219 return nil
220}
221
222func (database *Database) AddToStats(s Stats) error {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800223 statement, err := database.Prepare("UPDATE team_match_stats SET " +
Philipp Schrader7365d322022-03-06 16:40:08 -0800224 "TeamNumber = $1, MatchNumber = $2, " +
Philipp Schraderfee07e12022-03-17 22:19:47 -0700225 "StartingQuadrant = $3, " +
226 "AutoBall1PickedUp = $4, AutoBall2PickedUp = $5, AutoBall3PickedUp = $6, " +
227 "AutoBall4PickedUp = $7, AutoBall5PickedUp = $8, " +
228 "ShotsMissed = $9, UpperGoalShots = $10, LowerGoalShots = $11, " +
229 "ShotsMissedAuto = $12, UpperGoalAuto = $13, LowerGoalAuto = $14, " +
230 "PlayedDefense = $15, Climbing = $16, CollectedBy = $17 " +
231 "WHERE MatchNumber = $18 AND TeamNumber = $19")
Philipp Schrader83fc2722022-03-10 21:59:20 -0800232 if err != nil {
233 return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800234 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800235 defer statement.Close()
236
Philipp Schraderfee07e12022-03-17 22:19:47 -0700237 result, err := statement.Exec(
238 s.TeamNumber, s.MatchNumber,
239 s.StartingQuadrant,
240 s.AutoBallPickedUp[0], s.AutoBallPickedUp[1], s.AutoBallPickedUp[2],
241 s.AutoBallPickedUp[3], s.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800242 s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
243 s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700244 s.PlayedDefense, s.Climbing, s.CollectedBy,
Philipp Schrader83fc2722022-03-10 21:59:20 -0800245 s.MatchNumber, s.TeamNumber)
246 if err != nil {
247 return errors.New(fmt.Sprint("Failed to update stats database: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800248 }
Philipp Schrader83fc2722022-03-10 21:59:20 -0800249
250 numRowsAffected, err := result.RowsAffected()
251 if err != nil {
252 return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800253 }
254 if numRowsAffected == 0 {
255 return errors.New(fmt.Sprint(
256 "Failed to find team ", s.TeamNumber,
257 " in match ", s.MatchNumber, " in the schedule."))
258 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800259 return nil
260}
261
262func (database *Database) ReturnMatches() ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800263 rows, err := database.Query("SELECT * FROM matches")
264 if err != nil {
265 return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
266 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800267 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800268
269 matches := make([]Match, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800270 for rows.Next() {
271 var match Match
272 var id int
Philipp Schrader83fc2722022-03-10 21:59:20 -0800273 err := rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
274 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
275 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
276 if err != nil {
277 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800278 }
279 matches = append(matches, match)
280 }
281 return matches, nil
282}
283
284func (database *Database) ReturnStats() ([]Stats, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800285 rows, err := database.Query("SELECT * FROM team_match_stats")
286 if err != nil {
287 return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
Philipp Schrader30005e42022-03-06 13:53:58 -0800288 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800289 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800290
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800291 teams := make([]Stats, 0)
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800292 for rows.Next() {
293 var team Stats
Philipp Schrader83fc2722022-03-10 21:59:20 -0800294 var id int
Philipp Schraderfee07e12022-03-17 22:19:47 -0700295 err = rows.Scan(&id,
296 &team.TeamNumber, &team.MatchNumber,
297 &team.StartingQuadrant,
298 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
299 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800300 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
301 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700302 &team.PlayedDefense, &team.Climbing, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800303 if err != nil {
304 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800305 }
306 teams = append(teams, team)
307 }
308 return teams, nil
309}
310
Philipp Schraderd1c4bef2022-02-28 22:51:30 -0800311func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800312 rows, err := database.Query("SELECT * FROM matches WHERE "+
Philipp Schrader7365d322022-03-06 16:40:08 -0800313 "R1 = $1 OR R2 = $2 OR R3 = $3 OR B1 = $4 OR B2 = $5 OR B3 = $6",
Philipp Schrader83fc2722022-03-10 21:59:20 -0800314 teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
315 if err != nil {
316 return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800317 }
318 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800319
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800320 var matches []Match
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800321 for rows.Next() {
322 var match Match
Philipp Schrader83fc2722022-03-10 21:59:20 -0800323 var id int
324 err = rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
325 &match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
326 &match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
327 if err != nil {
328 return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
329 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800330 matches = append(matches, match)
331 }
332 return matches, nil
333}
334
335func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800336 rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = $1", teamNumber_)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800337 if err != nil {
338 return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800339 }
340 defer rows.Close()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800341
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800342 var teams []Stats
343 for rows.Next() {
344 var team Stats
345 var id int
Philipp Schraderfee07e12022-03-17 22:19:47 -0700346 err = rows.Scan(&id,
347 &team.TeamNumber, &team.MatchNumber,
348 &team.StartingQuadrant,
349 &team.AutoBallPickedUp[0], &team.AutoBallPickedUp[1], &team.AutoBallPickedUp[2],
350 &team.AutoBallPickedUp[3], &team.AutoBallPickedUp[4],
Philipp Schrader83fc2722022-03-10 21:59:20 -0800351 &team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
352 &team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
Philipp Schraderfae8a7e2022-03-13 22:51:54 -0700353 &team.PlayedDefense, &team.Climbing, &team.CollectedBy)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800354 if err != nil {
355 return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
356 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800357 teams = append(teams, team)
358 }
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800359 return teams, nil
360}
Alex Perry871eab92022-03-12 17:43:52 -0800361
362func (database *Database) QueryNotes(TeamNumber int32) (NotesData, error) {
Philipp Schrader7365d322022-03-06 16:40:08 -0800363 rows, err := database.Query("SELECT * FROM team_notes WHERE TeamNumber = $1", TeamNumber)
Alex Perry871eab92022-03-12 17:43:52 -0800364 if err != nil {
365 return NotesData{}, errors.New(fmt.Sprint("Failed to select from notes: ", err))
366 }
367 defer rows.Close()
368
369 var notes []string
370 for rows.Next() {
371 var id int32
372 var data string
373 err = rows.Scan(&id, &TeamNumber, &data)
374 if err != nil {
375 return NotesData{}, errors.New(fmt.Sprint("Failed to scan from notes: ", err))
376 }
377 notes = append(notes, data)
378 }
379 return NotesData{TeamNumber, notes}, nil
380}
381
382func (database *Database) AddNotes(data NotesData) error {
383 if len(data.Notes) > 1 {
384 return errors.New("Can only insert one row of notes at a time")
385 }
386 statement, err := database.Prepare("INSERT INTO " +
387 "team_notes(TeamNumber, Notes)" +
Philipp Schrader7365d322022-03-06 16:40:08 -0800388 "VALUES ($1, $2)")
Alex Perry871eab92022-03-12 17:43:52 -0800389 if err != nil {
390 return errors.New(fmt.Sprint("Failed to prepare insertion into notes table: ", err))
391 }
392 defer statement.Close()
393
394 _, err = statement.Exec(data.TeamNumber, data.Notes[0])
395 if err != nil {
396 return errors.New(fmt.Sprint("Failed to insert into Notes database: ", err))
397 }
398 return nil
399}