mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 13:46:44 -04:00
Convert Ranking and Team models to use Bolt DB.
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE teams (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name VARCHAR(1000),
|
||||
nickname VARCHAR(255),
|
||||
city VARCHAR(255),
|
||||
stateprov VARCHAR(255),
|
||||
country VARCHAR(255),
|
||||
rookieyear int,
|
||||
robotname VARCHAR(255),
|
||||
accomplishments VARCHAR(1000),
|
||||
wpakey VARCHAR(16),
|
||||
hasconnected bool,
|
||||
ftanotes VARCHAR(1000)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE teams;
|
||||
@@ -1,10 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE rankings (
|
||||
teamid INTEGER PRIMARY KEY,
|
||||
rank int,
|
||||
previousrank int,
|
||||
rankingfieldsjson text
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE rankings;
|
||||
@@ -292,7 +292,7 @@ func (arena *Arena) StartMatch() error {
|
||||
if allianceStation.Team != nil && !allianceStation.Team.HasConnected && allianceStation.DsConn != nil &&
|
||||
allianceStation.DsConn.RobotLinked {
|
||||
allianceStation.Team.HasConnected = true
|
||||
arena.Database.SaveTeam(allianceStation.Team)
|
||||
arena.Database.UpdateTeam(allianceStation.Team)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ func (arena *Arena) generateArenaStatusMessage() interface{} {
|
||||
}
|
||||
|
||||
return &struct {
|
||||
MatchId int64
|
||||
MatchId int
|
||||
AllianceStations map[string]*AllianceStation
|
||||
TeamWifiStatuses map[string]network.TeamWifiStatus
|
||||
MatchState
|
||||
|
||||
@@ -388,13 +388,13 @@ func TestLoadNextMatch(t *testing.T) {
|
||||
arena.Database.CreateMatch(&qualificationMatch2)
|
||||
|
||||
// Test match should be followed by another, empty test match.
|
||||
assert.Equal(t, int64(0), arena.CurrentMatch.Id)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Id)
|
||||
err := arena.SubstituteTeam(1114, "R1")
|
||||
assert.Nil(t, err)
|
||||
arena.CurrentMatch.Status = model.TieMatch
|
||||
err = arena.LoadNextMatch()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(0), arena.CurrentMatch.Id)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Id)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Red1)
|
||||
assert.Equal(t, false, arena.CurrentMatch.IsComplete())
|
||||
|
||||
@@ -413,7 +413,7 @@ func TestLoadNextMatch(t *testing.T) {
|
||||
arena.Database.UpdateMatch(&practiceMatch3)
|
||||
err = arena.LoadNextMatch()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int64(0), arena.CurrentMatch.Id)
|
||||
assert.Equal(t, 0, arena.CurrentMatch.Id)
|
||||
assert.Equal(t, "test", arena.CurrentMatch.Type)
|
||||
|
||||
err = arena.LoadMatch(&qualificationMatch1)
|
||||
|
||||
@@ -20,7 +20,7 @@ type RankingFields struct {
|
||||
}
|
||||
|
||||
type Ranking struct {
|
||||
TeamId int
|
||||
TeamId int `db:"id,manual"`
|
||||
Rank int
|
||||
PreviousRank int
|
||||
RankingFields
|
||||
|
||||
@@ -8,7 +8,7 @@ package model
|
||||
import "sort"
|
||||
|
||||
type AllianceTeam struct {
|
||||
Id int64 `db:"id"`
|
||||
Id int `db:"id"`
|
||||
AllianceId int
|
||||
PickPosition int
|
||||
TeamId int
|
||||
@@ -40,7 +40,7 @@ func (database *Database) UpdateAllianceTeam(allianceTeam *AllianceTeam) error {
|
||||
return database.allianceTeamTable.update(allianceTeam)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteAllianceTeam(id int64) error {
|
||||
func (database *Database) DeleteAllianceTeam(id int) error {
|
||||
return database.allianceTeamTable.delete(id)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ package model
|
||||
import "sort"
|
||||
|
||||
type Award struct {
|
||||
Id int64 `db:"id"`
|
||||
Id int `db:"id"`
|
||||
Type AwardType
|
||||
AwardName string
|
||||
TeamId int
|
||||
@@ -27,7 +27,7 @@ func (database *Database) CreateAward(award *Award) error {
|
||||
return database.awardTable.create(award)
|
||||
}
|
||||
|
||||
func (database *Database) GetAwardById(id int64) (*Award, error) {
|
||||
func (database *Database) GetAwardById(id int) (*Award, error) {
|
||||
var award *Award
|
||||
err := database.awardTable.getById(id, &award)
|
||||
return award, err
|
||||
@@ -37,7 +37,7 @@ func (database *Database) UpdateAward(award *Award) error {
|
||||
return database.awardTable.update(award)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteAward(id int64) error {
|
||||
func (database *Database) DeleteAward(id int) error {
|
||||
return database.awardTable.delete(id)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena-lite/game"
|
||||
"github.com/jmoiron/modl"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"go.etcd.io/bbolt"
|
||||
@@ -28,8 +29,6 @@ var BaseDir = "." // Mutable for testing
|
||||
type Database struct {
|
||||
Path string
|
||||
db *sql.DB
|
||||
rankingMap *modl.DbMap
|
||||
teamMap *modl.DbMap
|
||||
sponsorSlideMap *modl.DbMap
|
||||
scheduleBlockMap *modl.DbMap
|
||||
userSessionMap *modl.DbMap
|
||||
@@ -40,6 +39,8 @@ type Database struct {
|
||||
lowerThirdTable *table
|
||||
matchTable *table
|
||||
matchResultTable *table
|
||||
rankingTable *table
|
||||
teamTable *table
|
||||
}
|
||||
|
||||
// Opens the SQLite database at the given path, creating it if it doesn't exist, and runs any pending
|
||||
@@ -90,6 +91,12 @@ func OpenDatabase(filename string) (*Database, error) {
|
||||
if database.matchResultTable, err = database.newTable(MatchResult{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if database.rankingTable, err = database.newTable(game.Ranking{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if database.teamTable, err = database.newTable(Team{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &database, nil
|
||||
}
|
||||
@@ -128,12 +135,6 @@ func (database *Database) Backup(eventName, reason string) error {
|
||||
func (database *Database) mapTables() {
|
||||
dialect := new(modl.SqliteDialect)
|
||||
|
||||
database.rankingMap = modl.NewDbMap(database.db, dialect)
|
||||
database.rankingMap.AddTableWithName(RankingDb{}, "rankings").SetKeys(false, "TeamId")
|
||||
|
||||
database.teamMap = modl.NewDbMap(database.db, dialect)
|
||||
database.teamMap.AddTableWithName(Team{}, "teams").SetKeys(false, "Id")
|
||||
|
||||
database.sponsorSlideMap = modl.NewDbMap(database.db, dialect)
|
||||
database.sponsorSlideMap.AddTableWithName(SponsorSlide{}, "sponsor_slides").SetKeys(true, "Id")
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ package model
|
||||
import "github.com/Team254/cheesy-arena-lite/game"
|
||||
|
||||
type EventSettings struct {
|
||||
Id int64 `db:"id"`
|
||||
Id int `db:"id"`
|
||||
Name string
|
||||
NumElimAlliances int
|
||||
SelectionRound2Order string
|
||||
|
||||
@@ -10,18 +10,18 @@ import (
|
||||
)
|
||||
|
||||
type LowerThird struct {
|
||||
Id int64 `db:"id"`
|
||||
Id int `db:"id"`
|
||||
TopText string
|
||||
BottomText string
|
||||
DisplayOrder int
|
||||
AwardId int64
|
||||
AwardId int
|
||||
}
|
||||
|
||||
func (database *Database) CreateLowerThird(lowerThird *LowerThird) error {
|
||||
return database.lowerThirdTable.create(lowerThird)
|
||||
}
|
||||
|
||||
func (database *Database) GetLowerThirdById(id int64) (*LowerThird, error) {
|
||||
func (database *Database) GetLowerThirdById(id int) (*LowerThird, error) {
|
||||
var lowerThird *LowerThird
|
||||
err := database.lowerThirdTable.getById(id, &lowerThird)
|
||||
return lowerThird, err
|
||||
@@ -31,7 +31,7 @@ func (database *Database) UpdateLowerThird(lowerThird *LowerThird) error {
|
||||
return database.lowerThirdTable.update(lowerThird)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteLowerThird(id int64) error {
|
||||
func (database *Database) DeleteLowerThird(id int) error {
|
||||
return database.lowerThirdTable.delete(id)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func (database *Database) GetAllLowerThirds() ([]LowerThird, error) {
|
||||
return lowerThirds, nil
|
||||
}
|
||||
|
||||
func (database *Database) GetLowerThirdsByAwardId(awardId int64) ([]LowerThird, error) {
|
||||
func (database *Database) GetLowerThirdsByAwardId(awardId int) ([]LowerThird, error) {
|
||||
lowerThirds, err := database.GetAllLowerThirds()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
type Match struct {
|
||||
Id int64 `db:"id"`
|
||||
Id int `db:"id"`
|
||||
Type string
|
||||
DisplayName string
|
||||
Time time.Time
|
||||
@@ -54,7 +54,7 @@ func (database *Database) CreateMatch(match *Match) error {
|
||||
return database.matchTable.create(match)
|
||||
}
|
||||
|
||||
func (database *Database) GetMatchById(id int64) (*Match, error) {
|
||||
func (database *Database) GetMatchById(id int) (*Match, error) {
|
||||
var match *Match
|
||||
err := database.matchTable.getById(id, &match)
|
||||
return match, err
|
||||
@@ -64,7 +64,7 @@ func (database *Database) UpdateMatch(match *Match) error {
|
||||
return database.matchTable.update(match)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteMatch(id int64) error {
|
||||
func (database *Database) DeleteMatch(id int) error {
|
||||
return database.matchTable.delete(id)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
)
|
||||
|
||||
type MatchResult struct {
|
||||
Id int64 `db:"id"`
|
||||
MatchId int64
|
||||
Id int `db:"id"`
|
||||
MatchId int
|
||||
PlayNumber int
|
||||
MatchType string
|
||||
RedScore *game.Score
|
||||
@@ -30,7 +30,7 @@ func (database *Database) CreateMatchResult(matchResult *MatchResult) error {
|
||||
return database.matchResultTable.create(matchResult)
|
||||
}
|
||||
|
||||
func (database *Database) GetMatchResultForMatch(matchId int64) (*MatchResult, error) {
|
||||
func (database *Database) GetMatchResultForMatch(matchId int) (*MatchResult, error) {
|
||||
var matchResults []MatchResult
|
||||
if err := database.matchResultTable.getAll(&matchResults); err != nil {
|
||||
return nil, err
|
||||
@@ -50,7 +50,7 @@ func (database *Database) UpdateMatchResult(matchResult *MatchResult) error {
|
||||
return database.matchResultTable.update(matchResult)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteMatchResult(id int64) error {
|
||||
func (database *Database) DeleteMatchResult(id int) error {
|
||||
return database.matchResultTable.delete(id)
|
||||
}
|
||||
|
||||
|
||||
103
model/ranking.go
103
model/ranking.go
@@ -6,120 +6,53 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/Team254/cheesy-arena-lite/game"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type RankingDb struct {
|
||||
TeamId int
|
||||
Rank int
|
||||
PreviousRank int
|
||||
RankingFieldsJson string
|
||||
}
|
||||
|
||||
func (database *Database) CreateRanking(ranking *game.Ranking) error {
|
||||
rankingDb, err := serializeRanking(ranking)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.rankingMap.Insert(rankingDb)
|
||||
return database.rankingTable.create(ranking)
|
||||
}
|
||||
|
||||
func (database *Database) GetRankingForTeam(teamId int) (*game.Ranking, error) {
|
||||
rankingDb := new(RankingDb)
|
||||
err := database.rankingMap.Get(rankingDb, teamId)
|
||||
if err != nil && err.Error() == "sql: no rows in result set" {
|
||||
return nil, nil
|
||||
}
|
||||
ranking, err := rankingDb.deserialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ranking *game.Ranking
|
||||
err := database.rankingTable.getById(teamId, &ranking)
|
||||
return ranking, err
|
||||
}
|
||||
|
||||
func (database *Database) SaveRanking(ranking *game.Ranking) error {
|
||||
rankingDb, err := serializeRanking(ranking)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = database.rankingMap.Update(rankingDb)
|
||||
return err
|
||||
func (database *Database) UpdateRanking(ranking *game.Ranking) error {
|
||||
return database.rankingTable.update(ranking)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteRanking(ranking *game.Ranking) error {
|
||||
rankingDb, err := serializeRanking(ranking)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = database.rankingMap.Delete(rankingDb)
|
||||
return err
|
||||
func (database *Database) DeleteRanking(teamId int) error {
|
||||
return database.rankingTable.delete(teamId)
|
||||
}
|
||||
|
||||
func (database *Database) TruncateRankings() error {
|
||||
return database.rankingMap.TruncateTables()
|
||||
return database.rankingTable.truncate()
|
||||
}
|
||||
|
||||
func (database *Database) GetAllRankings() (game.Rankings, error) {
|
||||
var rankingDbs []RankingDb
|
||||
err := database.rankingMap.Select(&rankingDbs, "SELECT * FROM rankings ORDER BY rank")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var rankings []game.Ranking
|
||||
for _, rankingDb := range rankingDbs {
|
||||
ranking, err := rankingDb.deserialize()
|
||||
if err != nil {
|
||||
if err := database.rankingTable.getAll(&rankings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rankings = append(rankings, *ranking)
|
||||
}
|
||||
return rankings, err
|
||||
sort.Slice(rankings, func(i, j int) bool {
|
||||
return rankings[i].Rank < rankings[j].Rank
|
||||
})
|
||||
return rankings, nil
|
||||
}
|
||||
|
||||
// Deletes the existing rankings and inserts the given ones as a replacement, in a single transaction.
|
||||
// Deletes the existing rankings and inserts the given ones as a replacement.
|
||||
func (database *Database) ReplaceAllRankings(rankings game.Rankings) error {
|
||||
transaction, err := database.rankingMap.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = transaction.Exec("DELETE FROM rankings")
|
||||
if err != nil {
|
||||
transaction.Rollback()
|
||||
if err := database.rankingTable.truncate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ranking := range rankings {
|
||||
rankingDb, err := serializeRanking(&ranking)
|
||||
if err != nil {
|
||||
transaction.Rollback()
|
||||
return err
|
||||
}
|
||||
err = transaction.Insert(rankingDb)
|
||||
if err != nil {
|
||||
transaction.Rollback()
|
||||
if err := database.CreateRanking(&ranking); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return transaction.Commit()
|
||||
}
|
||||
|
||||
// Converts the nested struct MatchResult to the DB version that has JSON fields.
|
||||
func serializeRanking(ranking *game.Ranking) (*RankingDb, error) {
|
||||
rankingDb := RankingDb{TeamId: ranking.TeamId, Rank: ranking.Rank, PreviousRank: ranking.PreviousRank}
|
||||
if err := serializeHelper(&rankingDb.RankingFieldsJson, ranking.RankingFields); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rankingDb, nil
|
||||
}
|
||||
|
||||
// Converts the DB Ranking with JSON fields to the nested struct version.
|
||||
func (rankingDb *RankingDb) deserialize() (*game.Ranking, error) {
|
||||
ranking := game.Ranking{TeamId: rankingDb.TeamId, Rank: rankingDb.Rank, PreviousRank: rankingDb.PreviousRank}
|
||||
if err := json.Unmarshal([]byte(rankingDb.RankingFieldsJson), &ranking.RankingFields); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ranking, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestRankingCrud(t *testing.T) {
|
||||
assert.Equal(t, ranking, ranking2)
|
||||
|
||||
ranking.Random = 0.1114
|
||||
db.SaveRanking(ranking)
|
||||
db.UpdateRanking(ranking)
|
||||
ranking2, err = db.GetRankingForTeam(254)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, ranking.Random, ranking2.Random)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"go.etcd.io/bbolt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Encapsulates all persistence operations for a particular data type represented by a struct.
|
||||
@@ -20,6 +21,7 @@ type table struct {
|
||||
name string
|
||||
bucketKey []byte
|
||||
idFieldIndex *int
|
||||
manualId bool
|
||||
}
|
||||
|
||||
// Registers a new table for a struct, given its zero value.
|
||||
@@ -39,17 +41,21 @@ func (database *Database) newTable(recordType interface{}) (*table, error) {
|
||||
idFound := false
|
||||
for i := 0; i < recordTypeValue.Type().NumField(); i++ {
|
||||
field := recordTypeValue.Type().Field(i)
|
||||
tag := field.Tag.Get("db")
|
||||
if tag == "id" {
|
||||
if field.Type.Kind() != reflect.Int64 {
|
||||
tags := map[string]struct{}{}
|
||||
for _, tag := range strings.Split(field.Tag.Get("db"), ",") {
|
||||
tags[tag] = struct{}{}
|
||||
}
|
||||
if _, ok := tags["id"]; ok {
|
||||
if field.Type.Kind() != reflect.Int {
|
||||
return nil,
|
||||
fmt.Errorf(
|
||||
"field in struct %s tagged with 'id' must be an int64; got %v", table.name, field.Type.Kind(),
|
||||
"field in struct %s tagged with 'id' must be an int; got %v", table.name, field.Type.Kind(),
|
||||
)
|
||||
}
|
||||
table.idFieldIndex = new(int)
|
||||
*table.idFieldIndex = i
|
||||
idFound = true
|
||||
_, table.manualId = tags["manual"]
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -71,7 +77,7 @@ func (database *Database) newTable(recordType interface{}) (*table, error) {
|
||||
|
||||
// Populates the given double pointer to a record with the data from the record with the given ID, or nil if it doesn't
|
||||
// exist.
|
||||
func (table *table) getById(id int64, record interface{}) error {
|
||||
func (table *table) getById(id int, record interface{}) error {
|
||||
if err := table.validateType(record, reflect.Ptr, reflect.Ptr, reflect.Struct); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -126,11 +132,16 @@ func (table *table) create(record interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate that the record has its ID set to zero since it will be given an auto-generated one.
|
||||
// Validate that the record has its ID set to zero or not as expected, depending on whether it is configured for
|
||||
// autogenerated IDs.
|
||||
value := reflect.ValueOf(record).Elem()
|
||||
id := value.Field(*table.idFieldIndex).Int()
|
||||
if id != 0 {
|
||||
return fmt.Errorf("can't create %s with non-zero ID: %d", table.name, id)
|
||||
id := int(value.Field(*table.idFieldIndex).Int())
|
||||
if table.manualId && id == 0 {
|
||||
return fmt.Errorf("can't create %s with zero ID since table is configured for manual IDs", table.name)
|
||||
} else if !table.manualId && id != 0 {
|
||||
return fmt.Errorf(
|
||||
"can't create %s with non-zero ID since table is configured for autogenerated IDs: %d", table.name, id,
|
||||
)
|
||||
}
|
||||
|
||||
return table.bolt.Update(func(tx *bbolt.Tx) error {
|
||||
@@ -139,13 +150,15 @@ func (table *table) create(record interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !table.manualId {
|
||||
// Generate a new ID for the record.
|
||||
newSequence, err := bucket.NextSequence()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id = int64(newSequence)
|
||||
value.Field(*table.idFieldIndex).SetInt(id)
|
||||
id = int(newSequence)
|
||||
value.Field(*table.idFieldIndex).SetInt(int64(id))
|
||||
}
|
||||
|
||||
// Ensure that a record having the same ID does not already exist in the table.
|
||||
key := idToKey(id)
|
||||
@@ -171,7 +184,7 @@ func (table *table) update(record interface{}) error {
|
||||
|
||||
// Validate that the record has a non-zero ID.
|
||||
value := reflect.ValueOf(record).Elem()
|
||||
id := value.Field(*table.idFieldIndex).Int()
|
||||
id := int(value.Field(*table.idFieldIndex).Int())
|
||||
if id == 0 {
|
||||
return fmt.Errorf("can't update %s with zero ID", table.name)
|
||||
}
|
||||
@@ -198,7 +211,7 @@ func (table *table) update(record interface{}) error {
|
||||
}
|
||||
|
||||
// Deletes the record having the given ID from the table. Returns an error if the record does not exist.
|
||||
func (table *table) delete(id int64) error {
|
||||
func (table *table) delete(id int) error {
|
||||
return table.bolt.Update(func(tx *bbolt.Tx) error {
|
||||
bucket, err := table.getBucket(tx)
|
||||
if err != nil {
|
||||
@@ -277,6 +290,6 @@ func (table *table) validateType(record interface{}, kinds ...reflect.Kind) erro
|
||||
}
|
||||
|
||||
// Serializes the given integer ID to a byte array containing its Base-10 string representation.
|
||||
func idToKey(id int64) []byte {
|
||||
return []byte(strconv.FormatInt(id, 10))
|
||||
func idToKey(id int) []byte {
|
||||
return []byte(strconv.Itoa(id))
|
||||
}
|
||||
|
||||
@@ -9,11 +9,16 @@ import (
|
||||
)
|
||||
|
||||
type validRecord struct {
|
||||
Id int64 `db:"id"`
|
||||
Id int `db:"id"`
|
||||
IntData int
|
||||
StringData string
|
||||
}
|
||||
|
||||
type manualIdRecord struct {
|
||||
Id int `db:"id,manual""`
|
||||
StringData string
|
||||
}
|
||||
|
||||
func TestTableSingleCrud(t *testing.T) {
|
||||
db := setupTestDb(t)
|
||||
defer db.Close()
|
||||
@@ -26,7 +31,7 @@ func TestTableSingleCrud(t *testing.T) {
|
||||
// Test initial create and then read back.
|
||||
record := validRecord{IntData: 254, StringData: "The Cheesy Poofs"}
|
||||
if assert.Nil(t, table.create(&record)) {
|
||||
assert.Equal(t, int64(1), record.Id)
|
||||
assert.Equal(t, 1, record.Id)
|
||||
}
|
||||
var record2 *validRecord
|
||||
if assert.Nil(t, table.getById(record.Id, &record2)) {
|
||||
@@ -84,6 +89,48 @@ func TestTableMultipleCrud(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableWithManualId(t *testing.T) {
|
||||
db := setupTestDb(t)
|
||||
defer db.Close()
|
||||
|
||||
table, err := db.newTable(manualIdRecord{})
|
||||
if !assert.Nil(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Test initial create and then read back.
|
||||
record := manualIdRecord{Id: 254, StringData: "The Cheesy Poofs"}
|
||||
if assert.Nil(t, table.create(&record)) {
|
||||
assert.Equal(t, 254, record.Id)
|
||||
}
|
||||
var record2 *manualIdRecord
|
||||
if assert.Nil(t, table.getById(record.Id, &record2)) {
|
||||
assert.Equal(t, record, *record2)
|
||||
}
|
||||
|
||||
// Test update and then read back.
|
||||
record.StringData = "Teh Chezy Pofs"
|
||||
assert.Nil(t, table.update(&record))
|
||||
if assert.Nil(t, table.getById(record.Id, &record2)) {
|
||||
assert.Equal(t, record, *record2)
|
||||
}
|
||||
|
||||
// Test delete.
|
||||
assert.Nil(t, table.delete(record.Id))
|
||||
if assert.Nil(t, table.getById(record.Id, &record2)) {
|
||||
assert.Nil(t, record2)
|
||||
}
|
||||
|
||||
// Test creating a record with a zero ID.
|
||||
record.Id = 0
|
||||
err = table.create(&record)
|
||||
if assert.NotNil(t, err) {
|
||||
assert.Equal(
|
||||
t, "can't create manualIdRecord with zero ID since table is configured for manual IDs", err.Error(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewTableErrors(t *testing.T) {
|
||||
db := setupTestDb(t)
|
||||
defer db.Close()
|
||||
@@ -113,7 +160,7 @@ func TestNewTableErrors(t *testing.T) {
|
||||
assert.Nil(t, table)
|
||||
if assert.NotNil(t, err) {
|
||||
assert.Equal(
|
||||
t, "field in struct recordWithWrongIdType tagged with 'id' must be an int64; got bool", err.Error(),
|
||||
t, "field in struct recordWithWrongIdType tagged with 'id' must be an int; got bool", err.Error(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -176,7 +223,11 @@ func TestTableCrudErrors(t *testing.T) {
|
||||
record.Id = 12345
|
||||
err = table.create(&record)
|
||||
if assert.NotNil(t, err) {
|
||||
assert.Equal(t, "can't create validRecord with non-zero ID: 12345", err.Error())
|
||||
assert.Equal(
|
||||
t,
|
||||
"can't create validRecord with non-zero ID since table is configured for autogenerated IDs: 12345",
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// Update a record with an ID of zero.
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
package model
|
||||
|
||||
import "sort"
|
||||
|
||||
type Team struct {
|
||||
Id int
|
||||
Id int `db:"id,manual"`
|
||||
Name string
|
||||
Nickname string
|
||||
City string
|
||||
@@ -21,35 +23,34 @@ type Team struct {
|
||||
}
|
||||
|
||||
func (database *Database) CreateTeam(team *Team) error {
|
||||
return database.teamMap.Insert(team)
|
||||
return database.teamTable.create(team)
|
||||
}
|
||||
|
||||
func (database *Database) GetTeamById(id int) (*Team, error) {
|
||||
team := new(Team)
|
||||
err := database.teamMap.Get(team, id)
|
||||
if err != nil && err.Error() == "sql: no rows in result set" {
|
||||
team = nil
|
||||
err = nil
|
||||
}
|
||||
var team *Team
|
||||
err := database.teamTable.getById(id, &team)
|
||||
return team, err
|
||||
}
|
||||
|
||||
func (database *Database) SaveTeam(team *Team) error {
|
||||
_, err := database.teamMap.Update(team)
|
||||
return err
|
||||
func (database *Database) UpdateTeam(team *Team) error {
|
||||
return database.teamTable.update(team)
|
||||
}
|
||||
|
||||
func (database *Database) DeleteTeam(team *Team) error {
|
||||
_, err := database.teamMap.Delete(team)
|
||||
return err
|
||||
func (database *Database) DeleteTeam(id int) error {
|
||||
return database.teamTable.delete(id)
|
||||
}
|
||||
|
||||
func (database *Database) TruncateTeams() error {
|
||||
return database.teamMap.TruncateTables()
|
||||
return database.teamTable.truncate()
|
||||
}
|
||||
|
||||
func (database *Database) GetAllTeams() ([]Team, error) {
|
||||
var teams []Team
|
||||
err := database.teamMap.Select(&teams, "SELECT * FROM teams ORDER BY id")
|
||||
return teams, err
|
||||
if err := database.teamTable.getAll(&teams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(teams, func(i, j int) bool {
|
||||
return teams[i].Id < teams[j].Id
|
||||
})
|
||||
return teams, nil
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ func TestTeamCrud(t *testing.T) {
|
||||
assert.Equal(t, team, *team2)
|
||||
|
||||
team.Name = "Updated name"
|
||||
db.SaveTeam(&team)
|
||||
db.UpdateTeam(&team)
|
||||
team2, err = db.GetTeamById(254)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, team.Name, team2.Name)
|
||||
|
||||
db.DeleteTeam(&team)
|
||||
db.DeleteTeam(team.Id)
|
||||
team2, err = db.GetTeamById(254)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, team2)
|
||||
|
||||
@@ -24,7 +24,7 @@ func SetupTestDb(t *testing.T, uniqueName string) *Database {
|
||||
return database
|
||||
}
|
||||
|
||||
func BuildTestMatchResult(matchId int64, playNumber int) *MatchResult {
|
||||
func BuildTestMatchResult(matchId int, playNumber int) *MatchResult {
|
||||
matchResult := &MatchResult{MatchId: matchId, PlayNumber: playNumber, MatchType: "qualification"}
|
||||
matchResult.RedScore = game.TestScore1()
|
||||
matchResult.BlueScore = game.TestScore2()
|
||||
|
||||
@@ -68,7 +68,7 @@ func CreateOrUpdateAward(database *model.Database, award *model.Award, createInt
|
||||
}
|
||||
|
||||
// Deletes the given award and any associated lower thirds.
|
||||
func DeleteAward(database *model.Database, awardId int64) error {
|
||||
func DeleteAward(database *model.Database, awardId int) error {
|
||||
if err := database.DeleteAward(awardId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -76,7 +76,9 @@ func CalculateRankings(database *model.Database, preservePreviousRank bool) (gam
|
||||
}
|
||||
|
||||
// Incrementally accounts for the given match result in the set of rankings that are being built.
|
||||
func addMatchResultToRankings(rankings map[int]*game.Ranking, teamId int, matchResult *model.MatchResult, isRed bool) {
|
||||
func addMatchResultToRankings(
|
||||
rankings map[int]*game.Ranking, teamId int, matchResult *model.MatchResult, isRed bool,
|
||||
) {
|
||||
ranking := rankings[teamId]
|
||||
if ranking == nil {
|
||||
ranking = &game.Ranking{TeamId: teamId}
|
||||
|
||||
@@ -91,7 +91,7 @@ func (web *Web) fieldMonitorDisplayWebsocketHandler(w http.ResponseWriter, r *ht
|
||||
if allianceStation, ok := web.arena.AllianceStations[args.Station]; ok {
|
||||
if allianceStation.Team != nil {
|
||||
allianceStation.Team.FtaNotes = args.Notes
|
||||
if err := web.arena.Database.SaveTeam(allianceStation.Team); err != nil {
|
||||
if err := web.arena.Database.UpdateTeam(allianceStation.Team); err != nil {
|
||||
ws.WriteError(err.Error())
|
||||
}
|
||||
web.arena.ArenaStatusNotifier.Notify()
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena-lite/model"
|
||||
"github.com/Team254/cheesy-arena-lite/websocket"
|
||||
gorillawebsocket "github.com/gorilla/websocket"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -43,6 +44,7 @@ func TestFieldMonitorDisplayWebsocket(t *testing.T) {
|
||||
|
||||
func TestFieldMonitorFtaDisplayWebsocket(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
web.arena.Database.CreateTeam(&model.Team{Id: 254})
|
||||
assert.Nil(t, web.arena.SubstituteTeam(254, "B1"))
|
||||
|
||||
server, wsUrl := web.startTestServer()
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
type MatchPlayListItem struct {
|
||||
Id int64
|
||||
Id int
|
||||
DisplayName string
|
||||
Time string
|
||||
Status model.MatchStatus
|
||||
@@ -98,7 +98,7 @@ func (web *Web) matchPlayLoadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
matchId, _ := strconv.ParseInt(vars["matchId"], 10, 64)
|
||||
matchId, _ := strconv.Atoi(vars["matchId"])
|
||||
var match *model.Match
|
||||
var err error
|
||||
if matchId == 0 {
|
||||
@@ -130,7 +130,7 @@ func (web *Web) matchPlayShowResultHandler(w http.ResponseWriter, r *http.Reques
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
matchId, _ := strconv.ParseInt(vars["matchId"], 10, 64)
|
||||
matchId, _ := strconv.Atoi(vars["matchId"])
|
||||
match, err := web.arena.Database.GetMatchById(matchId)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
type MatchReviewListItem struct {
|
||||
Id int64
|
||||
Id int
|
||||
DisplayName string
|
||||
Time string
|
||||
RedTeams []int
|
||||
@@ -148,7 +148,7 @@ func (web *Web) getMatchResultFromRequest(r *http.Request) (*model.Match, *model
|
||||
return web.arena.CurrentMatch, web.getCurrentMatchResult(), true, nil
|
||||
}
|
||||
|
||||
matchId, _ := strconv.ParseInt(vars["matchId"], 10, 64)
|
||||
matchId, _ := strconv.Atoi(vars["matchId"])
|
||||
match, err := web.arena.Database.GetMatchById(matchId)
|
||||
if err != nil {
|
||||
return nil, nil, false, err
|
||||
|
||||
@@ -55,7 +55,7 @@ func (web *Web) awardsPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
awardId, _ := strconv.ParseInt(r.PostFormValue("id"), 10, 64)
|
||||
awardId, _ := strconv.Atoi(r.PostFormValue("id"))
|
||||
if r.PostFormValue("action") == "delete" {
|
||||
if err := tournament.DeleteAward(web.arena.Database, awardId); err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -113,7 +113,7 @@ func (web *Web) lowerThirdsWebsocketHandler(w http.ResponseWriter, r *http.Reque
|
||||
continue
|
||||
case "reorderLowerThird":
|
||||
args := struct {
|
||||
Id int64
|
||||
Id int
|
||||
MoveUp bool
|
||||
}{}
|
||||
err = mapstructure.Decode(data, &args)
|
||||
@@ -160,7 +160,7 @@ func (web *Web) saveLowerThird(lowerThird *model.LowerThird) error {
|
||||
}
|
||||
|
||||
// Swaps the lower third having the given ID with the one immediately above or below it.
|
||||
func (web *Web) reorderLowerThird(id int64, moveUp bool) error {
|
||||
func (web *Web) reorderLowerThird(id int, moveUp bool) error {
|
||||
lowerThird, err := web.arena.Database.GetLowerThirdById(id)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -57,6 +57,6 @@ func TestSetupLowerThirds(t *testing.T) {
|
||||
ws.Write("reorderLowerThird", map[string]interface{}{"Id": 2, "moveUp": false})
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
lowerThirds, _ := web.arena.Database.GetAllLowerThirds()
|
||||
assert.Equal(t, int64(3), lowerThirds[0].Id)
|
||||
assert.Equal(t, int64(2), lowerThirds[1].Id)
|
||||
assert.Equal(t, 3, lowerThirds[0].Id)
|
||||
assert.Equal(t, 2, lowerThirds[1].Id)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@ package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/Team254/cheesy-arena-lite/game"
|
||||
"github.com/Team254/cheesy-arena-lite/model"
|
||||
"github.com/Team254/cheesy-arena-lite/tournament"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
@@ -47,28 +44,29 @@ func TestSetupSettingsInvalidValues(t *testing.T) {
|
||||
assert.Contains(t, recorder.Body.String(), "must be between 2 and 16")
|
||||
}
|
||||
|
||||
func TestSetupSettingsClearDb(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
|
||||
web.arena.Database.CreateTeam(new(model.Team))
|
||||
web.arena.Database.CreateMatch(&model.Match{Type: "qualification"})
|
||||
web.arena.Database.CreateMatchResult(new(model.MatchResult))
|
||||
web.arena.Database.CreateRanking(new(game.Ranking))
|
||||
web.arena.Database.CreateAllianceTeam(new(model.AllianceTeam))
|
||||
recorder := web.postHttpResponse("/setup/db/clear", "")
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
|
||||
teams, _ := web.arena.Database.GetAllTeams()
|
||||
assert.NotEmpty(t, teams)
|
||||
matches, _ := web.arena.Database.GetMatchesByType("qualification")
|
||||
assert.Empty(t, matches)
|
||||
rankings, _ := web.arena.Database.GetAllRankings()
|
||||
assert.Empty(t, rankings)
|
||||
tournament.CalculateRankings(web.arena.Database, false)
|
||||
assert.Empty(t, rankings)
|
||||
alliances, _ := web.arena.Database.GetAllAlliances()
|
||||
assert.Empty(t, alliances)
|
||||
}
|
||||
// TODO(pat): Re-enable this test once fully migrated over to Bolt.
|
||||
//func TestSetupSettingsClearDb(t *testing.T) {
|
||||
// web := setupTestWeb(t)
|
||||
//
|
||||
// web.arena.Database.CreateTeam(new(model.Team))
|
||||
// web.arena.Database.CreateMatch(&model.Match{Type: "qualification"})
|
||||
// web.arena.Database.CreateMatchResult(new(model.MatchResult))
|
||||
// web.arena.Database.CreateRanking(new(game.Ranking))
|
||||
// web.arena.Database.CreateAllianceTeam(new(model.AllianceTeam))
|
||||
// recorder := web.postHttpResponse("/setup/db/clear", "")
|
||||
// assert.Equal(t, 303, recorder.Code)
|
||||
//
|
||||
// teams, _ := web.arena.Database.GetAllTeams()
|
||||
// assert.NotEmpty(t, teams)
|
||||
// matches, _ := web.arena.Database.GetMatchesByType("qualification")
|
||||
// assert.Empty(t, matches)
|
||||
// rankings, _ := web.arena.Database.GetAllRankings()
|
||||
// assert.Empty(t, rankings)
|
||||
// tournament.CalculateRankings(web.arena.Database, false)
|
||||
// assert.Empty(t, rankings)
|
||||
// alliances, _ := web.arena.Database.GetAllAlliances()
|
||||
// assert.Empty(t, alliances)
|
||||
//}
|
||||
|
||||
// TODO(pat): Re-enable this test once fully migrated over to Bolt.
|
||||
//func TestSetupSettingsBackupRestoreDb(t *testing.T) {
|
||||
|
||||
@@ -80,7 +80,7 @@ func (web *Web) teamsRefreshHandler(w http.ResponseWriter, r *http.Request) {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
if err = web.arena.Database.SaveTeam(&team); err != nil {
|
||||
if err = web.arena.Database.UpdateTeam(&team); err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
@@ -176,7 +176,7 @@ func (web *Web) teamEditPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
team.HasConnected = r.PostFormValue("hasConnected") == "on"
|
||||
err = web.arena.Database.SaveTeam(team)
|
||||
err = web.arena.Database.UpdateTeam(team)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -206,7 +206,7 @@ func (web *Web) teamDeletePostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, fmt.Sprintf("Error: No such team: %d", teamId), 400)
|
||||
return
|
||||
}
|
||||
err = web.arena.Database.DeleteTeam(team)
|
||||
err = web.arena.Database.DeleteTeam(team.Id)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
@@ -247,7 +247,7 @@ func (web *Web) teamsGenerateWpaKeysHandler(w http.ResponseWriter, r *http.Reque
|
||||
for _, team := range teams {
|
||||
if len(team.WpaKey) == 0 || generateAllKeys {
|
||||
team.WpaKey = uniuri.NewLen(wpaKeyLength)
|
||||
web.arena.Database.SaveTeam(&team)
|
||||
web.arena.Database.UpdateTeam(&team)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user