blob: d666f79c0e3b38ff37493992c67c4e5b988a2f77 [file] [log] [blame]
package db
import (
"database/sql"
"errors"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
type Database struct {
*sql.DB
}
type Match struct {
MatchNumber, Round int32
CompLevel string
R1, R2, R3, B1, B2, B3 int32
// Each of these variables holds the matchID of the corresponding Stats row
r1ID, r2ID, r3ID, b1ID, b2ID, b3ID int
}
type Stats struct {
TeamNumber, MatchNumber int32
ShotsMissed, UpperGoalShots, LowerGoalShots int32
ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, PlayedDefense int32
Climbing int32
}
// Opens a database at the specified path. If the path refers to a non-existent
// file, the database will be created and initialized with empty tables.
func NewDatabase(path string) (*Database, error) {
var err error
database := new(Database)
database.DB, err = sql.Open("sqlite3", path)
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to create postgres db: ", err))
}
statement, err := database.Prepare("CREATE TABLE IF NOT EXISTS matches (" +
"id INTEGER PRIMARY KEY, " +
"MatchNumber INTEGER, " +
"Round INTEGER, " +
"CompLevel INTEGER, " +
"R1 INTEGER, " +
"R2 INTEGER, " +
"R3 INTEGER, " +
"B1 INTEGER, " +
"B2 INTEGER, " +
"B3 INTEGER, " +
"r1ID INTEGER, " +
"r2ID INTEGER, " +
"r3ID INTEGER, " +
"b1ID INTEGER, " +
"b2ID INTEGER, " +
"b3ID INTEGER)")
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to prepare matches table creation: ", err))
}
defer statement.Close()
_, err = statement.Exec()
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to create matches table: ", err))
}
statement, err = database.Prepare("CREATE TABLE IF NOT EXISTS team_match_stats (" +
"id INTEGER PRIMARY KEY, " +
"TeamNumber INTEGER, " +
"MatchNumber INTEGER, " +
"ShotsMissed INTEGER, " +
"UpperGoalShots INTEGER, " +
"LowerGoalShots INTEGER, " +
"ShotsMissedAuto INTEGER, " +
"UpperGoalAuto INTEGER, " +
"LowerGoalAuto INTEGER, " +
"PlayedDefense INTEGER, " +
"Climbing INTEGER)")
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to prepare stats table creation: ", err))
}
defer statement.Close()
_, err = statement.Exec()
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to create team_match_stats table: ", err))
}
return database, nil
}
func (database *Database) Delete() error {
statement, err := database.Prepare("DROP TABLE IF EXISTS matches")
if err != nil {
return errors.New(fmt.Sprint("Failed to prepare dropping matches table: ", err))
}
_, err = statement.Exec()
if err != nil {
return errors.New(fmt.Sprint("Failed to drop matches table: ", err))
}
statement, err = database.Prepare("DROP TABLE IF EXISTS team_match_stats")
if err != nil {
return errors.New(fmt.Sprint("Failed to prepare dropping stats table: ", err))
}
_, err = statement.Exec()
if err != nil {
return errors.New(fmt.Sprint("Failed to drop stats table: ", err))
}
return nil
}
// This function will also populate the Stats table with six empty rows every time a match is added
func (database *Database) AddToMatch(m Match) error {
statement, err := database.Prepare("INSERT INTO team_match_stats(" +
"TeamNumber, MatchNumber, " +
"ShotsMissed, UpperGoalShots, LowerGoalShots, " +
"ShotsMissedAuto, UpperGoalAuto, LowerGoalAuto, " +
"PlayedDefense, Climbing) " +
"VALUES (" +
"?, ?, " +
"?, ?, ?, " +
"?, ?, ?, " +
"?, ?)")
if err != nil {
return errors.New(fmt.Sprint("Failed to prepare insertion into stats database: ", err))
}
defer statement.Close()
var rowIds [6]int64
for i, TeamNumber := range []int32{m.R1, m.R2, m.R3, m.B1, m.B2, m.B3} {
result, err := statement.Exec(TeamNumber, m.MatchNumber, 0, 0, 0, 0, 0, 0, 0, 0)
if err != nil {
return errors.New(fmt.Sprint("Failed to insert stats: ", err))
}
rowIds[i], err = result.LastInsertId()
if err != nil {
return errors.New(fmt.Sprint("Failed to get last insert ID: ", err))
}
}
statement, err = database.Prepare("INSERT INTO matches(" +
"MatchNumber, Round, CompLevel, " +
"R1, R2, R3, B1, B2, B3, " +
"r1ID, r2ID, r3ID, b1ID, b2ID, b3ID) " +
"VALUES (" +
"?, ?, ?, " +
"?, ?, ?, ?, ?, ?, " +
"?, ?, ?, ?, ?, ?)")
if err != nil {
return errors.New(fmt.Sprint("Failed to prepare insertion into match database: ", err))
}
defer statement.Close()
_, err = statement.Exec(m.MatchNumber, m.Round, m.CompLevel,
m.R1, m.R2, m.R3, m.B1, m.B2, m.B3,
rowIds[0], rowIds[1], rowIds[2], rowIds[3], rowIds[4], rowIds[5])
if err != nil {
return errors.New(fmt.Sprint("Failed to insert into match database: ", err))
}
return nil
}
func (database *Database) AddToStats(s Stats) error {
statement, err := database.Prepare("UPDATE team_match_stats SET " +
"TeamNumber = ?, MatchNumber = ?, " +
"ShotsMissed = ?, UpperGoalShots = ?, LowerGoalShots = ?, " +
"ShotsMissedAuto = ?, UpperGoalAuto = ?, LowerGoalAuto = ?, " +
"PlayedDefense = ?, Climbing = ? " +
"WHERE MatchNumber = ? AND TeamNumber = ?")
if err != nil {
return errors.New(fmt.Sprint("Failed to prepare stats update statement: ", err))
}
defer statement.Close()
result, err := statement.Exec(s.TeamNumber, s.MatchNumber,
s.ShotsMissed, s.UpperGoalShots, s.LowerGoalShots,
s.ShotsMissedAuto, s.UpperGoalAuto, s.LowerGoalAuto,
s.PlayedDefense, s.Climbing,
s.MatchNumber, s.TeamNumber)
if err != nil {
return errors.New(fmt.Sprint("Failed to update stats database: ", err))
}
numRowsAffected, err := result.RowsAffected()
if err != nil {
return errors.New(fmt.Sprint("Failed to query rows affected: ", err))
}
if numRowsAffected == 0 {
return errors.New(fmt.Sprint(
"Failed to find team ", s.TeamNumber,
" in match ", s.MatchNumber, " in the schedule."))
}
return nil
}
func (database *Database) ReturnMatches() ([]Match, error) {
rows, err := database.Query("SELECT * FROM matches")
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to select from matches: ", err))
}
defer rows.Close()
matches := make([]Match, 0)
for rows.Next() {
var match Match
var id int
err := rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
&match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
&match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
}
matches = append(matches, match)
}
return matches, nil
}
func (database *Database) ReturnStats() ([]Stats, error) {
rows, err := database.Query("SELECT * FROM team_match_stats")
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to SELECT * FROM team_match_stats: ", err))
}
defer rows.Close()
teams := make([]Stats, 0)
for rows.Next() {
var team Stats
var id int
err = rows.Scan(&id, &team.TeamNumber, &team.MatchNumber,
&team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
&team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
&team.PlayedDefense, &team.Climbing)
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
}
teams = append(teams, team)
}
return teams, nil
}
func (database *Database) QueryMatches(teamNumber_ int32) ([]Match, error) {
rows, err := database.Query("SELECT * FROM matches WHERE "+
"R1 = ? OR R2 = ? OR R3 = ? OR B1 = ? OR B2 = ? OR B3 = ?",
teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_, teamNumber_)
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to select from matches for team: ", err))
}
defer rows.Close()
var matches []Match
for rows.Next() {
var match Match
var id int
err = rows.Scan(&id, &match.MatchNumber, &match.Round, &match.CompLevel,
&match.R1, &match.R2, &match.R3, &match.B1, &match.B2, &match.B3,
&match.r1ID, &match.r2ID, &match.r3ID, &match.b1ID, &match.b2ID, &match.b3ID)
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to scan from matches: ", err))
}
matches = append(matches, match)
}
return matches, nil
}
func (database *Database) QueryStats(teamNumber_ int) ([]Stats, error) {
rows, err := database.Query("SELECT * FROM team_match_stats WHERE TeamNumber = ?", teamNumber_)
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to select from stats: ", err))
}
defer rows.Close()
var teams []Stats
for rows.Next() {
var team Stats
var id int
err = rows.Scan(&id, &team.TeamNumber, &team.MatchNumber,
&team.ShotsMissed, &team.UpperGoalShots, &team.LowerGoalShots,
&team.ShotsMissedAuto, &team.UpperGoalAuto, &team.LowerGoalAuto,
&team.PlayedDefense, &team.Climbing)
if err != nil {
return nil, errors.New(fmt.Sprint("Failed to scan from stats: ", err))
}
teams = append(teams, team)
}
return teams, nil
}