lib/strong_migrations/checks.rb in strong_migrations-2.0.2 vs lib/strong_migrations/checks.rb in strong_migrations-2.1.0

- old
+ new

@@ -8,11 +8,11 @@ table, expression = args if !new_table?(table) if postgresql? && options[:validate] != false add_options = options.merge(validate: false) - name = options[:name] || @migration.check_constraint_options(table, expression, options)[:name] + name = options[:name] || connection.check_constraint_options(table, expression, options)[:name] validate_options = {name: name} if StrongMigrations.safe_by_default safe_add_check_constraint(*args, add_options, validate_options) throw :safe @@ -226,36 +226,34 @@ def check_change_column_null(*args) table, column, null, default = args if !null if postgresql? - safe = adapter.constraints(table).any? { |c| c["def"] == "CHECK ((#{column} IS NOT NULL))" || c["def"] == "CHECK ((#{connection.quote_column_name(column)} IS NOT NULL))" } + constraints = connection.check_constraints(table) + safe = constraints.any? { |c| c.options[:validate] && (c.expression == "#{column} IS NOT NULL" || c.expression == "#{connection.quote_column_name(column)} IS NOT NULL") } unless safe # match https://github.com/nullobject/rein constraint_name = "#{table}_#{column}_null" - add_code = constraint_str("ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s IS NOT NULL) NOT VALID", [table, constraint_name, column]) - validate_code = constraint_str("ALTER TABLE %s VALIDATE CONSTRAINT %s", [table, constraint_name]) - remove_code = constraint_str("ALTER TABLE %s DROP CONSTRAINT %s", [table, constraint_name]) - - validate_constraint_code = String.new(command_str(:validate_check_constraint, [table, {name: constraint_name}])) - + add_args = [table, "#{quote_column_if_needed(column)} IS NOT NULL", {name: constraint_name, validate: false}] + validate_args = [table, {name: constraint_name}] change_args = [table, column, null] + remove_args = [table, {name: constraint_name}] - validate_constraint_code << "\n #{command_str(:change_column_null, change_args)}" - validate_constraint_code << "\n #{command_str(:remove_check_constraint, [table, {name: constraint_name}])}" - if StrongMigrations.safe_by_default - safe_change_column_null(add_code, validate_code, change_args, remove_code, default) + safe_change_column_null(add_args, validate_args, change_args, remove_args, default, constraints) throw :safe end - add_constraint_code = command_str(:add_check_constraint, [table, "#{quote_column_if_needed(column)} IS NOT NULL", {name: constraint_name, validate: false}]) + add_constraint_code = command_str(:add_check_constraint, add_args) + up_code = String.new(command_str(:validate_check_constraint, validate_args)) + up_code << "\n #{command_str(:change_column_null, change_args)}" + up_code << "\n #{command_str(:remove_check_constraint, remove_args)}" down_code = "#{add_constraint_code}\n #{command_str(:change_column_null, [table, column, true])}" - validate_constraint_code = "def up\n #{validate_constraint_code}\n end\n\n def down\n #{down_code}\n end" + validate_constraint_code = "def up\n #{up_code}\n end\n\n def down\n #{down_code}\n end" raise_error :change_column_null_postgresql, add_constraint_code: add_constraint_code, validate_constraint_code: validate_constraint_code end @@ -300,33 +298,32 @@ def check_remove_column(method, *args) columns = case method when :remove_timestamps - ["created_at", "updated_at"] + [:created_at, :updated_at] when :remove_column - [args[1].to_s] + [args[1]] when :remove_columns - # Active Record 6.1+ supports options if args.last.is_a?(Hash) - args[1..-2].map(&:to_s) + args[1..-2] else - args[1..-1].map(&:to_s) + args[1..-1] end else options = args[2] || {} reference = args[1] cols = [] - cols << "#{reference}_type" if options[:polymorphic] - cols << "#{reference}_id" + cols << "#{reference}_type".to_sym if options[:polymorphic] + cols << "#{reference}_id".to_sym cols end - code = "self.ignored_columns += #{columns.inspect}" + code = "self.ignored_columns += #{columns.map(&:to_s).inspect}" raise_error :remove_column, - model: args[0].to_s.classify, + model: model_name(args[0]), code: code, command: command_str(method, args), column_suffix: columns.size > 1 ? "s" : "" end @@ -390,11 +387,11 @@ message = StrongMigrations.error_messages[message_key] || "Missing message" message = message + append if append vars[:migration_name] = @migration.class.name - vars[:migration_suffix] = "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]" + vars[:migration_suffix] = migration_suffix vars[:base_model] = "ApplicationRecord" # escape % not followed by { message = message.gsub(/%(?!{)/, "%%") % vars if message.include?("%") @migration.stop!(message, header: header || "Dangerous operation detected") @@ -431,11 +428,11 @@ "#{command} #{str_args.join(", ")}" end def backfill_code(table, column, default, function = false) - model = table.to_s.classify + model = model_name(table) if function # update_all(column: Arel.sql(default)) also works in newer versions of Active Record update_expr = "#{quote_column_if_needed(column)} = #{default}" "#{model}.unscoped.in_batches do |relation| \n relation.where(#{column}: nil).update_all(#{update_expr.inspect})\n sleep(0.01)\n end" else @@ -453,8 +450,16 @@ @new_tables.include?(table.to_s) end def new_column?(table, column) new_table?(table) || @new_columns.include?([table.to_s, column.to_s]) + end + + def migration_suffix + "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]" + end + + def model_name(table) + table.to_s.classify end end end