package database import ( "database/sql" "log" "net/http" "os" "github.com/golang-migrate/migrate/v4" "github.com/golang-migrate/migrate/v4/database/postgres" "github.com/golang-migrate/migrate/v4/source/httpfs" "github.com/jmoiron/sqlx" ) // GetMigrator returns a Database Migrator for PostgreSQL for the supplied // http.FileSystem and path. func getMigrator(db *sql.DB, fs http.FileSystem, path string) (*migrate.Migrate, error) { driver, err := postgres.WithInstance(db, &postgres.Config{}) if err != nil { return nil, err } migrations, err := httpfs.New(fs, path) if err != nil { return nil, err } // the strings are only for logging purpose migrator, err := migrate.NewWithInstance( "assets", migrations, "database", driver, ) if err != nil { return nil, err } return migrator, err } type wrappedLogger struct { *log.Logger } func (l wrappedLogger) Verbose() bool { return true } const ( // MigrateDrop is the revision number that will cause all tables to be // dropped from the database. MigrateDrop = -3 // MigrateUp is the revision number that will cause the database to be // migrated to the very latest revision. MigrateUp = -1 ) // GetCurrentMigration returns the currently active migration version. // If no migration has been applied yet, it will return ErrNilVersion. func GetCurrentMigration(db *sqlx.DB) (version uint, dirty bool, err error) { migrator, err := getMigrator(db.DB, http.Dir("/invalid/path/unused"), "/unused") if err != nil { return 0, false, err } return migrator.Version() } // Migrate Migrates the schema of the supplied Database. Supported // methods are: // * database.MigrateUp – Migrate to the latest version // * database.MigrateDrop – empty everything // * `(integer)` – Migrate to specific version func Migrate(db *sqlx.DB, fs http.FileSystem, revision int) error { // migrate database const migrationPathInFs = "/migrations" migrator, err := getMigrator(db.DB, fs, migrationPathInFs) if err != nil { return err } wl := wrappedLogger{log.New(os.Stdout, "[MIGRATIONS] ", log.LstdFlags)} migrator.Log = wl switch revision { case MigrateUp: err = migrator.Up() case MigrateDrop: err = migrator.Drop() default: err = migrator.Migrate(uint(revision)) } if err == migrate.ErrNoChange { wl.Println("no change") } else if err != nil { return err } return nil }