improve constraint matching, migration structure

This commit is contained in:
2026-06-25 13:52:56 +01:00
parent 95c8c6a839
commit 6e3ff81381
2 changed files with 77 additions and 45 deletions
+10 -2
View File
@@ -4,11 +4,19 @@ package version
type List []*Version
// Match tests versions against a constraint and returns a new List of matching versions only.
func (list List) Match(c *Constraint) List {
func (list List) Match(constraints ...*Constraint) List {
filtered := List{}
for _, v := range list {
if v.Match(c) {
ok := true
for _, c := range constraints {
if !v.Match(c) {
ok = false
break
}
}
if ok {
filtered = append(filtered, v)
}
}
+67 -43
View File
@@ -4,11 +4,71 @@ import (
"sort"
)
// Migration maps provide a simple way to run functions wrapped in version constraints.
type Migration map[string]func() error
// Migration maps provide a simple way to store and run versioned 'patch' functions.
type Migration map[string]Patch
// AllVersions returns a List of all versions in the migration map.
func (m Migration) AllVersions() (List, error) {
// Down reverts all patches in reverse version order.
func (m Migration) Down(after func(*Version)) error {
versions, err := m.Versions()
if err != nil {
return err
}
for i := len(versions); i > 0; i-- {
v := versions[i-1]
patch := m[v.Text]
if err := patch.Down(); err != nil {
return err
}
if after != nil {
after(v)
}
}
return nil
}
// Match tests versions against a constraint and returns a new migration map of matching versions only.
func (m Migration) Match(constraints ...*Constraint) (Migration, error) {
l, err := m.Versions()
if err != nil {
return nil, err
}
l = l.Match(constraints...)
m2 := Migration{}
for _, v := range l {
m2[v.Text] = m[v.Text]
}
return m2, nil
}
// Up executes all patches in version order.
func (m Migration) Up(after func(*Version)) error {
versions, err := m.Versions()
if err != nil {
return err
}
for _, v := range versions {
patch := m[v.Text]
if err := patch.Up(); err != nil {
return err
}
if after != nil {
after(v)
}
}
return nil
}
// Versions returns a List of all versions in the migration map.
func (m Migration) Versions() (List, error) {
l := List{}
for str := range m {
v, err := Parse(str)
@@ -24,43 +84,7 @@ func (m Migration) AllVersions() (List, error) {
return l, nil
}
// RequiredVersions returns a List of all versions in the migration map that are newer than a given (presumed current) version.
// If currentVersion is nil, this is identical to AllVersions.
func (m Migration) RequiredVersions(currentVersion *Version) (List, error) {
l, err := m.AllVersions()
if err != nil {
return nil, err
}
if currentVersion != nil {
c := &Constraint{
Gt: currentVersion,
}
l = l.Match(c)
}
return l, nil
}
// Run all required migration functions in the migration map.
// If currentVersion is nil, all migrations will be run.
// If afterEachCallback is not nil, it will be called after each successful migration.
func (m Migration) Run(currentVersion *Version, afterEachCallback func(*Version)) error {
versions, err := m.RequiredVersions(currentVersion)
if err != nil {
return err
}
for _, v := range versions {
f := m[v.Text]
if err := f(); err != nil {
return err
}
if afterEachCallback != nil {
afterEachCallback(v)
}
}
return nil
type Patch struct {
Down func() error
Up func() error
}