diff options
author | Sean Griffin <sean@thoughtbot.com> | 2015-01-28 15:21:23 -0700 |
---|---|---|
committer | Sean Griffin <sean@thoughtbot.com> | 2015-01-28 15:21:23 -0700 |
commit | 9e42cf019f2417473e7dcbfcb885709fa2709f89 (patch) | |
tree | 9e8848ac512b875435f358e2db1399b1d2e584cb /activerecord/lib/active_record | |
parent | 96ac14a3856b9e48e11c7f1e0552ef2f3a87e4d6 (diff) | |
parent | ff45b9e9f7c4ff0fb4fdab8beb539913b876d63b (diff) | |
download | rails-9e42cf019f2417473e7dcbfcb885709fa2709f89.tar.gz rails-9e42cf019f2417473e7dcbfcb885709fa2709f89.tar.bz2 rails-9e42cf019f2417473e7dcbfcb885709fa2709f89.zip |
Merge Pull Request #16052 Added #or to ActiveRecord::Relation
Diffstat (limited to 'activerecord/lib/active_record')
4 files changed, 49 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb index b406da14dc..63ca29305d 100644 --- a/activerecord/lib/active_record/null_relation.rb +++ b/activerecord/lib/active_record/null_relation.rb @@ -75,5 +75,9 @@ module ActiveRecord def exists?(_id = false) false end + + def or(other) + other.spawn + end end end diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index 91c9a0db99..4e597590e9 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -7,7 +7,7 @@ module ActiveRecord delegate :find_by, :find_by!, to: :all delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, to: :all delegate :find_each, :find_in_batches, to: :all - delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, + delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :or, :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :uniq, :distinct, :references, :none, :unscope, to: :all delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 0078b0f32e..b0edb3b1f2 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -582,6 +582,37 @@ module ActiveRecord unscope(where: conditions.keys).where(conditions) end + # Returns a new relation, which is the logical union of this relation and the one passed as an + # argument. + # + # The two relations must be structurally compatible: they must be scoping the same model, and + # they must differ only by +where+ (if no +group+ has been defined) or +having+ (if a +group+ is + # present). Neither relation may have a +limit+, +offset+, or +uniq+ set. + # + # Post.where("id = 1").or(Post.where("id = 2")) + # # SELECT `posts`.* FROM `posts` WHERE (('id = 1' OR 'id = 2')) + # + def or(other) + spawn.or!(other) + end + + def or!(other) # :nodoc: + unless structurally_compatible_for_or?(other) + raise ArgumentError, 'Relation passed to #or must be structurally compatible' + end + + self.where_clause = self.where_clause.or(other.where_clause) + self.having_clause = self.having_clause.or(other.having_clause) + + self + end + + private def structurally_compatible_for_or?(other) # :nodoc: + Relation::SINGLE_VALUE_METHODS.all? { |m| send("#{m}_value") == other.send("#{m}_value") } && + (Relation::MULTI_VALUE_METHODS - [:extending]).all? { |m| send("#{m}_values") == other.send("#{m}_values") } && + (Relation::CLAUSE_METHODS - [:having, :where]).all? { |m| send("#{m}_clause") != other.send("#{m}_clause") } + end + # Allows to specify a HAVING clause. Note that you can't use HAVING # without also specifying a GROUP clause. # diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb index ae5667dfd6..ce307e4f0c 100644 --- a/activerecord/lib/active_record/relation/where_clause.rb +++ b/activerecord/lib/active_record/relation/where_clause.rb @@ -31,6 +31,19 @@ module ActiveRecord ) end + def or(other) + if empty? + other + elsif other.empty? + self + else + WhereClause.new( + [ast.or(other.ast)], + binds + other.binds + ) + end + end + def to_h(table_name = nil) equalities = predicates.grep(Arel::Nodes::Equality) if table_name |