diff --git a/.gitignore b/.gitignore index 8365624..fe97be4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.o *.a *.so +cheesy-arena # Folders _obj @@ -21,3 +22,4 @@ _testmain.go *.exe *.test +*.db diff --git a/database.go b/database.go new file mode 100644 index 0000000..1669a65 --- /dev/null +++ b/database.go @@ -0,0 +1,58 @@ +// Copyright 2014 Team 254. All Rights Reserved. +// Author: pat@patfairbank.com (Patrick Fairbank) +// +// Functions for manipulating the per-event SQLite datastore. + +package main + +import ( + "bitbucket.org/liamstask/goose/lib/goose" + "database/sql" + "github.com/jmoiron/modl" + _ "github.com/mattn/go-sqlite3" +) + +const migrationsDir = "db/migrations" + +type Database struct { + path string + db *sql.DB + teamMap *modl.DbMap +} + +// Opens the SQLite database at the given path, creating it if it doesn't exist, and runs any pending +// migrations. +func OpenDatabase(path string) (*Database, error) { + // Find and run the migrations using goose. This also auto-creates the DB. + dbDriver := goose.DBDriver{"sqlite3", path, "github.com/mattn/go-sqlite3", &goose.Sqlite3Dialect{}} + dbConf := goose.DBConf{migrationsDir, "prod", dbDriver} + target, err := goose.GetMostRecentDBVersion(migrationsDir) + if err != nil { + return nil, err + } + err = goose.RunMigrations(&dbConf, migrationsDir, target) + if err != nil { + return nil, err + } + + db, err := sql.Open("sqlite3", path) + if err != nil { + return nil, err + } + database := Database{path: path, db: db} + database.mapTables() + + return &database, nil +} + +func (database *Database) Close() { + database.db.Close() +} + +// Sets up table-object associations. +func (database *Database) mapTables() { + dialect := new(modl.SqliteDialect) + + database.teamMap = modl.NewDbMap(database.db, dialect) + database.teamMap.AddTableWithName(Team{}, "teams").SetKeys(false, "Id") +} diff --git a/database_test.go b/database_test.go new file mode 100644 index 0000000..78aaa34 --- /dev/null +++ b/database_test.go @@ -0,0 +1,15 @@ +// Copyright 2014 Team 254. All Rights Reserved. +// Author: pat@patfairbank.com (Patrick Fairbank) + +package main + +import ( + "testing" +) + +func TestOpenUnreachableDatabase(t *testing.T) { + _, err := OpenDatabase("nonexistentdir/test.db") + if err == nil { + t.Errorf("Expected error not raised") + } +} diff --git a/db/migrations/20140520222523_CreateTeams.sql b/db/migrations/20140520222523_CreateTeams.sql new file mode 100644 index 0000000..87e310b --- /dev/null +++ b/db/migrations/20140520222523_CreateTeams.sql @@ -0,0 +1,14 @@ +-- +goose Up +CREATE TABLE teams ( + id INTEGER PRIMARY KEY, + name VARCHAR(255), + nickname VARCHAR(255), + city VARCHAR(255), + stateprov VARCHAR(255), + country VARCHAR(255), + rookieyear int, + robotname VARCHAR(255) +); + +-- +goose Down +DROP TABLE teams; diff --git a/main.go b/main.go new file mode 100644 index 0000000..70d206e --- /dev/null +++ b/main.go @@ -0,0 +1,19 @@ +// Copyright 2014 Team 254. All Rights Reserved. +// Author: pat@patfairbank.com (Patrick Fairbank) + +package main + +import ( + "fmt" + "log" +) + +func main() { + fmt.Println("Cheesy Arena") +} + +func checkErr(err error) { + if err != nil { + log.Fatalln("Error: ", err) + } +} diff --git a/team.go b/team.go new file mode 100644 index 0000000..9068251 --- /dev/null +++ b/team.go @@ -0,0 +1,46 @@ +// Copyright 2014 Team 254. All Rights Reserved. +// Author: pat@patfairbank.com (Patrick Fairbank) +// +// Model and datastore CRUD methods for a team at an event. + +package main + +import () + +type Team struct { + Id int + Name string + Nickname string + City string + StateProv string + Country string + RookieYear int + RobotName string +} + +func (database *Database) CreateTeam(team *Team) error { + return database.teamMap.Insert(team) +} + +func (database *Database) GetTeamById(id int) (*Team, error) { + team := new(Team) + err := database.teamMap.Get(team, id) + if err != nil { + team = nil + } + return team, err +} + +func (database *Database) SaveTeam(team *Team) error { + _, err := database.teamMap.Update(team) + return err +} + +func (database *Database) DeleteTeam(team *Team) error { + _, err := database.teamMap.Delete(team) + return err +} + +func (database *Database) TruncateTeams() error { + return database.teamMap.TruncateTables() +} diff --git a/team_test.go b/team_test.go new file mode 100644 index 0000000..cdad9c3 --- /dev/null +++ b/team_test.go @@ -0,0 +1,69 @@ +// Copyright 2014 Team 254. All Rights Reserved. +// Author: pat@patfairbank.com (Patrick Fairbank) + +package main + +import ( + "os" + "testing" +) + +const testDbPath = "test.db" + +func clearDb() { + os.Remove(testDbPath) +} + +func TestGetNonexistentTeam(t *testing.T) { + clearDb() + defer clearDb() + + db, _ := OpenDatabase(testDbPath) + defer db.Close() + team, _ := db.GetTeamById(1114) + if team != nil { + t.Errorf("Expected '%v' to be nil", team) + } +} + +func TestTeamCrud(t *testing.T) { + clearDb() + defer clearDb() + + db, _ := OpenDatabase(testDbPath) + defer db.Close() + team := Team{254, "NASA Ames Research Center", "The Cheesy Poofs", "San Jose", "CA", "USA", 1999, "Barrage"} + db.CreateTeam(&team) + team2, _ := db.GetTeamById(254) + if team != *team2 { + t.Errorf("Expected '%v', got '%v'", team, team2) + } + + team.Name = "Updated name" + db.SaveTeam(&team) + team2, _ = db.GetTeamById(254) + if team.Name != team2.Name { + t.Errorf("Expected '%v', got '%v'", team.Name, team2.Name) + } + + db.DeleteTeam(&team) + team2, _ = db.GetTeamById(254) + if team2 != nil { + t.Errorf("Expected '%v' to be nil", team2) + } +} + +func TestTruncateTeams(t *testing.T) { + clearDb() + defer clearDb() + + db, _ := OpenDatabase(testDbPath) + defer db.Close() + team := Team{254, "NASA Ames Research Center", "The Cheesy Poofs", "San Jose", "CA", "USA", 1999, "Barrage"} + db.CreateTeam(&team) + db.TruncateTeams() + team2, _ := db.GetTeamById(254) + if team2 != nil { + t.Errorf("Expected '%v' to be nil", team2) + } +}