Refactored, removed old remnants from v0.1.0, documentation added
This commit is contained in:
parent
a38bd4304f
commit
d290a67800
20
schema.go
20
schema.go
@ -1,3 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Package dbschema is used to keep the SQL schema up to date.
|
||||||
|
|
||||||
|
func sqlProvider(dbName string, version int) (sql []byte, found bool) {
|
||||||
|
// read an SQL file and return the contents
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrader := dbschema.NewUpgrader()
|
||||||
|
upgrader.SetSqlCallback(sqlProvider)
|
||||||
|
|
||||||
|
if err = upgrader.AddDatabase("127.0.0.1", 5432, "foo", "postgres", "password"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = upgrader.Run(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
*/
|
||||||
package dbschema
|
package dbschema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -8,6 +27,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// An upgrader verifies the schema for one or more databases and upgrades them if possible.
|
||||||
type Upgrader struct {
|
type Upgrader struct {
|
||||||
databases map[string]Database
|
databases map[string]Database
|
||||||
logCallback func(string, string)
|
logCallback func(string, string)
|
||||||
|
77
upgrader.go
77
upgrader.go
@ -1,6 +1,9 @@
|
|||||||
package dbschema
|
package dbschema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
// External
|
||||||
|
"github.com/lib/pq"
|
||||||
|
|
||||||
// Standard
|
// Standard
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -9,19 +12,49 @@ import (
|
|||||||
func defaultCallback(topic, msg string) {// {{{
|
func defaultCallback(topic, msg string) {// {{{
|
||||||
fmt.Printf("[%s] %s\n", topic, msg)
|
fmt.Printf("[%s] %s\n", topic, msg)
|
||||||
}// }}}
|
}// }}}
|
||||||
func NewUpgrader(host string, port int, dbName, user, pass string) (upgrader Upgrader, err error) {// {{{
|
|
||||||
|
// NewUpgrader creates an upgrader with an empty list of databases.
|
||||||
|
func NewUpgrader() (upgrader Upgrader) {// {{{
|
||||||
upgrader.logCallback = defaultCallback
|
upgrader.logCallback = defaultCallback
|
||||||
upgrader.databases = map[string]Database{}
|
upgrader.databases = map[string]Database{}
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
||||||
|
// SetLogCallback allows to set a callback for custom logging.
|
||||||
func (upgrader *Upgrader) SetLogCallback(callback func(string, string)) {// {{{
|
func (upgrader *Upgrader) SetLogCallback(callback func(string, string)) {// {{{
|
||||||
upgrader.logCallback = callback
|
upgrader.logCallback = callback
|
||||||
}// }}}
|
}// }}}
|
||||||
|
// SetSqlCallback is required for providing the SQL schema updates.
|
||||||
func (upgrader *Upgrader) SetSqlCallback(callback func(string, int) ([]byte, bool)) {// {{{
|
func (upgrader *Upgrader) SetSqlCallback(callback func(string, int) ([]byte, bool)) {// {{{
|
||||||
upgrader.sqlCallback = callback
|
upgrader.sqlCallback = callback
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
||||||
|
func (dbase Database) createSchemaTable() (err error) {// {{{
|
||||||
|
dbase.upgrader.logCallback("create", fmt.Sprintf("%s, _db.schema", dbase.DbName))
|
||||||
|
_, err = dbase.db.Exec(`CREATE SCHEMA "_db"`)
|
||||||
|
|
||||||
|
// Error code 42P06 "duplicate_schema" is an OK error,
|
||||||
|
// table can still be missing and created.
|
||||||
|
pqErr, _ := err.(*pq.Error)
|
||||||
|
if pqErr != nil && pqErr.Code != "42P06" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dbase.db.Exec(`
|
||||||
|
CREATE TABLE "_db"."schema" (
|
||||||
|
version int4 NOT NULL,
|
||||||
|
updated timestamp NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT schema_pk PRIMARY KEY (version)
|
||||||
|
)`,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}// }}}
|
||||||
|
func (dbase Database) appendSchemaVersion(version int) (err error) {// {{{
|
||||||
|
_, err = dbase.db.Exec(`INSERT INTO _db.schema(version) VALUES($1)`, version)
|
||||||
|
return
|
||||||
|
}// }}}
|
||||||
|
|
||||||
func (dbase Database) verifySchemaTable() (err error) {// {{{
|
func (dbase Database) verifySchemaTable() (err error) {// {{{
|
||||||
var rows *sql.Rows
|
var rows *sql.Rows
|
||||||
if rows, err = dbase.db.Query(
|
if rows, err = dbase.db.Query(
|
||||||
@ -41,37 +74,21 @@ func (dbase Database) verifySchemaTable() (err error) {// {{{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !exists {
|
if exists {
|
||||||
dbase.upgrader.logCallback("create", fmt.Sprintf("%s, _db.schema", dbase.DbName))
|
return
|
||||||
dbase.db.Exec(`CREATE SCHEMA "_db"`)
|
|
||||||
|
|
||||||
if _, err = dbase.db.Exec(`
|
|
||||||
CREATE TABLE "_db"."schema" (
|
|
||||||
version int4 NOT NULL,
|
|
||||||
updated timestamp NOT NULL DEFAULT NOW(),
|
|
||||||
|
|
||||||
CONSTRAINT schema_pk PRIMARY KEY (version)
|
|
||||||
)`,
|
|
||||||
); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
err = dbase.createSchemaTable()
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
func (dbase Database) verifySchemaEntry() (err error) {// {{{
|
func (dbase Database) verifySchemaEntry() (err error) {// {{{
|
||||||
var rows *sql.Rows
|
var version int
|
||||||
rows, err = dbase.db.Query(`SELECT version FROM _db.schema LIMIT 1`)
|
var row *sql.Row
|
||||||
if err != nil {
|
row = dbase.db.QueryRow(`SELECT version FROM _db.schema LIMIT 1`)
|
||||||
return
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
if !rows.Next() {
|
err = row.Scan(&version)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
dbase.upgrader.logCallback("initiate version", dbase.DbName)
|
dbase.upgrader.logCallback("initiate version", dbase.DbName)
|
||||||
_, err = dbase.db.Exec(`INSERT INTO _db.schema(version) VALUES(0)`)
|
err = dbase.appendSchemaVersion(0)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -94,6 +111,7 @@ func (dbase Database) version() (version int, err error) {// {{{
|
|||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
||||||
|
// AddDatabase sets a database up for the Run() function with verifying/creating the _db.schema table.
|
||||||
func (upgrader Upgrader) AddDatabase(host string, port int, dbName, user, pass string) (err error) {// {{{
|
func (upgrader Upgrader) AddDatabase(host string, port int, dbName, user, pass string) (err error) {// {{{
|
||||||
var db Database
|
var db Database
|
||||||
if db, err = newDatabase(host, port, dbName, user, pass); err != nil {
|
if db, err = newDatabase(host, port, dbName, user, pass); err != nil {
|
||||||
@ -110,6 +128,7 @@ func (upgrader Upgrader) AddDatabase(host string, port int, dbName, user, pass s
|
|||||||
err = db.verifySchemaEntry()
|
err = db.verifySchemaEntry()
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
|
// Run executes the actual schema updates until there are no more available.
|
||||||
func (upgrader Upgrader) Run() (err error) {// {{{
|
func (upgrader Upgrader) Run() (err error) {// {{{
|
||||||
var version int
|
var version int
|
||||||
|
|
||||||
@ -131,11 +150,7 @@ func (upgrader Upgrader) Run() (err error) {// {{{
|
|||||||
if _, err = dbase.db.Exec(string(sql)); err != nil {
|
if _, err = dbase.db.Exec(string(sql)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = dbase.db.Exec(`
|
if err = dbase.appendSchemaVersion(version); err != nil {
|
||||||
INSERT INTO _db.schema(version)
|
|
||||||
VALUES($1)
|
|
||||||
`, version)
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user