class DataMapper::Migration
Attributes
Public Class Methods
# 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
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
# 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
# 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
# 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
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
# 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 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
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
# File lib/dm-migrations/migration.rb, line 175 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 203 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 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
# 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
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
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
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 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
# 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
# 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
Quote the name of the migration for use in SQL
# File lib/dm-migrations/migration.rb, line 171 def quoted_name "'#{name}'" end
Output some text. Optional indent level
# File lib/dm-migrations/migration.rb, line 130 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 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
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
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
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