Change match structure in db

Change match structure so it contains information on a single team in a match rather than all matches to make querying easier

Signed-off-by: Emily Markova <emily.markova@gmail.com>
Change-Id: Id558680d0c897f356f280657be2aa4ebbd1b14d9
diff --git a/scouting/db/db.go b/scouting/db/db.go
index 8f043de..940d96e 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -3,7 +3,6 @@
 import (
 	"errors"
 	"fmt"
-
 	"gorm.io/driver/postgres"
 	"gorm.io/gorm"
 	"gorm.io/gorm/clause"
@@ -14,13 +13,13 @@
 	*gorm.DB
 }
 
-type Match struct {
-	// TODO(phil): Rework this be be one team per row.
-	// Makes queries much simpler.
-	MatchNumber            int32  `gorm:"primaryKey"`
-	SetNumber              int32  `gorm:"primaryKey"`
-	CompLevel              string `gorm:"primaryKey"`
-	R1, R2, R3, B1, B2, B3 int32
+type TeamMatch struct {
+	MatchNumber      int32  `gorm:"primaryKey"`
+	SetNumber        int32  `gorm:"primaryKey"`
+	CompLevel        string `gorm:"primaryKey"`
+	Alliance         string `gorm:"primaryKey"` // "R" or "B"
+	AlliancePosition int32  `gorm:"primaryKey"` // 1, 2, or 3
+	TeamNumber       int32
 }
 
 type Shift struct {
@@ -141,7 +140,7 @@
 		return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
 	}
 
-	err = database.AutoMigrate(&Match{}, &Shift{}, &Stats{}, &Stats2023{}, &Action{}, &NotesData{}, &Ranking{}, &DriverRankingData{})
+	err = database.AutoMigrate(&TeamMatch{}, &Shift{}, &Stats{}, &Stats2023{}, &Action{}, &NotesData{}, &Ranking{}, &DriverRankingData{})
 	if err != nil {
 		database.Delete()
 		return nil, errors.New(fmt.Sprint("Failed to create/migrate tables: ", err))
@@ -162,7 +161,7 @@
 	database.DB.Logger = database.DB.Logger.LogMode(logger.Info)
 }
 
-func (database *Database) AddToMatch(m Match) error {
+func (database *Database) AddToMatch(m TeamMatch) error {
 	result := database.Clauses(clause.OnConflict{
 		UpdateAll: true,
 	}).Create(&m)
@@ -240,8 +239,8 @@
 	return result.Error
 }
 
-func (database *Database) ReturnMatches() ([]Match, error) {
-	var matches []Match
+func (database *Database) ReturnMatches() ([]TeamMatch, error) {
+	var matches []TeamMatch
 	result := database.Find(&matches)
 	return matches, result.Error
 }
@@ -304,18 +303,18 @@
 	return rankins, result.Error
 }
 
-func (database *Database) queryMatches(teamNumber_ int32) ([]Match, error) {
-	var matches []Match
+func (database *Database) queryMatches(teamNumber_ int32) ([]TeamMatch, error) {
+	var matches []TeamMatch
 	result := database.
-		Where("r1 = $1 OR r2 = $1 OR r3 = $1 OR b1 = $1 OR b2 = $1 OR b3 = $1", teamNumber_).
+		Where("team_number = $1", teamNumber_).
 		Find(&matches)
 	return matches, result.Error
 }
 
-func (database *Database) QueryMatchesString(teamNumber_ string) ([]Match, error) {
-	var matches []Match
+func (database *Database) QueryMatchesString(teamNumber_ string) ([]TeamMatch, error) {
+	var matches []TeamMatch
 	result := database.
-		Where("r1 = $1 OR r2 = $1 OR r3 = $1 OR b1 = $1 OR b2 = $1 OR b3 = $1", teamNumber_).
+		Where("team_number = $1", teamNumber_).
 		Find(&matches)
 	return matches, result.Error
 }
diff --git a/scouting/db/db_test.go b/scouting/db/db_test.go
index 9e85651..ec5e776 100644
--- a/scouting/db/db_test.go
+++ b/scouting/db/db_test.go
@@ -71,17 +71,37 @@
 	fixture := createDatabase(t)
 	defer fixture.TearDown()
 
-	correct := []Match{
-		Match{
-			MatchNumber: 7,
-			SetNumber:   1,
-			CompLevel:   "quals",
-			R1:          9999, R2: 1000, R3: 777, B1: 0000, B2: 4321, B3: 1234,
+	correct := []TeamMatch{
+		TeamMatch{
+			MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 1, TeamNumber: 9999,
+		},
+		TeamMatch{
+			MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 2, TeamNumber: 1000,
+		},
+		TeamMatch{
+			MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 3, TeamNumber: 777,
+		},
+		TeamMatch{
+			MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 1, TeamNumber: 0000,
+		},
+		TeamMatch{
+			MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 2, TeamNumber: 4321,
+		},
+		TeamMatch{
+			MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 3, TeamNumber: 1234,
 		},
 	}
 
-	err := fixture.db.AddToMatch(correct[0])
-	check(t, err, "Failed to add match data")
+	for _, match := range correct {
+		err := fixture.db.AddToMatch(match)
+		check(t, err, "Failed to add match data")
+	}
 
 	got, err := fixture.db.ReturnMatches()
 	check(t, err, "Failed ReturnMatches()")
@@ -179,15 +199,28 @@
 			Comment: "final comment", CollectedBy: "beth",
 		},
 	}
+	matches := []TeamMatch{
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 1, TeamNumber: 1236},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 2, TeamNumber: 1001},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 3, TeamNumber: 777},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 1, TeamNumber: 1000},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 2, TeamNumber: 4321},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 3, TeamNumber: 1234},
+	}
 
