strong_migrations 0.7.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module StrongMigrations
2
- VERSION = "0.7.8"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,11 +1,19 @@
1
1
  # dependencies
2
2
  require "active_support"
3
3
 
4
+ # adapters
5
+ require "strong_migrations/adapters/abstract_adapter"
6
+ require "strong_migrations/adapters/mysql_adapter"
7
+ require "strong_migrations/adapters/mariadb_adapter"
8
+ require "strong_migrations/adapters/postgresql_adapter"
9
+
4
10
  # modules
11
+ require "strong_migrations/checks"
5
12
  require "strong_migrations/safe_methods"
6
13
  require "strong_migrations/checker"
7
14
  require "strong_migrations/database_tasks"
8
15
  require "strong_migrations/migration"
16
+ require "strong_migrations/migrator"
9
17
  require "strong_migrations/version"
10
18
 
11
19
  # integrations
@@ -14,235 +22,21 @@ require "strong_migrations/railtie" if defined?(Rails)
14
22
  module StrongMigrations
15
23
  class Error < StandardError; end
16
24
  class UnsafeMigration < Error; end
25
+ class UnsupportedVersion < Error; end
17
26
 
18
27
  class << self
19
28
  attr_accessor :auto_analyze, :start_after, :checks, :error_messages,
20
29
  :target_postgresql_version, :target_mysql_version, :target_mariadb_version,
21
30
  :enabled_checks, :lock_timeout, :statement_timeout, :check_down, :target_version,
22
- :safe_by_default
31
+ :safe_by_default, :target_sql_mode, :lock_timeout_retries, :lock_timeout_retry_delay
23
32
  attr_writer :lock_timeout_limit
24
33
  end
25
34
  self.auto_analyze = false
26
35
  self.start_after = 0
36
+ self.lock_timeout_retries = 0
37
+ self.lock_timeout_retry_delay = 10 # seconds
27
38
  self.checks = []
28
39
  self.safe_by_default = false
