Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

- Added `add_foreign_key_safely` method
- Added `add_null_constraint_safely` and `remove_null_constraint_safely` methods
- Added `add_column_safely` method
- Added `backfill_column_safely` method
- Added `statement_timeout` and `lock_timeout` functionality

## 0.5.1 (2019-12-17)
Expand Down
20 changes: 4 additions & 16 deletions lib/strong_migrations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require "active_support"

# modules
require "strong_migrations/util"
require "strong_migrations/checker"
require "strong_migrations/database_tasks"
require "strong_migrations/migration"
Expand All @@ -25,28 +26,15 @@ class << self
self.error_messages = {
add_column_default:
"Adding a column with a non-null default causes the entire table to be rewritten.
Instead, add the column without a default value, then change the default.
Instead, add the column without a default value, backfill and then change the default.

class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
def up
%{add_command}
%{change_command}
end

def down
%{remove_command}
end
end

Then backfill the existing rows in the Rails console or a separate migration with disable_ddl_transaction!.

class Backfill%{migration_name} < ActiveRecord::Migration%{migration_suffix}
disable_ddl_transaction!

def change
%{code}
%{command}
end
end%{append}",
end",

add_column_json:
"There's no equality operator for the json column type, which can
Expand Down
38 changes: 4 additions & 34 deletions lib/strong_migrations/checker.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module StrongMigrations
class Checker
include Util

attr_accessor :direction

def initialize(migration)
Expand Down Expand Up @@ -81,20 +83,8 @@ def perform(method, *args)
default = options[:default]

if !default.nil? && !(postgresql? && postgresql_version >= 110000)

if options[:null] == false
options = options.except(:null)
append = "

Then add the NOT NULL constraint."
end

raise_error :add_column_default,
add_command: command_str("add_column", [table, column, type, options.except(:default)]),
change_command: command_str("change_column_default", [table, column, default]),
remove_command: command_str("remove_column", [table, column]),
code: backfill_code(table, column, default),
append: append
command: command_str("add_column_safely", [table, column, type, options])
end

if type.to_s == "json" && postgresql?
Expand Down Expand Up @@ -186,10 +176,6 @@ def set_timeouts

private

def connection
@migration.connection
end

def version
@migration.version
end
Expand All @@ -202,22 +188,6 @@ def version_safe?
version && version <= StrongMigrations.start_after
end

def postgresql?
%w(PostgreSQL PostGIS).include?(connection.adapter_name)
end

def postgresql_version
@postgresql_version ||= begin
target_version = StrongMigrations.target_postgresql_version
if target_version && defined?(Rails) && (Rails.env.development? || Rails.env.test?)
# we only need major version right now
target_version.to_i * 10000
else
connection.execute("SHOW server_version_num").first["server_version_num"].to_i
end
end
end

def raise_error(message_key, header: nil, **vars)
return unless StrongMigrations.check_enabled?(message_key, version: version)

Expand All @@ -238,7 +208,7 @@ def raise_error(message_key, header: nil, **vars)

def constraint_str(statement, identifiers)
# not all identifiers are tables, but this method of quoting should be fine
code = statement % identifiers.map { |v| connection.quote_table_name(v) }
code = quote_identifiers(statement, identifiers)
"safety_assured do\n execute '#{code}' \n end"
end

Expand Down
Loading