-	err := fixture.db.AddToMatch(Match{
-		MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
-		R1: 1236, R2: 1001, R3: 777, B1: 1000, B2: 4321, B3: 1234,
-	})
-	check(t, err, "Failed to add match")
+	for _, match := range matches {
+		err := fixture.db.AddToMatch(match)
+		check(t, err, "Failed to add match")
+	}
 
 	for i := 0; i < len(correct); i++ {
-		err = fixture.db.AddToStats(correct[i])
+		err := fixture.db.AddToStats(correct[i])
 		check(t, err, "Failed to add stats to DB")
 	}
 
@@ -214,14 +247,28 @@
 		Comment: "this is a comment", CollectedBy: "josh",
 	}
 
-	err := fixture.db.AddToMatch(Match{
-		MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
-		R1: 1236, R2: 1001, R3: 777, B1: 1000, B2: 4321, B3: 1234,
-	})
-	check(t, err, "Failed to add match")
+	matches := []TeamMatch{
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 1, TeamNumber: 1236},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 2, TeamNumber: 1001},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 3, TeamNumber: 777},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 1, TeamNumber: 1000},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 2, TeamNumber: 4321},
+		TeamMatch{MatchNumber: 7, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 3, TeamNumber: 1234},
+	}
+
+	for _, match := range matches {
+		err := fixture.db.AddToMatch(match)
+		check(t, err, "Failed to add match")
+	}
 
 	// Add stats. This should succeed.
-	err = fixture.db.AddToStats(stats)
+	err := fixture.db.AddToStats(stats)
 	check(t, err, "Failed to add stats to DB")
 
 	// Try again. It should fail this time.
@@ -323,13 +370,28 @@
 		},
 	}
 
-	err := fixture.db.AddToMatch(Match{
-		MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
-		R1: 1235, R2: 1234, R3: 1233, B1: 1232, B2: 1231, B3: 1239})
-	check(t, err, "Failed to add match")
+	matches := []TeamMatch{
+		TeamMatch{MatchNumber: 94, SetNumber: 2, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 1, TeamNumber: 1235},
+		TeamMatch{MatchNumber: 94, SetNumber: 2, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 2, TeamNumber: 1234},
+		TeamMatch{MatchNumber: 94, SetNumber: 2, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 3, TeamNumber: 1233},
+		TeamMatch{MatchNumber: 94, SetNumber: 2, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 1, TeamNumber: 1232},
+		TeamMatch{MatchNumber: 94, SetNumber: 2, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 2, TeamNumber: 1231},
+		TeamMatch{MatchNumber: 94, SetNumber: 2, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 3, TeamNumber: 1239},
+	}
+
+	for _, match := range matches {
+		err := fixture.db.AddToMatch(match)
+		check(t, err, "Failed to add match")
+	}
 
 	for i := 0; i < len(testDatabase); i++ {
-		err = fixture.db.AddToStats(testDatabase[i])
+		err := fixture.db.AddToStats(testDatabase[i])
 		check(t, err, fmt.Sprint("Failed to add stats ", i))
 	}
 
