loggalicious/backend/internal/database/migrations/registration.go

104 lines
2.6 KiB
Go

package migrations
import (
"net/http"
"git.icedream.tech/icedream/loggalicious/backend/internal/database"
"github.com/blang/semver"
"github.com/fjl/go-couchdb"
)
type MigrationFunc func(*database.DatabaseServer) error
var (
orderedRegisteredVersions = []semver.Version{}
registeredMigrations = map[string][]MigrationFunc{}
)
func RegisteredVersions() []semver.Version {
return orderedRegisteredVersions
}
func RegisteredMigrations(version semver.Version) []MigrationFunc {
return registeredMigrations[version.String()]
}
func RegisterVersionIfNotRegistered(version semver.Version) {
versionStr := version.String()
if _, ok := registeredMigrations[versionStr]; !ok {
registeredMigrations[versionStr] = []MigrationFunc{}
injected := false
for index, currentVersion := range orderedRegisteredVersions {
if currentVersion.GT(version) /* first version to be newer than this version */ {
newOrderedRegisteredVersions := append(orderedRegisteredVersions[0:index], version)
newOrderedRegisteredVersions = append(newOrderedRegisteredVersions, orderedRegisteredVersions[index:]...)
orderedRegisteredVersions = newOrderedRegisteredVersions
injected = true
break
}
}
if !injected {
orderedRegisteredVersions = append(orderedRegisteredVersions, version)
}
}
}
func RegisterMigration(versionStr string, cb MigrationFunc) {
version := MustParseVersion(versionStr)
RegisterVersionIfNotRegistered(version)
registeredMigrations[versionStr] = append(registeredMigrations[versionStr], cb)
}
func MustParseVersion(version string) semver.Version {
semverVersion, err := semver.Parse(version)
if err != nil {
panic(err)
}
return semverVersion
}
func Run(s *database.DatabaseServer) (err error) {
// Fetch current version
migrationDatabase := s.GetMigrationDatabase()
version, rev, err := migrationDatabase.GetVersion()
if err != nil {
isActuallyAnError := true
if cerr, ok := err.(*couchdb.Error); ok {
// CouchDB error
if cerr.StatusCode == http.StatusNotFound {
isActuallyAnError = false
}
}
if isActuallyAnError {
return
}
version = semver.Version{
Major: 0,
Minor: 0,
Patch: 0,
}
err = nil
}
for _, targetVersion := range orderedRegisteredVersions {
// log.Println("Check if migration is needed:", targetVersion)
if targetVersion.GT(version) {
// log.Println("Migrating database:", version, "->", targetVersion)
for _, cb := range registeredMigrations[targetVersion.String()] {
err = cb(s)
if err != nil {
return
}
}
version = targetVersion
rev, err = migrationDatabase.PutVersion(version, rev)
if err != nil {
return
}
}
}
return
}