strong_migrations 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bce49483e36caa343a3496771d052e4cc7d4db1e72c0ca23d80be1339bcb4dae
4
- data.tar.gz: e15a13f2c41a610c8a6825a209581b2b66d28584ecc41fcc6c46f2f0d69ff293
3
+ metadata.gz: a77b960928e0167e1842dbd337dc0e47ecae009fec7e6b13cdfba539cb2addc5
4
+ data.tar.gz: 154e03c69d7790a81051bf55b0d2a04a0a1ce0ed83d347f5a44f7255f950f794
5
5
  SHA512:
6
- metadata.gz: 68f4b5e294502c361c23cf17bf921310a285b27b4f5112c115ac26683af0f3841bf2815229bf793feab85ae71cac93e3e4e76f6928aa47cfe913669d2c3219ce
7
- data.tar.gz: 2dc364a36b8aa88408554a5671d8380cc6d27ab17321542181cebac3568cc5bcc4ea61d14508e6c59a9641e41e074ee0120d7f4098648c1f6508be1d479289c5
6
+ metadata.gz: 90839d0e1af71af600a220dd689262c6472190d437a61e97da40bd79c7ec5f4d418d45c2b3ff88514e3ab1ceca8cc04bb912f1f3e6553ba3efac53eb6d171992
7
+ data.tar.gz: bbf6f7b9645391d8fdaa54b8edf59904d2f75c806bcd7d0940eb762cc102c2355fafa231114d20a1cb8cae603eea807fd654868da3f6f40846a8fe022bd58778
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.4.2
2
+
3
+ - Allow `add_reference` with concurrent indexes
4
+
1
5
  ## 0.4.1
2
6
 
3
7
  - Added `target_postgresql_version`
data/README.md CHANGED
@@ -50,7 +50,7 @@ Also checks for best practices:
50
50
  ActiveRecord caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
51
51
 
52
52
  ```ruby
53
- class RemoveSomeColumnFromUsers < ActiveRecord::Migration[5.2]
53
+ class RemoveSomeColumnFromUsers < ActiveRecord::Migration[6.0]
54
54
  def change
55
55
  remove_column :users, :some_column
56
56
  end
@@ -71,7 +71,7 @@ end
71
71
  3. Write a migration to remove the column (wrap in `safety_assured` block)
72
72
 
73
73
  ```ruby
74
- class RemoveSomeColumnFromUsers < ActiveRecord::Migration[5.2]
74
+ class RemoveSomeColumnFromUsers < ActiveRecord::Migration[6.0]
75
75
  def change
76
76
  safety_assured { remove_column :users, :some_column }
77
77
  end
@@ -87,7 +87,7 @@ end
87
87
  Adding a column with a default value to an existing table causes the entire table to be rewritten.
88
88
 
89
89
  ```ruby
90
- class AddSomeColumnToUsers < ActiveRecord::Migration[5.2]
90
+ class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
91
91
  def change
92
92
  add_column :users, :some_column, :text, default: "default_value"
93
93
  end
@@ -101,7 +101,7 @@ end
101
101
  Instead, add the column without a default value, then change the default.
102
102
 
103
103
  ```ruby
104
- class AddSomeColumnToUsers < ActiveRecord::Migration[5.2]
104
+ class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
105
105
  def up
106
106
  add_column :users, :some_column, :text
107
107
  change_column_default :users, :some_column, "default_value"