@@ -404,27 +466,17 @@
 	fixture := createDatabase(t)
 	defer fixture.TearDown()
 
-	correct := []Match{
-		Match{
-			MatchNumber: 2, SetNumber: 1, CompLevel: "quals",
-			R1: 251, R2: 169, R3: 286, B1: 253, B2: 538, B3: 149,
-		},
-		Match{
-			MatchNumber: 3, SetNumber: 1, CompLevel: "quals",
-			R1: 147, R2: 421, R3: 538, B1: 126, B2: 448, B3: 262,
-		},
-		Match{
-			MatchNumber: 4, SetNumber: 1, CompLevel: "quals",
-			R1: 251, R2: 169, R3: 286, B1: 653, B2: 538, B3: 149,
-		},
-		Match{
-			MatchNumber: 5, SetNumber: 1, CompLevel: "quals",
-			R1: 198, R2: 1421, R3: 538, B1: 26, B2: 448, B3: 262,
-		},
-		Match{
-			MatchNumber: 6, SetNumber: 1, CompLevel: "quals",
-			R1: 251, R2: 188, R3: 286, B1: 555, B2: 538, B3: 149,
-		},
+	correct := []TeamMatch{
+		TeamMatch{
+			MatchNumber: 8, SetNumber: 1, CompLevel: "quals", Alliance: "R", AlliancePosition: 1, TeamNumber: 6835},
+		TeamMatch{
+			MatchNumber: 8, SetNumber: 1, CompLevel: "quals", Alliance: "R", AlliancePosition: 2, TeamNumber: 4834},
+		TeamMatch{
+			MatchNumber: 9, SetNumber: 1, CompLevel: "quals", Alliance: "B", AlliancePosition: 3, TeamNumber: 9824},
+		TeamMatch{
+			MatchNumber: 7, SetNumber: 2, CompLevel: "quals", Alliance: "B", AlliancePosition: 1, TeamNumber: 3732},
+		TeamMatch{
+			MatchNumber: 8, SetNumber: 1, CompLevel: "quals", Alliance: "B", AlliancePosition: 1, TeamNumber: 3732},
 	}
 
 	for i := 0; i < len(correct); i++ {
@@ -444,19 +496,13 @@
 	fixture := createDatabase(t)
 	defer fixture.TearDown()
 
-	testDatabase := []Match{
-		Match{
-			MatchNumber: 1, SetNumber: 1, CompLevel: "quals",
-			R1: 251, R2: 169, R3: 286, B1: 253, B2: 538, B3: 149,
-		},
-		Match{
-			MatchNumber: 2, SetNumber: 1, CompLevel: "quals",
-			R1: 198, R2: 135, R3: 777, B1: 999, B2: 434, B3: 698,
-		},
-		Match{
-			MatchNumber: 1, SetNumber: 1, CompLevel: "quals",
-			R1: 147, R2: 421, R3: 538, B1: 126, B2: 448, B3: 262,
-		},
+	testDatabase := []TeamMatch{
+		TeamMatch{
+			MatchNumber: 9, SetNumber: 1, CompLevel: "quals", Alliance: "B", AlliancePosition: 3, TeamNumber: 4464},
+		TeamMatch{
+			MatchNumber: 8, SetNumber: 1, CompLevel: "quals", Alliance: "R", AlliancePosition: 2, TeamNumber: 2352},
+		TeamMatch{
+			MatchNumber: 9, SetNumber: 1, CompLevel: "quals", Alliance: "B", AlliancePosition: 3, TeamNumber: 6321},
 	}
 
 	for i := 0; i < len(testDatabase); i++ {
@@ -464,15 +510,11 @@
 		check(t, err, fmt.Sprint("Failed to add match", i))
 	}
 
-	correct := []Match{
-		Match{
-			MatchNumber: 2, SetNumber: 1, CompLevel: "quals",
-			R1: 198, R2: 135, R3: 777, B1: 999, B2: 434, B3: 698,
-		},
-		Match{
-			MatchNumber: 1, SetNumber: 1, CompLevel: "quals",
-			R1: 147, R2: 421, R3: 538, B1: 126, B2: 448, B3: 262,
-		},
+	correct := []TeamMatch{
+		TeamMatch{
+			MatchNumber: 8, SetNumber: 1, CompLevel: "quals", Alliance: "R", AlliancePosition: 2, TeamNumber: 2352},
+		TeamMatch{
+			MatchNumber: 9, SetNumber: 1, CompLevel: "quals", Alliance: "B", AlliancePosition: 3, TeamNumber: 6321},
 	}
 
 	got, err := fixture.db.ReturnMatches()
@@ -605,13 +647,28 @@
 		},
 	}
 
-	err := fixture.db.AddToMatch(Match{
-		MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
-		R1: 1235, R2: 1236, R3: 1237, B1: 1238, B2: 1239, B3: 1233})
-	check(t, err, "Failed to add match")
+	matches := []TeamMatch{
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 1, TeamNumber: 1235},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 2, TeamNumber: 1236},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 3, TeamNumber: 1237},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 1, TeamNumber: 1238},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 2, TeamNumber: 1239},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 3, TeamNumber: 1233},
+	}
+
+	for _, match := range matches {
+		err := fixture.db.AddToMatch(match)
+		check(t, err, "Failed to add match")
+	}
 
 	for i := 0; i < len(correct); i++ {
-		err = fixture.db.AddToStats(correct[i])
+		err := fixture.db.AddToStats(correct[i])
 		check(t, err, fmt.Sprint("Failed to add stats ", i))
 	}
 
