strong_migrations 0.6.8 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,211 +1,59 @@
1
1
  # dependencies
2
2
  require "active_support"
3
3
 
4
+ # adapters
5
+ require_relative "strong_migrations/adapters/abstract_adapter"
6
+ require_relative "strong_migrations/adapters/mysql_adapter"
7
+ require_relative "strong_migrations/adapters/mariadb_adapter"
8
+ require_relative "strong_migrations/adapters/postgresql_adapter"
9
+
4
10
  # modules
5
- require "strong_migrations/checker"
6
- require "strong_migrations/database_tasks"
7
- require "strong_migrations/migration"
8
- require "strong_migrations/version"
11
+ require_relative "strong_migrations/checks"
12
+ require_relative "strong_migrations/safe_methods"
13
+ require_relative "strong_migrations/checker"
14
+ require_relative "strong_migrations/database_tasks"
15
+ require_relative "strong_migrations/migration"
16
+ require_relative "strong_migrations/migrator"
17
+ require_relative "strong_migrations/version"
9
18
 
10
19
  # integrations
11
- require "strong_migrations/railtie" if defined?(Rails)
20
+ require_relative "strong_migrations/railtie" if defined?(Rails)
12
21
 
13
22
  module StrongMigrations
14
23
  class Error < StandardError; end
15
24
  class UnsafeMigration < Error; end
25
+ class UnsupportedVersion < Error; end
16
26
 
17
27
  class << self
18
28
  attr_accessor :auto_analyze, :start_after, :checks, :error_messages,
19
29
  :target_postgresql_version, :target_mysql_version, :target_mariadb_version,
20
- :enabled_checks, :lock_timeout, :statement_timeout
30
+ :enabled_checks, :lock_timeout, :statement_timeout, :check_down, :target_version,
31
+ :safe_by_default, :target_sql_mode, :lock_timeout_retries, :lock_timeout_retry_delay,
32
+ :alphabetize_schema
21
33
  attr_writer :lock_timeout_limit
22
34
  end
23
35
  self.auto_analyze = false
24
36
  self.start_after = 0
37
+ self.lock_timeout_retries = 0
38
+ self.lock_timeout_retry_delay = 10 # seconds
25
39
  self.checks = []
