diff options
-rw-r--r-- | activerecord/lib/active_record/relation/where_clause.rb | 21 | ||||
-rw-r--r-- | activerecord/test/cases/relation/where_clause_test.rb | 17 |
2 files changed, 25 insertions, 13 deletions
diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb index 2c2d6cfa47..e39dbac0d5 100644 --- a/activerecord/lib/active_record/relation/where_clause.rb +++ b/activerecord/lib/active_record/relation/where_clause.rb @@ -18,9 +18,10 @@ module ActiveRecord end def merge(other) + conflict_indices = indices_of_predicates_referenced_by(other).to_set WhereClause.new( - predicates_unreferenced_by(other) + other.predicates, - non_conflicting_binds(other) + other.binds, + non_conflicting(predicates, conflict_indices) + other.predicates, + non_conflicting(binds, conflict_indices) + other.binds, ) end @@ -97,20 +98,18 @@ module ActiveRecord private - def predicates_unreferenced_by(other) - predicates.reject do |n| + def indices_of_predicates_referenced_by(other) + predicates.each_with_index.select do |(n, _)| equality_node?(n) && other.referenced_columns.include?(n.left) - end + end.map(&:last) end - def equality_node?(node) - node.respond_to?(:operator) && node.operator == :== + def non_conflicting(values, conflict_indices) + values.reject.with_index { |_, i| conflict_indices.include?(i) } end - def non_conflicting_binds(other) - conflicts = referenced_columns & other.referenced_columns - conflicts.map! { |node| node.name.to_s } - binds.reject { |attr| conflicts.include?(attr.name) } + def equality_node?(node) + node.respond_to?(:operator) && node.operator == :== end def inverted_predicates diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb index c20ed94d90..c3296b28fd 100644 --- a/activerecord/test/cases/relation/where_clause_test.rb +++ b/activerecord/test/cases/relation/where_clause_test.rb @@ -62,8 +62,21 @@ class ActiveRecord::Relation end test "merge allows for columns with the same name from different tables" do - skip "This is not possible as of 4.2, and the binds do not yet contain sufficient information for this to happen" - # We might be able to change the implementation to remove conflicts by index, rather than column name + table2 = Arel::Table.new("table2") + a = WhereClause.new( + [table["id"].eq(bind_param), table2["id"].eq(bind_param), table["name"].eq(bind_param)], + [attribute("id", 3), attribute("id", 2), attribute("name", "Jim")] + ) + b = WhereClause.new( + [table["id"].eq(bind_param), table["name"].eq(bind_param)], + [attribute("id", 1), attribute("name", "Sean")], + ) + expected = WhereClause.new( + [table2["id"].eq(bind_param), table["id"].eq(bind_param), table["name"].eq(bind_param)], + [attribute("id", 2), attribute("id", 1), attribute("name", "Sean")], + ) + + assert_equal expected, a.merge(b) end test "a clause knows if it is empty" do |