Skip to content

Commit

Permalink
Break ties in timestamp migrator version handling using lexicographic…
Browse files Browse the repository at this point in the history
… sort of rest of migration filename

While I consider it a bad practice to have multiple migrations
with the same version that are interdependent, having
non-deterministic behavior in this case isn't great either.

This makes Sequel::Migrator::MIGRATION_FILE_PATTERN add another
capture, which could affect users using it directly, but that
seems unlikely.
  • Loading branch information
jeremyevans committed Dec 18, 2024
1 parent 267daa5 commit 31d28f2
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Break ties in timestamp migrator version handling using lexicographic sort of rest of migration filename (jeremyevans)

* Fix strict_unused_block warnings when running specs on Ruby 3.4 (jeremyevans)

=== 5.87.0 (2024-12-01)
Expand Down
20 changes: 18 additions & 2 deletions lib/sequel/extensions/migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def self.migration(&block)
#
# Part of the +migration+ extension.
class Migrator
MIGRATION_FILE_PATTERN = /\A(\d+)_.+\.rb\z/i.freeze
MIGRATION_FILE_PATTERN = /\A(\d+)_(.+)\.rb\z/i.freeze

# Mutex used around migration file loading
MUTEX = Mutex.new
Expand Down Expand Up @@ -791,7 +791,23 @@ def get_migration_files
next unless MIGRATION_FILE_PATTERN.match(file)
files << File.join(directory, file)
end
files.sort_by{|f| MIGRATION_FILE_PATTERN.match(File.basename(f))[1].to_i}
files.sort! do |a, b|
a_ver, a_name = split_migration_filename(a)
b_ver, b_name = split_migration_filename(b)
x = a_ver <=> b_ver
if x.zero?
x = a_name <=> b_name
end
x
end
files
end

# Return an integer and name (without extension) for the given path.
def split_migration_filename(path)
version, name = MIGRATION_FILE_PATTERN.match(File.basename(path)).captures
version = version.to_i
[version, name]
end

# Returns tuples of migration, filename, and direction
Expand Down
16 changes: 16 additions & 0 deletions spec/extensions/migration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,22 @@ def create_table(name, *args, &block)
@db[:schema_migrations].select_order_map(:filename).must_equal []
end

it "should sort lexicographically by name for same timestamp" do
@dir = 'spec/files/duplicate_timestamped_migrations'
files = nil
migrator_class = Class.new(Sequel::TimestampMigrator) do
define_method(:get_migration_files) do
files = super()
end
end
@m = migrator_class.new(@db, @dir)
@m.run
files.map{|x| File.basename(x)}.must_equal %w'1273253849_create_sessions.rb 1273253853_create_nodes.rb 1273253853_create_users.rb'

[:schema_migrations, :sm1111, :sm2222, :sm3333].each{|n| @db.table_exists?(n).must_equal true}
@db[:schema_migrations].select_order_map(:filename).must_equal %w'1273253849_create_sessions.rb 1273253853_create_nodes.rb 1273253853_create_users.rb'
end

it "should convert schema_info table to schema_migrations table" do
@dir = 'spec/files/integer_migrations'
@m.apply(@db, @dir)
Expand Down

0 comments on commit 31d28f2

Please sign in to comment.