26
- self.error_messages = {
27
- add_column_default:
28
- "Adding a column with a non-null default causes the entire table to be rewritten.
29
- Instead, add the column without a default value, then change the default.
30
-
31
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
32
- def up
33
- %{add_command}
34
- %{change_command}
35
- end
36
-
37
- def down
38
- %{remove_command}
39
- end
40
- end
41
-
42
- Then backfill the existing rows in the Rails console or a separate migration with disable_ddl_transaction!.
43
-
44
- class Backfill%{migration_name} < ActiveRecord::Migration%{migration_suffix}
45
- disable_ddl_transaction!
46
-
47
- def up
48
- %{code}
49
- end
50
- end",
51
-
52
- add_column_json:
53
- "There's no equality operator for the json column type, which can
54
- cause errors for existing SELECT DISTINCT queries. Use jsonb instead.",
55
-
56
- change_column:
57
- "Changing the type of an existing column requires the entire
58
- table and indexes to be rewritten. A safer approach is to:
59
-
60
- 1. Create a new column
61
- 2. Write to both columns
62
- 3. Backfill data from the old column to the new column
63
- 4. Move reads from the old column to the new column
64
- 5. Stop writing to the old column
65
- 6. Drop the old column",
66
-
67
- remove_column: "Active Record caches attributes which causes problems
68
- when removing columns. Be sure to ignore the column%{column_suffix}:
69
-
70
- class %{model} < %{base_model}
71
- %{code}
72
- end
73
-
74
- Deploy the code, then wrap this step in a safety_assured { ... } block.
75
-
76
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
77
- def change
78
- safety_assured { %{command} }
79
- end
80
- end",
81
-
82
- rename_column:
83
- "Renaming a column is dangerous. A safer approach is to:
84
-
85
- 1. Create a new column
86
- 2. Write to both columns
87
- 3. Backfill data from the old column to new column
88
- 4. Move reads from the old column to the new column
89
- 5. Stop writing to the old column
90
- 6. Drop the old column",
91
-
92
- rename_table:
93
- "Renaming a table is dangerous. A safer approach is to:
94
-
95
- 1. Create a new table. Don't forget to recreate indexes from the old table
96
- 2. Write to both tables
97
- 3. Backfill data from the old table to new table
98
- 4. Move reads from the old table to the new table
99
- 5. Stop writing to the old table
100
- 6. Drop the old table",
101
-
102
- add_reference:
103
- "%{headline} Instead, use:
104
-
105
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
106
- disable_ddl_transaction!
107
-
108
- def change
109
- %{command}
110
- end
111
- end",
112
-
113
- add_index:
114
- "Adding an index non-concurrently locks the table. Instead, use:
115
-
116
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
117
- disable_ddl_transaction!
118
-
119
- def change
120
- %{command}
121
- end
122
- end",
40
+ self.safe_by_default = false
41
+ self.check_down = false
42
+ self.alphabetize_schema = false
123
43
 
124
- remove_index:
125
- "Removing an index non-concurrently locks the table. Instead, use:
126
-
127
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
128
- disable_ddl_transaction!
129
-
130
- def change
131
- %{command}
132
- end
133
- end",
134
-
135
- add_index_columns:
136
- "Adding a non-unique index with more than three columns rarely improves performance.
137
- Instead, start an index with columns that narrow down the results the most.",
138
-
139
- change_table:
140
- "Strong Migrations does not support inspecting what happens inside a
141
- change_table block, so cannot help you here. Please make really sure that what
142
- you're doing is safe before proceeding, then wrap it in a safety_assured { ... } block.",
143
-
144
- create_table:
145
- "The force option will destroy existing tables.
146
- If this is intended, drop the existing table first.
147
- Otherwise, remove the force option.",
148
-
149
- execute:
150
- "Strong Migrations does not support inspecting what happens inside an
151
- execute call, so cannot help you here. Please make really sure that what
152
- you're doing is safe before proceeding, then wrap it in a safety_assured { ... } block.",
153
-
154
- change_column_null:
155
- "Passing a default value to change_column_null runs a single UPDATE query,
156
- which can cause downtime. Instead, backfill the existing rows in the
157
- Rails console or a separate migration with disable_ddl_transaction!.
158
-
159
- class Backfill%{migration_name} < ActiveRecord::Migration%{migration_suffix}
160
- disable_ddl_transaction!
161
-
162
- def up
163
- %{code}
164
- end
165
- end",
166
-
167
- change_column_null_postgresql:
168
- "Setting NOT NULL on a column requires an AccessExclusiveLock,
169
- which is expensive on large tables. Instead, use a constraint and
170
- validate it in a separate migration with a more agreeable RowShareLock.
171
-
172
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
173
- def change
174
- %{add_constraint_code}
175
- end
176
- end
177
-
178
- class Validate%{migration_name} < ActiveRecord::Migration%{migration_suffix}
179
- def change
180
- %{validate_constraint_code}
181
- end
182
- end",
183
-
184
- change_column_null_mysql:
185
- "Setting NOT NULL on an existing column is not safe with your database engine.",
186
-
187
- add_foreign_key:
188
- "New foreign keys are validated by default. This acquires an AccessExclusiveLock,
189
- which is expensive on large tables. Instead, validate it in a separate migration
190
- with a more agreeable RowShareLock.
191
-
192
- class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
193
- def change
194
- %{add_foreign_key_code}
195
- end
196
- end
197
-
198
- class Validate%{migration_name} < ActiveRecord::Migration%{migration_suffix}
199
- def change
200
- %{validate_foreign_key_code}
44
+ # private
45
+ def self.developer_env?
46
+ env == "development" || env == "test"
201
47
  end
202
- end"
203
- }
204
- self.enabled_checks = (error_messages.keys - [:remove_index]).map { |k| [k, {}] }.to_h
205
48
 
206
49
  # private
207
- def self.developer_env?
208
- defined?(Rails) && (Rails.env.development? || Rails.env.test?)
50
+ def self.env
51
+ if defined?(Rails.env)
52
+ Rails.env
53
+ else
54
+ # default to production for safety
55
+ ENV["RACK_ENV"] || "production"
56
+ end
209
57
  end
210
58
 
211
59
  def self.lock_timeout_limit
