class DataMapper::Migration
Attributes
The name of the migration
The position or version the migration belongs to
The repository the migration operates on
Public Class Methods
Creates a new migration.
@param [Symbol, String, Integer] position
The position or version the migration belongs to.
@param [Symbol] name
The name of the migration.
@param [Hash] options
Additional options for the migration.
@option options [Boolean] :verbose (true)
Enables or disables verbose output.
@option options [Symbol] :repository (:default)
The DataMapper repository the migration will operate on.
# File lib/dm-migrations/migration.rb, line 37 def initialize(position, name, options = {}, &block) @position = position @name = name @options = options @verbose = options.fetch(:verbose, true) @up_action = nil @down_action = nil @repository = if options.key?(:database) warn 'Using the :database option with migrations is deprecated, use :repository instead' options[:database] else options.fetch(:repository, :default) end instance_eval(&block) end
Public Instance Methods
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 173 def <=> other if self.position == other.position self.name.to_s <=> other.name.to_s else self.position <=> other.position end end
The adapter the migration will use.
@return [DataMapper::Adapter]
The adapter the migration will operate on.
@since 1.0.1
# File lib/dm-migrations/migration.rb, line 78 def adapter setup! unless setup? @adapter end
# File lib/dm-migrations/migration.rb, line 155 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 DataMapper::Ext::String.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(', ') }) ") end
# File lib/dm-migrations/migration.rb, line 214 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
# File lib/dm-migrations/migration.rb, line 141 def create_table(table_name, opts = {}, &block) execute TableCreator.new(adapter, table_name, opts, &block).to_sql end
The repository the migration will operate on.
@return [Symbol, nil]
The name of the DataMapper repository the migration will run against.
@deprecated Use {#repository} instead.
@since 1.0.1.
# File lib/dm-migrations/migration.rb, line 65 def database warn "Using the DataMapper::Migration#database method is deprecated, use #repository instead" @repository end
define the actions that should be performed on a down migration
# File lib/dm-migrations/migration.rb, line 90 def down(&block) @down_action = block end
# File lib/dm-migrations/migration.rb, line 145 def drop_table(table_name, opts = {}) execute "DROP TABLE #{adapter.send(:quote_name, table_name.to_s)}" end
execute raw SQL
# File lib/dm-migrations/migration.rb, line 135 def execute(sql, *bind_values) say_with_time(sql) do adapter.execute(sql, *bind_values) end end
Quoted table name, for the adapter
# File lib/dm-migrations/migration.rb, line 250 def migration_info_table @migration_info_table ||= quote_table_name('migration_info') end
# File lib/dm-migrations/migration.rb, line 227 def migration_info_table_exists? adapter.storage_exists?('migration_info') end
Quoted `migration_name` column, for the adapter
# File lib/dm-migrations/migration.rb, line 255 def migration_name_column @migration_name_column ||= quote_column_name('migration_name') end
Fetch the record for this migration out of the migration_info table
# File lib/dm-migrations/migration.rb, line 232 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
# File lib/dm-migrations/migration.rb, line 149 def modify_table(table_name, opts = {}, &block) TableModifier.new(adapter, table_name, opts, &block).statements.each do |sql| execute(sql) end end
True if the migration has already been run
# File lib/dm-migrations/migration.rb, line 244 def needs_down? return false unless migration_info_table_exists? ! migration_record.empty? end
True if the migration needs to be run
# File lib/dm-migrations/migration.rb, line 238 def needs_up? return true unless migration_info_table_exists? migration_record.empty? end
un-do the migration by running the code in the down block
# File lib/dm-migrations/migration.rb, line 115 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 if @down_action say_with_time "== Performing Down Migration ##{position}: #{name}", 0 do result = @down_action.call end end update_migration_info(:down) # end end result end
perform the migration by running the code in the up block
# File lib/dm-migrations/migration.rb, line 95 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 if @up_action say_with_time "== Performing Up Migration ##{position}: #{name}", 0 do result = @up_action.call end end update_migration_info(:up) # end end result end
# File lib/dm-migrations/migration.rb, line 264 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
# File lib/dm-migrations/migration.rb, line 259 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
Quote the name of the migration for use in SQL
# File lib/dm-migrations/migration.rb, line 223 def quoted_name "'#{name}'" end
Output some text. Optional indent level
# File lib/dm-migrations/migration.rb, line 182 def say(message, indent = 4) write "#{" " * indent} #{message}" end
Time how long the block takes to run, and output it with the message.
# File lib/dm-migrations/migration.rb, line 187 def say_with_time(message, indent = 2) say(message, indent) result = nil time = Benchmark.measure { result = yield } say("-> %.4fs" % time.real, indent) result end
define the actions that should be performed on an up migration
# File lib/dm-migrations/migration.rb, line 85 def up(&block) @up_action = block end
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 201 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
output the given text, but only if verbose mode is on
# File lib/dm-migrations/migration.rb, line 196 def write(text="") puts text if @verbose end
Protected Instance Methods
Sets up the migration.
@since 1.0.1
# File lib/dm-migrations/migration.rb, line 288 def setup! @adapter = DataMapper.repository(@repository).adapter case @adapter.class.name when /Sqlite/ then @adapter.extend(SQL::Sqlite) when /Mysql/ then @adapter.extend(SQL::Mysql) when /Postgres/ then @adapter.extend(SQL::Postgres) else raise(RuntimeError,"Unsupported Migration Adapter #{@adapter.class}",caller) end end
Determines whether the migration has been setup.
@return [Boolean]
Specifies whether the migration has been setup.
@since 1.0.1
# File lib/dm-migrations/migration.rb, line 279 def setup? !(@adapter.nil?) end