package db import ( _ "embed" "fmt" "strings" "github.com/jmoiron/sqlx" "github.com/spf13/viper" ) // srrdbSchema is the DDL of the srrdb database. Keeping it in a file lets the // schema be read and edited without touching Go code; go:embed pulls it into the // binary at build time. // //go:embed srrdb.sql var srrdbSchema string // NewSrrdb opens the separate SQLite database that holds srrdb_releases. // The driver name is read from db.ext.driver (sqlite, modernc.org/sqlite), so // the driver can be replaced in configuration without touching this file. func NewSrrdb() *sqlx.DB { driver := viper.GetString("db.ext.driver") path := viper.GetString("srrdb.database") db, err := sqlx.Connect(driver, path) if err != nil { panic("Failed to connect to the srrdb database: " + err.Error()) } if err = db.Ping(); err != nil { panic("Failed to ping the srrdb database: " + err.Error()) } if err = srrdbCreate(db); err != nil { panic("Failed to create the srrdb schema: " + err.Error()) } return db } // srrdbCreate applies the embedded DDL statement by statement. Every statement is // written to be repeatable, so an existing database is left alone: this creates // missing objects, it does not alter existing ones. // // Splitting on ";" is safe for this schema because no statement holds a semicolon // inside a literal. func srrdbCreate(db *sqlx.DB) error { for _, statement := range strings.Split(srrdbSchema, ";") { if statement = strings.TrimSpace(statement); statement == "" { continue } if _, err := db.Exec(statement); err != nil { return fmt.Errorf("apply srrdb schema statement %q: %w", statement, err) } } return nil }