class DataMapper::Migration

Attributes

adapter[RW]
database[RW]
name[RW]
position[RW]

Public Class Methods

new( position, name, opts = {}, &block ) click to toggle source
# File lib/dm-migrations/migration.rb, line 17
def initialize( position, name, opts = {}, &block )
  @position, @name = position, name
  @options = opts

  @database = DataMapper.repository(@options[:database] || :default)
  @adapter = @database.adapter

  if @adapter.respond_to?(:dialect)
    begin
      @adapter.extend(SQL.const_get("#{@adapter.dialect}"))
    rescue NameError
      raise "Unsupported Migration Adapter #{@adapter.class} with SQL dialect #{@adapter.dialect}"
    end
  else
    raise "Unsupported Migration Adapter #{@adapter.class}"
  end

  @verbose = @options.has_key?(:verbose) ? @options[:verbose] : true

  @up_action   = lambda {}
  @down_action = lambda {}

  instance_eval &block
end

Public Instance Methods

<=>(other) click to toggle source

Orders migrations by position, so we know what order to run them in. First order by position, then by name, so at least the order is predictable.

# File lib/dm-migrations/migration.rb, line 121
def <=> other
  if self.position == other.position
    self.name.to_s <=> other.name.to_s
  else
    self.position <=> other.position
  end
end
create_index(table_name, *columns_and_options) click to toggle source
# File lib/dm-migrations/migration.rb, line 103
    def create_index(table_name, *columns_and_options)
      if columns_and_options.last.is_a?(Hash)
        opts = columns_and_options.pop
      else
        opts = {}
      end
      columns = columns_and_options.flatten

      opts[:name] ||= "#{opts[:unique] ? 'unique_' : ''}index_#{table_name}_#{columns.join('_')}"

      execute <<-SQL.compress_lines
        CREATE #{opts[:unique] ? 'UNIQUE ' : '' }INDEX #{quote_column_name(opts[:name])} ON
        #{quote_table_name(table_name)} (#{columns.map { |c| quote_column_name(c) }.join(', ') })
      SQL
    end
create_migration_info_table_if_needed() click to toggle source
# File lib/dm-migrations/migration.rb, line 162
def create_migration_info_table_if_needed
  save, @verbose = @verbose, false
  unless migration_info_table_exists?
    execute("CREATE TABLE #{migration_info_table} (#{migration_name_column} VARCHAR(255) UNIQUE)")
  end
  @verbose = save
end
create_table(table_name, opts = {}, &block) click to toggle source
# File lib/dm-migrations/migration.rb, line 89
def create_table(table_name, opts = {}, &block)
  execute TableCreator.new(@adapter, table_name, opts, &block).to_sql
end
down(&block) click to toggle source

define the actions that should be performed on a down migration

# File lib/dm-migrations/migration.rb, line 48
def down(&block)
  @down_action = block
end
drop_table(table_name, opts = {}) click to toggle source
# File lib/dm-migrations/migration.rb, line 93
def drop_table(table_name, opts = {})
  execute "DROP TABLE #{@adapter.send(:quote_name, table_name.to_s)}"
end
execute(sql, *bind_values) click to toggle source

execute raw SQL

# File lib/dm-migrations/migration.rb, line 83
def execute(sql, *bind_values)
  say_with_time(sql) do
    @adapter.execute(sql, *bind_values)
  end
end
migration_info_table() click to toggle source

Quoted table name, for the adapter

# File lib/dm-migrations/migration.rb, line 198
def migration_info_table
  @migration_info_table ||= quote_table_name('migration_info')
end
migration_info_table_exists?() click to toggle source
# File lib/dm-migrations/migration.rb, line 175
def migration_info_table_exists?
  adapter.storage_exists?('migration_info')
end
migration_name_column() click to toggle source

