online_migrations 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/online_migrations/background_migrations/migration.rb +8 -0
- data/lib/online_migrations/background_migrations/migration_job.rb +1 -0
- data/lib/online_migrations/background_migrations/migration_runner.rb +1 -0
- data/lib/online_migrations/change_column_type_helpers.rb +1 -1
- data/lib/online_migrations/command_recorder.rb +16 -1
- data/lib/online_migrations/schema_cache.rb +13 -11
- data/lib/online_migrations/schema_statements.rb +106 -25
- data/lib/online_migrations/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '029dd11fe1935f72c4933c081b45c972613caa252c578a005b34a902122923d6'
|
4
|
+
data.tar.gz: 04d66e91c1c54f1fe19d8a743d4b6f70ef218bbe2310eb58a779602a92e72736
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '07865cb5068a3cba7956db786f78d0999070b9445798af0df17f9360fa9b3e5b3f19409756f383b9eb402fa8cfa0a2b2bb6ca57475267f915844a248598004b5'
|
7
|
+
data.tar.gz: 0f44b2cd5bd9bad6f85c2980da2ea41ad79c100c46bdce0c4be2d9630cc239b42a0217ae07fd6f568503a42a640da6b63a2840d3b714994fce65708bd8dbf289
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
## master (unreleased)
|
2
2
|
|
3
|
+
## 0.7.0 (2023-02-14)
|
4
|
+
|
5
|
+
- Add support for renaming multiple columns at once in the same table
|
6
|
+
- Fix quoting table/column names across the library
|
7
|
+
- Fix deffered foreign keys support in `add_foreign_key` (Active Record >= 7)
|
8
|
+
- Reset attempts of failing jobs before executing background migration inline
|
9
|
+
|
3
10
|
## 0.6.0 (2023-02-04)
|
4
11
|
|
5
12
|
- Ignore internal Active Record migrations compatibility related options when suggesting a safe column type change
|
@@ -123,6 +123,14 @@ module OnlineMigrations
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
# @private
|
127
|
+
def reset_failed_jobs_attempts
|
128
|
+
iterator = BatchIterator.new(migration_jobs.failed.attempts_exceeded)
|
129
|
+
iterator.each_batch(of: 100) do |relation|
|
130
|
+
relation.update_all(attempts: 0)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
126
134
|
# @private
|
127
135
|
def next_batch_range
|
128
136
|
iterator = BatchIterator.new(migration_relation)
|
@@ -570,7 +570,7 @@ module OnlineMigrations
|
|
570
570
|
transaction do
|
571
571
|
# We'll need ACCESS EXCLUSIVE lock on the related tables,
|
572
572
|
# lets make sure it can be acquired from the start.
|
573
|
-
execute("LOCK TABLE #{table_name}, #{referencing_table_name} IN ACCESS EXCLUSIVE MODE")
|
573
|
+
execute("LOCK TABLE #{quote_table_name(table_name)}, #{quote_table_name(referencing_table_name)} IN ACCESS EXCLUSIVE MODE")
|
574
574
|
|
575
575
|
remove_foreign_key(referencing_table_name, name: existing_name)
|
576
576
|
__rename_constraint(referencing_table_name, tmp_name, existing_name)
|
@@ -6,9 +6,13 @@ module OnlineMigrations
|
|
6
6
|
REVERSIBLE_AND_IRREVERSIBLE_METHODS = [
|
7
7
|
:update_column_in_batches,
|
8
8
|
:initialize_column_rename,
|
9
|
+
:initialize_columns_rename,
|
9
10
|
:revert_initialize_column_rename,
|
11
|
+
:revert_initialize_columns_rename,
|
10
12
|
:finalize_column_rename,
|
13
|
+
:finalize_columns_rename,
|
11
14
|
:revert_finalize_column_rename,
|
15
|
+
:revert_finalize_columns_rename,
|
12
16
|
:initialize_table_rename,
|
13
17
|
:revert_initialize_table_rename,
|
14
18
|
:finalize_table_rename,
|
@@ -49,7 +53,9 @@ module OnlineMigrations
|
|
49
53
|
module StraightReversions
|
50
54
|
{
|
51
55
|
initialize_column_rename: :revert_initialize_column_rename,
|
56
|
+
initialize_columns_rename: :revert_initialize_columns_rename,
|
52
57
|
finalize_column_rename: :revert_finalize_column_rename,
|
58
|
+
finalize_columns_rename: :revert_finalize_columns_rename,
|
53
59
|
initialize_table_rename: :revert_initialize_table_rename,
|
54
60
|
finalize_table_rename: :revert_finalize_table_rename,
|
55
61
|
add_not_null_constraint: :remove_not_null_constraint,
|
@@ -84,11 +90,20 @@ module OnlineMigrations
|
|
84
90
|
_table, column, new_column = args
|
85
91
|
if !column || !new_column
|
86
92
|
raise ActiveRecord::IrreversibleMigration,
|
87
|
-
"
|
93
|
+
"revert_initialize_column_rename is only reversible if given a column and new_column."
|
88
94
|
end
|
89
95
|
[:initialize_column_rename, args]
|
90
96
|
end
|
91
97
|
|
98
|
+
def invert_revert_initialize_columns_rename(args)
|
99
|
+
_table, old_new_column_hash = args
|
100
|
+
unless old_new_column_hash
|
101
|
+
raise ActiveRecord::IrreversibleMigration,
|
102
|
+
"revert_initialize_columns_rename is only reversible if given a hash of old and new columns."
|
103
|
+
end
|
104
|
+
[:initialize_columns_rename, args]
|
105
|
+
end
|
106
|
+
|
92
107
|
def invert_finalize_table_rename(args)
|
93
108
|
_table_name, new_name = args
|
94
109
|
unless new_name
|
@@ -18,17 +18,10 @@ module OnlineMigrations
|
|
18
18
|
super(renamed_tables[table_name])
|
19
19
|
elsif renamed_columns.key?(table_name)
|
20
20
|
columns = super(column_rename_table(table_name))
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
new_column = old_column.dup
|
26
|
-
|
27
|
-
# ActiveRecord defines only reader for :name
|
28
|
-
new_column.instance_variable_set(:@name, new_column_name)
|
29
|
-
|
30
|
-
# Correspond to the ActiveRecord freezing of each column
|
31
|
-
columns << new_column.freeze
|
21
|
+
renamed_columns[table_name].each do |old_column_name, new_column_name|
|
22
|
+
duplicate_column(old_column_name, new_column_name, columns)
|
23
|
+
end
|
24
|
+
columns
|
32
25
|
else
|
33
26
|
super.reject { |column| column.name.end_with?("_for_type_change") }
|
34
27
|
end
|
@@ -94,5 +87,14 @@ module OnlineMigrations
|
|
94
87
|
@renamed_columns = nil
|
95
88
|
@renamed_tables = nil
|
96
89
|
end
|
90
|
+
|
91
|
+
def duplicate_column(old_column_name, new_column_name, columns)
|
92
|
+
old_column = columns.find { |column| column.name == old_column_name }
|
93
|
+
new_column = old_column.dup
|
94
|
+
# ActiveRecord defines only reader for :name
|
95
|
+
new_column.instance_variable_set(:@name, new_column_name)
|
96
|
+
# Correspond to the ActiveRecord freezing of each column
|
97
|
+
columns << new_column.freeze
|
98
|
+
end
|
97
99
|
end
|
98
100
|
end
|
@@ -177,20 +177,34 @@ module OnlineMigrations
|
|
177
177
|
# until `finalize_column_rename` is run
|
178
178
|
#
|
179
179
|
def initialize_column_rename(table_name, column_name, new_column_name)
|
180
|
-
|
180
|
+
initialize_columns_rename(table_name, { column_name => new_column_name })
|
181
|
+
end
|
181
182
|
|
183
|
+
# Same as `initialize_column_rename` but for multiple columns.
|
184
|
+
#
|
185
|
+
# This is useful to avoid multiple iterations of the safe column rename steps
|
186
|
+
# when renaming multiple columns.
|
187
|
+
#
|
188
|
+
# @param table_name [String, Symbol] table name
|
189
|
+
# @param old_new_column_hash [Hash] the hash of old and new columns
|
190
|
+
#
|
191
|
+
# @example
|
192
|
+
# initialize_columns_rename(:users, { fname: :first_name, lname: :last_name })
|
193
|
+
#
|
194
|
+
# @see #initialize_column_rename
|
195
|
+
#
|
196
|
+
def initialize_columns_rename(table_name, old_new_column_hash)
|
182
197
|
transaction do
|
183
|
-
|
184
|
-
execute("CREATE VIEW #{table_name} AS SELECT *, #{column_name} AS #{new_column_name} FROM #{tmp_table}")
|
198
|
+
rename_table_create_view(table_name, old_new_column_hash)
|
185
199
|
end
|
186
200
|
end
|
187
201
|
|
188
202
|
# Reverts operations performed by initialize_column_rename
|
189
203
|
#
|
190
204
|
# @param table_name [String, Symbol] table name
|
191
|
-
# @param
|
205
|
+
# @param column_name [String, Symbol] the name of the column to be renamed.
|
192
206
|
# Passing this argument will make this change reversible in migration
|
193
|
-
# @param
|
207
|
+
# @param new_column_name [String, Symbol] new new name of the column.
|
194
208
|
# Passing this argument will make this change reversible in migration
|
195
209
|
#
|
196
210
|
# @return [void]
|
@@ -198,9 +212,24 @@ module OnlineMigrations
|
|
198
212
|
# @example
|
199
213
|
# revert_initialize_column_rename(:users, :name, :first_name)
|
200
214
|
#
|
201
|
-
def revert_initialize_column_rename(table_name,
|
215
|
+
def revert_initialize_column_rename(table_name, column_name = nil, new_column_name = nil)
|
216
|
+
revert_initialize_columns_rename(table_name, { column_name => new_column_name })
|
217
|
+
end
|
218
|
+
|
219
|
+
# Same as `revert_initialize_column_rename` but for multiple columns.
|
220
|
+
#
|
221
|
+
# @param table_name [String, Symbol] table name
|
222
|
+
# @param _old_new_column_hash [Hash] the hash of old and new columns
|
223
|
+
# Passing this argument will make this change reversible in migration
|
224
|
+
#
|
225
|
+
# @return [void]
|
226
|
+
#
|
227
|
+
# @example
|
228
|
+
# revert_initialize_columns_rename(:users, { fname: :first_name, lname: :last_name })
|
229
|
+
#
|
230
|
+
def revert_initialize_columns_rename(table_name, _old_new_column_hash = nil)
|
202
231
|
transaction do
|
203
|
-
execute("DROP VIEW #{table_name}")
|
232
|
+
execute("DROP VIEW #{quote_table_name(table_name)}")
|
204
233
|
rename_table("#{table_name}_column_rename", table_name)
|
205
234
|
end
|
206
235
|
end
|
@@ -214,10 +243,24 @@ module OnlineMigrations
|
|
214
243
|
# finalize_column_rename(:users, :name, :first_name)
|
215
244
|
#
|
216
245
|
def finalize_column_rename(table_name, column_name, new_column_name)
|
246
|
+
finalize_columns_rename(table_name, { column_name => new_column_name })
|
247
|
+
end
|
248
|
+
|
249
|
+
# Same as `finalize_column_rename` but for multiple columns.
|
250
|
+
#
|
251
|
+
# @param (see #initialize_columns_rename)
|
252
|
+
# @return [void]
|
253
|
+
#
|
254
|
+
# @example
|
255
|
+
# finalize_columns_rename(:users, { fname: :first_name, lname: :last_name })
|
256
|
+
#
|
257
|
+
def finalize_columns_rename(table_name, old_new_column_hash)
|
217
258
|
transaction do
|
218
|
-
execute("DROP VIEW #{table_name}")
|
259
|
+
execute("DROP VIEW #{quote_table_name(table_name)}")
|
219
260
|
rename_table("#{table_name}_column_rename", table_name)
|
220
|
-
|
261
|
+
old_new_column_hash.each do |column_name, new_column_name|
|
262
|
+
rename_column(table_name, column_name, new_column_name)
|
263
|
+
end
|
221
264
|
end
|
222
265
|
end
|
223
266
|
|
@@ -230,12 +273,23 @@ module OnlineMigrations
|
|
230
273
|
# revert_finalize_column_rename(:users, :name, :first_name)
|
231
274
|
#
|
232
275
|
def revert_finalize_column_rename(table_name, column_name, new_column_name)
|
233
|
-
|
276
|
+
revert_finalize_columns_rename(table_name, { column_name => new_column_name })
|
277
|
+
end
|
234
278
|
|
279
|
+
# Same as `revert_finalize_column_rename` but for multiple columns.
|
280
|
+
#
|
281
|
+
# @param (see #initialize_columns_rename)
|
282
|
+
# @return [void]
|
283
|
+
#
|
284
|
+
# @example
|
285
|
+
# revert_finalize_columns_rename(:users, { fname: :first_name, lname: :last_name })
|
286
|
+
#
|
287
|
+
def revert_finalize_columns_rename(table_name, old_new_column_hash)
|
235
288
|
transaction do
|
236
|
-
|
237
|
-
|
238
|
-
|
289
|
+
old_new_column_hash.each do |column_name, new_column_name|
|
290
|
+
rename_column(table_name, new_column_name, column_name)
|
291
|
+
end
|
292
|
+
rename_table_create_view(table_name, old_new_column_hash)
|
239
293
|
end
|
240
294
|
end
|
241
295
|
|
@@ -286,7 +340,7 @@ module OnlineMigrations
|
|
286
340
|
def initialize_table_rename(table_name, new_name)
|
287
341
|
transaction do
|
288
342
|
rename_table(table_name, new_name)
|
289
|
-
execute("CREATE VIEW #{table_name} AS SELECT * FROM #{new_name}")
|
343
|
+
execute("CREATE VIEW #{quote_table_name(table_name)} AS SELECT * FROM #{quote_table_name(new_name)}")
|
290
344
|
end
|
291
345
|
end
|
292
346
|
|
@@ -300,7 +354,7 @@ module OnlineMigrations
|
|
300
354
|
#
|
301
355
|
def revert_initialize_table_rename(table_name, new_name)
|
302
356
|
transaction do
|
303
|
-
execute("DROP VIEW IF EXISTS #{table_name}")
|
357
|
+
execute("DROP VIEW IF EXISTS #{quote_table_name(table_name)}")
|
304
358
|
rename_table(new_name, table_name)
|
305
359
|
end
|
306
360
|
end
|
@@ -316,7 +370,7 @@ module OnlineMigrations
|
|
316
370
|
# finalize_table_rename(:users, :clients)
|
317
371
|
#
|
318
372
|
def finalize_table_rename(table_name, _new_name = nil)
|
319
|
-
execute("DROP VIEW IF EXISTS #{table_name}")
|
373
|
+
execute("DROP VIEW IF EXISTS #{quote_table_name(table_name)}")
|
320
374
|
end
|
321
375
|
|
322
376
|
# Reverts operations performed by finalize_table_rename
|
@@ -329,7 +383,7 @@ module OnlineMigrations
|
|
329
383
|
# revert_finalize_table_rename(:users, :clients)
|
330
384
|
#
|
331
385
|
def revert_finalize_table_rename(table_name, new_name)
|
332
|
-
execute("CREATE VIEW #{table_name} AS SELECT * FROM #{new_name}")
|
386
|
+
execute("CREATE VIEW #{quote_table_name(table_name)} AS SELECT * FROM #{quote_table_name(new_name)}")
|
333
387
|
end
|
334
388
|
|
335
389
|
# Swaps two column names in a table
|
@@ -738,14 +792,18 @@ module OnlineMigrations
|
|
738
792
|
options[:name] ||= __foreign_key_name(to_table, options[:column])
|
739
793
|
|
740
794
|
query = <<-SQL.strip_heredoc.dup
|
741
|
-
ALTER TABLE #{from_table}
|
742
|
-
ADD CONSTRAINT #{options[:name]}
|
743
|
-
FOREIGN KEY (#{options[:column]})
|
744
|
-
REFERENCES #{to_table} (#{options[:primary_key]})
|
795
|
+
ALTER TABLE #{quote_table_name(from_table)}
|
796
|
+
ADD CONSTRAINT #{quote_column_name(options[:name])}
|
797
|
+
FOREIGN KEY (#{quote_column_name(options[:column])})
|
798
|
+
REFERENCES #{quote_table_name(to_table)} (#{quote_column_name(options[:primary_key])})
|
745
799
|
SQL
|
746
800
|
query << "#{__action_sql('DELETE', options[:on_delete])}\n" if options[:on_delete].present?
|
747
801
|
query << "#{__action_sql('UPDATE', options[:on_update])}\n" if options[:on_update].present?
|
748
802
|
query << "NOT VALID\n" if !validate
|
803
|
+
if Utils.ar_version >= 7.0 && options[:deferrable]
|
804
|
+
query << " DEFERRABLE"
|
805
|
+
query << " INITIALLY #{options[:deferrable].to_s.upcase}\n" if options[:deferrable] != true
|
806
|
+
end
|
749
807
|
|
750
808
|
execute(query.squish)
|
751
809
|
end
|
@@ -766,7 +824,7 @@ module OnlineMigrations
|
|
766
824
|
# "VALIDATE CONSTRAINT" requires a "SHARE UPDATE EXCLUSIVE" lock.
|
767
825
|
# It only conflicts with other validations, creating/removing indexes,
|
768
826
|
# and some other "ALTER TABLE"s.
|
769
|
-
execute("ALTER TABLE #{from_table} VALIDATE CONSTRAINT #{fk_name_to_validate}")
|
827
|
+
execute("ALTER TABLE #{quote_table_name(from_table)} VALIDATE CONSTRAINT #{quote_column_name(fk_name_to_validate)}")
|
770
828
|
end
|
771
829
|
end
|
772
830
|
|
@@ -786,7 +844,10 @@ module OnlineMigrations
|
|
786
844
|
Utils.say("Check constraint was not created because it already exists (this may be due to an aborted migration " \
|
787
845
|
"or similar) table_name: #{table_name}, expression: #{expression}, constraint name: #{constraint_name}")
|
788
846
|
else
|
789
|
-
query =
|
847
|
+
query = <<-SQL.squish
|
848
|
+
ALTER TABLE #{quote_table_name(table_name)}
|
849
|
+
ADD CONSTRAINT #{quote_column_name(constraint_name)} CHECK (#{expression})
|
850
|
+
SQL
|
790
851
|
query += " NOT VALID" if !validate
|
791
852
|
|
792
853
|
execute(query)
|
@@ -808,7 +869,10 @@ module OnlineMigrations
|
|
808
869
|
# "VALIDATE CONSTRAINT" requires a "SHARE UPDATE EXCLUSIVE" lock.
|
809
870
|
# It only conflicts with other validations, creating/removing indexes,
|
810
871
|
# and some other "ALTER TABLE"s.
|
811
|
-
execute(
|
872
|
+
execute(<<-SQL.squish)
|
873
|
+
ALTER TABLE #{quote_table_name(table_name)}
|
874
|
+
VALIDATE CONSTRAINT #{quote_column_name(constraint_name)}
|
875
|
+
SQL
|
812
876
|
end
|
813
877
|
end
|
814
878
|
|
@@ -818,7 +882,10 @@ module OnlineMigrations
|
|
818
882
|
#
|
819
883
|
def remove_check_constraint(table_name, expression = nil, **options)
|
820
884
|
constraint_name = __check_constraint_name!(table_name, expression: expression, **options)
|
821
|
-
execute(
|
885
|
+
execute(<<-SQL.squish)
|
886
|
+
ALTER TABLE #{quote_table_name(table_name)}
|
887
|
+
DROP CONSTRAINT #{quote_column_name(constraint_name)}
|
888
|
+
SQL
|
822
889
|
end
|
823
890
|
end
|
824
891
|
|
@@ -1084,5 +1151,19 @@ module OnlineMigrations
|
|
1084
1151
|
_, schema = table_name.to_s.split(".").reverse
|
1085
1152
|
schema ? quote(schema) : "current_schema()"
|
1086
1153
|
end
|
1154
|
+
|
1155
|
+
def rename_table_create_view(table_name, old_new_column_hash)
|
1156
|
+
tmp_table = "#{table_name}_column_rename"
|
1157
|
+
rename_table(table_name, tmp_table)
|
1158
|
+
column_mapping = old_new_column_hash.map do |column_name, new_column_name|
|
1159
|
+
"#{quote_column_name(column_name)} AS #{quote_column_name(new_column_name)}"
|
1160
|
+
end.join(", ")
|
1161
|
+
|
1162
|
+
execute(<<-SQL.squish)
|
1163
|
+
CREATE VIEW #{quote_table_name(table_name)} AS
|
1164
|
+
SELECT *, #{column_mapping}
|
1165
|
+
FROM #{quote_table_name(tmp_table)}
|
1166
|
+
SQL
|
1167
|
+
end
|
1087
1168
|
end
|
1088
1169
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: online_migrations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fatkodima
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|