@@ -653,13 +710,28 @@
 		},
 	}
 
-	err := fixture.db.AddToMatch(Match{
-		MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
-		R1: 1235, R2: 1236, R3: 1237, B1: 1238, B2: 1239, B3: 1233})
-	check(t, err, "Failed to add match")
+	matches := []TeamMatch{
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 1, TeamNumber: 1235},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 2, TeamNumber: 1236},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "R", AlliancePosition: 3, TeamNumber: 1237},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 1, TeamNumber: 1238},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 2, TeamNumber: 1239},
+		TeamMatch{MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+			Alliance: "B", AlliancePosition: 3, TeamNumber: 1233},
+	}
+
+	for _, match := range matches {
+		err := fixture.db.AddToMatch(match)
+		check(t, err, "Failed to add match")
+	}
 
 	for i := 0; i < len(correct); i++ {
-		err = fixture.db.AddAction(correct[i])
+		err := fixture.db.AddAction(correct[i])
 		check(t, err, fmt.Sprint("Failed to add to actions ", i))
 	}
 
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 99b5459..1fc0ae4 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -7,6 +7,7 @@
 	"io"
 	"log"
 	"net/http"
+	"sort"
 	"strconv"
 	"strings"
 
@@ -69,10 +70,10 @@
 // The interface we expect the database abstraction to conform to.
 // We use an interface here because it makes unit testing easier.
 type Database interface {
-	AddToMatch(db.Match) error
+	AddToMatch(db.TeamMatch) error
 	AddToShift(db.Shift) error
 	AddToStats(db.Stats) error
-	ReturnMatches() ([]db.Match, error)
+	ReturnMatches() ([]db.TeamMatch, error)
 	ReturnAllNotes() ([]db.NotesData, error)
 	ReturnAllDriverRankings() ([]db.DriverRankingData, error)
 	ReturnAllShifts() ([]db.Shift, error)
@@ -212,6 +213,15 @@
 	db Database
 }
 
