113 lines
2.3 KiB
Go
113 lines
2.3 KiB
Go
|
package orm
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"time"
|
||
|
|
||
|
"github.com/jinzhu/gorm"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
type VersionResolver interface {
|
||
|
Current(context.Context) (string, error)
|
||
|
Set(context.Context, string) error
|
||
|
}
|
||
|
|
||
|
type DBVersionResolver struct {
|
||
|
db *gorm.DB
|
||
|
}
|
||
|
|
||
|
type DatabaseVersion struct {
|
||
|
ID uint `gorm:"primary_key"`
|
||
|
Version string `gorm:"unique; not null"`
|
||
|
MigratedAt time.Time
|
||
|
IsCurrent bool
|
||
|
}
|
||
|
|
||
|
func (r *DBVersionResolver) Current(ctx context.Context) (string, error) {
|
||
|
var version string
|
||
|
|
||
|
err := WithTx(ctx, r.db, func(ctx context.Context, tx *gorm.DB) error {
|
||
|
dbVersion := &DatabaseVersion{}
|
||
|
err := tx.Where("is_current = ?", true).First(dbVersion).Error
|
||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
version = dbVersion.Version
|
||
|
|
||
|
return nil
|
||
|
})
|
||
|
|
||
|
if err != nil {
|
||
|
return "", errors.Wrap(err, "could execute version resolver init transaction")
|
||
|
}
|
||
|
|
||
|
return version, nil
|
||
|
}
|
||
|
|
||
|
func (r *DBVersionResolver) Set(ctx context.Context, version string) error {
|
||
|
err := WithTx(ctx, r.db, func(ctx context.Context, tx *gorm.DB) error {
|
||
|
dbVersion := &DatabaseVersion{
|
||
|
Version: version,
|
||
|
MigratedAt: time.Now(),
|
||
|
}
|
||
|
|
||
|
if version != "" {
|
||
|
if err := tx.FirstOrCreate(dbVersion).Error; err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err := tx.Model(dbVersion).
|
||
|
UpdateColumn("is_current", true).Error
|
||
|
if err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err := tx.Model(&DatabaseVersion{}).
|
||
|
Where("version <> ?", version).
|
||
|
UpdateColumn("is_current", false).Error
|
||
|
|
||
|
if err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
return err
|
||
|
})
|
||
|
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "could not update schema version")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *DBVersionResolver) Init(ctx context.Context) error {
|
||
|
err := WithTx(ctx, r.db, func(ctx context.Context, tx *gorm.DB) error {
|
||
|
if err := tx.AutoMigrate(&DatabaseVersion{}).Error; err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
if err := tx.Model(&DatabaseVersion{}).AddUniqueIndex("idx_unique_version", "version").Error; err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "could execute version resolver init transaction")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func NewDBVersionResolver(db *gorm.DB) *DBVersionResolver {
|
||
|
return &DBVersionResolver{
|
||
|
db: db,
|
||
|
}
|
||
|
}
|