@@ -122,7 +122,7 @@ See the next section for how to backfill.
122
122
  Backfilling in the same transaction that alters a table locks the table for the [duration of the backfill](https://wework.github.io/data/2015/11/05/add-columns-with-default-values-to-large-tables-in-rails-postgres/).
123
123
 
124
124
  ```ruby
125
- class AddSomeColumnToUsers < ActiveRecord::Migration[5.2]
125
+ class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
126
126
  def change
127
127
  add_column :users, :some_column, :text
128
128
  User.update_all some_column: "default_value"
@@ -134,10 +134,10 @@ Also, running a single query to update data can cause issues for large tables.
134
134
 
135
135
  #### Good
136
136
 
137
- There are three keys: batching, throttling, and running it outside a transaction. Use the Rails console or a separate migration with `disable_ddl_transaction!`.
137
+ There are three keys to backfilling safely: batching, throttling, and running it outside a transaction. Use the Rails console or a separate migration with `disable_ddl_transaction!`.
138
138
 
139
139
  ```ruby
140
- class BackfillSomeColumn < ActiveRecord::Migration[5.2]
140
+ class BackfillSomeColumn < ActiveRecord::Migration[6.0]
141
141
  disable_ddl_transaction!
142
142
 
143
143
  def change
@@ -156,7 +156,7 @@ end
156
156
  In Postgres, adding a non-concurrent index locks the table.
157
157
 
158
158
  ```ruby
159
- class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
159
+ class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
160
160
  def change
161
161
  add_index :users, :some_column
162
162
  end
@@ -168,7 +168,7 @@ end
168
168
  Add indexes concurrently.
169
169
 
170
170
  ```ruby
171
- class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
171
+ class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
172
172
  disable_ddl_transaction!
173
173
 
174
174
  def change
@@ -186,7 +186,7 @@ If you forget `disable_ddl_transaction!`, the migration will fail. Also, note th
186
186
  Rails adds a non-concurrent index to references by default, which is problematic for Postgres.
187
187
 
188
188
  ```ruby
189
- class AddReferenceToUsers < ActiveRecord::Migration[5.2]
189
+ class AddReferenceToUsers < ActiveRecord::Migration[6.0]
190
190
  def change
191
191
  add_reference :users, :city
192
192
  end
@@ -198,12 +198,11 @@ end
198
198
  Make sure the index is added concurrently.
199
199
 
200
200
  ```ruby
201
- class AddReferenceToUsers < ActiveRecord::Migration[5.2]
201
+ class AddReferenceToUsers < ActiveRecord::Migration[6.0]
202
202
  disable_ddl_transaction!
203
203
 
204
204
  def change
205
- add_reference :users, :city, index: false
206
- add_index :users, :city_id, algorithm: :concurrently
205
+ add_reference :users, :city, index: {algorithm: :concurrently}
207
206
  end
208
207
  end
209
208
  ```
@@ -217,7 +216,7 @@ For polymorphic references, add a compound index on type and id.
217
216
  In Postgres, new foreign keys are validated by default, which acquires an `AccessExclusiveLock` that can be [expensive on large tables](https://travisofthenorth.com/blog/2017/2/2/postgres-adding-foreign-keys-with-zero-downtime).
218
217
 
219
218
  ```ruby
220
- class AddForeignKeyOnUsers < ActiveRecord::Migration[5.2]
219
+ class AddForeignKeyOnUsers < ActiveRecord::Migration[6.0]
221
220
  def change
222
221
  add_foreign_key :users, :orders
223
222
  end
@@ -231,7 +230,7 @@ Instead, validate it in a separate migration with a more agreeable `RowShareLock
231
230
  For Rails 5.2+, use:
232
231
 
233
232
  ```ruby
234
- class AddForeignKeyOnUsers < ActiveRecord::Migration[5.2]
233
+ class AddForeignKeyOnUsers < ActiveRecord::Migration[6.0]
235
234
  def change
236
235
  add_foreign_key :users, :orders, validate: false
237
236
  end
@@ -241,7 +240,7 @@ end
241
240
  Then validate it in a separate migration.
242
241
 
243
242
  ```ruby
244
- class ValidateForeignKeyOnUsers < ActiveRecord::Migration[5.2]
243
+ class ValidateForeignKeyOnUsers < ActiveRecord::Migration[6.0]
245
244
  def change
246
245
  validate_foreign_key :users, :orders
247
246
  end
@@ -277,7 +276,7 @@ end
277
276
  #### Bad
278
277
 
279
278
  ```ruby
280
- class RenameSomeColumn < ActiveRecord::Migration[5.2]
279
+ class RenameSomeColumn < ActiveRecord::Migration[6.0]
281
280
  def change
282
281
  rename_column :users, :some_column, :new_name
283
282
  end
@@ -287,7 +286,7 @@ end
287
286
  or
288
287
 
289
288
  ```ruby
290
- class ChangeSomeColumnType < ActiveRecord::Migration[5.2]
289
+ class ChangeSomeColumnType < ActiveRecord::Migration[6.0]
291
290
  def change
292
291
  change_column :users, :some_column, :new_type
293
292
  end
@@ -312,7 +311,7 @@ A safer approach is to:
312
311
  #### Bad
313
312
 
314
313
  ```ruby
315
- class RenameUsersToCustomers < ActiveRecord::Migration[5.2]
314
+ class RenameUsersToCustomers < ActiveRecord::Migration[6.0]
316
315
  def change
317
316
  rename_table :users, :customers
318
317
  end
@@ -337,7 +336,7 @@ A safer approach is to:
337
336
  The `force` option can drop an existing table.
338
337
 
339
338
  ```ruby
340
- class CreateUsers < ActiveRecord::Migration[5.2]
339
+ class CreateUsers < ActiveRecord::Migration[6.0]
341
340
  def change
342
341
  create_table :users, force: true do |t|
343
342
  # ...
@@ -348,10 +347,10 @@ end
348
347
 
349
348
  #### Good
350
349
 
351
- If you intend to drop a table, do it explicitly. Then create the new table without the `force` option:
350
+ Create tables without the `force` option.
352
351
 
353
352
  ```ruby
354
- class CreateUsers < ActiveRecord::Migration[5.2]
353
+ class CreateUsers < ActiveRecord::Migration[6.0]
355
354
  def change
356
355
  create_table :users do |t|
357
356
  # ...
@@ -367,7 +366,7 @@ end
367
366
  This generates a single `UPDATE` statement to set the default value.
368
367
 
369
368
  ```ruby
370
- class ChangeSomeColumnNull < ActiveRecord::Migration[5.2]
369
+ class ChangeSomeColumnNull < ActiveRecord::Migration[6.0]
371
370
  def change
372
371
  change_column_null :users, :some_column, false, "default_value"
373
372
  end
@@ -379,7 +378,7 @@ end
379
378
  Backfill the column [safely](#backfilling-data). Then use:
380
379
 
381
380
  ```ruby
382
- class ChangeSomeColumnNull < ActiveRecord::Migration[5.2]
381
+ class ChangeSomeColumnNull < ActiveRecord::Migration[6.0]
383
382
  def change
384
383
  change_column_null :users, :some_column, false
385
384
  end
@@ -393,7 +392,7 @@ end
393
392
  In Postgres, there’s no equality operator for the `json` column type, which causes issues for `SELECT DISTINCT` queries.
394
393
 
395
394
  ```ruby
396
- class AddPropertiesToUsers < ActiveRecord::Migration[5.2]
395
+ class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
397
396
  def change
398
397
  add_column :users, :properties, :json
399
398
  end
@@ -405,7 +404,7 @@ end
405
404
  Use `jsonb` instead.
406
405
 
407
406
  ```ruby
408
- class AddPropertiesToUsers < ActiveRecord::Migration[5.2]
407
+ class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
409
408
  def change
410
409
  add_column :users, :properties, :jsonb
411
410
  end
@@ -421,7 +420,7 @@ end
421
420
  Adding a non-unique index with more than three columns rarely improves performance.
422
421
 
423
422
  ```ruby
424
- class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
423
+ class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
425
424
  def change
426
425
  add_index :users, [:a, :b, :c, :d]
427
426
  end
@@ -433,7 +432,7 @@ end
433
432
  Instead, start an index with columns that narrow down the results the most.
434
433
 
435
434
  ```ruby
436
- class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
435
+ class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
437
436
  def change
438
437
  add_index :users, [:b, :d]
439
438
  end
@@ -447,7 +446,7 @@ end
447
446
  To mark a step in the migration as safe, despite using a method that might otherwise be dangerous, wrap it in a `safety_assured` block.
448
447
 
449
448
  ```ruby
450
- class MySafeMigration < ActiveRecord::Migration[5.2]
449
+ class MySafeMigration < ActiveRecord::Migration[6.0]
451
450
  def change
452
451
  safety_assured { remove_column :users, :some_column }
453
452
  end
@@ -97,8 +97,7 @@ class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
97
97
  disable_ddl_transaction!
98
98
 
99
99
  def change
100
- %{reference_command}
101
- %{index_command}
100
+ %{command}
102
101
  end
103
102
  end",
104
103
 
@@ -116,12 +116,18 @@ end"
116
116
  options ||= {}
117
117
 
118
118
  index_value = options.fetch(:index, true)
119
- if postgresql? && index_value
119
+ concurrently_set = index_value.is_a?(Hash) && index_value[:algorithm] == :concurrently
120
+
121
+ if postgresql? && index_value && !concurrently_set
120
122
  columns = options[:polymorphic] ? [:"#{reference}_type", :"#{reference}_id"] : :"#{reference}_id"
121
123
 
122
- raise_error :add_reference,
123
- reference_command: command_str(method, [table, reference, options.merge(index: false)]),
124
- index_command: command_str("add_index", [table, columns, {algorithm: :concurrently}])
124
+ if index_value.is_a?(Hash)
125
+ options[:index] = options[:index].merge(algorithm: :concurrently)
126
+ else
127
+ options = options.merge(index: {algorithm: :concurrently})
128
+ end
129
+
130
+ raise_error :add_reference, command: command_str(method, [table, reference, options])
125
131
  end
126
132
  when :execute
127
133
  raise_error :execute, header: "Possibly dangerous operation"
@@ -236,7 +242,14 @@ end"
236
242
  last_arg = args[-1]
237
243
  if last_arg.is_a?(Hash)
238
244
  if last_arg.any?
239
- str_args << last_arg.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")
245
+ str_args << last_arg.map do |k, v|
246
+ if v.is_a?(Hash)
247
+ # pretty index: {algorithm: :concurrently}
248
+ "#{k}: {#{v.map { |k2, v2| "#{k2}: #{v2.inspect}" }.join(", ")}}"
249
+ else
250
+ "#{k}: #{v.inspect}"
251
+ end
252
+ end.join(", ")
240
253
  end
241
254
  else
242
255
  str_args << last_arg.inspect
@@ -1,23 +1,18 @@
1
1
  module StrongMigrations
2
2
  module Migration
3
- def initialize(*args)
4
- super
5
- @checker = StrongMigrations::Checker.new(self)
6
- end
7
-
8
3
  def migrate(direction)
9
- @checker.direction = direction
4
+ strong_migrations_checker.direction = direction
10
5
  super
11
6
  end
12
7
 
13
8
  def method_missing(method, *args)
14
- @checker.perform(method, *args) do
9
+ strong_migrations_checker.perform(method, *args) do
15
10
  super
16
11
  end
17
12
  end
18
13
 
19
14
  def safety_assured
20
- @checker.safety_assured do
15
+ strong_migrations_checker.safety_assured do
21
16
  yield
22
17
  end
23
18
  end
@@ -25,5 +20,11 @@ module StrongMigrations
25
20
  def stop!(message, header: "Custom check")
26
21
  raise StrongMigrations::UnsafeMigration, "\n=== #{header} #strong_migrations ===\n\n#{message}\n"
27
22
  end
23
+
24
+ private
25
+
26
+ def strong_migrations_checker
27
+ @strong_migrations_checker ||= StrongMigrations::Checker.new(self)
28
+ end
28
29
  end
29
30
  end
@@ -1,3 +1,3 @@
1
1
  module StrongMigrations
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strong_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-07-12 00:00:00.000000000 Z
13
+ date: 2019-10-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -122,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
122
  - !ruby/object:Gem::Version
123
123
  version: '0'
124
124
  requirements: []
125
- rubygems_version: 3.0.4
125
+ rubygems_version: 3.0.3
126
126
  signing_key:
127
127
  specification_version: 4
128
128
  summary: Catch unsafe migrations in development