+func findIndexInList(list []string, comp_level string) (int, error) {
+	for index, value := range list {
+		if value == comp_level {
+			return index, nil
+		}
+	}
+	return -1, errors.New(fmt.Sprint("Failed to find comp level ", comp_level, " in list ", list))
+}
+
 func (handler requestAllMatchesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	requestBytes, err := io.ReadAll(req.Body)
 	if err != nil {
@@ -230,19 +240,123 @@
 		return
 	}
 
-	var response RequestAllMatchesResponseT
+	// Change structure of match objects in the database(1 per team) to
+	// the old match structure(1 per match) that the webserver uses.
+	type Key struct {
+		MatchNumber int32
+		SetNumber   int32
+		CompLevel   string
+	}
+
+	assembledMatches := map[Key]request_all_matches_response.MatchT{}
+
 	for _, match := range matches {
-		response.MatchList = append(response.MatchList, &request_all_matches_response.MatchT{
-			MatchNumber: match.MatchNumber,
-			SetNumber:   match.SetNumber,
-			CompLevel:   match.CompLevel,
-			R1:          match.R1,
-			R2:          match.R2,
-			R3:          match.R3,
-			B1:          match.B1,
-			B2:          match.B2,
-			B3:          match.B3,
-		})
+		key := Key{match.MatchNumber, match.SetNumber, match.CompLevel}
+		log.Println("Key : ", key)
+		entry, ok := assembledMatches[key]
+		if !ok {
+			entry = request_all_matches_response.MatchT{
+				MatchNumber: match.MatchNumber,
+				SetNumber:   match.SetNumber,
+				CompLevel:   match.CompLevel,
+			}
+		}
+		log.Println("Entry : ", entry)
+		switch match.Alliance {
+		case "R":
+			switch match.AlliancePosition {
+			case 1:
+				entry.R1 = match.TeamNumber
+			case 2:
+				entry.R2 = match.TeamNumber
+			case 3:
+				entry.R3 = match.TeamNumber
+			default:
+				respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown red position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber))))
+				return
+			}
+		case "B":
+			switch match.AlliancePosition {
+			case 1:
+				entry.B1 = match.TeamNumber
+			case 2:
+				entry.B2 = match.TeamNumber
+			case 3:
+				entry.B3 = match.TeamNumber
+			default:
+				respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown blue position ", strconv.Itoa(int(match.AlliancePosition)), " in match ", strconv.Itoa(int(match.MatchNumber))))
+				return
+			}
+		default:
+			respondWithError(w, http.StatusInternalServerError, fmt.Sprint("Unknown alliance ", match.Alliance, " in match ", strconv.Itoa(int(match.AlliancePosition))))
+			return
+		}
+		assembledMatches[key] = entry
+	}
+
+	var response RequestAllMatchesResponseT
+	for _, match := range assembledMatches {
+		copied_match := match
+		response.MatchList = append(response.MatchList, &copied_match)
+	}
+
+	var MATCH_TYPE_ORDERING = []string{"qm", "ef", "qf", "sf", "f"}
+
+	err = nil
+	sort.Slice(response.MatchList, func(i, j int) bool {
+		if err != nil {
+			return false
+		}
+		a := response.MatchList[i]
+		b := response.MatchList[j]
+
+		aMatchTypeIndex, err := findIndexInList(MATCH_TYPE_ORDERING, a.CompLevel)
+		if err != nil {
+			err = errors.New(fmt.Sprint("Comp level ", a.CompLevel, " not found in sorting list ", MATCH_TYPE_ORDERING, " : ", err))
+			return false
+		}
+		bMatchTypeIndex, err := findIndexInList(MATCH_TYPE_ORDERING, b.CompLevel)
+		if err != nil {
+			err = errors.New(fmt.Sprint("Comp level ", b.CompLevel, " not found in sorting list ", MATCH_TYPE_ORDERING, " : ", err))
+			return false
+		}
+
+		if aMatchTypeIndex < bMatchTypeIndex {
+			return true
+		}
+		if aMatchTypeIndex > bMatchTypeIndex {
+			return false
+		}
+
+		// Then sort by match number. E.g. in semi finals, all match 1 rounds
+		// are done first. Then come match 2 rounds. And then, if necessary,
+		// the match 3 rounds.
+		aMatchNumber := a.MatchNumber
+		bMatchNumber := b.MatchNumber
+		if aMatchNumber < bMatchNumber {
+			return true
+		}
+		if aMatchNumber > bMatchNumber {
+			return false
+		}
+		// Lastly, sort by set number. I.e. Semi Final 1 Match 1 happens first.
+		// Then comes Semi Final 2 Match 1. Then comes Semi Final 1 Match 2. Then
+		// Semi Final 2 Match 2.
+		aSetNumber := a.SetNumber
+		bSetNumber := b.SetNumber
+		if aSetNumber < bSetNumber {
+			return true
+		}
+		if aSetNumber > bSetNumber {
+			return false
+		}
+		return true
+	})
+
+	if err != nil {
+		// check if error happened during sorting and notify webpage if that
+		respondWithError(w, http.StatusInternalServerError, fmt.Sprint(err))
+		return
 	}
 
 	builder := flatbuffers.NewBuilder(50 * 1024)
