db initialization
parent
75c3e67f41
commit
a7b7670d5f
|
@ -4,11 +4,13 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
@ -38,10 +40,12 @@ type Opts struct {
|
||||||
Logf func(string, ...interface{})
|
Logf func(string, ...interface{})
|
||||||
Config Config
|
Config Config
|
||||||
DB *sql.DB
|
DB *sql.DB
|
||||||
|
Reset bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var configFlag = flag.String("config", "config.yml", "A path to a config file.")
|
var configFlag = flag.String("config", "config.yml", "A path to a config file.")
|
||||||
|
var resetFlag = flag.Bool("reset", false, "reset the database. WARNING this wipes everything.")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
io := iostreams{
|
io := iostreams{
|
||||||
Err: os.Stderr,
|
Err: os.Stderr,
|
||||||
|
@ -49,6 +53,7 @@ func main() {
|
||||||
}
|
}
|
||||||
opts := &Opts{
|
opts := &Opts{
|
||||||
ConfigPath: *configFlag,
|
ConfigPath: *configFlag,
|
||||||
|
Reset: *resetFlag,
|
||||||
IO: io,
|
IO: io,
|
||||||
// TODO use real logger
|
// TODO use real logger
|
||||||
Log: func(s string) {
|
Log: func(s string) {
|
||||||
|
@ -92,7 +97,7 @@ func _main(opts *Opts) error {
|
||||||
}
|
}
|
||||||
defer teardown()
|
defer teardown()
|
||||||
|
|
||||||
err = ensureSchema(*opts, "1.0.0")
|
err = ensureSchema(*opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -108,10 +113,34 @@ func _main(opts *Opts) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureSchema(opts Opts, version string) error {
|
func ensureSchema(opts Opts) error {
|
||||||
// TODO make idempotent
|
db := opts.DB
|
||||||
// TODO actually respect version
|
|
||||||
_, err := opts.DB.Exec(schemaSQL)
|
if opts.Reset {
|
||||||
|
err := os.Remove(opts.Config.DBPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete database: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rows, err := db.Query("select version from meta")
|
||||||
|
if err == nil {
|
||||||
|
//defer rows.Close()
|
||||||
|
rows.Next()
|
||||||
|
var version string
|
||||||
|
err = rows.Scan(&version)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to check database schema version: %w", err)
|
||||||
|
} else if version == "" {
|
||||||
|
return errors.New("database is in unknown state")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(err.Error(), "no such table") {
|
||||||
|
return fmt.Errorf("got error checking database state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec(schemaSQL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to initialize database schema: %w", err)
|
return fmt.Errorf("failed to initialize database schema: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ create table meta (
|
||||||
version text -- schema version
|
version text -- schema version
|
||||||
);
|
);
|
||||||
|
|
||||||
|
insert into meta values ("1.0.0");
|
||||||
|
|
||||||
create table users (
|
create table users (
|
||||||
user_id text, -- string (uuid1)
|
user_id text, -- string (uuid1)
|
||||||
user_name text, -- string
|
user_name text, -- string
|
||||||
|
|
Loading…
Reference in New Issue