mirror of
https://github.com/TECHNOFAB11/dbmate.git
synced 2025-12-11 23:50:04 +01:00
Add status command (#120)
Add new command to list applied and pending migrations. Closes #28 Closes #32 Closes #66 Closes #120
This commit is contained in:
parent
f7a3390299
commit
256f92ad19
5 changed files with 143 additions and 4 deletions
|
|
@ -93,6 +93,7 @@ dbmate drop # drop the database
|
|||
dbmate migrate # run any pending migrations
|
||||
dbmate rollback # roll back the most recent migration
|
||||
dbmate down # alias for rollback
|
||||
dbmate status # show the status of all migrations
|
||||
dbmate dump # write the database schema.sql file
|
||||
dbmate wait # wait for the database server to become available
|
||||
```
|
||||
|
|
|
|||
7
main.go
7
main.go
|
|
@ -102,6 +102,13 @@ func NewApp() *cli.App {
|
|||
return db.Rollback()
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "status",
|
||||
Usage: "List applied and pending migrations",
|
||||
Action: action(func(db *dbmate.DB, c *cli.Context) error {
|
||||
return db.Status()
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "dump",
|
||||
Usage: "Write the database schema to disk",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,14 @@ type DB struct {
|
|||
WaitTimeout time.Duration
|
||||
}
|
||||
|
||||
// migrationFileRegexp pattern for valid migration files
|
||||
var migrationFileRegexp = regexp.MustCompile(`^\d.*\.sql$`)
|
||||
|
||||
type statusResult struct {
|
||||
filename string
|
||||
applied bool
|
||||
}
|
||||
|
||||
// New initializes a new dbmate database
|
||||
func New(databaseURL *url.URL) *DB {
|
||||
return &DB{
|
||||
|
|
@ -253,8 +261,7 @@ func (db *DB) openDatabaseForMigration() (Driver, *sql.DB, error) {
|
|||
|
||||
// Migrate migrates database to the latest version
|
||||
func (db *DB) Migrate() error {
|
||||
re := regexp.MustCompile(`^\d.*\.sql$`)
|
||||
files, err := findMigrationFiles(db.MigrationsDir, re)
|
||||
files, err := findMigrationFiles(db.MigrationsDir, migrationFileRegexp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -445,3 +452,66 @@ func (db *DB) Rollback() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMigrationsStatus(db *DB) ([]statusResult, error) {
|
||||
files, err := findMigrationFiles(db.MigrationsDir, migrationFileRegexp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return nil, fmt.Errorf("no migration files found")
|
||||
}
|
||||
|
||||
drv, sqlDB, err := db.openDatabaseForMigration()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer mustClose(sqlDB)
|
||||
|
||||
applied, err := drv.SelectMigrations(sqlDB, -1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results []statusResult
|
||||
|
||||
for _, filename := range files {
|
||||
ver := migrationVersion(filename)
|
||||
res := statusResult{filename: filename}
|
||||
if ok := applied[ver]; ok {
|
||||
res.applied = true
|
||||
} else {
|
||||
res.applied = false
|
||||
}
|
||||
|
||||
results = append(results, res)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// Status shows the status of all migrations
|
||||
func (db *DB) Status() error {
|
||||
results, err := checkMigrationsStatus(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var totalApplied int
|
||||
|
||||
for _, res := range results {
|
||||
if res.applied {
|
||||
fmt.Println("[X]", res.filename)
|
||||
totalApplied++
|
||||
} else {
|
||||
fmt.Println("[ ]", res.filename)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Printf("Applied: %d\n", totalApplied)
|
||||
fmt.Printf("Pending: %d\n", len(results)-totalApplied)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,6 +298,9 @@ func testRollbackURL(t *testing.T, u *url.URL) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 1, count)
|
||||
|
||||
err = sqlDB.QueryRow("select count(*) from posts").Scan(&count)
|
||||
require.Nil(t, err)
|
||||
|
||||
// rollback
|
||||
err = db.Rollback()
|
||||
require.NoError(t, err)
|
||||
|
|
@ -305,9 +308,9 @@ func testRollbackURL(t *testing.T, u *url.URL) {
|
|||
// verify rollback
|
||||
err = sqlDB.QueryRow("select count(*) from schema_migrations").Scan(&count)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, count)
|
||||
require.Equal(t, 1, count)
|
||||
|
||||
err = sqlDB.QueryRow("select count(*) from users").Scan(&count)
|
||||
err = sqlDB.QueryRow("select count(*) from posts").Scan(&count)
|
||||
require.NotNil(t, err)
|
||||
require.Regexp(t, "(does not exist|doesn't exist|no such table)", err.Error())
|
||||
}
|
||||
|
|
@ -317,3 +320,53 @@ func TestRollback(t *testing.T) {
|
|||
testRollbackURL(t, u)
|
||||
}
|
||||
}
|
||||
|
||||
func testStatusUrl(t *testing.T, u *url.URL) {
|
||||
db := newTestDB(t, u)
|
||||
|
||||
// drop, recreate, and migrate database
|
||||
err := db.Drop()
|
||||
require.NoError(t, err)
|
||||
err = db.Create()
|
||||
require.NoError(t, err)
|
||||
|
||||
// verify migration
|
||||
sqlDB, err := GetDriverOpen(u)
|
||||
require.NoError(t, err)
|
||||
defer mustClose(sqlDB)
|
||||
|
||||
// two pending
|
||||
results, err := checkMigrationsStatus(db)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, results, 2)
|
||||
require.False(t, results[0].applied)
|
||||
require.False(t, results[1].applied)
|
||||
|
||||
// run migrations
|
||||
err = db.Migrate()
|
||||
require.NoError(t, err)
|
||||
|
||||
// two applied
|
||||
results, err = checkMigrationsStatus(db)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, results, 2)
|
||||
require.True(t, results[0].applied)
|
||||
require.True(t, results[1].applied)
|
||||
|
||||
// rollback last migration
|
||||
err = db.Rollback()
|
||||
require.NoError(t, err)
|
||||
|
||||
// one applied, one pending
|
||||
results, err = checkMigrationsStatus(db)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, results, 2)
|
||||
require.True(t, results[0].applied)
|
||||
require.False(t, results[1].applied)
|
||||
}
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
for _, u := range testURLs(t) {
|
||||
testStatusUrl(t, u)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
8
testdata/db/migrations/20200227231541_test_posts.sql
vendored
Normal file
8
testdata/db/migrations/20200227231541_test_posts.sql
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
-- migrate:up
|
||||
create table posts (
|
||||
id integer,
|
||||
name varchar(255)
|
||||
);
|
||||
|
||||
-- migrate:down
|
||||
drop table posts;
|
||||
Loading…
Add table
Add a link
Reference in a new issue