sql-migrate
sql-migrate copied to clipboard
Migration doesn't apply
Hi, I'm trying to figure out why my migration doesn't apply.
I use bleeding edge version of gorp and postgres driver. To embed the migration files I use bindata. So first of all I run following command:
$ go-bindata -pkg repository -o repository/migrations.go migrations/...
package repository
import (
"database/sql"
"github.com/go-gorp/gorp"
_ "github.com/lib/pq"
migrate "github.com/rubenv/sql-migrate"
)
func InitStorage(storage string, dsn string) (*gorp.DbMap, error) {
dbmap := createStorage(storage, dsn)
migrations := &migrate.AssetMigrationSource{
Asset: Asset,
AssetDir: AssetDir,
Dir: "migrations",
}
n, err := migrate.Exec(dbmap.Db, "postgres", migrations, migrate.Up)
if err != nil {
return nil, err
}
fmt.Printf("Applied %d migrations!\n", n)
return dbmap, nil
}
func createStorage(storage string, dsn string) *gorp.DbMap {
dialect, driver := dialectAndDriver(storage)
dbmap := &gorp.DbMap{Db: connect(driver, dsn), Dialect: dialect}
return dbmap
}
func connect(driver string, dsn string) *sql.DB {
if dsn == "" {
panic("DSN is no set.")
}
db, err := sql.Open(driver, dsn)
if err != nil {
panic("Error connecting to db: " + err.Error())
}
return db
}
func dialectAndDriver(storage string) (gorp.Dialect, string) {
switch storage {
case "postgres":
return gorp.PostgresDialect{}, "postgres"
case "sqlite":
return gorp.SqliteDialect{}, "sqlite3"
default:
return gorp.PostgresDialect{}, "postgres"
}
}
My migration file looks like:
migrations/1_init.sql
-- +migrate UP
CREATE TABLE IF NOT EXISTS "organization" (
"id" VARCHAR(250) PRIMARY KEY,
"name" VARCHAR(20) NOT NULL,
"email" VARCHAR(25) NOT NULL,
"description" VARCHAR(150),
"location" VARCHAR(50)
);
-- +migrate Down
DROP TABLE IF EXISTS "organization";
But after running my application, I receive following console output:
Applied 0 migrations!
And my DB is empty, table organization was not created. What am I doing wrong?
@ok2ju try to use packr for you trouble instead of &migrate.AssetMigrationSource. For example:
migrations := &migrate.PackrMigrationSource{
Box: packr.NewBox(migrationFolder),
}
findedMigrations, err := migrations.FindMigrations()
if err != nil {
logger.Error(err.Error())
return err
}
for _, migr := range findedMigrations {
n, err := migrate.Exec(
db,
"postgres",
migrate.MemoryMigrationSource{Migrations: []*migrate.Migration{migr}},
migrate.Up,
)
if err != nil {
logger.Error(err.Error())
return err
}
if n != 0 {
logger.Info(fmt.Sprintf("%s are migrated!", migr.Id))
} else {
logger.Info(fmt.Sprintf("%s are not migrated!", migr.Id))
}
}
I am using sql-migrate + packr for mysql. However
- can't call
migrate.Execmultiple times with for loop. latermigrate.Execalways returnsn == 0after first migration. So I use sql-migrate in this way.
func Migrate(db *sql.DB, dialect string) {
logger := getDbLogger()
migrationSrc := &migrate.PackrMigrationSource{
Box: packr.NewBox(SqlSchemaDir),
}
migrations, err := migrationSrc.FindMigrations()
if err != nil {
logger.Fatalw("Failed to find sql migrations")
}
appliedMigrationCount, err := migrate.Exec(
db,
dialect,
migrate.MemoryMigrationSource{Migrations: migrations},
migrate.Up,
)
if err != nil {
failedMigr := migrations[appliedMigrationCount]
logger.Warnw("Found sql migration error. Doing rollback...", "down", failedMigr.Down)
_, downErr := migrate.Exec(
db,
dialect,
migrate.MemoryMigrationSource{Migrations: []*migrate.Migration{failedMigr}},
migrate.Down,
)
if downErr != nil {
logger.Errorw("Failed to do rollback sql migration", "error", downErr)
}
logger.Fatalw("Failed to do sql migration", "error", err)
}
totalMigrationCount := len(migrations)
if appliedMigrationCount != totalMigrationCount {
logger.Infow("Some migrations are skipped", "total", totalMigrationCount, "applied", appliedMigrationCount)
}
for i := 0; i < totalMigrationCount; i++ {
skipped := true
if totalMigrationCount-appliedMigrationCount <= i {
skipped = false
}
logger.Infow("Migration File", "filename", migrations[i].Id, "skip", skipped)
}
logger.Infow("Finished migration")
}