mirror of
https://github.com/TECHNOFAB11/dbmate.git
synced 2026-02-02 17:35:08 +01:00
Add Up command to create database and migrate
This commit is contained in:
parent
1c4cf2c122
commit
164ec81370
5 changed files with 125 additions and 31 deletions
26
commands.go
26
commands.go
|
|
@ -14,6 +14,32 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UpCommand creates the database (if necessary) and runs migrations
|
||||||
|
func UpCommand(ctx *cli.Context) error {
|
||||||
|
u, err := GetDatabaseURL(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
drv, err := driver.Get(u.Scheme)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create database if it does not already exist
|
||||||
|
// skip this step if we cannot determine status
|
||||||
|
// (e.g. user does not have list database permission)
|
||||||
|
exists, err := drv.DatabaseExists(u)
|
||||||
|
if err == nil && !exists {
|
||||||
|
if err := drv.CreateDatabase(u); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// migrate
|
||||||
|
return MigrateCommand(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateCommand creates the current database
|
// CreateCommand creates the current database
|
||||||
func CreateCommand(ctx *cli.Context) error {
|
func CreateCommand(ctx *cli.Context) error {
|
||||||
u, err := GetDatabaseURL(ctx)
|
u, err := GetDatabaseURL(ctx)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
// Driver provides top level database functions
|
// Driver provides top level database functions
|
||||||
type Driver interface {
|
type Driver interface {
|
||||||
Open(*url.URL) (*sql.DB, error)
|
Open(*url.URL) (*sql.DB, error)
|
||||||
|
DatabaseExists(*url.URL) (bool, error)
|
||||||
CreateDatabase(*url.URL) error
|
CreateDatabase(*url.URL) error
|
||||||
DropDatabase(*url.URL) error
|
DropDatabase(*url.URL) error
|
||||||
CreateMigrationsTable(*sql.DB) error
|
CreateMigrationsTable(*sql.DB) error
|
||||||
|
|
|
||||||
|
|
@ -18,39 +18,66 @@ func (postgres Driver) Open(u *url.URL) (*sql.DB, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// postgresExec runs a sql statement on the "postgres" database
|
// postgresExec runs a sql statement on the "postgres" database
|
||||||
func (postgres Driver) postgresExec(u *url.URL, statement string) error {
|
func (postgres Driver) openPostgresDB(u *url.URL) (*sql.DB, error) {
|
||||||
// connect to postgres database
|
// connect to postgres database
|
||||||
postgresURL := *u
|
postgresURL := *u
|
||||||
postgresURL.Path = "postgres"
|
postgresURL.Path = "postgres"
|
||||||
|
|
||||||
db, err := postgres.Open(&postgresURL)
|
return postgres.Open(&postgresURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDatabase creates the specified database
|
||||||
|
func (postgres Driver) CreateDatabase(u *url.URL) error {
|
||||||
|
name := shared.DatabaseName(u)
|
||||||
|
fmt.Printf("Creating: %s\n", name)
|
||||||
|
|
||||||
|
db, err := postgres.openPostgresDB(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// run statement
|
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s",
|
||||||
_, err = db.Exec(statement)
|
pq.QuoteIdentifier(name)))
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateDatabase creates the specified database
|
|
||||||
func (postgres Driver) CreateDatabase(u *url.URL) error {
|
|
||||||
database := shared.DatabaseName(u)
|
|
||||||
fmt.Printf("Creating: %s\n", database)
|
|
||||||
|
|
||||||
return postgres.postgresExec(u, fmt.Sprintf("CREATE DATABASE %s",
|
|
||||||
pq.QuoteIdentifier(database)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DropDatabase drops the specified database (if it exists)
|
// DropDatabase drops the specified database (if it exists)
|
||||||
func (postgres Driver) DropDatabase(u *url.URL) error {
|
func (postgres Driver) DropDatabase(u *url.URL) error {
|
||||||
database := shared.DatabaseName(u)
|
name := shared.DatabaseName(u)
|
||||||
fmt.Printf("Dropping: %s\n", database)
|
fmt.Printf("Dropping: %s\n", name)
|
||||||
|
|
||||||
return postgres.postgresExec(u, fmt.Sprintf("DROP DATABASE IF EXISTS %s",
|
db, err := postgres.openPostgresDB(u)
|
||||||
pq.QuoteIdentifier(database)))
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
_, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s",
|
||||||
|
pq.QuoteIdentifier(name)))
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DatabaseExists determines whether the database exists
|
||||||
|
func (postgres Driver) DatabaseExists(u *url.URL) (bool, error) {
|
||||||
|
name := shared.DatabaseName(u)
|
||||||
|
|
||||||
|
db, err := postgres.openPostgresDB(u)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
exists := false
|
||||||
|
err = db.QueryRow("SELECT true FROM pg_database WHERE datname = $1", name).
|
||||||
|
Scan(&exists)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasMigrationsTable returns true if the schema_migrations table exists
|
// HasMigrationsTable returns true if the schema_migrations table exists
|
||||||
|
|
|
||||||
|
|
@ -61,3 +61,36 @@ func TestCreateDropDatabase(t *testing.T) {
|
||||||
require.Equal(t, "pq: database \"dbmate\" does not exist", err.Error())
|
require.Equal(t, "pq: database \"dbmate\" does not exist", err.Error())
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDatabaseExists(t *testing.T) {
|
||||||
|
d := postgres.Driver{}
|
||||||
|
u := testURL(t)
|
||||||
|
|
||||||
|
// drop any existing database
|
||||||
|
err := d.DropDatabase(u)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// DatabaseExists should return false
|
||||||
|
exists, err := d.DatabaseExists(u)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, false, exists)
|
||||||
|
|
||||||
|
// create database
|
||||||
|
err = d.CreateDatabase(u)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// DatabaseExists should return true
|
||||||
|
exists, err = d.DatabaseExists(u)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, true, exists)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDatabaseExists_error(t *testing.T) {
|
||||||
|
d := postgres.Driver{}
|
||||||
|
u := testURL(t)
|
||||||
|
u.User = url.User("invalid")
|
||||||
|
|
||||||
|
exists, err := d.DatabaseExists(u)
|
||||||
|
require.Equal(t, "pq: role \"invalid\" does not exist", err.Error())
|
||||||
|
require.Equal(t, false, exists)
|
||||||
|
}
|
||||||
|
|
|
||||||
35
main.go
35
main.go
|
|
@ -35,20 +35,6 @@ func NewApp() *cli.App {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
{
|
|
||||||
Name: "migrate",
|
|
||||||
Usage: "Migrate to the latest version",
|
|
||||||
Action: func(ctx *cli.Context) {
|
|
||||||
runCommand(MigrateCommand, ctx)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "rollback",
|
|
||||||
Usage: "Rollback the most recent migration",
|
|
||||||
Action: func(ctx *cli.Context) {
|
|
||||||
runCommand(RollbackCommand, ctx)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "new",
|
Name: "new",
|
||||||
Usage: "Generate a new migration file",
|
Usage: "Generate a new migration file",
|
||||||
|
|
@ -56,6 +42,13 @@ func NewApp() *cli.App {
|
||||||
runCommand(NewCommand, ctx)
|
runCommand(NewCommand, ctx)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "up",
|
||||||
|
Usage: "Create database (if necessary) and migrate to the latest version",
|
||||||
|
Action: func(ctx *cli.Context) {
|
||||||
|
runCommand(UpCommand, ctx)
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "create",
|
Name: "create",
|
||||||
Usage: "Create database",
|
Usage: "Create database",
|
||||||
|
|
@ -70,6 +63,20 @@ func NewApp() *cli.App {
|
||||||
runCommand(DropCommand, ctx)
|
runCommand(DropCommand, ctx)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "migrate",
|
||||||
|
Usage: "Migrate to the latest version",
|
||||||
|
Action: func(ctx *cli.Context) {
|
||||||
|
runCommand(MigrateCommand, ctx)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "rollback",
|
||||||
|
Usage: "Rollback the most recent migration",
|
||||||
|
Action: func(ctx *cli.Context) {
|
||||||
|
runCommand(RollbackCommand, ctx)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue