package data import ( "database/sql" "fmt" "path/filepath" gonanoid "github.com/matoous/go-nanoid" ) type RemoteDatabase struct { Connection *sql.DB databaseDirectory string } func (db *RemoteDatabase) Initialize() error { connection, error := sql.Open("sqlite3", filepath.Join(db.databaseDirectory, "remotes.db")) if error != nil { return error } db.Connection = connection _, error = db.Connection.Exec(`PRAGMA foreign_keys = ON;`) if error != nil { return fmt.Errorf("error enabling foreign keys: %s", error) } _, error = db.Connection.Exec(` CREATE TABLE IF NOT EXISTS Remotes ( id TEXT PRIMARY KEY, title TEXT NOT NULL );`) if error != nil { return fmt.Errorf("error creating remotes table: %s", error) } _, error = db.Connection.Exec(` CREATE TABLE IF NOT EXISTS Commands ( id TEXT PRIMARY KEY, protocol TEXT, commandNumber INTEGER, device INTEGER, commandType TEXT, title TEXT );`) if error != nil { return fmt.Errorf("error creating commands table: %s", error) } _, error = db.Connection.Exec(` CREATE TABLE IF NOT EXISTS RemoteCommands ( remote_id TEXT NOT NULL, command_id TEXT NOT NULL, PRIMARY KEY (remote_id, command_id), FOREIGN KEY (remote_id) REFERENCES Remotes(id) ON DELETE CASCADE, FOREIGN KEY (command_id) REFERENCES Commands(id) ON DELETE CASCADE );`) if error != nil { return fmt.Errorf("error creating remote-commands table: %s", error) } return nil } func (db *RemoteDatabase) Close() error { return db.Connection.Close() } func (db *RemoteDatabase) CreateRemote(remote Remote) (string, error) { remoteId, err := gonanoid.Nanoid(8) if err != nil { return "", err } queryString := "INSERT INTO Remotes (id, title) VALUES (?, ?)" _, err = db.Connection.Exec(queryString, remoteId, remote.Title) if err != nil { return "", err } commandIds := []string{} for _, command := range remote.Commands { commandIds = append(commandIds, command.Id) } err = db.CreateRemoteCommands(remoteId, commandIds) if err != nil { return "", err } return remoteId, nil } func (db *RemoteDatabase) CreateRemoteCommands(remoteId string, commandIds []string) error { for _, commandId := range commandIds { queryString := "INSERT INTO RemoteCommands (remote_id, command_id) VALUES (?, ?)" _, err := db.Connection.Exec(queryString, remoteId, commandId) if err != nil { return err } } return nil } func (db *RemoteDatabase) GetRemote(remoteId string) (Remote, error) { var remote Remote queryString := "SELECT id, title FROM Remotes WHERE id = ?" row := db.Connection.QueryRow(queryString, remoteId) error := row.Scan(&remote.Id, &remote.Title) if error != nil { return Remote{}, fmt.Errorf("error scanning remote: %s", error) } commands, error := db.GetCommandsByRemoteId(remoteId) if error != nil { return Remote{}, error } remote.Commands = commands return remote, nil } func (db *RemoteDatabase) GetRemotes() ([]Remote, error) { rows, error := db.Connection.Query("SELECT id, title FROM Remotes") if error != nil { return nil, fmt.Errorf("error querying remotes: %s", error) } defer rows.Close() remotes := []Remote{} for rows.Next() { var remote Remote error = rows.Scan(&remote.Id, &remote.Title) if error != nil { return nil, fmt.Errorf("error scanning remote: %s", error) } remotes = append(remotes, remote) } return remotes, nil } func (db *RemoteDatabase) DeleteRemote(remoteId string) error { queryString := "DELETE FROM Remotes WHERE id = ?" _, error := db.Connection.Exec(queryString, remoteId) if error != nil { return fmt.Errorf("error deleting remote %s: %s", remoteId, error) } return nil } func (db *RemoteDatabase) GetCommandsByRemoteId(remoteId string) ([]Command, error) { rows, error := db.Connection.Query("SELECT id, protocol, commandNumber, device, commandType, title FROM Commands WHERE id IN (SELECT command_id FROM RemoteCommands WHERE remote_id = ?)", remoteId) if error != nil { return nil, fmt.Errorf("error querying commands for remote %s: %s", remoteId, error) } defer rows.Close() commands := []Command{} for rows.Next() { var command Command error = rows.Scan(&command.Id, &command.Protocol, &command.CommandNumber, &command.Device, &command.CommandType, &command.Title) if error != nil { return nil, fmt.Errorf("error scanning command: %s", error) } commands = append(commands, command) } return commands, nil } func (db *RemoteDatabase) CreateCommand(command Command) (string, error) { commandId, err := gonanoid.Nanoid(8) if err != nil { return "", err } queryString := "INSERT INTO Commands (id, protocol, commandNumber, device, commandType, title) VALUES (?, ?, ?, ?, ?, ?)" _, err = db.Connection.Exec(queryString, commandId, command.Protocol, command.CommandNumber, command.Device, command.CommandType, command.Title) if err != nil { return "", err } return commandId, nil } func (db *RemoteDatabase) CreateCommands(commands []Command) error { for _, command := range commands { _, err := db.CreateCommand(command) if err != nil { return err } } return nil } func (db *RemoteDatabase) GetCommands() ([]Command, error) { rows, error := db.Connection.Query("SELECT id, protocol, commandNumber, device, commandType, title FROM Commands") if error != nil { return nil, fmt.Errorf("error querying commands: %s", error) } defer rows.Close() commands := []Command{} for rows.Next() { var command Command error = rows.Scan(&command.Id, &command.Protocol, &command.CommandNumber, &command.Device, &command.CommandType, &command.Title) if error != nil { return nil, fmt.Errorf("error scanning command: %s", error) } commands = append(commands, command) } return commands, nil } func (db *RemoteDatabase) UpdateCommand(command Command) error { queryString := "UPDATE Commands SET protocol = ?, commandNumber = ?, device = ?, commandType = ?, title = ? WHERE id = ?" _, error := db.Connection.Exec(queryString, command.Protocol, command.CommandNumber, command.Device, command.CommandType, command.Title, command.Id) if error != nil { return fmt.Errorf("error updating command %s: %s", command.Id, error) } return nil } func (db *RemoteDatabase) DeleteCommand(commandId string) error { queryString := "DELETE FROM Commands WHERE id = ?" _, error := db.Connection.Exec(queryString, commandId) if error != nil { return fmt.Errorf("error deleting command %s: %s", commandId, error) } return nil } func (db *RemoteDatabase) SetDirectory(directory string) { db.databaseDirectory = directory }