blob: b879cab17a34b3d3baf7c2a0132d5ea2ca0d93e1 [file] [log] [blame]
Sabina Leaverc5fd2772022-01-29 17:00:23 -08001package db
2
3import (
Philipp Schrader30005e42022-03-06 13:53:58 -08004 "errors"
Sabina Leaverc5fd2772022-01-29 17:00:23 -08005 "fmt"
Philipp Schradereecb8962022-06-01 21:02:42 -07006 "gorm.io/driver/postgres"
7 "gorm.io/gorm"
8 "gorm.io/gorm/clause"
9 "gorm.io/gorm/logger"
Emily Markovab8551572023-03-22 19:49:39 -070010 "strconv"
Sabina Leaverc5fd2772022-01-29 17:00:23 -080011)
12
13type Database struct {
Philipp Schradereecb8962022-06-01 21:02:42 -070014 *gorm.DB
Sabina Leaverc5fd2772022-01-29 17:00:23 -080015}
16
Emily Markovabf24c9e2023-02-08 20:31:11 -080017type TeamMatch struct {
18 MatchNumber int32 `gorm:"primaryKey"`
19 SetNumber int32 `gorm:"primaryKey"`
20 CompLevel string `gorm:"primaryKey"`
21 Alliance string `gorm:"primaryKey"` // "R" or "B"
22 AlliancePosition int32 `gorm:"primaryKey"` // 1, 2, or 3
Emily Markovab8551572023-03-22 19:49:39 -070023 TeamNumber string
Sabina Leaverc5fd2772022-01-29 17:00:23 -080024}
25
Milo Lina72e2002022-04-06 20:31:13 -070026type Shift struct {
Philipp Schradereecb8962022-06-01 21:02:42 -070027 MatchNumber int32 `gorm:"primaryKey"`
Milo Lina72e2002022-04-06 20:31:13 -070028 R1scouter, R2scouter, R3scouter, B1scouter, B2scouter, B3scouter string
29}
30
Sabina Leaverc5fd2772022-01-29 17:00:23 -080031type Stats struct {
Philipp Schradereecb8962022-06-01 21:02:42 -070032 TeamNumber int32 `gorm:"primaryKey"`
33 MatchNumber int32 `gorm:"primaryKey"`
34 SetNumber int32 `gorm:"primaryKey"`
35 CompLevel string `gorm:"primaryKey"`
36 StartingQuadrant int32
37 // This field is for the balls picked up during auto. Use this field
38 // when using this library. Ignore the AutoBallPickedUpX fields below.
39 AutoBallPickedUp [5]bool `gorm:"-:all"`
40 // These fields are internal implementation details. Do not use these.
41 // TODO(phil): Figure out how to use the JSON gorm serializer instead
42 // of manually serializing/deserializing these.
43 AutoBallPickedUp1 bool
44 AutoBallPickedUp2 bool
45 AutoBallPickedUp3 bool
46 AutoBallPickedUp4 bool
47 AutoBallPickedUp5 bool
Philipp Schraderfee07e12022-03-17 22:19:47 -070048 // TODO(phil): Re-order auto and teleop fields so auto comes first.
Philipp Schraderfa45d742022-03-18 19:29:05 -070049 ShotsMissed, UpperGoalShots, LowerGoalShots int32
50 ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto int32
51 PlayedDefense, DefenseReceivedScore int32
Philipp Schrader36df73a2022-03-17 23:27:24 -070052 // Climbing level:
53 // 0 -> "NoAttempt"
54 // 1 -> "Failed"
55 // 2 -> "FailedWithPlentyOfTime"
56 // 3 -> "Low"
57 // 4 -> "Medium"
58 // 5 -> "High"
Philipp Schrader85f6e5b2022-04-16 14:20:06 -070059 // 6 -> "Traversal"
Philipp Schrader36df73a2022-03-17 23:27:24 -070060 Climbing int32
Philipp Schraderfa45d742022-03-18 19:29:05 -070061 // Some non-numerical data that the scout felt worth noting.
62 Comment string
Philipp Schraderfae8a7e2022-03-13 22:51:54 -070063 // The username of the person who collected these statistics.
64 // "unknown" if submitted without logging in.
65 // Empty if the stats have not yet been collected.
66 CollectedBy string
Sabina Leaverc5fd2772022-01-29 17:00:23 -080067}
68
Sabina Leaver759090b2023-01-14 20:42:56 -080069type Stats2023 struct {
70 TeamNumber string `gorm:"primaryKey"`
71 MatchNumber int32 `gorm:"primaryKey"`
72 SetNumber int32 `gorm:"primaryKey"`
73 CompLevel string `gorm:"primaryKey"`
74 StartingQuadrant int32
75 LowCubesAuto, MiddleCubesAuto, HighCubesAuto, CubesDroppedAuto int32
76 LowConesAuto, MiddleConesAuto, HighConesAuto, ConesDroppedAuto int32
77 LowCubes, MiddleCubes, HighCubes, CubesDropped int32
78 LowCones, MiddleCones, HighCones, ConesDropped int32
Philipp Schrader8c878a22023-03-20 22:36:38 -070079 AvgCycle int64
Emily Markova46a69bf2023-03-22 20:45:52 -070080 DockedAuto, EngagedAuto bool
81 Docked, Engaged bool
Sabina Leaver759090b2023-01-14 20:42:56 -080082 // The username of the person who collected these statistics.
83 // "unknown" if submitted without logging in.
84 // Empty if the stats have not yet been collected.
85 CollectedBy string
86}
87
88type Action struct {
89 TeamNumber string `gorm:"primaryKey"`
90 MatchNumber int32 `gorm:"primaryKey"`
91 SetNumber int32 `gorm:"primaryKey"`
92 CompLevel string `gorm:"primaryKey"`
93 CompletedAction []byte
94 // This contains a serialized scouting.webserver.requests.ActionType flatbuffer.
95 TimeStamp int32 `gorm:"primaryKey"`
96 CollectedBy string
97}
98
Alex Perry871eab92022-03-12 17:43:52 -080099type NotesData struct {
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800100 ID uint `gorm:"primaryKey"`
101 TeamNumber int32
102 Notes string
103 GoodDriving bool
104 BadDriving bool
Filip Kujawa6f7f0b32023-03-30 13:26:08 -0700105 SolidPickup bool
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800106 SketchyPlacing bool
107 GoodDefense bool
108 BadDefense bool
109 EasilyDefended bool
Alex Perry871eab92022-03-12 17:43:52 -0800110}
111
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700112type Ranking struct {
Philipp Schradereecb8962022-06-01 21:02:42 -0700113 TeamNumber int `gorm:"primaryKey"`
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700114 Losses, Wins, Ties int32
115 Rank, Dq int32
116}
117
Filip Kujawa210a03b2022-11-24 14:41:11 -0800118type DriverRankingData struct {
119 // Each entry in the table is a single scout's ranking.
120 // Multiple scouts can submit a driver ranking for the same
121 // teams in the same match.
122 // The teams being ranked are stored in Rank1, Rank2, Rank3,
123 // Rank1 being the best driving and Rank3 being the worst driving.
124
125 ID uint `gorm:"primaryKey"`
126 MatchNumber int32
127 Rank1 int32
128 Rank2 int32
129 Rank3 int32
130}
131
Philipp Schradera8955fb2023-03-05 15:47:19 -0800132type ParsedDriverRankingData struct {
133 // This data stores the output of DriverRank.jl.
134
135 TeamNumber string `gorm:"primaryKey"`
136
137 // The score of the team. A difference of 100 in two team's scores
138 // indicates that one team will outperform the other in 90% of the
139 // matches.
140 Score float32
141}
142
Philipp Schrader7365d322022-03-06 16:40:08 -0800143// Opens a database at the specified port on localhost. We currently don't
144// support connecting to databases on other hosts.
145func NewDatabase(user string, password string, port int) (*Database, error) {
Philipp Schrader83fc2722022-03-10 21:59:20 -0800146 var err error
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800147 database := new(Database)
Philipp Schrader83fc2722022-03-10 21:59:20 -0800148
Philipp Schradereecb8962022-06-01 21:02:42 -0700149 dsn := fmt.Sprintf("host=localhost user=%s password=%s dbname=postgres port=%d sslmode=disable", user, password, port)
150 database.DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
151 Logger: logger.Default.LogMode(logger.Silent),
152 })
Philipp Schrader7365d322022-03-06 16:40:08 -0800153 if err != nil {
Philipp Schradereecb8962022-06-01 21:02:42 -0700154 database.Delete()
Philipp Schrader7365d322022-03-06 16:40:08 -0800155 return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
156 }
Philipp Schrader36df73a2022-03-17 23:27:24 -0700157
Philipp Schradera8955fb2023-03-05 15:47:19 -0800158 err = database.AutoMigrate(&TeamMatch{}, &Shift{}, &Stats{}, &Stats2023{}, &Action{}, &NotesData{}, &Ranking{}, &DriverRankingData{}, &ParsedDriverRankingData{})
Philipp Schrader83fc2722022-03-10 21:59:20 -0800159 if err != nil {
Philipp Schradereecb8962022-06-01 21:02:42 -0700160 database.Delete()
161 return nil, errors.New(fmt.Sprint("Failed to create/migrate tables: ", err))
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700162 }
163
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800164 return database, nil
165}
166
167func (database *Database) Delete() error {
Philipp Schradereecb8962022-06-01 21:02:42 -0700168 sql, err := database.DB.DB()
Philipp Schrader83fc2722022-03-10 21:59:20 -0800169 if err != nil {
Philipp Schradereecb8962022-06-01 21:02:42 -0700170 return err
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800171 }
Philipp Schradereecb8962022-06-01 21:02:42 -0700172 return sql.Close()
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800173}
174
Philipp Schradereecb8962022-06-01 21:02:42 -0700175func (database *Database) SetDebugLogLevel() {
176 database.DB.Logger = database.DB.Logger.LogMode(logger.Info)
177}
Philipp Schradercd12c952022-04-08 18:58:49 -0700178
Emily Markovabf24c9e2023-02-08 20:31:11 -0800179func (database *Database) AddToMatch(m TeamMatch) error {
Philipp Schradereecb8962022-06-01 21:02:42 -0700180 result := database.Clauses(clause.OnConflict{
181 UpdateAll: true,
182 }).Create(&m)
183 return result.Error
Philipp Schradercd12c952022-04-08 18:58:49 -0700184}
185
Milo Lina72e2002022-04-06 20:31:13 -0700186func (database *Database) AddToShift(sh Shift) error {
Philipp Schradereecb8962022-06-01 21:02:42 -0700187 result := database.Clauses(clause.OnConflict{
188 UpdateAll: true,
189 }).Create(&sh)
190 return result.Error
Milo Lina72e2002022-04-06 20:31:13 -0700191}
192
Sabina Leaver759090b2023-01-14 20:42:56 -0800193func (database *Database) AddAction(a Action) error {
194 result := database.Clauses(clause.OnConflict{
195 UpdateAll: true,
196 }).Create(&a)
197 return result.Error
198}
199
Philipp Schradercd12c952022-04-08 18:58:49 -0700200func (database *Database) AddToStats(s Stats) error {
Emily Markovab8551572023-03-22 19:49:39 -0700201 matches, err := database.queryMatches(strconv.Itoa(int(s.TeamNumber)))
Philipp Schradercd12c952022-04-08 18:58:49 -0700202 if err != nil {
203 return err
204 }
205 foundMatch := false
206 for _, match := range matches {
207 if match.MatchNumber == s.MatchNumber {
208 foundMatch = true
209 break
210 }
211 }
212 if !foundMatch {
213 return errors.New(fmt.Sprint(
214 "Failed to find team ", s.TeamNumber,
215 " in match ", s.MatchNumber, " in the schedule."))
216 }
217
Philipp Schradereecb8962022-06-01 21:02:42 -0700218 // Unpack the auto balls array.
219 s.AutoBallPickedUp1 = s.AutoBallPickedUp[0]
220 s.AutoBallPickedUp2 = s.AutoBallPickedUp[1]
221 s.AutoBallPickedUp3 = s.AutoBallPickedUp[2]
222 s.AutoBallPickedUp4 = s.AutoBallPickedUp[3]
223 s.AutoBallPickedUp5 = s.AutoBallPickedUp[4]
224 result := database.Create(&s)
225 return result.Error
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800226}
227
Sabina Leaver759090b2023-01-14 20:42:56 -0800228func (database *Database) AddToStats2023(s Stats2023) error {
229 matches, err := database.QueryMatchesString(s.TeamNumber)
230 if err != nil {
231 return err
232 }
233 foundMatch := false
234 for _, match := range matches {
235 if match.MatchNumber == s.MatchNumber {
236 foundMatch = true
237 break
238 }
239 }
240 if !foundMatch {
241 return errors.New(fmt.Sprint(
242 "Failed to find team ", s.TeamNumber,
243 " in match ", s.MatchNumber, " in the schedule."))
244 }
245
246 result := database.Create(&s)
247 return result.Error
248}
249
Emily Markova6b551e02023-02-18 17:37:40 -0800250func (database *Database) DeleteFromStats(compLevel_ string, matchNumber_ int32, setNumber_ int32, teamNumber_ string) error {
251 var stats2023 []Stats2023
252 result := database.
253 Where("comp_level = ? AND match_number = ? AND set_number = ? AND team_number = ?", compLevel_, matchNumber_, setNumber_, teamNumber_).
254 Delete(&stats2023)
255 return result.Error
256}
257
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700258func (database *Database) AddOrUpdateRankings(r Ranking) error {
Philipp Schradereecb8962022-06-01 21:02:42 -0700259 result := database.Clauses(clause.OnConflict{
260 UpdateAll: true,
261 }).Create(&r)
262 return result.Error
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700263}
264
Emily Markovabf24c9e2023-02-08 20:31:11 -0800265func (database *Database) ReturnMatches() ([]TeamMatch, error) {
266 var matches []TeamMatch
Philipp Schradereecb8962022-06-01 21:02:42 -0700267 result := database.Find(&matches)
268 return matches, result.Error
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800269}
270
Filip Kujawaf882e022022-12-14 13:14:08 -0800271func (database *Database) ReturnAllNotes() ([]NotesData, error) {
272 var notes []NotesData
273 result := database.Find(&notes)
274 return notes, result.Error
275}
276
277func (database *Database) ReturnAllDriverRankings() ([]DriverRankingData, error) {
278 var rankings []DriverRankingData
279 result := database.Find(&rankings)
280 return rankings, result.Error
281}
282
Philipp Schradera8955fb2023-03-05 15:47:19 -0800283func (database *Database) ReturnAllParsedDriverRankings() ([]ParsedDriverRankingData, error) {
284 var rankings []ParsedDriverRankingData
285 result := database.Find(&rankings)
286 return rankings, result.Error
287}
288
Milo Lina72e2002022-04-06 20:31:13 -0700289func (database *Database) ReturnAllShifts() ([]Shift, error) {
Philipp Schradereecb8962022-06-01 21:02:42 -0700290 var shifts []Shift
291 result := database.Find(&shifts)
292 return shifts, result.Error
293}
Milo Lina72e2002022-04-06 20:31:13 -0700294
Sabina Leaver759090b2023-01-14 20:42:56 -0800295func (database *Database) ReturnActions() ([]Action, error) {
296 var actions []Action
297 result := database.Find(&actions)
298 return actions, result.Error
299}
300
Philipp Schradereecb8962022-06-01 21:02:42 -0700301// Packs the stats. This really just consists of taking the individual auto
302// ball booleans and turning them into an array. The individual booleans are
303// cleared so that they don't affect struct comparisons.
304func packStats(stats *Stats) {
305 stats.AutoBallPickedUp = [5]bool{
306 stats.AutoBallPickedUp1,
307 stats.AutoBallPickedUp2,
308 stats.AutoBallPickedUp3,
309 stats.AutoBallPickedUp4,
310 stats.AutoBallPickedUp5,
Milo Lina72e2002022-04-06 20:31:13 -0700311 }
Philipp Schradereecb8962022-06-01 21:02:42 -0700312 stats.AutoBallPickedUp1 = false
313 stats.AutoBallPickedUp2 = false
314 stats.AutoBallPickedUp3 = false
315 stats.AutoBallPickedUp4 = false
316 stats.AutoBallPickedUp5 = false
Milo Lina72e2002022-04-06 20:31:13 -0700317}
318
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800319func (database *Database) ReturnStats() ([]Stats, error) {
Philipp Schradereecb8962022-06-01 21:02:42 -0700320 var stats []Stats
321 result := database.Find(&stats)
322 // Pack the auto balls array.
323 for i := range stats {
324 packStats(&stats[i])
Philipp Schrader30005e42022-03-06 13:53:58 -0800325 }
Philipp Schradereecb8962022-06-01 21:02:42 -0700326 return stats, result.Error
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800327}
328
Emily Markova6b551e02023-02-18 17:37:40 -0800329func (database *Database) ReturnStats2023() ([]Stats2023, error) {
330 var stats2023 []Stats2023
331 result := database.Find(&stats2023)
332 return stats2023, result.Error
333}
334
Philipp Schrader78dc96b2023-03-11 15:23:44 -0800335func (database *Database) ReturnStats2023ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string) ([]Stats2023, error) {
336 var stats2023 []Stats2023
337 result := database.
338 Where("team_number = ? AND match_number = ? AND set_number = ? AND comp_level = ?",
339 teamNumber, matchNumber, setNumber, compLevel).
340 Find(&stats2023)
341 return stats2023, result.Error
342}
343
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700344func (database *Database) ReturnRankings() ([]Ranking, error) {
Philipp Schradereecb8962022-06-01 21:02:42 -0700345 var rankins []Ranking
346 result := database.Find(&rankins)
347 return rankins, result.Error
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700348}
349
Emily Markovab8551572023-03-22 19:49:39 -0700350func (database *Database) queryMatches(teamNumber_ string) ([]TeamMatch, error) {
Emily Markovabf24c9e2023-02-08 20:31:11 -0800351 var matches []TeamMatch
Philipp Schradereecb8962022-06-01 21:02:42 -0700352 result := database.
Emily Markovabf24c9e2023-02-08 20:31:11 -0800353 Where("team_number = $1", teamNumber_).
Philipp Schradereecb8962022-06-01 21:02:42 -0700354 Find(&matches)
355 return matches, result.Error
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800356}
357
Emily Markovabf24c9e2023-02-08 20:31:11 -0800358func (database *Database) QueryMatchesString(teamNumber_ string) ([]TeamMatch, error) {
359 var matches []TeamMatch
Sabina Leaver759090b2023-01-14 20:42:56 -0800360 result := database.
Emily Markovabf24c9e2023-02-08 20:31:11 -0800361 Where("team_number = $1", teamNumber_).
Sabina Leaver759090b2023-01-14 20:42:56 -0800362 Find(&matches)
363 return matches, result.Error
364}
365
Milo Lina72e2002022-04-06 20:31:13 -0700366func (database *Database) QueryAllShifts(matchNumber_ int) ([]Shift, error) {
Milo Lina72e2002022-04-06 20:31:13 -0700367 var shifts []Shift
Philipp Schradereecb8962022-06-01 21:02:42 -0700368 result := database.Where("match_number = ?", matchNumber_).Find(&shifts)
369 return shifts, result.Error
Milo Lina72e2002022-04-06 20:31:13 -0700370}
371
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800372func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
Philipp Schradereecb8962022-06-01 21:02:42 -0700373 var stats []Stats
374 result := database.Where("team_number = ?", teamNumber_).Find(&stats)
375 // Pack the auto balls array.
376 for i := range stats {
377 packStats(&stats[i])
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800378 }
Philipp Schradereecb8962022-06-01 21:02:42 -0700379 return stats, result.Error
Sabina Leaverc5fd2772022-01-29 17:00:23 -0800380}
Alex Perry871eab92022-03-12 17:43:52 -0800381
Sabina Leaver759090b2023-01-14 20:42:56 -0800382func (database *Database) QueryActions(teamNumber_ int) ([]Action, error) {
383 var actions []Action
384 result := database.
385 Where("team_number = ?", teamNumber_).Find(&actions)
386 return actions, result.Error
387}
388
Philipp Schradereecb8962022-06-01 21:02:42 -0700389func (database *Database) QueryNotes(TeamNumber int32) ([]string, error) {
390 var rawNotes []NotesData
391 result := database.Where("team_number = ?", TeamNumber).Find(&rawNotes)
392 if result.Error != nil {
393 return nil, result.Error
Alex Perry871eab92022-03-12 17:43:52 -0800394 }
Alex Perry871eab92022-03-12 17:43:52 -0800395
Philipp Schradereecb8962022-06-01 21:02:42 -0700396 notes := make([]string, len(rawNotes))
397 for i := range rawNotes {
398 notes[i] = rawNotes[i].Notes
Alex Perry871eab92022-03-12 17:43:52 -0800399 }
Philipp Schradereecb8962022-06-01 21:02:42 -0700400 return notes, nil
Alex Perry871eab92022-03-12 17:43:52 -0800401}
402
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700403func (database *Database) QueryRankings(TeamNumber int) ([]Ranking, error) {
Philipp Schradereecb8962022-06-01 21:02:42 -0700404 var rankins []Ranking
405 result := database.Where("team_number = ?", TeamNumber).Find(&rankins)
406 return rankins, result.Error
Yash Chainanibcd1bb32022-04-02 17:10:24 -0700407}
408
Filip Kujawaf947cb42022-11-21 10:00:30 -0800409func (database *Database) AddNotes(data NotesData) error {
Philipp Schradereecb8962022-06-01 21:02:42 -0700410 result := database.Create(&NotesData{
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800411 TeamNumber: data.TeamNumber,
412 Notes: data.Notes,
413 GoodDriving: data.GoodDriving,
414 BadDriving: data.BadDriving,
Filip Kujawa6f7f0b32023-03-30 13:26:08 -0700415 SolidPickup: data.SolidPickup,
Filip Kujawa7ddd5652023-03-07 19:56:15 -0800416 SketchyPlacing: data.SketchyPlacing,
417 GoodDefense: data.GoodDefense,
418 BadDefense: data.BadDefense,
419 EasilyDefended: data.EasilyDefended,
Philipp Schradereecb8962022-06-01 21:02:42 -0700420 })
421 return result.Error
Alex Perry871eab92022-03-12 17:43:52 -0800422}
Filip Kujawa210a03b2022-11-24 14:41:11 -0800423
424func (database *Database) AddDriverRanking(data DriverRankingData) error {
425 result := database.Create(&DriverRankingData{
426 MatchNumber: data.MatchNumber,
427 Rank1: data.Rank1,
428 Rank2: data.Rank2,
429 Rank3: data.Rank3,
430 })
431 return result.Error
432}
433
Philipp Schradera8955fb2023-03-05 15:47:19 -0800434func (database *Database) AddParsedDriverRanking(data ParsedDriverRankingData) error {
435 result := database.Clauses(clause.OnConflict{
436 UpdateAll: true,
437 }).Create(&data)
438 return result.Error
439}
440
Filip Kujawa210a03b2022-11-24 14:41:11 -0800441func (database *Database) QueryDriverRanking(MatchNumber int) ([]DriverRankingData, error) {
442 var data []DriverRankingData
443 result := database.Where("match_number = ?", MatchNumber).Find(&data)
444 return data, result.Error
445}