@@ -400,22 +514,48 @@
 				"TheBlueAlliance data for match %d is malformed: %v", match.MatchNumber, err))
 			return
 		}
-		// Add the match to the database.
-		err = handler.db.AddToMatch(db.Match{
-			MatchNumber: int32(match.MatchNumber),
-			SetNumber:   int32(match.SetNumber),
-			CompLevel:   match.CompLevel,
-			R1:          red[0],
-			R2:          red[1],
-			R3:          red[2],
-			B1:          blue[0],
-			B2:          blue[1],
-			B3:          blue[2],
-		})
-		if err != nil {
-			respondWithError(w, http.StatusInternalServerError, fmt.Sprintf(
-				"Failed to add match %d to the database: %v", match.MatchNumber, err))
-			return
+
+		team_matches := []db.TeamMatch{
+			{
+				MatchNumber: int32(match.MatchNumber),
+				SetNumber:   int32(match.SetNumber), CompLevel: match.CompLevel,
+				Alliance: "R", AlliancePosition: 1, TeamNumber: red[0],
+			},
+			{
+				MatchNumber: int32(match.MatchNumber),
+				SetNumber:   int32(match.SetNumber), CompLevel: match.CompLevel,
+				Alliance: "R", AlliancePosition: 2, TeamNumber: red[1],
+			},
+			{
+				MatchNumber: int32(match.MatchNumber),
+				SetNumber:   int32(match.SetNumber), CompLevel: match.CompLevel,
+				Alliance: "R", AlliancePosition: 3, TeamNumber: red[2],
+			},
+			{
+				MatchNumber: int32(match.MatchNumber),
+				SetNumber:   int32(match.SetNumber), CompLevel: match.CompLevel,
+				Alliance: "B", AlliancePosition: 1, TeamNumber: blue[0],
+			},
+			{
+				MatchNumber: int32(match.MatchNumber),
+				SetNumber:   int32(match.SetNumber), CompLevel: match.CompLevel,
+				Alliance: "B", AlliancePosition: 2, TeamNumber: blue[1],
+			},
+			{
+				MatchNumber: int32(match.MatchNumber),
+				SetNumber:   int32(match.SetNumber), CompLevel: match.CompLevel,
+				Alliance: "B", AlliancePosition: 3, TeamNumber: blue[2],
+			},
+		}
+
+		for _, match := range team_matches {
+			// Iterate through matches to check they can be added to database.
+			err = handler.db.AddToMatch(match)
+			if err != nil {
+				respondWithError(w, http.StatusInternalServerError, fmt.Sprintf(
+					"Failed to add team %d from match %d to the database: %v", match.TeamNumber, match.MatchNumber, err))
+				return
+			}
 		}
 	}
 
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index 9775eae..de8e697 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -125,18 +125,78 @@
 // Validates that we can request the full match list.
 func TestRequestAllMatches(t *testing.T) {
 	db := MockDatabase{
-		matches: []db.Match{
+		matches: []db.TeamMatch{
 			{
 				MatchNumber: 1, SetNumber: 1, CompLevel: "qual",
-				R1: 5, R2: 42, R3: 600, B1: 971, B2: 400, B3: 200,
+				Alliance: "R", AlliancePosition: 1, TeamNumber: 5,
+			},
+			{
+				MatchNumber: 1, SetNumber: 1, CompLevel: "qual",
+				Alliance: "R", AlliancePosition: 2, TeamNumber: 42,
+			},
+			{
+				MatchNumber: 1, SetNumber: 1, CompLevel: "qual",
+				Alliance: "R", AlliancePosition: 3, TeamNumber: 600,
+			},
+			{
+				MatchNumber: 1, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 1, TeamNumber: 971,
+			},
+			{
+				MatchNumber: 1, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 2, TeamNumber: 400,
+			},
+			{
+				MatchNumber: 1, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 3, TeamNumber: 200,
 			},
 			{
 				MatchNumber: 2, SetNumber: 1, CompLevel: "qual",
-				R1: 6, R2: 43, R3: 601, B1: 972, B2: 401, B3: 201,
+				Alliance: "R", AlliancePosition: 1, TeamNumber: 6,
+			},
+			{
+				MatchNumber: 2, SetNumber: 1, CompLevel: "qual",
+				Alliance: "R", AlliancePosition: 2, TeamNumber: 43,
+			},
+			{
+				MatchNumber: 2, SetNumber: 1, CompLevel: "qual",
+				Alliance: "R", AlliancePosition: 3, TeamNumber: 601,
+			},
+			{
+				MatchNumber: 2, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 1, TeamNumber: 972,
+			},
+			{
+				MatchNumber: 2, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 2, TeamNumber: 401,
+			},
+			{
+				MatchNumber: 2, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 3, TeamNumber: 201,
 			},
 			{
 				MatchNumber: 3, SetNumber: 1, CompLevel: "qual",
-				R1: 7, R2: 44, R3: 602, B1: 973, B2: 402, B3: 202,
+				Alliance: "R", AlliancePosition: 1, TeamNumber: 7,
+			},
+			{
+				MatchNumber: 3, SetNumber: 1, CompLevel: "qual",
+				Alliance: "R", AlliancePosition: 2, TeamNumber: 44,
+			},
+			{
+				MatchNumber: 3, SetNumber: 1, CompLevel: "qual",
+				Alliance: "R", AlliancePosition: 3, TeamNumber: 602,
+			},
+			{
+				MatchNumber: 3, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 1, TeamNumber: 973,
+			},
+			{
+				MatchNumber: 3, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 2, TeamNumber: 402,
+			},
+			{
+				MatchNumber: 3, SetNumber: 1, CompLevel: "qual",
+				Alliance: "B", AlliancePosition: 3, TeamNumber: 202,
 			},
 		},
 	}
@@ -496,19 +556,33 @@
 	}
 
 	// Make sure that the data made it into the database.
-	expectedMatches := []db.Match{
+	expectedMatches := []db.TeamMatch{
 		{
-			MatchNumber: 1,
-			SetNumber:   2,
-			CompLevel:   "qual",
-			R1:          100,
-			R2:          200,
-			R3:          300,
-			B1:          101,
-			B2:          201,
-			B3:          301,
+			MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
+			Alliance: "R", AlliancePosition: 1, TeamNumber: 100,
+		},
+		{
+			MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
+			Alliance: "R", AlliancePosition: 2, TeamNumber: 200,
+		},
+		{
+			MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
+			Alliance: "R", AlliancePosition: 3, TeamNumber: 300,
+		},
+		{
+			MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
+			Alliance: "B", AlliancePosition: 1, TeamNumber: 101,
+		},
+		{
+			MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
+			Alliance: "B", AlliancePosition: 2, TeamNumber: 201,
+		},
+		{
+			MatchNumber: 1, SetNumber: 2, CompLevel: "qual",
+			Alliance: "B", AlliancePosition: 3, TeamNumber: 301,
 		},
 	}
+
 	if !reflect.DeepEqual(expectedMatches, database.matches) {
 		t.Fatal("Expected ", expectedMatches, ", but got ", database.matches)
 	}
@@ -677,14 +751,14 @@
 // needed for your tests.
 
 type MockDatabase struct {
-	matches        []db.Match
+	matches        []db.TeamMatch
 	stats          []db.Stats
 	notes          []db.NotesData
 	shiftSchedule  []db.Shift
 	driver_ranking []db.DriverRankingData
 }
 
-func (database *MockDatabase) AddToMatch(match db.Match) error {
+func (database *MockDatabase) AddToMatch(match db.TeamMatch) error {
 	database.matches = append(database.matches, match)
 	return nil
 }
@@ -694,7 +768,7 @@
 	return nil
 }
 
-func (database *MockDatabase) ReturnMatches() ([]db.Match, error) {
+func (database *MockDatabase) ReturnMatches() ([]db.TeamMatch, error) {
 	return database.matches, nil
 }