strong_migrations 1.2.0 → 1.3.0

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: 4c0ea5c8cf3e904b89b8c4ab2f28ff60031515e40edf5b0c617ca4b8f8249650
4
- data.tar.gz: 5cb0fd63058bf618595cd929ef90de3cf90f02963f0adca21182c578f41c3320
3
+ metadata.gz: 4da88a3161110bc4e7fd6cc989ea51e0db2e32681c8026db11ac74c763f253b3
4
+ data.tar.gz: 583cd8b1e9665842ff6017c6d7242dcbfd9583157327b33ec023d5357c4e799f
5
5
  SHA512:
6
- metadata.gz: 50db9d240d49b60b75d97c76765b8f5e3b252c2cc826bd5e50e9b57311082dfea2c9cc5790fd905a2eac45a3eb6afb2784c7ed7962dcaf0172157548e1c8d233
7
- data.tar.gz: 2f2e5311cad061b712ee9dfb69a41b5e81f31be8db257bd095cbd8124bc461551afebb305d95b0bb090d6f7ef85c61618d61e64e9b73f266338a0aa7f5101b53
6
+ metadata.gz: 68356a9f5966f33a2a43f35a5f74ce21943798e4d85eb1c52710808dbac0efab6659d67a22d89aa4360cfc4f87e0dce6312e16f3a71dc0a739e87bb335d42f84
7
+ data.tar.gz: 67038470a20b75fd3dfb8642fea4775aedb08bff959255a44aa92271e2214300e9140f3d7cce21eae83e81ea314739c06999ce8d46a72f76f75f675e6c8914fb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 1.3.0 (2022-08-30)
2
+
3
+ - Added check for `add_column` with `uuid` type and volatile default value
4
+
1
5
  ## 1.2.0 (2022-06-10)
2
6
 
3
7
  - Added check for index corruption with Postgres 14.0 to 14.3
data/README.md CHANGED
@@ -135,7 +135,7 @@ class AddSomeColumnToUsers < ActiveRecord::Migration[7.0]
135
135
  end
136
136
  ```
137
137
 
138
- In Postgres 11+, MySQL 8.0.12+, and MariaDB 10.3.2+, this no longer requires a table rewrite and is safe.
138
+ In Postgres 11+, MySQL 8.0.12+, and MariaDB 10.3.2+, this no longer requires a table rewrite and is safe (except for volatile functions like `gen_random_uuid()`).
139
139
 
140
140
  #### Good
141
141
 
@@ -681,7 +681,7 @@ Disable specific checks with:
681
681
  StrongMigrations.disable_check(:add_index)
682
682
  ```
683
683
 
684
- Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations.rb) for the list of keys.
684
+ Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations/error_messages.rb) for the list of keys.
685
685
 
686
686
  ## Down Migrations / Rollbacks
687
687
 
@@ -14,11 +14,7 @@ module StrongMigrations
14
14
  target_version(StrongMigrations.target_postgresql_version) do
15
15
  version = select_all("SHOW server_version_num").first["server_version_num"].to_i
16
16
  # major and minor version
17
- if version >= 100000
18
- "#{version / 10000}.#{(version % 10000)}"
19
- else
20
- "#{version / 10000}.#{(version % 10000) / 100}"
21
- end
17
+ "#{version / 10000}.#{(version % 10000)}"
22
18
  end
23
19
  end
24
20
  end
@@ -76,7 +72,7 @@ module StrongMigrations
76
72
  # but there doesn't seem to be a way to set/modify it
77
73
  # https://wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.2#Reduce_ALTER_TABLE_rewrites
78
74
  when "numeric", "decimal"
79
- # numeric and decimal are equivalent and can be used interchangably
75
+ # numeric and decimal are equivalent and can be used interchangeably
80
76
  safe = ["numeric", "decimal"].include?(existing_type) &&
