You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
website/database/sqlite.go

162 lines
3.2 KiB
Go

package database
import (
"fmt"
"log"
"os"
"path"
"time"
"git.phc.dm.unipi.it/phc/website/util"
"github.com/jmoiron/sqlx"
_ "github.com/mattn/go-sqlite3"
)
type migration struct {
Timestamp string
Filename string
}
type sqliteDB struct {
*sqlx.DB
}
func (db *sqliteDB) Migrate(migrationFolder string) error {
if _, err := db.Exec(`CREATE TABLE IF NOT EXISTS migrations(timestamp TEXT, filename TEXT)`); err != nil {
return err
}
appliedMigrations := []migration{}
if err := db.Select(&appliedMigrations, `SELECT * FROM migrations`); err != nil {
return err
}
entries, err := os.ReadDir(migrationFolder)
if err != nil {
return err
}
for i, entry := range entries {
if entry.IsDir() {
return fmt.Errorf("no dirs in migrations folder")
}
if i < len(appliedMigrations) {
if appliedMigrations[i].Filename != entry.Name() {
return fmt.Errorf("misapplied migration %q with %q", appliedMigrations[i].Filename, entry.Name())
}
log.Printf("Found applied migration %q", entry.Name())
continue
}
log.Printf("Applying new migration %q", entry.Name())
migrationPath := path.Join(migrationFolder, entry.Name())
sqlStmts, err := os.ReadFile(migrationPath)
if err != nil {
return err
}
tx, err := db.Beginx()
if err != nil {
return err
}
if _, err := tx.Exec(string(sqlStmts)); err != nil {
return err
}
if _, err := tx.Exec(`INSERT INTO migrations VALUES (?, ?)`,
time.Now().Format(time.RFC3339),
entry.Name(),
); err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
}
log.Printf("All migrations applied successfully, database up to date")
return nil
}
func (db *sqliteDB) CreateDispensa(template Dispensa) (string, error) {
template.Id = "dispensa/" + util.GenerateRandomString(15)
if _, err := db.NamedExec(`
INSERT INTO
dispense(id, title, description)
VALUES
(:id, :title, :description)
`, &template); err != nil {
return "", err
}
return template.Id, nil
}
func (db *sqliteDB) GetDispensa(id string) (Dispensa, error) {
var dispensa Dispensa
if err := db.Get(&dispensa, `SELECT * FROM dispense WHERE id = ?`, id); err != nil {
return Dispensa{}, err
}
return dispensa, nil
}
func (db *sqliteDB) AllDispense() ([]Dispensa, error) {
var dispense []Dispensa
if err := db.Select(&dispense, `SELECT * FROM dispense`); err != nil {
return nil, err
}
return dispense, nil
}
func (db *sqliteDB) UpdateDispensa(d Dispensa) error {
if _, err := db.NamedExec(`
UPDATE dispense
SET title = :title,
description = :description
WHERE id = :id
`, &d); err != nil {
return err
}
return nil
}
func (db *sqliteDB) DeleteDispensa(id string) error {
panic("TODO: Not implemented")
}
func NewSqlite3Database(filename string) (*DB, error) {
sqlDB, err := sqlx.Open("sqlite3", filename)
if err != nil {
panic(err)
}
if err := sqlDB.Ping(); err != nil {
return nil, err
}
db := &sqliteDB{sqlDB}
// in this case the type "sqliteDB" implements all the interfaces declared in "database.DB" so we can pass "db" to all the fields.
return &DB{
DBMigrate: db,
DBDispense: db,
// DBUpload: db,
// DBApprovedHashes: db,
// DBRejectedHashes: db,
// DBOther: db,
}, nil
}