DB migrations в Golang
github.com/golang-migrate/migrate/v4
. Работает как cli и как библиотека для Go.
CLI
Создать новую миграцию:
migrate create -ext sql -seq -dir db/migrations create_token_table
Где -seq
нужен чтобы миграции создавались с номерами вместо дат.
Применить миграцию к БД:
migrate --database sqlite3://auth.db --path db/migrations up
Golang
import (
"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/sqlite3"
_ "github.com/golang-migrate/migrate/v4/source/file"
)
type SQLiteStore struct{}
func NewSQLiteStore() (*SQLiteStore, error) {
m, err := migrate.New("file://db/migrations", "sqlite3://auth.db")
if err != nil {
return nil, err
}
err = m.Up()
if err != nil && err.Error() != "no change" {
return nil, err
}
var ss SQLiteStore
return &ss, nil
}
Следует помнить, что метод Up возвращает “no change” как ошибку! Её надо обрабатывать в явном виде.
Пример с embed миграциями
Так же в этом примере показано как использовать существующее соединение с БД, вместо формирования новой строки подключения.
//go:embed migrations/pg/*
var migrations embed.FS
type PgStorage struct {
*sqlx.DB
}
func NewPgStorage(conf config.Db) *PgStorage {
db, err := otelsqlx.Open("pgx", fmt.Sprintf("user=%s password=%s host=%s port=%d dbname=%s", conf.User, conf.Pass, conf.Host, conf.Port, conf.Name), otelsql.WithAttributes(semconv.DBSystemPostgreSQL))
if err != nil {
log.Fatal(err)
}
d, err := iofs.New(migrations, "migrations/pg")
if err != nil {
log.Fatal(err)
}
driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
if err != nil {
log.Fatal(err)
}
m, err := migrate.NewWithInstance("iofs", d, "postgres", driver)
if err != nil {
log.Fatal(err)
}
err = m.Up()
if err != nil && err.Error() != "no change" {
log.Fatal(err)
}
return &PgStorage{db}
}