Skip to content

Commit 515aa1e

Browse files
committed
Change how Merging conditions on the same column works
Merging conditions on the same column no longer maintain both conditions, and will be consistently replaced by the latter condition. ```ruby # Rails 6.1 (IN clause is replaced by merger side equality condition) Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob] # Rails 6.1 (both conflict conditions exists, deprecated) Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => [] # Rails 6.1 with rewhere to migrate to Rails 7.0's behavior Author.where(id: david.id..mary.id).merge(Author.where(id: bob), rewhere: true) # => [bob] # Rails 7.0 (same behavior with IN clause, mergee side condition is consistently replaced) Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob] Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => [bob] ```
1 parent b93e843 commit 515aa1e

File tree

4 files changed

+47
-66
lines changed

4 files changed

+47
-66
lines changed

activerecord/CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
* Merging conditions on the same column no longer maintain both conditions,
2+
and will be consistently replaced by the latter condition.
3+
4+
```ruby
5+
# Rails 6.1 (IN clause is replaced by merger side equality condition)
6+
Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
7+
# Rails 6.1 (both conflict conditions exists, deprecated)
8+
Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => []
9+
# Rails 6.1 with rewhere to migrate to Rails 7.0's behavior
10+
Author.where(id: david.id..mary.id).merge(Author.where(id: bob), rewhere: true) # => [bob]
11+
# Rails 7.0 (same behavior with IN clause, mergee side condition is consistently replaced)
12+
Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
13+
Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => [bob]
14+
15+
*Rafael Mendonça França*
16+
17+
118
* Remove deprecated support to `Model.reorder(nil).first` to search using non-deterministic order.
219

320
*Rafael Mendonça França*

activerecord/lib/active_record/relation/where_clause.rb

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -163,21 +163,8 @@ def predicates_unreferenced_by(other)
163163
attr = extract_attribute(node) || begin
164164
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
165165
end
166-
next false unless attr
167-
168-
ref = referenced_columns[attr]
169-
next false unless ref
170-
171-
if equality_node?(node) && equality_node?(ref) || node == ref
172-
true
173-
else
174-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
175-
Merging (#{node.to_sql}) and (#{ref.to_sql}) no longer maintain
176-
both conditions, and will be replaced by the latter in Rails 7.0.
177-
To migrate to Rails 7.0's behavior, use `relation.merge(other, rewhere: true)`.
178-
MSG
179-
false
180-
end
166+
167+
attr && referenced_columns[attr]
181168
end
182169
end
183170

activerecord/test/cases/relation/merging_test.rb

Lines changed: 14 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -60,38 +60,23 @@ def test_merge_between_clause
6060
assert_equal [david, mary], david_and_mary
6161
assert_equal [mary, bob], mary_and_bob
6262

63-
author_id = Regexp.escape(Author.connection.quote_table_name("authors.id"))
64-
message = %r/Merging \(#{author_id} BETWEEN (\?|\W?\w?\d) AND \g<1>\) and \(#{author_id} (?:= \g<1>|IN \(\g<1>, \g<1>\))\) no longer maintain both conditions, and will be replaced by the latter in Rails 7\.0\./
65-
66-
assert_deprecated(message) do
67-
assert_equal [mary], david_and_mary.merge(Author.where(id: mary))
68-
end
63+
assert_equal [mary], david_and_mary.merge(Author.where(id: mary))
6964
assert_equal [mary], david_and_mary.merge(Author.rewhere(id: mary))
7065
assert_equal [mary], david_and_mary.merge(Author.where(id: mary), rewhere: true)
7166

72-
assert_deprecated(message) do
73-
assert_equal [], david_and_mary.merge(Author.where(id: bob))
74-
end
67+
assert_equal [bob], david_and_mary.merge(Author.where(id: bob))
7568
assert_equal [bob], david_and_mary.merge(Author.rewhere(id: bob))
7669
assert_equal [bob], david_and_mary.merge(Author.where(id: bob), rewhere: true)
7770

78-
assert_deprecated(message) do
79-
assert_equal [bob], mary_and_bob.merge(Author.where(id: [david, bob]))
80-
end
71+
assert_equal [david, bob], mary_and_bob.merge(Author.where(id: [david, bob]))
8172
assert_equal [david, bob], mary_and_bob.merge(Author.where(id: [david, bob]), rewhere: true)
8273

83-
message = %r/Merging \(#{author_id} BETWEEN (\?|\W?\w?\d) AND \g<1>\) and \(#{author_id} BETWEEN \g<1> AND \g<1>\) no longer maintain both conditions, and will be replaced by the latter in Rails 7\.0\./
84-
85-
assert_deprecated(message) do
86-
assert_equal [mary], david_and_mary.merge(mary_and_bob)
87-
end
74+
assert_equal [mary, bob], david_and_mary.merge(mary_and_bob)
8875
assert_equal [mary, bob], david_and_mary.merge(mary_and_bob, rewhere: true)
8976
assert_equal [mary], david_and_mary.and(mary_and_bob)
9077
assert_equal authors, david_and_mary.or(mary_and_bob)
9178

92-
assert_deprecated(message) do
93-
assert_equal [mary], mary_and_bob.merge(david_and_mary)
94-
end
79+
assert_equal [david, mary], mary_and_bob.merge(david_and_mary)
9580
assert_equal [david, mary], mary_and_bob.merge(david_and_mary, rewhere: true)
9681
assert_equal [mary], david_and_mary.and(mary_and_bob)
9782
assert_equal authors, david_and_mary.or(mary_and_bob)
@@ -113,38 +98,24 @@ def test_merge_or_clause
11398
assert_equal [david, mary], david_and_mary
11499
assert_equal [mary, bob], mary_and_bob
115100

116-
author_id = Regexp.escape(Author.connection.quote_table_name("authors.id"))
117-
message = %r/Merging \(\(#{author_id} = (\?|\W?\w?\d) OR #{author_id} = \g<1>\)\) and \(#{author_id} (?:= \g<1>|IN \(\g<1>, \g<1>\))\) no longer maintain both conditions, and will be replaced by the latter in Rails 7\.0\./
118-
119-
assert_deprecated(message) do
120-
assert_equal [mary], david_and_mary.merge(Author.where(id: mary))
121-
end
101+
assert_equal [mary], david_and_mary.merge(Author.where(id: mary))
122102
assert_equal [mary], david_and_mary.merge(Author.rewhere(id: mary))
123103
assert_equal [mary], david_and_mary.merge(Author.where(id: mary), rewhere: true)
124104

125-
assert_deprecated(message) do
126-
assert_equal [], david_and_mary.merge(Author.where(id: bob))
127-
end
105+
assert_equal [bob], david_and_mary.merge(Author.where(id: bob))
128106
assert_equal [bob], david_and_mary.merge(Author.rewhere(id: bob))
129107
assert_equal [bob], david_and_mary.merge(Author.where(id: bob), rewhere: true)
130108

131-
assert_deprecated(message) do
132-
assert_equal [bob], mary_and_bob.merge(Author.where(id: [david, bob]))
133-
end
109+
assert_equal [david, bob], mary_and_bob.merge(Author.where(id: [david, bob]))
134110
assert_equal [david, bob], mary_and_bob.merge(Author.where(id: [david, bob]), rewhere: true)
135111

136-
message = %r/Merging \(\(#{author_id} = (\?|\W?\w?\d) OR #{author_id} = \g<1>\)\) and \(\(#{author_id} = \g<1> OR #{author_id} = \g<1>\)\) no longer maintain both conditions, and will be replaced by the latter in Rails 7\.0\./
137112

138-
assert_deprecated(message) do
139-
assert_equal [mary], david_and_mary.merge(mary_and_bob)
140-
end
113+
assert_equal [mary, bob], david_and_mary.merge(mary_and_bob)
141114
assert_equal [mary, bob], david_and_mary.merge(mary_and_bob, rewhere: true)
142115
assert_equal [mary], david_and_mary.and(mary_and_bob)
143116
assert_equal authors, david_and_mary.or(mary_and_bob)
144117

145-
assert_deprecated(message) do
146-
assert_equal [mary], mary_and_bob.merge(david_and_mary)
147-
end
118+
assert_equal [david, mary], mary_and_bob.merge(david_and_mary)
148119
assert_equal [david, mary], mary_and_bob.merge(david_and_mary, rewhere: true)
149120
assert_equal [mary], david_and_mary.and(mary_and_bob)
150121
assert_equal authors, david_and_mary.or(mary_and_bob)
@@ -164,14 +135,10 @@ def test_merge_not_in_clause
164135

165136
assert_equal [david], non_mary_and_bob
166137

167-
assert_deprecated do
168-
assert_equal [david], Author.where(id: david).merge(non_mary_and_bob)
169-
end
138+
assert_equal [david], Author.where(id: david).merge(non_mary_and_bob)
170139
assert_equal [david], Author.where(id: david).merge(non_mary_and_bob, rewhere: true)
171140

172-
assert_deprecated do
173-
assert_equal [], Author.where(id: mary).merge(non_mary_and_bob)
174-
end
141+
assert_equal [david], Author.where(id: mary).merge(non_mary_and_bob)
175142
assert_equal [david], Author.where(id: mary).merge(non_mary_and_bob, rewhere: true)
176143
end
177144

@@ -182,14 +149,10 @@ def test_merge_not_range_clause
182149

183150
assert_equal [david, mary], less_than_bob
184151

185-
assert_deprecated do
186-
assert_equal [david], Author.where(id: david).merge(less_than_bob)
187-
end
152+
assert_equal [david, mary], Author.where(id: david).merge(less_than_bob)
188153
assert_equal [david, mary], Author.where(id: david).merge(less_than_bob, rewhere: true)
189154

190-
assert_deprecated do
191-
assert_equal [mary], Author.where(id: mary).merge(less_than_bob)
192-
end
155+
assert_equal [david, mary], Author.where(id: mary).merge(less_than_bob)
193156
assert_equal [david, mary], Author.where(id: mary).merge(less_than_bob, rewhere: true)
194157
end
195158

guides/source/7_0_release_notes.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,20 @@ Please refer to the [Changelog][active-record] for detailed changes.
150150
The problem is that timeouts triggered inside the transaction block was also making the incomplete transaction
151151
to be committed, so in order to avoid this mistake, the transaction block is rolled back.
152152

153+
* Merging conditions on the same column no longer maintain both conditions,
154+
and will be consistently replaced by the latter condition.
155+
156+
```ruby
157+
# Rails 6.1 (IN clause is replaced by merger side equality condition)
158+
Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
159+
# Rails 6.1 (both conflict conditions exists, deprecated)
160+
Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => []
161+
# Rails 6.1 with rewhere to migrate to Rails 7.0's behavior
162+
Author.where(id: david.id..mary.id).merge(Author.where(id: bob), rewhere: true) # => [bob]
163+
# Rails 7.0 (same behavior with IN clause, mergee side condition is consistently replaced)
164+
Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
165+
Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => [bob]
166+
153167
Active Storage
154168
--------------
155169

0 commit comments

Comments
 (0)