diff options
author | Sean Griffin <sean@seantheprogrammer.com> | 2016-01-12 14:34:42 -0700 |
---|---|---|
committer | Sean Griffin <sean@seantheprogrammer.com> | 2016-01-12 14:38:25 -0700 |
commit | 5d41cb3bfd6b19833261622ce5d339b1e580bd8b (patch) | |
tree | 46ed63b4dd8f07e9b13abb0987eb3afe41962b1d /activerecord/lib | |
parent | 858b9652ced5438127e6c6404bf3f9cae9699985 (diff) | |
download | rails-5d41cb3bfd6b19833261622ce5d339b1e580bd8b.tar.gz rails-5d41cb3bfd6b19833261622ce5d339b1e580bd8b.tar.bz2 rails-5d41cb3bfd6b19833261622ce5d339b1e580bd8b.zip |
Change `WhereClause#merge` to same named columns on diff tables
While the predicates are an arel equality node where the left side is a
full arel attribute, the binds just have the name of the column and
nothing else. This means that while splitting the predicates can include
the table as a factor, the binds cannot. It's entirely possible that we
might be able to have the bind params carry a bit more information (I
don't believe the name is used for anything but logging), and that is
probably a worthwhile change to make in the future.
However the simplest (and likely slightly faster) solution is to simply
use the indices of the conflicts in both cases. This means that we only
have to compute the collision space once, instead of twice even though
we're doing an additional array iteration. Regardless, this method isn't
a performance hotspot.
Close #22823.
[Ben Woosley & Sean Griffin]
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/relation/where_clause.rb | 21 |
1 files changed, 10 insertions, 11 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 |