1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Allow difference for and/or unless other values are set explicitly

I often hit the inconvenience (recently in #39558).

`and`/`or` are focused to combine where-like clauses, so we often use
one-time relation which has only where clause. But if the receiver has
values other than where clause (e.g. `order`, `select`, `includes`,
etc), `and`/`or` will raise structurally incompatible error.

Since it is harder to predict the receiver has which values other than
where clause before doing `and`/`or`, that restriction is a little
annoying to me.

So I'd like to relax that restriction, at least unless other values are
set explicitly for multiple values.
This commit is contained in:
Ryuta Kamizono 2020-06-15 16:31:41 +09:00
parent 28e089dbbc
commit 0ea798a47b
3 changed files with 10 additions and 6 deletions

View file

@ -1513,8 +1513,11 @@ module ActiveRecord
values = other.values
STRUCTURAL_OR_METHODS.reject do |method|
v1, v2 = @values[method], values[method]
v1 = v1.uniq if v1.is_a?(Array)
v2 = v2.uniq if v2.is_a?(Array)
if v1.is_a?(Array)
next true unless v2.is_a?(Array)
v1 = v1.uniq
v2 = v2.uniq
end
v1 == v2 || (!v1 || v1.empty?) && (!v2 || v2.empty?)
end
end

View file

@ -43,7 +43,7 @@ class RelationMergingTest < ActiveRecord::TestCase
assert_equal [mary], david_and_mary.and(mary_and_bob)
assert_equal authors, david_and_mary.or(mary_and_bob)
david_and_bob = Author.where(id: david).or(Author.where(name: "Bob")).order(:id)
david_and_bob = Author.where(id: david).or(Author.where(name: "Bob"))
assert_equal [david], david_and_mary.merge(david_and_bob)
assert_equal [david], david_and_mary.merge(david_and_bob, rewhere: true)
@ -96,7 +96,7 @@ class RelationMergingTest < ActiveRecord::TestCase
assert_equal [mary], david_and_mary.and(mary_and_bob)
assert_equal authors, david_and_mary.or(mary_and_bob)
david_and_bob = Author.where(id: david).or(Author.where(name: "Bob")).order(:id)
david_and_bob = Author.where(id: david).or(Author.where(name: "Bob"))
assert_equal [david], david_and_mary.merge(david_and_bob)
assert_equal [david], david_and_mary.merge(david_and_bob, rewhere: true)
@ -149,7 +149,7 @@ class RelationMergingTest < ActiveRecord::TestCase
assert_equal [mary], david_and_mary.and(mary_and_bob)
assert_equal authors, david_and_mary.or(mary_and_bob)
david_and_bob = Author.where(id: david).or(Author.where(name: "Bob")).order(:id)
david_and_bob = Author.where(id: david).or(Author.where(name: "Bob"))
assert_equal [david], david_and_mary.merge(david_and_bob)
assert_equal [david], david_and_mary.merge(david_and_bob, rewhere: true)

View file

@ -84,11 +84,12 @@ module ActiveRecord
def test_or_with_unscope_order
expected = Post.where("id = 1 or id = 2")
assert_equal expected, Post.order("body asc").where("id = 1").unscope(:order).or(Post.where("id = 2")).to_a
assert_equal expected, Post.order(:id).where("id = 1").or(Post.order(:id).where("id = 2").unscope(:order)).to_a
end
def test_or_with_incompatible_unscope
error = assert_raises ArgumentError do
Post.order("body asc").where("id = 1").or(Post.order("body asc").where("id = 2").unscope(:order)).to_a
Post.order("body asc").where("id = 1").unscope(:order).or(Post.order("body asc").where("id = 2")).to_a
end
assert_equal "Relation passed to #or must be structurally compatible. Incompatible values: [:order]", error.message