104 lines
2.6 KiB
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
|
||
|
}
|