diff options
Diffstat (limited to 'src/dbx/db.go')
| -rw-r--r-- | src/dbx/db.go | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/dbx/db.go b/src/dbx/db.go new file mode 100644 index 0000000..5ee3782 --- /dev/null +++ b/src/dbx/db.go @@ -0,0 +1,144 @@ +package dbx + +import ( + "context" + "fmt" + "io/fs" + "log" + "sort" + + "git.thomasvoss.com/euro-cash.eu/pkg/atexit" + . "git.thomasvoss.com/euro-cash.eu/pkg/try" + "github.com/jmoiron/sqlx" + "github.com/mattn/go-sqlite3" +) + +var ( + db *sqlx.DB + DBName string +) + +func Init(sqlDir fs.FS) { + db = sqlx.MustConnect("sqlite3", DBName) + atexit.Register(Close) + + conn := Try2(db.Conn(context.Background())) + Try(conn.Raw(func(driverConn any) error { + return driverConn.(*sqlite3.SQLiteConn).RegisterFunc("C_", + func(s, _ string) string { + return s + }, true) + })) + conn.Close() + + Try(applyMigrations(sqlDir)) + + /* TODO: Remove debug code */ + /* Try(CreateUser(User{ + Email: "mail@thomasvoss.com", + Username: "Thomas", + Password: "69", + AdminP: true, + })) + Try(CreateUser(User{ + Email: "foo@BAR.baz", + Username: "Foobar", + Password: "420", + AdminP: false, + })) + Try2(GetMintages("ad", TypeCirc)) */ +} + +func Close() { + db.Close() +} + +func applyMigrations(dir fs.FS) error { + var latest int + migratedp := true + + err := db.QueryRow("SELECT latest FROM migration").Scan(&latest) + if err != nil { + e, ok := err.(sqlite3.Error) + /* IDK if there is a better way to do this… lol */ + if ok && e.Error() == "no such table: migration" { + migratedp = false + } else { + return err + } + } + + if !migratedp { + latest = -1 + } + + files, err := fs.ReadDir(dir, ".") + if err != nil { + return err + } + + var ( + last string + scripts []string + ) + + for _, f := range files { + if n := f.Name(); n == "last.sql" { + last = n + } else { + scripts = append(scripts, f.Name()) + } + } + + sort.Strings(scripts) + for _, f := range scripts[latest+1:] { + qry, err := fs.ReadFile(dir, f) + if err != nil { + return err + } + + tx, err := db.Begin() + if err != nil { + return err + } + + var n int + if _, err = fmt.Sscanf(f, "%d", &n); err != nil { + goto error + } + + if _, err = tx.Exec(string(qry)); err != nil { + err = fmt.Errorf("error in ‘%s’: %w", f, err) + goto error + } + + _, err = tx.Exec("UPDATE migration SET latest = ? WHERE id = 1", n) + if err != nil { + goto error + } + + if err = tx.Commit(); err != nil { + goto error + } + + log.Printf("Applied database migration ‘%s’\n", f) + continue + + error: + tx.Rollback() + return err + } + + if last != "" { + qry, err := fs.ReadFile(dir, last) + if err != nil { + return err + } + if _, err := db.Exec(string(qry)); err != nil { + return fmt.Errorf("error in ‘%s’: %w", last, err) + } + log.Printf("Ran ‘%s’\n", last) + } + + return nil +} |