Merge pull request #49178 from ccutrer/add_check_constraint_if_not_exists

Adds support for `if_not_exists` when adding a check constraint.
This commit is contained in:
Ryuta Kamizono 2023-09-09 11:06:57 +09:00 committed by GitHub
commit 234eff4cbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 2 deletions

View File

@ -1,3 +1,11 @@
* Adds support for `if_not_exists` when adding a check constraint.
```ruby
add_check_constraint :posts, "post_type IN ('blog', 'comment', 'share')", if_not_exists: true
```
*Cody Cutrer*
* Raise an `ArgumentError` when `#accepts_nested_attributes_for` is declared more than once for an association in
the same class. Previously, the last declaration would silently override the previous one. Overriding in a subclass
is still allowed.

View File

@ -1225,12 +1225,16 @@ module ActiveRecord
# The +options+ hash can include the following keys:
# [<tt>:name</tt>]
# The constraint name. Defaults to <tt>chk_rails_<identifier></tt>.
# [<tt>:if_not_exists</tt>]
# Silently ignore if the constraint already exists, rather than raise an error.
# [<tt>:validate</tt>]
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
def add_check_constraint(table_name, expression, **options)
def add_check_constraint(table_name, expression, if_not_exists: false, **options)
return unless supports_check_constraints?
options = check_constraint_options(table_name, expression, options)
return if if_not_exists && check_constraint_exists?(table_name, **options)
at = create_alter_table(table_name)
at.add_check_constraint(expression, options)

View File

@ -308,12 +308,19 @@ module ActiveRecord
end
def invert_add_check_constraint(args)
args.last.delete(:validate) if args.last.is_a?(Hash)
if (options = args.last).is_a?(Hash)
options.delete(:validate)
options[:if_exists] = options.delete(:if_not_exists) if options.key?(:if_not_exists)
end
super
end
def invert_remove_check_constraint(args)
raise ActiveRecord::IrreversibleMigration, "remove_check_constraint is only reversible if given an expression." if args.size < 2
if (options = args.last).is_a?(Hash)
options[:if_not_exists] = options.delete(:if_exists) if options.key?(:if_exists)
end
super
end

View File

@ -123,6 +123,14 @@ if ActiveRecord::Base.connection.supports_check_constraints?
end
end
def test_add_check_constraint_with_if_not_exists_options
@connection.add_check_constraint :trades, "quantity > 0"
assert_nothing_raised do
@connection.add_check_constraint :trades, "quantity > 0", if_not_exists: true
end
end
if supports_non_unique_constraint_name?
def test_add_constraint_with_same_name_to_different_table
@connection.add_check_constraint :trades, "quantity > 0", name: "greater_than_zero"

View File

@ -460,6 +460,16 @@ module ActiveRecord
end
end
def test_invert_add_check_constraint
enable = @recorder.inverse_of :add_check_constraint, [:dogs, "speed > 0", name: "speed_check"]
assert_equal [:remove_check_constraint, [:dogs, "speed > 0", name: "speed_check"], nil], enable
end
def test_invert_add_check_constraint_if_not_exists
enable = @recorder.inverse_of :add_check_constraint, [:dogs, "speed > 0", name: "speed_check", if_not_exists: true]
assert_equal [:remove_check_constraint, [:dogs, "speed > 0", name: "speed_check", if_exists: true], nil], enable
end
def test_invert_remove_check_constraint
enable = @recorder.inverse_of :remove_check_constraint, [:dogs, "speed > 0", name: "speed_check"]
assert_equal [:add_check_constraint, [:dogs, "speed > 0", name: "speed_check"], nil], enable
@ -471,6 +481,11 @@ module ActiveRecord
end
end
def test_invert_remove_check_constraint_if_exists
enable = @recorder.inverse_of :remove_check_constraint, [:dogs, "speed > 0", name: "speed_check", if_exists: true]
assert_equal [:add_check_constraint, [:dogs, "speed > 0", name: "speed_check", if_not_exists: true], nil], enable
end
def test_invert_add_unique_key_constraint_with_using_index
assert_raises(ActiveRecord::IrreversibleMigration) do
@recorder.inverse_of :add_unique_key, [:dogs, using_index: "unique_index"]