29
- self.error_messages = {
30
- add_column_default:
31
- "Adding a column with a non-null default blocks %{rewrite_blocks} while the entire table is rewritten.
32
- Instead, add the column without a default value, then change the default.
33
-
34
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
35
- def up
36
- %{add_command}
37
- %{change_command}
38
- end
39
-
40
- def down
41
- %{remove_command}
42
- end
43
- end
44
-
45
- Then backfill the existing rows in the Rails console or a separate migration with disable_ddl_transaction!.
46
-
47
- class Backfill%{migration_name} < ActiveRecord::Migration%{migration_suffix}
48
- disable_ddl_transaction!
49
-
50
- def up
51
- %{code}
52
- end
53
- end",
54
-
55
- add_column_json:
56
- "There's no equality operator for the json column type, which can cause errors for
57
- existing SELECT DISTINCT queries in your application. Use jsonb instead.
58
-
59
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
60
- def change
61
- %{command}
62
- end
63
- end",
64
-
65
- change_column:
66
- "Changing the type of an existing column blocks %{rewrite_blocks}
67
- while the entire table is rewritten. A safer approach is to:
68
-
69
- 1. Create a new column
70
- 2. Write to both columns
71
- 3. Backfill data from the old column to the new column
72
- 4. Move reads from the old column to the new column
73
- 5. Stop writing to the old column
74
- 6. Drop the old column",
75
-
76
- change_column_with_not_null:
77
- "Changing the type is safe, but setting NOT NULL is not.",
78
-
79
- remove_column: "Active Record caches attributes, which causes problems
80
- when removing columns. Be sure to ignore the column%{column_suffix}:
81
-
82
- class %{model} < %{base_model}
83
- %{code}
84
- end
85
-
86
- Deploy the code, then wrap this step in a safety_assured { ... } block.
87
-
88
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
89
- def change
90
- safety_assured { %{command} }
91
- end
92
- end",
93
-
94
- rename_column:
95
- "Renaming a column that's in use will cause errors
96
- in your application. A safer approach is to:
97
-
98
- 1. Create a new column
99
- 2. Write to both columns
100
- 3. Backfill data from the old column to new column
101
- 4. Move reads from the old column to the new column
102
- 5. Stop writing to the old column
103
- 6. Drop the old column",
104
-
105
- rename_table:
106
- "Renaming a table that's in use will cause errors
107
- in your application. A safer approach is to:
108
-
109
- 1. Create a new table. Don't forget to recreate indexes from the old table
110
- 2. Write to both tables
111
- 3. Backfill data from the old table to new table
112
- 4. Move reads from the old table to the new table
113
- 5. Stop writing to the old table
114
- 6. Drop the old table",
115
-
116
- add_reference:
117
- "%{headline} Instead, use:
118
-
119
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
120
- disable_ddl_transaction!
121
-
122
- def change
123
- %{command}
124
- end
125
- end",
126
-
127
- add_index:
128
- "Adding an index non-concurrently blocks writes. Instead, use:
129
-
130
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
131
- disable_ddl_transaction!
132
-
133
- def change
134
- %{command}
135
- end
136
- end",
137
-
138
- remove_index:
139
- "Removing an index non-concurrently blocks writes. Instead, use:
140
-
141
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
142
- disable_ddl_transaction!
143
-
144
- def change
145
- %{command}
146
- end
147
- end",
148
-
149
- add_index_columns:
150
- "Adding a non-unique index with more than three columns rarely improves performance.
151
- Instead, start an index with columns that narrow down the results the most.",
152
-
153
- change_table:
154
- "Strong Migrations does not support inspecting what happens inside a
155
- change_table block, so cannot help you here. Please make really sure that what
156
- you're doing is safe before proceeding, then wrap it in a safety_assured { ... } block.",
157
-
158
- create_table:
159
- "The force option will destroy existing tables.
160
- If this is intended, drop the existing table first.
161
- Otherwise, remove the force option.",
162
-
163
- execute:
164
- "Strong Migrations does not support inspecting what happens inside an
165
- execute call, so cannot help you here. Please make really sure that what
166
- you're doing is safe before proceeding, then wrap it in a safety_assured { ... } block.",
167
-
168
- change_column_null:
169
- "Passing a default value to change_column_null runs a single UPDATE query,
170
- which can cause downtime. Instead, backfill the existing rows in the
171
- Rails console or a separate migration with disable_ddl_transaction!.
172
-
173
- class Backfill%{migration_name} < ActiveRecord::Migration%{migration_suffix}
174
- disable_ddl_transaction!
175
-
176
- def up
177
- %{code}
178
- end
179
- end",
180
-
181
- change_column_null_postgresql:
182
- "Setting NOT NULL on an existing column blocks reads and writes while every row is checked.
183
- Instead, add a check constraint and validate it in a separate migration.
184
-
185
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
186
- def change
187
- %{add_constraint_code}
188
- end
189
- end
190
-
191
- class Validate%{migration_name} < ActiveRecord::Migration%{migration_suffix}
192
- def change
193
- %{validate_constraint_code}
194
- end
195
- end",
196
-
197
- change_column_null_mysql:
198
- "Setting NOT NULL on an existing column is not safe with your database engine.",
199
-
200
- add_foreign_key:
201
- "Adding a foreign key blocks writes on both tables. Instead,
202
- add the foreign key without validating existing rows,
203
- then validate them in a separate migration.
204
-
205
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
206
- def change
207
- %{add_foreign_key_code}
208
- end
209
- end
210
-
211
- class Validate%{migration_name} < ActiveRecord::Migration%{migration_suffix}
212
- def change
213
- %{validate_foreign_key_code}
214
- end
215
- end",
216
-
217
- validate_foreign_key:
218
- "Validating a foreign key while writes are blocked is dangerous.
219
- Use disable_ddl_transaction! or a separate migration.",
220
-
221
- add_check_constraint:
222
- "Adding a check constraint key blocks reads and writes while every row is checked.
223
- Instead, add the check constraint without validating existing rows,
224
- then validate them in a separate migration.
225
-
226
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
227
- def change
228
- %{add_check_constraint_code}
229
- end
230
- end
231
-
232
- class Validate%{migration_name} < ActiveRecord::Migration%{migration_suffix}
233
- def change
234
- %{validate_check_constraint_code}
235
- end
236
- end",
237
-
238
- add_check_constraint_mysql:
239
- "Adding a check constraint to an existing table is not safe with your database engine.",
240
-
241
- validate_check_constraint:
242
- "Validating a check constraint while writes are blocked is dangerous.
243
- Use disable_ddl_transaction! or a separate migration."
244
- }
245
- self.enabled_checks = (error_messages.keys - [:remove_index]).map { |k| [k, {}] }.to_h
246
40
  self.check_down = false