Quoted ‘migration_name` column, for the adapter

# File lib/dm-migrations/migration.rb, line 203
def migration_name_column
  @migration_name_column ||= quote_column_name('migration_name')
end
migration_record() click to toggle source

Fetch the record for this migration out of the migration_info table

# File lib/dm-migrations/migration.rb, line 180
def migration_record
  return [] unless migration_info_table_exists?
  @adapter.select("SELECT #{migration_name_column} FROM #{migration_info_table} WHERE #{migration_name_column} = #{quoted_name}")
end
modify_table(table_name, opts = {}, &block) click to toggle source
# File lib/dm-migrations/migration.rb, line 97
def modify_table(table_name, opts = {}, &block)
  TableModifier.new(@adapter, table_name, opts, &block).statements.each do |sql|
    execute(sql)
  end
end
needs_down?() click to toggle source

True if the migration has already been run

# File lib/dm-migrations/migration.rb, line 192
def needs_down?
  return false unless migration_info_table_exists?
  ! migration_record.empty?
end
needs_up?() click to toggle source

True if the migration needs to be run

# File lib/dm-migrations/migration.rb, line 186
def needs_up?
  return true unless migration_info_table_exists?
  migration_record.empty?
end
perform_down() click to toggle source

un-do the migration by running the code in the down block

# File lib/dm-migrations/migration.rb, line 68
def perform_down
  result = nil
  if needs_down?
    # TODO: fix this so it only does transactions for databases that support create/drop
    # database.transaction.commit do
      say_with_time "== Performing Down Migration ##{position}: #{name}", 0 do
        result = @down_action.call
      end
      update_migration_info(:down)
    # end
  end
  result
end
perform_up() click to toggle source

perform the migration by running the code in the up block

# File lib/dm-migrations/migration.rb, line 53
def perform_up
  result = nil
  if needs_up?
    # TODO: fix this so it only does transactions for databases that support create/drop
    # database.transaction.commit do
      say_with_time "== Performing Up Migration ##{position}: #{name}", 0 do
        result = @up_action.call
      end
      update_migration_info(:up)
    # end
  end
  result
end
quote_column_name(column_name) click to toggle source
# File lib/dm-migrations/migration.rb, line 212
def quote_column_name(column_name)
  # TODO: Fix this for 1.9 - can't use this hack to access a private method
  @adapter.send(:quote_name, column_name.to_s)
end
quote_table_name(table_name) click to toggle source
# File lib/dm-migrations/migration.rb, line 207
def quote_table_name(table_name)
  # TODO: Fix this for 1.9 - can't use this hack to access a private method
  @adapter.send(:quote_name, table_name.to_s)
end
quoted_name() click to toggle source

Quote the name of the migration for use in SQL

# File lib/dm-migrations/migration.rb, line 171
def quoted_name
  "'#{name}'"
end
say(message, indent = 4) click to toggle source

Output some text. Optional indent level

# File lib/dm-migrations/migration.rb, line 130
def say(message, indent = 4)
  write "#{" " * indent} #{message}"
end
say_with_time(message, indent = 2) { || ... } click to toggle source

Time how long the block takes to run, and output it with the message.

# File lib/dm-migrations/migration.rb, line 135
def say_with_time(message, indent = 2)
  say(message, indent)
  result = nil
  time = Benchmark.measure { result = yield }
  say("-> %.4fs" % time.real, indent)
  result
end
up(&block) click to toggle source

define the actions that should be performed on an up migration

# File lib/dm-migrations/migration.rb, line 43
def up(&block)
  @up_action = block
end
update_migration_info(direction) click to toggle source

Inserts or removes a row into the ‘migration_info` table, so we can mark this migration as run, or un-done

# File lib/dm-migrations/migration.rb, line 149
def update_migration_info(direction)
  save, @verbose = @verbose, false

  create_migration_info_table_if_needed

  if direction.to_sym == :up
    execute("INSERT INTO #{migration_info_table} (#{migration_name_column}) VALUES (#{quoted_name})")
  elsif direction.to_sym == :down
    execute("DELETE FROM #{migration_info_table} WHERE #{migration_name_column} = #{quoted_name}")
  end
  @verbose = save
end
write(text="") click to toggle source

output the given text, but only if verbose mode is on

# File lib/dm-migrations/migration.rb, line 144
def write(text="")
  puts text if @verbose
end