Scouting app: Add "actions" to database for 2023 scouting changes
Signed-off-by: Sabina Leaver <100027607@mvla.net>
Change-Id: If37799307e6e7e41c3936d6de336d01bb20f2802
diff --git a/BUILD b/BUILD
index a568e20..413620d 100644
--- a/BUILD
+++ b/BUILD
@@ -35,6 +35,8 @@
# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/refresh_match_list_response //scouting/webserver/requests/messages:refresh_match_list_response_go_fbs
# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule //scouting/webserver/requests/messages:request_shift_schedule_go_fbs
# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response //scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs
+# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions //scouting/webserver/requests/messages:submit_actions_go_fbs
+# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response //scouting/webserver/requests/messages:submit_actions_response_go_fbs
# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule //scouting/webserver/requests/messages:submit_shift_schedule_go_fbs
# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response //scouting/webserver/requests/messages:submit_shift_schedule_response_go_fbs
# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking //scouting/webserver/requests/messages:submit_driver_ranking_go_fbs
diff --git a/scouting/db/db.go b/scouting/db/db.go
index 8a28db4..121ba52 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -66,6 +66,34 @@
CollectedBy string
}
+type Stats2023 struct {
+ TeamNumber string `gorm:"primaryKey"`
+ MatchNumber int32 `gorm:"primaryKey"`
+ SetNumber int32 `gorm:"primaryKey"`
+ CompLevel string `gorm:"primaryKey"`
+ StartingQuadrant int32
+ LowCubesAuto, MiddleCubesAuto, HighCubesAuto, CubesDroppedAuto int32
+ LowConesAuto, MiddleConesAuto, HighConesAuto, ConesDroppedAuto int32
+ LowCubes, MiddleCubes, HighCubes, CubesDropped int32
+ LowCones, MiddleCones, HighCones, ConesDropped int32
+ AvgCycle int32
+ // The username of the person who collected these statistics.
+ // "unknown" if submitted without logging in.
+ // Empty if the stats have not yet been collected.
+ CollectedBy string
+}
+
+type Action struct {
+ TeamNumber string `gorm:"primaryKey"`
+ MatchNumber int32 `gorm:"primaryKey"`
+ SetNumber int32 `gorm:"primaryKey"`
+ CompLevel string `gorm:"primaryKey"`
+ CompletedAction []byte
+ // This contains a serialized scouting.webserver.requests.ActionType flatbuffer.
+ TimeStamp int32 `gorm:"primaryKey"`
+ CollectedBy string
+}
+
type NotesData struct {
ID uint `gorm:"primaryKey"`
TeamNumber int32
@@ -113,7 +141,7 @@
return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
}
- err = database.AutoMigrate(&Match{}, &Shift{}, &Stats{}, &NotesData{}, &Ranking{}, &DriverRankingData{})
+ err = database.AutoMigrate(&Match{}, &Shift{}, &Stats{}, &Stats2023{}, &Action{}, &NotesData{}, &Ranking{}, &DriverRankingData{})
if err != nil {
database.Delete()
return nil, errors.New(fmt.Sprint("Failed to create/migrate tables: ", err))
@@ -148,6 +176,13 @@
return result.Error
}
+func (database *Database) AddAction(a Action) error {
+ result := database.Clauses(clause.OnConflict{
+ UpdateAll: true,
+ }).Create(&a)
+ return result.Error
+}
+
func (database *Database) AddToStats(s Stats) error {
matches, err := database.QueryMatches(s.TeamNumber)
if err != nil {
@@ -176,6 +211,28 @@
return result.Error
}
+func (database *Database) AddToStats2023(s Stats2023) error {
+ matches, err := database.QueryMatchesString(s.TeamNumber)
+ if err != nil {
+ return err
+ }
+ foundMatch := false
+ for _, match := range matches {
+ if match.MatchNumber == s.MatchNumber {
+ foundMatch = true
+ break
+ }
+ }
+ if !foundMatch {
+ return errors.New(fmt.Sprint(
+ "Failed to find team ", s.TeamNumber,
+ " in match ", s.MatchNumber, " in the schedule."))
+ }
+
+ result := database.Create(&s)
+ return result.Error
+}
+
func (database *Database) AddOrUpdateRankings(r Ranking) error {
result := database.Clauses(clause.OnConflict{
UpdateAll: true,
@@ -207,6 +264,12 @@
return shifts, result.Error
}
+func (database *Database) ReturnActions() ([]Action, error) {
+ var actions []Action
+ result := database.Find(&actions)
+ return actions, result.Error
+}
+
// Packs the stats. This really just consists of taking the individual auto
// ball booleans and turning them into an array. The individual booleans are
// cleared so that they don't affect struct comparisons.
@@ -249,6 +312,14 @@
return matches, result.Error
}
+func (database *Database) QueryMatchesString(teamNumber_ string) ([]Match, error) {
+ var matches []Match
+ result := database.
+ Where("r1 = $1 OR r2 = $1 OR r3 = $1 OR b1 = $1 OR b2 = $1 OR b3 = $1", teamNumber_).
+ Find(&matches)
+ return matches, result.Error
+}
+
func (database *Database) QueryAllShifts(matchNumber_ int) ([]Shift, error) {
var shifts []Shift
result := database.Where("match_number = ?", matchNumber_).Find(&shifts)
@@ -265,6 +336,13 @@
return stats, result.Error
}
+func (database *Database) QueryActions(teamNumber_ int) ([]Action, error) {
+ var actions []Action
+ result := database.
+ Where("team_number = ?", teamNumber_).Find(&actions)
+ return actions, result.Error
+}
+
func (database *Database) QueryNotes(TeamNumber int32) ([]string, error) {
var rawNotes []NotesData
result := database.Where("team_number = ?", TeamNumber).Find(&rawNotes)
diff --git a/scouting/db/db_test.go b/scouting/db/db_test.go
index 460b177..642fb6d 100644
--- a/scouting/db/db_test.go
+++ b/scouting/db/db_test.go
@@ -658,6 +658,54 @@
}
}
+func TestReturnActionsDB(t *testing.T) {
+ fixture := createDatabase(t)
+ defer fixture.TearDown()
+ correct := []Action{
+ Action{
+ TeamNumber: "1235", MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+ CompletedAction: []byte(""), TimeStamp: 0000, CollectedBy: "",
+ },
+ Action{
+ TeamNumber: "1236", MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+ CompletedAction: []byte(""), TimeStamp: 0321, CollectedBy: "",
+ },
+ Action{
+ TeamNumber: "1237", MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+ CompletedAction: []byte(""), TimeStamp: 0222, CollectedBy: "",
+ },
+ Action{
+ TeamNumber: "1238", MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+ CompletedAction: []byte(""), TimeStamp: 0110, CollectedBy: "",
+ },
+ Action{
+ TeamNumber: "1239", MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+ CompletedAction: []byte(""), TimeStamp: 0004, CollectedBy: "",
+ },
+ Action{
+ TeamNumber: "1233", MatchNumber: 94, SetNumber: 1, CompLevel: "quals",
+ CompletedAction: []byte(""), TimeStamp: 0004, CollectedBy: "",
+ },
+ }
+
+ 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")
+
+ for i := 0; i < len(correct); i++ {
+ err = fixture.db.AddAction(correct[i])
+ check(t, err, fmt.Sprint("Failed to add to actions ", i))
+ }
+
+ got, err := fixture.db.ReturnActions()
+ check(t, err, "Failed ReturnActions()")
+
+ if !reflect.DeepEqual(correct, got) {
+ t.Errorf("Got %#v,\nbut expected %#v.", got, correct)
+ }
+}
+
func TestRankingsDbUpdate(t *testing.T) {
fixture := createDatabase(t)
defer fixture.TearDown()
diff --git a/scouting/webserver/requests/BUILD b/scouting/webserver/requests/BUILD
index 53bc385..1d90a78 100644
--- a/scouting/webserver/requests/BUILD
+++ b/scouting/webserver/requests/BUILD
@@ -26,6 +26,8 @@
"//scouting/webserver/requests/messages:request_notes_for_team_response_go_fbs",
"//scouting/webserver/requests/messages:request_shift_schedule_go_fbs",
"//scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs",
+ "//scouting/webserver/requests/messages:submit_actions_go_fbs",
+ "//scouting/webserver/requests/messages:submit_actions_response_go_fbs",
"//scouting/webserver/requests/messages:submit_data_scouting_go_fbs",
"//scouting/webserver/requests/messages:submit_data_scouting_response_go_fbs",
"//scouting/webserver/requests/messages:submit_driver_ranking_go_fbs",
diff --git a/scouting/webserver/requests/messages/BUILD b/scouting/webserver/requests/messages/BUILD
index 392ee80..fcda246 100644
--- a/scouting/webserver/requests/messages/BUILD
+++ b/scouting/webserver/requests/messages/BUILD
@@ -27,6 +27,8 @@
"submit_shift_schedule_response",
"submit_driver_ranking",
"submit_driver_ranking_response",
+ "submit_actions",
+ "submit_actions_response",
)
filegroup(
diff --git a/scouting/webserver/requests/messages/request_data_scouting_response.fbs b/scouting/webserver/requests/messages/request_data_scouting_response.fbs
index 071a848..6048210 100644
--- a/scouting/webserver/requests/messages/request_data_scouting_response.fbs
+++ b/scouting/webserver/requests/messages/request_data_scouting_response.fbs
@@ -49,4 +49,4 @@
stats_list:[Stats] (id:0);
}
-root_type RequestDataScoutingResponse;
+root_type RequestDataScoutingResponse;
\ No newline at end of file
diff --git a/scouting/webserver/requests/messages/submit_actions.fbs b/scouting/webserver/requests/messages/submit_actions.fbs
new file mode 100644
index 0000000..9d9efa4
--- /dev/null
+++ b/scouting/webserver/requests/messages/submit_actions.fbs
@@ -0,0 +1,53 @@
+namespace scouting.webserver.requests;
+
+table StartMatchAction {
+ position:int (id:0);
+}
+
+enum ObjectType: short {
+ kCube,
+ kCone
+}
+
+enum ScoreLevel: short {
+ kLow,
+ kMiddle,
+ kHigh
+}
+
+table PickupObjectAction {
+ object_type:ObjectType (id:0);
+ auto:bool (id:1);
+}
+
+table PlaceObjectAction {
+ object_type:ObjectType (id:0);
+ score_level:ScoreLevel (id:1);
+ auto:bool (id:2);
+}
+
+table RobotDeathAction {
+ robot_on:bool (id:0);
+}
+
+table EndMatchAction {
+}
+
+union ActionType {
+ StartMatchAction,
+ PickupObjectAction,
+ PlaceObjectAction,
+ RobotDeathAction,
+ EndMatchAction
+}
+
+table Action {
+ timestamp:int (id:0);
+ action_taken:ActionType (id:2);
+}
+
+table SubmitActions {
+ actions_list:[Action] (id:0);
+}
+
+root_type SubmitActions;
\ No newline at end of file
diff --git a/scouting/webserver/requests/messages/submit_actions_response.fbs b/scouting/webserver/requests/messages/submit_actions_response.fbs
new file mode 100644
index 0000000..4079914
--- /dev/null
+++ b/scouting/webserver/requests/messages/submit_actions_response.fbs
@@ -0,0 +1,7 @@
+namespace scouting.webserver.requests;
+
+table SubmitActionsResponse {
+ // empty response
+}
+
+root_type SubmitActionsResponse;
\ No newline at end of file
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index a7f1a77..11fd317 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -29,6 +29,8 @@
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking"
@@ -65,6 +67,8 @@
type SubmitShiftScheduleResponseT = submit_shift_schedule_response.SubmitShiftScheduleResponseT
type SubmitDriverRanking = submit_driver_ranking.SubmitDriverRanking
type SubmitDriverRankingResponseT = submit_driver_ranking_response.SubmitDriverRankingResponseT
+type SubmitActions = submit_actions.SubmitActions
+type SubmitActionsResponseT = submit_actions_response.SubmitActionsResponseT
// The interface we expect the database abstraction to conform to.
// We use an interface here because it makes unit testing easier.