@@ -237,10 +85,17 @@ end"
237
85
  end
238
86
  end
239
87
 
88
+ # load error messages
89
+ require_relative "strong_migrations/error_messages"
90
+
240
91
  ActiveSupport.on_load(:active_record) do
241
92
  ActiveRecord::Migration.prepend(StrongMigrations::Migration)
93
+ ActiveRecord::Migrator.prepend(StrongMigrations::Migrator)
242
94
 
243
95
  if defined?(ActiveRecord::Tasks::DatabaseTasks)
244
96
  ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(StrongMigrations::DatabaseTasks)
245
97
  end
98
+
99
+ require_relative "strong_migrations/schema_dumper"
100
+ ActiveRecord::SchemaDumper.prepend(StrongMigrations::SchemaDumper)
246
101
  end
@@ -1,20 +1,9 @@
1
- # https://nithinbekal.com/posts/safe-rake-tasks
2
-
3
1
  namespace :strong_migrations do
4
- task safety_assured: :environment do
5
- raise "Set SAFETY_ASSURED=1 to run this task in production" if Rails.env.production? && !ENV["SAFETY_ASSURED"]
6
- end
7
-
8
- # https://www.pgrs.net/2008/03/13/alphabetize-schema-rb-columns/
2
+ # https://www.pgrs.net/2008/03/12/alphabetize-schema-rb-columns/
9
3
  task :alphabetize_columns do
10
4
  $stderr.puts "Dumping schema"
11
5
  ActiveRecord::Base.logger.level = Logger::INFO
12
6
 
13
- require "strong_migrations/alphabetize_columns"
14
- ActiveRecord::Base.connection.class.prepend StrongMigrations::AlphabetizeColumns
15
- if ActiveRecord::ConnectionAdapters.const_defined?('PostGISAdapter')
16
- ActiveRecord::ConnectionAdapters::PostGISAdapter.prepend StrongMigrations::AlphabetizeColumns
17
- end
18
- ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend StrongMigrations::AlphabetizeColumns
7
+ StrongMigrations.alphabetize_schema = true
19
8
  end
20
9
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strong_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.8
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  - Bob Remeika
9
9
  - David Waller
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-05-14 00:00:00.000000000 Z
13
+ date: 2023-08-09 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'
99
- description:
28
+ version: '5.2'
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,18 +41,26 @@ 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
114
- - lib/strong_migrations/alphabetize_columns.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
115
48
  - lib/strong_migrations/checker.rb
49
+ - lib/strong_migrations/checks.rb
116
50
  - lib/strong_migrations/database_tasks.rb
51
+ - lib/strong_migrations/error_messages.rb
117
52
  - lib/strong_migrations/migration.rb
53
+ - lib/strong_migrations/migrator.rb
118
54
  - lib/strong_migrations/railtie.rb
55
+ - lib/strong_migrations/safe_methods.rb
56
+ - lib/strong_migrations/schema_dumper.rb
119
57
  - lib/strong_migrations/version.rb
120
58
  - lib/tasks/strong_migrations.rake
121
59
  homepage: https://github.com/ankane/strong_migrations
122
60
  licenses:
123
61
  - MIT
124
62
  metadata: {}
125
- post_install_message:
63
+ post_install_message:
126
64
  rdoc_options: []
127
65
  require_paths:
128
66
  - lib
@@ -130,15 +68,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
68
  requirements:
131
69
  - - ">="
132
70
  - !ruby/object:Gem::Version
133
- version: '2.4'
71
+ version: '2.6'
134
72
  required_rubygems_version: !ruby/object:Gem::Requirement
135
73
  requirements:
136
74
  - - ">="
137
75
  - !ruby/object:Gem::Version
138
76
  version: '0'
139
77
  requirements: []
140
- rubygems_version: 3.1.2
141
- signing_key:
78
+ rubygems_version: 3.4.10
79
+ signing_key:
142
80
  specification_version: 4
143
81
  summary: Catch unsafe migrations in development
144
82
  test_files: []
@@ -1,11 +0,0 @@
1
- module StrongMigrations
2
- module AlphabetizeColumns
3
- def columns(*args)
4
- super.sort_by(&:name)
5
- end
6
-
7
- def extensions(*args)
8
- super.sort
9
- end
10
- end
11
- end