strong_migrations 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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