Class: DataMapper::Migration

Inherits:
Object
  • Object
show all
Includes:
SQL
Defined in:
lib/dm-migrations/migration.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(position, name, options = {}, &block) ⇒ Migration

Creates a new migration.

Parameters:

  • position (Symbol, String, Integer)

    The position or version the migration belongs to.

  • name (Symbol)

    The name of the migration.

  • options (Hash) (defaults to: {})

    Additional options for the migration.

Options Hash (options):

  • :verbose (Boolean) — default: true

    Enables or disables verbose output.

  • :repository (Symbol) — default: :default

    The DataMapper repository the migration will operate on.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 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

Instance Attribute Details

#nameObject (readonly)

The name of the migration



14
15
16
# File 'lib/dm-migrations/migration.rb', line 14

def name
  @name
end

#positionObject (readonly)

The position or version the migration belongs to



11
12
13
# File 'lib/dm-migrations/migration.rb', line 11

def position
  @position
end

#repositoryObject (readonly)

The repository the migration operates on



17
18
19
# File 'lib/dm-migrations/migration.rb', line 17

def repository
  @repository
end

Instance Method Details

#<=>(other) ⇒ Object

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.



173
174
175
176
177
178
179
# 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

#adapterDataMapper::Adapter

The adapter the migration will use.

Returns:

  • (DataMapper::Adapter)

    The adapter the migration will operate on.

Since:

  • 1.0.1



78
79
80
81
82
# File 'lib/dm-migrations/migration.rb', line 78

def adapter
  setup! unless setup?

  @adapter
end

#create_index(table_name, *columns_and_options) ⇒ Object



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# 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(<<-SQL)
    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_neededObject



214
215
216
217
218
219
220
# 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

#create_table(table_name, opts = {}, &block) ⇒ Object



141
142
143
# 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

#databaseSymbol?

Deprecated.

Use #repository instead.

The repository the migration will operate on.

Returns:

  • (Symbol, nil)

    The name of the DataMapper repository the migration will run against.

Since:

  • 1.0.1.



65
66
67
68
# File 'lib/dm-migrations/migration.rb', line 65

def database
  warn "Using the DataMapper::Migration#database method is deprecated, use #repository instead"
  @repository
end

#down(&block) ⇒ Object

define the actions that should be performed on a down migration



90
91
92
# File 'lib/dm-migrations/migration.rb', line 90

def down(&block)
  @down_action = block
end

#drop_table(table_name, opts = {}) ⇒ Object



145
146
147
# 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(sql, *bind_values) ⇒ Object

execute raw SQL



135
136
137
138
139
# 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

#migration_info_tableObject

Quoted table name, for the adapter



250
251
252
# File 'lib/dm-migrations/migration.rb', line 250

def migration_info_table
  @migration_info_table ||= quote_table_name('migration_info')
end

#migration_info_table_exists?Boolean

Returns:

  • (Boolean)


227
228
229
# File 'lib/dm-migrations/migration.rb', line 227

def migration_info_table_exists?
  adapter.storage_exists?('migration_info')
end

#migration_name_columnObject

Quoted ‘migration_name` column, for the adapter



255
256
257
# File 'lib/dm-migrations/migration.rb', line 255

def migration_name_column
  @migration_name_column ||= quote_column_name('migration_name')
end

#migration_recordObject

Fetch the record for this migration out of the migration_info table



232
233
234
235
# 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

#modify_table(table_name, opts = {}, &block) ⇒ Object



149
150
151
152
153
# 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

#needs_down?Boolean

True if the migration has already been run

Returns:

  • (Boolean)


244
245
246
247
# File 'lib/dm-migrations/migration.rb', line 244

def needs_down?
  return false unless migration_info_table_exists?
  ! migration_record.empty?
end

#needs_up?Boolean

True if the migration needs to be run

Returns:

  • (Boolean)


238
239
240
241
# File 'lib/dm-migrations/migration.rb', line 238

def needs_up?
  return true unless migration_info_table_exists?
  migration_record.empty?
end

#perform_downObject

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



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# 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_upObject

perform the migration by running the code in the #up block



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 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

#quote_column_name(column_name) ⇒ Object



264
265
266
267
# 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

#quote_table_name(table_name) ⇒ Object



259
260
261
262
# 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

#quoted_nameObject

Quote the name of the migration for use in SQL



223
224
225
# File 'lib/dm-migrations/migration.rb', line 223

def quoted_name
  "'#{name}'"
end

#say(message, indent = 4) ⇒ Object

Output some text. Optional indent level



182
183
184
# File 'lib/dm-migrations/migration.rb', line 182

def say(message, indent = 4)
  write "#{" " * indent} #{message}"
end

#say_with_time(message, indent = 2) ⇒ Object

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



187
188
189
190
191
192
193
# 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

#up(&block) ⇒ Object

define the actions that should be performed on an up migration



85
86
87
# File 'lib/dm-migrations/migration.rb', line 85

def up(&block)
  @up_action = block
end

#update_migration_info(direction) ⇒ Object

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



201
202
203
204
205
206
207
208
209
210
211
212
# 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

#write(text = "") ⇒ Object

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



196
197
198
# File 'lib/dm-migrations/migration.rb', line 196

def write(text="")
  puts text if @verbose
end