From 60f07c318d0cb9a8b4a461aa2b64996ad00ff5e9 Mon Sep 17 00:00:00 2001 From: Jeffrey Walter Date: Thu, 17 Apr 2025 17:10:06 -0500 Subject: [PATCH 1/4] fix(migrations): sort migrations as ints not strings Fixes https://github.com/uptrace/bun/issues/1185 --- migrate/migration.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/migrate/migration.go b/migrate/migration.go index 3f4076d2b..73a89affc 100644 --- a/migrate/migration.go +++ b/migrate/migration.go @@ -8,6 +8,7 @@ import ( "io" "io/fs" "sort" + "strconv" "strings" "time" @@ -291,12 +292,22 @@ func WithNopMigration() MigrationOption { func sortAsc(ms MigrationSlice) { sort.Slice(ms, func(i, j int) bool { + ni, ei := strconv.ParseInt(ms[i].Name, 10, 64) + nj, ej := strconv.ParseInt(ms[j].Name, 10, 64) + if ei == nil && ej == nil && ni != nj { + return ni < nj + } return ms[i].Name < ms[j].Name }) } func sortDesc(ms MigrationSlice) { sort.Slice(ms, func(i, j int) bool { + ni, ei := strconv.ParseInt(ms[i].Name, 10, 64) + nj, ej := strconv.ParseInt(ms[j].Name, 10, 64) + if ei == nil && ej == nil && ni != nj { + return ni > nj + } return ms[i].Name > ms[j].Name }) } From 3de66a6d0109f4fff7f4b5ebca474eaf6cc56396 Mon Sep 17 00:00:00 2001 From: Jeffrey Walter Date: Mon, 5 May 2025 13:10:25 -0500 Subject: [PATCH 2/4] feat(migrate): implement migration sort customization --- migrate/migration.go | 31 +++------------------------ migrate/migrations.go | 2 +- migrate/migrator.go | 9 ++++++++ migrate/sort.go | 49 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 29 deletions(-) create mode 100644 migrate/sort.go diff --git a/migrate/migration.go b/migrate/migration.go index 8c3968334..295b72555 100644 --- a/migrate/migration.go +++ b/migrate/migration.go @@ -7,8 +7,6 @@ import ( "fmt" "io" "io/fs" - "sort" - "strconv" "strings" "text/template" "time" @@ -233,7 +231,7 @@ func (ms MigrationSlice) Applied() MigrationSlice { applied = append(applied, ms[i]) } } - sortDesc(applied) + SafeDescSort(applied) return applied } @@ -246,7 +244,7 @@ func (ms MigrationSlice) Unapplied() MigrationSlice { unapplied = append(unapplied, ms[i]) } } - sortAsc(unapplied) + SafeAscSort(unapplied) return unapplied } @@ -276,6 +274,7 @@ func (ms MigrationSlice) LastGroup() *MigrationGroup { group.Migrations = append(group.Migrations, ms[i]) } } + return group } @@ -322,27 +321,3 @@ func WithNopMigration() MigrationOption { cfg.nop = true } } - -//------------------------------------------------------------------------------ - -func sortAsc(ms MigrationSlice) { - sort.Slice(ms, func(i, j int) bool { - ni, ei := strconv.ParseInt(ms[i].Name, 10, 64) - nj, ej := strconv.ParseInt(ms[j].Name, 10, 64) - if ei == nil && ej == nil && ni != nj { - return ni < nj - } - return ms[i].Name < ms[j].Name - }) -} - -func sortDesc(ms MigrationSlice) { - sort.Slice(ms, func(i, j int) bool { - ni, ei := strconv.ParseInt(ms[i].Name, 10, 64) - nj, ej := strconv.ParseInt(ms[j].Name, 10, 64) - if ei == nil && ej == nil && ni != nj { - return ni > nj - } - return ms[i].Name > ms[j].Name - }) -} diff --git a/migrate/migrations.go b/migrate/migrations.go index a22e615cb..5908b86b0 100644 --- a/migrate/migrations.go +++ b/migrate/migrations.go @@ -38,7 +38,7 @@ func NewMigrations(opts ...MigrationsOption) *Migrations { func (m *Migrations) Sorted() MigrationSlice { migrations := make(MigrationSlice, len(m.ms)) copy(migrations, m.ms) - sortAsc(migrations) + SafeAscSort(migrations) return migrations } diff --git a/migrate/migrator.go b/migrate/migrator.go index a325c3993..30bf85207 100644 --- a/migrate/migrator.go +++ b/migrate/migrator.go @@ -47,6 +47,15 @@ func WithTemplateData(data any) MigratorOption { } } +// WithSort overrides the default ascending sort function for all migrations. +// This affects all sorting operations in the entire migrate package. +func WithSort(ascSortFn, descSortFn MigrationSortFunc) { + sortMutex.Lock() + defer sortMutex.Unlock() + AscSort = ascSortFn + DescSort = descSortFn +} + type Migrator struct { db *bun.DB migrations *Migrations diff --git a/migrate/sort.go b/migrate/sort.go new file mode 100644 index 000000000..e8a7eb46a --- /dev/null +++ b/migrate/sort.go @@ -0,0 +1,49 @@ +package migrate + +import ( + "sort" + "sync" +) + +// MigrationSortFunc defines the signature for functions that sort migrations. +type MigrationSortFunc func(ms MigrationSlice) + +// sortMutex protects access to the global sort functions. +var sortMutex sync.RWMutex + +// Default sort implementations +var defaultAscSort MigrationSortFunc = func(ms MigrationSlice) { + sort.Slice(ms, func(i, j int) bool { + return ms[i].Name < ms[j].Name + }) +} + +var defaultDescSort MigrationSortFunc = func(ms MigrationSlice) { + sort.Slice(ms, func(i, j int) bool { + return ms[i].Name > ms[j].Name + }) +} + +// AscSort is the global ascending sort function. +// Default is to sort by migration name in ascending order. +// Can be overridden to use custom sorting logic. +var AscSort MigrationSortFunc = defaultAscSort + +// DescSort is the global descending sort function. +// Default is to sort by migration name in descending order. +// Can be overridden to use custom sorting logic. +var DescSort MigrationSortFunc = defaultDescSort + +// SafeAscSort applies the current ascending sort function in a thread-safe manner. +func SafeAscSort(ms MigrationSlice) { + sortMutex.RLock() + defer sortMutex.RUnlock() + AscSort(ms) +} + +// SafeDescSort applies the current descending sort function in a thread-safe manner. +func SafeDescSort(ms MigrationSlice) { + sortMutex.RLock() + defer sortMutex.RUnlock() + DescSort(ms) +} From 43ec5185372fc5f4c32efa42ffab811cb45215db Mon Sep 17 00:00:00 2001 From: Jeffrey Walter Date: Tue, 6 May 2025 17:40:51 -0500 Subject: [PATCH 3/4] Update migrate/migrator.go Co-authored-by: dyma solovei <53943884+bevzzz@users.noreply.github.com> --- migrate/migrator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrate/migrator.go b/migrate/migrator.go index 30bf85207..67c58f8f6 100644 --- a/migrate/migrator.go +++ b/migrate/migrator.go @@ -49,7 +49,7 @@ func WithTemplateData(data any) MigratorOption { // WithSort overrides the default ascending sort function for all migrations. // This affects all sorting operations in the entire migrate package. -func WithSort(ascSortFn, descSortFn MigrationSortFunc) { +func SetSort(ascSortFn, descSortFn MigrationSortFunc) { sortMutex.Lock() defer sortMutex.Unlock() AscSort = ascSortFn From 5b9b52c1d42d033392f1644be0bca8a15e903f9f Mon Sep 17 00:00:00 2001 From: Jeffrey Walter Date: Tue, 6 May 2025 17:42:55 -0500 Subject: [PATCH 4/4] Update migrator.go Update SetSort comment to match func name. --- migrate/migrator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrate/migrator.go b/migrate/migrator.go index 67c58f8f6..b64479c0d 100644 --- a/migrate/migrator.go +++ b/migrate/migrator.go @@ -47,7 +47,7 @@ func WithTemplateData(data any) MigratorOption { } } -// WithSort overrides the default ascending sort function for all migrations. +// SetSort overrides the default ascending sort function for all migrations. // This affects all sorting operations in the entire migrate package. func SetSort(ascSortFn, descSortFn MigrationSortFunc) { sortMutex.Lock()