Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 198 lines (169 sloc) 6.454 kb
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
1 module ActiveRecord
2 class Migration
6e02164 Vijay Dev styling changes
vijaydev authored
3 # <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
0034b78 Sebastian Martinez Remove extra white spaces on ActiveRecord docs.
smartinez87 authored
4 # a migration and knows how to reverse those commands. The CommandRecorder
a4d9b1d Aaron Patterson adding documentation for reversible migrations
tenderlove authored
5 # knows how to invert the following commands:
6 #
7 # * add_column
8 # * add_index
5a79ca6 Vijay Dev fix typo in method name
vijaydev authored
9 # * add_timestamps
a4d9b1d Aaron Patterson adding documentation for reversible migrations
tenderlove authored
10 # * create_table
080bd83 Rafael Mendonça França Add `create_join_table` migration helper to create HABTM join tables
rafaelfranca authored
11 # * create_join_table
a4d9b1d Aaron Patterson adding documentation for reversible migrations
tenderlove authored
12 # * remove_timestamps
13 # * rename_column
14 # * rename_index
15 # * rename_table
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
16 class CommandRecorder
080bd83 Rafael Mendonça França Add `create_join_table` migration helper to create HABTM join tables
rafaelfranca authored
17 include JoinTable
18
d327c18 Marc-André Lafortune Allow reverting of migration commands with Migration#revert [#8267]
marcandre authored
19 attr_accessor :commands, :delegate, :reverting
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
20
6519df4 Aaron Patterson command recorder will record commands sent to a delegate object
tenderlove authored
21 def initialize(delegate = nil)
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
22 @commands = []
6519df4 Aaron Patterson command recorder will record commands sent to a delegate object
tenderlove authored
23 @delegate = delegate
d327c18 Marc-André Lafortune Allow reverting of migration commands with Migration#revert [#8267]
marcandre authored
24 @reverting = false
25 end
26
27 # While executing the given block, the recorded will be in reverting mode.
28 # All commands recorded will end up being recorded reverted
29 # and in reverse order.
30 # For example:
31 #
32 # recorder.revert{ recorder.record(:rename_table, [:old, :new]) }
33 # # same effect as recorder.record(:rename_table, [:new, :old])
34 def revert
35 @reverting = !@reverting
36 previous = @commands
37 @commands = []
38 yield
39 ensure
40 @commands = previous.concat(@commands.reverse)
41 @reverting = !@reverting
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
42 end
43
0034b78 Sebastian Martinez Remove extra white spaces on ActiveRecord docs.
smartinez87 authored
44 # record +command+. +command+ should be a method name and arguments.
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
45 # For example:
46 #
6e02164 Vijay Dev styling changes
vijaydev authored
47 # recorder.record(:method_name, [:arg1, :arg2])
d327c18 Marc-André Lafortune Allow reverting of migration commands with Migration#revert [#8267]
marcandre authored
48 def record(*command, &block)
49 if @reverting
50 @commands << inverse_of(*command, &block)
51 else
52 @commands << (command << block)
53 end
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
54 end
55
d327c18 Marc-André Lafortune Allow reverting of migration commands with Migration#revert [#8267]
marcandre authored
56 # Returns the inverse of the given command. For example:
0d7410f Aaron Patterson updating documentation
tenderlove authored
57 #
d327c18 Marc-André Lafortune Allow reverting of migration commands with Migration#revert [#8267]
marcandre authored
58 # recorder.inverse_of(:rename_table, [:old, :new])
59 # # => [:rename_table, [:new, :old]]
0d7410f Aaron Patterson updating documentation
tenderlove authored
60 #
6e02164 Vijay Dev styling changes
vijaydev authored
61 # This method will raise an +IrreversibleMigration+ exception if it cannot
d327c18 Marc-André Lafortune Allow reverting of migration commands with Migration#revert [#8267]
marcandre authored
62 # invert the +command+.
63 def inverse_of(command, args, &block)
64 method = :"invert_#{command}"
65 raise IrreversibleMigration unless respond_to?(method, true)
66 send(method, args, &block)
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
67 end
68
6519df4 Aaron Patterson command recorder will record commands sent to a delegate object
tenderlove authored
69 def respond_to?(*args) # :nodoc:
70 super || delegate.respond_to?(*args)
71 end
72
e43e8e2 Marc-André Lafortune Make change_table reversible when possible [#8267]
marcandre authored
73 [:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
740dbf8 Marc-André Lafortune Split ridiculously long line
marcandre authored
74 :rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
4da76d7 Carlos Antonio da Silva Remove duplicated methods in command recorder and duplicated test name
carlosantoniodasilva authored
75 :change_column_default, :add_reference, :remove_reference, :transaction,
3a21870 Eric Tipton Make 'enable_extension' revertible
etipton authored
76 :drop_join_table, :drop_table, :execute_block, :enable_extension,
6073d7c Yves Senn fk: make `add_foreign_key` reversible.
senny authored
77 :change_column, :execute, :remove_columns, :change_column_null,
78 :add_foreign_key, :remove_foreign_key
79 # irreversible methods need to be here too
740dbf8 Marc-André Lafortune Split ridiculously long line
marcandre authored
80 ].each do |method|
30176f2 Pratik Add :bulk => true option to change_table
lifo authored
81 class_eval <<-EOV, __FILE__, __LINE__ + 1
d327c18 Marc-André Lafortune Allow reverting of migration commands with Migration#revert [#8267]
marcandre authored
82 def #{method}(*args, &block) # def create_table(*args, &block)
83 record(:"#{method}", args, &block) # record(:create_table, args, &block)
84 end # end
30176f2 Pratik Add :bulk => true option to change_table
lifo authored
85 EOV
6519df4 Aaron Patterson command recorder will record commands sent to a delegate object
tenderlove authored
86 end
057fa33 Aleksei Magusev Make references statements reversible
lexmag authored
87 alias :add_belongs_to :add_reference
88 alias :remove_belongs_to :remove_reference
6519df4 Aaron Patterson command recorder will record commands sent to a delegate object
tenderlove authored
89
9fb2fdc Tom Kadwill Added nodoc to change_table
tomkadwill authored
90 def change_table(table_name, options = {}) # :nodoc:
eb589fe Nishant Modak Make change_table use object of current database adapter
nishantmodak authored
91 yield delegate.update_table_definition(table_name, self)
e43e8e2 Marc-André Lafortune Make change_table reversible when possible [#8267]
marcandre authored
92 end
93
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
94 private
30176f2 Pratik Add :bulk => true option to change_table
lifo authored
95
7204d3c Marc-André Lafortune Factorize methods that are easily reversible [#8267]
marcandre authored
96 module StraightReversions
97 private
98 { transaction: :transaction,
a4932d6 Marc-André Lafortune Fixes for PR [#8267]
marcandre authored
99 execute_block: :execute_block,
7204d3c Marc-André Lafortune Factorize methods that are easily reversible [#8267]
marcandre authored
100 create_table: :drop_table,
101 create_join_table: :drop_join_table,
102 add_column: :remove_column,
103 add_timestamps: :remove_timestamps,
104 add_reference: :remove_reference,
3a21870 Eric Tipton Make 'enable_extension' revertible
etipton authored
105 enable_extension: :disable_extension
7204d3c Marc-André Lafortune Factorize methods that are easily reversible [#8267]
marcandre authored
106 }.each do |cmd, inv|
4da76d7 Carlos Antonio da Silva Remove duplicated methods in command recorder and duplicated test name
carlosantoniodasilva authored
107 [[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
7204d3c Marc-André Lafortune Factorize methods that are easily reversible [#8267]
marcandre authored
108 class_eval <<-EOV, __FILE__, __LINE__ + 1
109 def invert_#{method}(args, &block) # def invert_create_table(args, &block)
110 [:#{inverse}, args, block] # [:drop_table, args, block]
111 end # end
112 EOV
113 end
114 end
99770e4 Marc-André Lafortune Add Migration#reversible for reversible data operations [#8267]
marcandre authored
115 end
116
7204d3c Marc-André Lafortune Factorize methods that are easily reversible [#8267]
marcandre authored
117 include StraightReversions
af871a0 Marc-André Lafortune Make drop_table reversible [#8267]
marcandre authored
118
119 def invert_drop_table(args, &block)
120 if args.size == 1 && block == nil
121 raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
122 end
7204d3c Marc-André Lafortune Factorize methods that are easily reversible [#8267]
marcandre authored
123 super
080bd83 Rafael Mendonça França Add `create_join_table` migration helper to create HABTM join tables
rafaelfranca authored
124 end
125
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
126 def invert_rename_table(args)
127 [:rename_table, args.reverse]
128 end
129
e28ddea Marc-André Lafortune Differentiate between remove_column and remove_columns. Make remove_colu...
marcandre authored
130 def invert_remove_column(args)
131 raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2
7204d3c Marc-André Lafortune Factorize methods that are easily reversible [#8267]
marcandre authored
132 super
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
133 end
134
135 def invert_rename_index(args)
24674b3 Jean-Baptiste Barth Fixed bad options order in ActiveRecord::Migration::CommandRecorder#inve...
jbbarth authored
136 [:rename_index, [args.first] + args.last(2).reverse]
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
137 end
138
139 def invert_rename_column(args)
140 [:rename_column, [args.first] + args.last(2).reverse]
141 end
24b637a Aaron Patterson inverting add_index
tenderlove authored
142
143 def invert_add_index(args)
a7fad65 David Workman Simple fix for correctly inverting an add_index migration when a name ha...
workmad3 authored
144 table, columns, options = *args
e1d4673 Hubert Dąbrowski Drop the correct index after reverting a migration
hdabrows authored
145 options ||= {}
146
147 index_name = options[:name]
148 options_hash = index_name ? { name: index_name } : { column: columns }
149
150 [:remove_index, [table, options_hash]]
3132324 Marc-André Lafortune Make remove_index reversible [#8267]
marcandre authored
151 end
152
153 def invert_remove_index(args)
154 table, options = *args
3771e4d Neeraj Singh raise IrreversibleMigration if no column given
neerajdotname authored
155
156 unless options && options.is_a?(Hash) && options[:column]
157 raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
158 end
3132324 Marc-André Lafortune Make remove_index reversible [#8267]
marcandre authored
159
160 options = options.dup
161 [:add_index, [table, options.delete(:column), options]]
24b637a Aaron Patterson inverting add_index
tenderlove authored
162 end
5d93900 Aaron Patterson add and remove timestamps can be inverted
tenderlove authored
163
057fa33 Aleksei Magusev Make references statements reversible
lexmag authored
164 alias :invert_add_belongs_to :invert_add_reference
165 alias :invert_remove_belongs_to :invert_remove_reference
166
724509a Yves Senn make `change_column_null` reversible. Closes #13576.
senny authored
167 def invert_change_column_null(args)
168 args[2] = !args[2]
169 [:change_column_null, args]
170 end
171
6073d7c Yves Senn fk: make `add_foreign_key` reversible.
senny authored
172 def invert_add_foreign_key(args)
24e1aef Yves Senn fk: review corrections: indent, visibility, syntax, wording.
senny authored
173 from_table, to_table, add_options = args
6073d7c Yves Senn fk: make `add_foreign_key` reversible.
senny authored
174 add_options ||= {}
175
176 if add_options[:name]
24e1aef Yves Senn fk: review corrections: indent, visibility, syntax, wording.
senny authored
177 options = { name: add_options[:name] }
6073d7c Yves Senn fk: make `add_foreign_key` reversible.
senny authored
178 elsif add_options[:column]
24e1aef Yves Senn fk: review corrections: indent, visibility, syntax, wording.
senny authored
179 options = { column: add_options[:column] }
d074b82 Yves Senn fk: infere column name from table names.
senny authored
180 else
181 options = to_table
6073d7c Yves Senn fk: make `add_foreign_key` reversible.
senny authored
182 end
183
184 [:remove_foreign_key, [from_table, options]]
185 end
186
15f35c0 Vijay Dev Reversing the changes done in c278a2c while still resolving #1857.
vijaydev authored
187 # Forwards any missing method call to the \target.
30176f2 Pratik Add :bulk => true option to change_table
lifo authored
188 def method_missing(method, *args, &block)
eb589fe Nishant Modak Make change_table use object of current database adapter
nishantmodak authored
189 if @delegate.respond_to?(method)
190 @delegate.send(method, *args, &block)
191 else
192 super
193 end
30176f2 Pratik Add :bulk => true option to change_table
lifo authored
194 end
843e319 Aaron Patterson partial implementation of the command recorder
tenderlove authored
195 end
196 end
197 end
Something went wrong with that request. Please try again.