class Sequel::TimestampMigrator

The migrator used if any migration file version is greater than 20000101. Stores filenames of migration files, and can figure out which migrations have not been applied and apply them, even if earlier migrations are added after later migrations. If you plan to do that, the responsibility is on you to make sure the migrations don't conflict. Part of the migration extension.

Constants

Error

Attributes

applied_migrations[R]

Array of strings of applied migration filenames

migration_tuples[R]

Get tuples of migrations, filenames, and actions for each migration

Public Class Methods

new(db, directory, opts=OPTS) click to toggle source

Set up all state for the migrator instance

Calls superclass method Sequel::Migrator.new
# File lib/sequel/extensions/migration.rb, line 699
def initialize(db, directory, opts=OPTS)
  super
  @target = opts[:target]
  @applied_migrations = get_applied_migrations
  @migration_tuples = get_migration_tuples
end
run_single(db, path, opts=OPTS) click to toggle source

Apply the migration in the given file path. See Sequel::Migrator.run for the available options. Additionally, this method supports the :direction option for whether to run the migration up (default) or down.

# File lib/sequel/extensions/migration.rb, line 709
def self.run_single(db, path, opts=OPTS)
  new(db, File.dirname(path), opts).run_single(path, opts[:direction] || :up)
end

Public Instance Methods

is_current?() click to toggle source

The timestamp migrator is current if there are no migrations to apply in either direction.

# File lib/sequel/extensions/migration.rb, line 715
def is_current?
  migration_tuples.empty?
end
run() click to toggle source

Apply all migration tuples on the database

# File lib/sequel/extensions/migration.rb, line 720
def run
  migration_tuples.each do |m, f, direction|
    apply_migration(m, f, direction)
  end
  nil
end
run_single(path, direction) click to toggle source

Apply single migration tuple at the given path with the given direction on the database.

# File lib/sequel/extensions/migration.rb, line 729
def run_single(path, direction)
  migration = load_migration_file(path)
  file_name = File.basename(path)
  already_applied = applied_migrations.include?(file_name.downcase)

  return if direction == :up ? already_applied : !already_applied

  apply_migration(migration, file_name, direction)
  nil
end

Private Instance Methods

apply_migration(migration, file_name, direction) click to toggle source

Apply a single migration with the given filename in the given direction.

# File lib/sequel/extensions/migration.rb, line 743
def apply_migration(migration, file_name, direction)
  fi = file_name.downcase
  t = Time.now

  db.log_info("Begin applying migration #{file_name}, direction: #{direction}")
  checked_transaction(migration) do
    migration.apply(db, direction)
    direction == :up ? ds.insert(column=>fi) : ds.where(column=>fi).delete
  end
  db.log_info("Finished applying migration #{file_name}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
end
convert_from_schema_info() click to toggle source

Convert the schema_info table to the new schema_migrations table format, using the version of the schema_info table and the current migration files.

# File lib/sequel/extensions/migration.rb, line 757
def convert_from_schema_info
  v = db[:schema_info].get(:version)
  ds = db.from(table)
  files.each do |path|
    f = File.basename(path)
    if migration_version_from_file(f) <= v
      ds.insert(column=>f)
    end
  end
end
default_schema_column() click to toggle source

The default column storing migration filenames.

# File lib/sequel/extensions/migration.rb, line 769
def default_schema_column
  :filename
end
default_schema_table() click to toggle source

The default table storing migration filenames.

# File lib/sequel/extensions/migration.rb, line 774
def default_schema_table
  :schema_migrations
end
get_applied_migrations() click to toggle source

Returns filenames of all applied migrations

# File lib/sequel/extensions/migration.rb, line 779
def get_applied_migrations
  am = ds.select_order_map(column)
  missing_migration_files = am - files.map{|f| File.basename(f).downcase}
  raise(Error, "Applied migration files not in file system: #{missing_migration_files.join(', ')}") if missing_migration_files.length > 0 && !@allow_missing_migration_files
  am
end
get_migration_files() click to toggle source

Returns any migration files found in the migrator's directory.

# File lib/sequel/extensions/migration.rb, line 787
def get_migration_files
  files = []
  Dir.new(directory).each do |file|
    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}
end
get_migration_tuples() click to toggle source

Returns tuples of migration, filename, and direction

# File lib/sequel/extensions/migration.rb, line 797
def get_migration_tuples
  up_mts = []
  down_mts = []
  files.each do |path|
    f = File.basename(path)
    fi = f.downcase
    if target
      if migration_version_from_file(f) > target
        if applied_migrations.include?(fi)
          down_mts << [load_migration_file(path), f, :down]
        end
      elsif !applied_migrations.include?(fi)
        up_mts << [load_migration_file(path), f, :up]
      end
    elsif !applied_migrations.include?(fi)
      up_mts << [load_migration_file(path), f, :up]
    end
  end
  up_mts + down_mts.reverse
end
schema_dataset() click to toggle source

Returns the dataset for the schema_migrations table. If no such table exists, it is automatically created.

# File lib/sequel/extensions/migration.rb, line 820
def schema_dataset
  c = column
  ds = db.from(table)
  if !db.table_exists?(table)
    begin
      db.create_table(table){String c, :primary_key=>true}
    rescue Sequel::DatabaseError => e
      if db.database_type == :mysql && e.message =~ /max key length/
        # Handle case where MySQL is used with utf8mb4 charset default, which
        # only allows a maximum length of about 190 characters for string
        # primary keys due to InnoDB limitations.
        db.create_table(table){String c, :primary_key=>true, :size=>190}
      else
        raise e
      end
    end
    if db.table_exists?(:schema_info) and vha = db[:schema_info].all and vha.length == 1 and
       vha.first.keys == [:version] and vha.first.values.first.is_a?(Integer)
      convert_from_schema_info
    end
  elsif !ds.columns.include?(c)
    raise(Error, "Migrator table #{table} does not contain column #{c}")
  end
  ds
end