81
77
  (
82
78
  (
@@ -166,6 +162,13 @@ module StrongMigrations
166
162
  !StrongMigrations.developer_env?
167
163
  end
168
164
 
165
+ # default to true if unsure
166
+ def default_volatile?(default)
167
+ name = default.to_s.delete_suffix("()")
168
+ rows = select_all("SELECT provolatile FROM pg_proc WHERE proname = #{connection.quote(name)}").to_a
169
+ rows.empty? || rows.any? { |r| r["provolatile"] == "v" }
170
+ end
171
+
169
172
  private
170
173
 
171
174
  def set_timeout(setting, timeout)
@@ -32,7 +32,9 @@ module StrongMigrations
32
32
  table, column, type = args
33
33
  default = options[:default]
34
34
 
35
- if !default.nil? && !adapter.add_column_default_safe?
35
+ # Active Record has special case for uuid columns that allows function default values
36
+ # https://github.com/rails/rails/blob/v7.0.3.1/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb#L92-L93
37
+ if !default.nil? && (!adapter.add_column_default_safe? || (volatile = (postgresql? && type.to_s == "uuid" && default.to_s.include?("()") && adapter.default_volatile?(default))))
36
38
  if options[:null] == false
37
39
  options = options.except(:null)
38
40
  append = "
@@ -44,9 +46,10 @@ Then add the NOT NULL constraint in separate migrations."
44
46
  add_command: command_str("add_column", [table, column, type, options.except(:default)]),
45
47
  change_command: command_str("change_column_default", [table, column, default]),
46
48
  remove_command: command_str("remove_column", [table, column]),
47
- code: backfill_code(table, column, default),
49
+ code: backfill_code(table, column, default, volatile),
48
50
  append: append,
49
- rewrite_blocks: adapter.rewrite_blocks
51
+ rewrite_blocks: adapter.rewrite_blocks,
52
+ default_type: (volatile ? "volatile" : "non-null")
50
53
  elsif default.is_a?(Proc) && postgresql?
51
54
  # adding a column with a VOLATILE default is not safe
52
55
  # https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-NOTES
@@ -226,9 +229,17 @@ Then add the foreign key in separate migrations."
226
229
  safety_assured_str(add_code)
227
230
  end
228
231
 
232
+ validate_constraint_code =
233
+ if safe_with_check_constraint
234
+ down_code = "#{add_constraint_code}\n #{command_str(:change_column_null, [table, column, true])}"
235
+ "def up\n #{validate_constraint_code}\n end\n\n def down\n #{down_code}\n end"
236
+ else
237
+ "def change\n #{validate_constraint_code}\n end"
238
+ end
239
+
229
240
  raise_error :change_column_null_postgresql,
230
241
  add_constraint_code: add_constraint_code,
231
- validate_constraint_code: "def change\n #{validate_constraint_code}\n end"
242
+ validate_constraint_code: validate_constraint_code
232
243
  end
233
244
  elsif mysql? || mariadb?
234
245
  unless adapter.strict_mode?
@@ -409,9 +420,14 @@ Then add the foreign key in separate migrations."
409
420
  "#{command} #{str_args.join(", ")}"
410
421
  end
411
422
 
412
- def backfill_code(table, column, default)
423
+ def backfill_code(table, column, default, function = false)
413
424
  model = table.to_s.classify
414
- "#{model}.unscoped.in_batches do |relation| \n relation.update_all #{column}: #{default.inspect}\n sleep(0.01)\n end"
425
+ if function
426
+ # update_all(column: Arel.sql(default)) also works in newer versions of Active Record
427
+ "#{model}.unscoped.in_batches do |relation| \n relation.where(#{column}: nil).update_all(\"#{column} = #{default}\")\n sleep(0.01)\n end"
428
+ else
429
+ "#{model}.unscoped.in_batches do |relation| \n relation.update_all #{column}: #{default.inspect}\n sleep(0.01)\n end"
430
+ end
415
431
  end
416
432
 
417
433
  def new_table?(table)
@@ -1,7 +1,7 @@
1
1
  module StrongMigrations
2
2
  self.error_messages = {
3
3
  add_column_default:
4
- "Adding a column with a non-null default blocks %{rewrite_blocks} while the entire table is rewritten.
4
+ "Adding a column with a %{default_type} default blocks %{rewrite_blocks} while the entire table is rewritten.
5
5
  Instead, add the column without a default value, then change the default.
6
6
 
7
7
  class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
@@ -1,3 +1,3 @@
1
1
  module StrongMigrations
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -1,5 +1,5 @@
1
1
  namespace :strong_migrations do
2
- # https://www.pgrs.net/2008/03/13/alphabetize-schema-rb-columns/
2
+ # https://www.pgrs.net/2008/03/12/alphabetize-schema-rb-columns/
3
3
  task :alphabetize_columns do
4
4
  $stderr.puts "Dumping schema"
5
5
  ActiveRecord::Base.logger.level = Logger::INFO
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: 1.2.0
4
+ version: 1.3.0
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: 2022-06-10 00:00:00.000000000 Z
13
+ date: 2022-08-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord