Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
b83c7b1e17 | |||
08df526c02 | |||
95335125d3 | |||
2cb694f534 |
3 changed files with 38 additions and 20 deletions
|
@ -19,11 +19,11 @@ func newDatabase(host string, port int, dbName, user, pass string) (dbase Databa
|
||||||
|
|
||||||
func (dbase Database) sqlConnString() string {// {{{
|
func (dbase Database) sqlConnString() string {// {{{
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"postgresql://%s:%s@%s:%d/%s?sslmode=disable",
|
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
||||||
dbase.Username,
|
|
||||||
dbase.Password,
|
|
||||||
dbase.Host,
|
dbase.Host,
|
||||||
dbase.Port,
|
dbase.Port,
|
||||||
|
dbase.Username,
|
||||||
|
dbase.Password,
|
||||||
dbase.DbName,
|
dbase.DbName,
|
||||||
)
|
)
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
|
@ -29,7 +29,8 @@ import (
|
||||||
|
|
||||||
// An upgrader verifies the schema for one or more databases and upgrades them if possible.
|
// 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
|
schema string
|
||||||
|
databases map[string]Database
|
||||||
logCallback func(string, string)
|
logCallback func(string, string)
|
||||||
sqlCallback func(string, int) ([]byte, bool)
|
sqlCallback func(string, int) ([]byte, bool)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,7 @@ type Database struct {
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
|
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
upgrader *Upgrader
|
upgrader *Upgrader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
47
upgrader.go
47
upgrader.go
|
@ -14,7 +14,14 @@ func defaultCallback(topic, msg string) {// {{{
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
||||||
// NewUpgrader creates an upgrader with an empty list of databases.
|
// NewUpgrader creates an upgrader with an empty list of databases.
|
||||||
func NewUpgrader() (upgrader Upgrader) {// {{{
|
func NewUpgrader(schema ...string) (upgrader Upgrader) {// {{{
|
||||||
|
// Using a variadic function for backward compatibility.
|
||||||
|
if len(schema) > 0 {
|
||||||
|
upgrader.schema = schema[0]
|
||||||
|
} else {
|
||||||
|
upgrader.schema = "_db"
|
||||||
|
}
|
||||||
|
|
||||||
upgrader.logCallback = defaultCallback
|
upgrader.logCallback = defaultCallback
|
||||||
upgrader.databases = map[string]Database{}
|
upgrader.databases = map[string]Database{}
|
||||||
return
|
return
|
||||||
|
@ -28,10 +35,21 @@ func (upgrader *Upgrader) SetLogCallback(callback func(string, string)) {// {{{
|
||||||
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
|
||||||
}// }}}
|
}// }}}
|
||||||
|
// Version returns the current dbschema version for the given database name.
|
||||||
|
func (upgrader *Upgrader) Version(dbName string) (version int, err error) {// {{{
|
||||||
|
dbase, found := upgrader.databases[dbName]
|
||||||
|
if !found {
|
||||||
|
err = fmt.Errorf("Database %s not previously added to the upgrader", dbName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err = dbase.Version()
|
||||||
|
return
|
||||||
|
}// }}}
|
||||||
|
|
||||||
func (dbase Database) createSchemaTable() (err error) {// {{{
|
func (dbase Database) createSchemaTable() (err error) {// {{{
|
||||||
dbase.upgrader.logCallback("create", fmt.Sprintf("%s, _db.schema", dbase.DbName))
|
dbase.upgrader.logCallback("create", fmt.Sprintf("%s, %s.schema", dbase.DbName, dbase.upgrader.schema))
|
||||||
_, err = dbase.db.Exec(`CREATE SCHEMA "_db"`)
|
_, err = dbase.db.Exec(`CREATE SCHEMA "`+dbase.upgrader.schema+`"`)
|
||||||
|
|
||||||
// Error code 42P06 "duplicate_schema" is an OK error,
|
// Error code 42P06 "duplicate_schema" is an OK error,
|
||||||
// table can still be missing and created.
|
// table can still be missing and created.
|
||||||
|
@ -41,7 +59,7 @@ func (dbase Database) createSchemaTable() (err error) {// {{{
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = dbase.db.Exec(`
|
_, err = dbase.db.Exec(`
|
||||||
CREATE TABLE "_db"."schema" (
|
CREATE TABLE "`+dbase.upgrader.schema+`"."schema" (
|
||||||
version int4 NOT NULL,
|
version int4 NOT NULL,
|
||||||
updated timestamp NOT NULL DEFAULT NOW(),
|
updated timestamp NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
@ -51,7 +69,7 @@ func (dbase Database) createSchemaTable() (err error) {// {{{
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
func (dbase Database) appendSchemaVersion(version int) (err error) {// {{{
|
func (dbase Database) appendSchemaVersion(version int) (err error) {// {{{
|
||||||
_, err = dbase.db.Exec(`INSERT INTO _db.schema(version) VALUES($1)`, version)
|
_, err = dbase.db.Exec(`INSERT INTO `+dbase.upgrader.schema+`.schema(version) VALUES($1)`, version)
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
||||||
|
@ -61,7 +79,7 @@ func (dbase Database) verifySchemaTable() (err error) {// {{{
|
||||||
`SELECT EXISTS (
|
`SELECT EXISTS (
|
||||||
SELECT FROM pg_catalog.pg_class c
|
SELECT FROM pg_catalog.pg_class c
|
||||||
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||||
WHERE n.nspname = '_db'
|
WHERE n.nspname = '`+dbase.upgrader.schema+`'
|
||||||
AND c.relname = 'schema'
|
AND c.relname = 'schema'
|
||||||
)`,
|
)`,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
@ -83,7 +101,7 @@ func (dbase Database) verifySchemaTable() (err error) {// {{{
|
||||||
func (dbase Database) verifySchemaEntry() (err error) {// {{{
|
func (dbase Database) verifySchemaEntry() (err error) {// {{{
|
||||||
var version int
|
var version int
|
||||||
var row *sql.Row
|
var row *sql.Row
|
||||||
row = dbase.db.QueryRow(`SELECT version FROM _db.schema LIMIT 1`)
|
row = dbase.db.QueryRow(`SELECT version FROM `+dbase.upgrader.schema+`.schema LIMIT 1`)
|
||||||
|
|
||||||
err = row.Scan(&version)
|
err = row.Scan(&version)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
|
@ -93,10 +111,10 @@ func (dbase Database) verifySchemaEntry() (err error) {// {{{
|
||||||
|
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
func (dbase Database) version() (version int, err error) {// {{{
|
func (dbase Database) Version() (version int, err error) {// {{{
|
||||||
var rows *sql.Rows
|
var rows *sql.Rows
|
||||||
rows, err = dbase.db.Query(
|
rows, err = dbase.db.Query(
|
||||||
`SELECT version FROM _db.schema ORDER BY version DESC LIMIT 1`,
|
`SELECT version FROM `+dbase.upgrader.schema+`.schema ORDER BY version DESC LIMIT 1`,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -106,14 +124,13 @@ func (dbase Database) version() (version int, err error) {// {{{
|
||||||
if rows.Next() {
|
if rows.Next() {
|
||||||
err = rows.Scan(&version)
|
err = rows.Scan(&version)
|
||||||
} else {
|
} else {
|
||||||
err = fmt.Errorf(`Database "%s" is missing an entry in _db.schema`, dbase.DbName)
|
err = fmt.Errorf(`Database "%s" is missing an entry in `+dbase.upgrader.schema+`.schema`, dbase.DbName)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
||||||
// AddDatabase sets a database up for the Run() function with verifying/creating the _db.schema table.
|
// 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) (db Database, err error) {// {{{
|
||||||
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 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -133,11 +150,11 @@ func (upgrader Upgrader) Run() (err error) {// {{{
|
||||||
var version int
|
var version int
|
||||||
|
|
||||||
for dbName, dbase := range upgrader.databases {
|
for dbName, dbase := range upgrader.databases {
|
||||||
version, err = dbase.version()
|
version, err = dbase.Version()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
upgrader.logCallback("version", fmt.Sprintf("%s: %d", dbName, version))
|
upgrader.logCallback("version", fmt.Sprintf("%s.%s: %d", dbName, upgrader.schema, version))
|
||||||
|
|
||||||
for {
|
for {
|
||||||
version++
|
version++
|
||||||
|
@ -146,7 +163,7 @@ func (upgrader Upgrader) Run() (err error) {// {{{
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
upgrader.logCallback("exec", fmt.Sprintf("%s: %d", dbName, version))
|
upgrader.logCallback("exec", fmt.Sprintf("%s.%s: %d", dbName, upgrader.schema, version))
|
||||||
if _, err = dbase.db.Exec(string(sql)); err != nil {
|
if _, err = dbase.db.Exec(string(sql)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue