mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #29950 from MaxLap/avoid_or_clause_duplicates
Avoid duplicate clauses when using #or
This commit is contained in:
commit
0f245882c9
3 changed files with 66 additions and 6 deletions
|
@ -1,3 +1,7 @@
|
|||
* When using #or, extract the common conditions and put them before the OR condition.
|
||||
|
||||
*Maxime Handfield Lapointe*
|
||||
|
||||
* `Relation#or` now accepts two relations who have different values for
|
||||
`references` only, as `references` can be implicitly called by `where`.
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@ module ActiveRecord
|
|||
)
|
||||
end
|
||||
|
||||
def -(other)
|
||||
WhereClause.new(
|
||||
predicates - other.predicates,
|
||||
)
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
WhereClause.new(
|
||||
predicates_unreferenced_by(other) + other.predicates,
|
||||
|
@ -26,14 +32,17 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def or(other)
|
||||
if empty?
|
||||
self
|
||||
elsif other.empty?
|
||||
other
|
||||
left = self - other
|
||||
common = self - left
|
||||
right = other - common
|
||||
|
||||
if left.empty? || right.empty?
|
||||
common
|
||||
else
|
||||
WhereClause.new(
|
||||
[ast.or(other.ast)],
|
||||
or_clause = WhereClause.new(
|
||||
[left.ast.or(right.ast)],
|
||||
)
|
||||
common + or_clause
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -181,6 +181,53 @@ class ActiveRecord::Relation
|
|||
assert_equal WhereClause.empty, WhereClause.empty.or(where_clause)
|
||||
end
|
||||
|
||||
test "or places common conditions before the OR" do
|
||||
a = WhereClause.new(
|
||||
[table["id"].eq(bind_param(1)), table["name"].eq(bind_param("Sean"))],
|
||||
)
|
||||
b = WhereClause.new(
|
||||
[table["id"].eq(bind_param(1)), table["hair_color"].eq(bind_param("black"))],
|
||||
)
|
||||
|
||||
common = WhereClause.new(
|
||||
[table["id"].eq(bind_param(1))],
|
||||
)
|
||||
|
||||
or_clause = WhereClause.new([table["name"].eq(bind_param("Sean"))])
|
||||
.or(WhereClause.new([table["hair_color"].eq(bind_param("black"))]))
|
||||
|
||||
assert_equal common + or_clause, a.or(b)
|
||||
end
|
||||
|
||||
test "or can detect identical or as being a common condition" do
|
||||
common_or = WhereClause.new([table["name"].eq(bind_param("Sean"))])
|
||||
.or(WhereClause.new([table["hair_color"].eq(bind_param("black"))]))
|
||||
|
||||
a = common_or + WhereClause.new([table["id"].eq(bind_param(1))])
|
||||
b = common_or + WhereClause.new([table["foo"].eq(bind_param("bar"))])
|
||||
|
||||
new_or = WhereClause.new([table["id"].eq(bind_param(1))])
|
||||
.or(WhereClause.new([table["foo"].eq(bind_param("bar"))]))
|
||||
|
||||
assert_equal common_or + new_or, a.or(b)
|
||||
end
|
||||
|
||||
test "or will use only common conditions if one side only has common conditions" do
|
||||
only_common = WhereClause.new([
|
||||
table["id"].eq(bind_param(1)),
|
||||
"foo = bar",
|
||||
])
|
||||
|
||||
common_with_extra = WhereClause.new([
|
||||
table["id"].eq(bind_param(1)),
|
||||
"foo = bar",
|
||||
table["extra"].eq(bind_param("pluto")),
|
||||
])
|
||||
|
||||
assert_equal only_common, only_common.or(common_with_extra)
|
||||
assert_equal only_common, common_with_extra.or(only_common)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def table
|
||||
|
|
Loading…
Reference in a new issue