247
41
 
248
42
  # private
@@ -279,8 +73,12 @@ Use disable_ddl_transaction! or a separate migration."
279
73
  end
280
74
  end
281
75
 
76
+ # load error messages
77
+ require "strong_migrations/error_messages"
78
+
282
79
  ActiveSupport.on_load(:active_record) do
283
80
  ActiveRecord::Migration.prepend(StrongMigrations::Migration)
81
+ ActiveRecord::Migrator.prepend(StrongMigrations::Migrator)
284
82
 
285
83
  if defined?(ActiveRecord::Tasks::DatabaseTasks)
286
84
  ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(StrongMigrations::DatabaseTasks)
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.7.8
4
+ version: 1.0.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: 2021-08-03 00:00:00.000000000 Z
13
+ date: 2022-03-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -18,87 +18,17 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: '5'
21
+ version: '5.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: '5'
29
- - !ruby/object:Gem::Dependency
30
- name: bundler
31
- requirement: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - ">="
34
- - !ruby/object:Gem::Version
35
- version: '0'
36
- type: :development
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: '0'
43
- - !ruby/object:Gem::Dependency
44
- name: rake
45
- requirement: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: '0'
50
- type: :development
51
- prerelease: false
52
- version_requirements: !ruby/object:Gem::Requirement
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: '0'
57
- - !ruby/object:Gem::Dependency
58
- name: minitest
59
- requirement: !ruby/object:Gem::Requirement
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: '0'
64
- type: :development
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: '0'
71
- - !ruby/object:Gem::Dependency
72
- name: pg
73
- requirement: !ruby/object:Gem::Requirement
74
- requirements:
75
- - - ">="
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
- type: :development
79
- prerelease: false
80
- version_requirements: !ruby/object:Gem::Requirement
81
- requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- version: '0'
85
- - !ruby/object:Gem::Dependency
86
- name: mysql2
87
- requirement: !ruby/object:Gem::Requirement
88
- requirements:
89
- - - ">="
90
- - !ruby/object:Gem::Version
91
- version: '0'
92
- type: :development
93
- prerelease: false
94
- version_requirements: !ruby/object:Gem::Requirement
95
- requirements:
96
- - - ">="
97
- - !ruby/object:Gem::Version
98
- version: '0'
28
+ version: '5.2'
99
29
  description:
100
30
  email:
101
- - andrew@chartkick.com
31
+ - andrew@ankane.org
102
32
  - bob.remeika@gmail.com
103
33
  executables: []
104
34
  extensions: []
@@ -111,10 +41,17 @@ files:
111
41
  - lib/generators/strong_migrations/install_generator.rb
112
42
  - lib/generators/strong_migrations/templates/initializer.rb.tt
113
43
  - lib/strong_migrations.rb
44
+ - lib/strong_migrations/adapters/abstract_adapter.rb
45
+ - lib/strong_migrations/adapters/mariadb_adapter.rb
46
+ - lib/strong_migrations/adapters/mysql_adapter.rb
47
+ - lib/strong_migrations/adapters/postgresql_adapter.rb
114
48
  - lib/strong_migrations/alphabetize_columns.rb
115
49
  - lib/strong_migrations/checker.rb
50
+ - lib/strong_migrations/checks.rb
116
51
  - lib/strong_migrations/database_tasks.rb
52
+ - lib/strong_migrations/error_messages.rb
117
53
  - lib/strong_migrations/migration.rb
54
+ - lib/strong_migrations/migrator.rb
118
55
  - lib/strong_migrations/railtie.rb
119
56
  - lib/strong_migrations/safe_methods.rb
120
57
  - lib/strong_migrations/version.rb
@@ -131,14 +68,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
131
68
  requirements:
132
69
  - - ">="
133
70
  - !ruby/object:Gem::Version
134
- version: '2.4'
71
+ version: '2.6'
135
72
  required_rubygems_version: !ruby/object:Gem::Requirement
136
73
  requirements:
137
74
  - - ">="
138
75
  - !ruby/object:Gem::Version
139
76
  version: '0'
140
77
  requirements: []
141
- rubygems_version: 3.2.22
78
+ rubygems_version: 3.3.7
142
79
  signing_key:
143
80
  specification_version: 4
144
81
  summary: Catch unsafe migrations in development