package database import ( "os" "github.com/jmoiron/sqlx" _ "github.com/mattn/go-sqlite3" ) // This struct is a wrapper type that holds the database connection // Internally DB holds a connection pool, so it's safe for concurrent use type Db struct { *sqlx.DB } const userInsert = "INSERT INTO users (username, password) VALUES (?, ?)" const projectInsert = "INSERT INTO projects (name, description, user_id) SELECT ?, ?, id FROM users WHERE username = ?" // DbConnect connects to the database func DbConnect() *Db { // Check for the environment variable dbpath := os.Getenv("SQLITE_DB_PATH") // Default to something reasonable if dbpath == "" { // This should obviously not be like this dbpath = "../../db.sqlite3" // This is disaster waiting to happen // WARNING // If the file doesn't exist, panic if _, err := os.Stat(dbpath); os.IsNotExist(err) { panic("Database file does not exist: " + dbpath) } } // Open the database db, err := sqlx.Connect("sqlite3", dbpath) if err != nil { panic(err) } // Ping forces the connection to be established err = db.Ping() if err != nil { panic(err) } return &Db{db} } // AddUser adds a user to the database func (d *Db) AddUser(username string, password string) error { _, err := d.Exec(userInsert, username, password) return err } // Removes a user from the database func (d *Db) RemoveUser(username string) error { _, err := d.Exec("DELETE FROM users WHERE username = ?", username) return err } func (d *Db) GetUserId(username string) (int, error) { var id int err := d.Get(&id, "SELECT id FROM users WHERE username = ?", username) return id, err } // Creates a new project in the database, associated with a user func (d *Db) AddProject(name string, description string, username string) error { _, err := d.Exec(projectInsert, name, description, username) return err }