From b0b37942d729b6bdcd2e3178eda7fa1de203b3d0 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Mon, 23 Jun 2014 11:42:46 +0800 Subject: Added #or to ActiveRecord::Relation Post.where('id = 1').or(Post.where('id = 2')) # => SELECT * FROM posts WHERE (id = 1) OR (id = 2) [Matthew Draper & Gael Muller] --- activerecord/test/cases/relation/or_test.rb | 81 +++++++++++++++++++++++++++++ activerecord/test/models/post.rb | 3 ++ 2 files changed, 84 insertions(+) create mode 100644 activerecord/test/cases/relation/or_test.rb (limited to 'activerecord/test') diff --git a/activerecord/test/cases/relation/or_test.rb b/activerecord/test/cases/relation/or_test.rb new file mode 100644 index 0000000000..f2115d8aa6 --- /dev/null +++ b/activerecord/test/cases/relation/or_test.rb @@ -0,0 +1,81 @@ +require "cases/helper" +require 'models/post' + +module ActiveRecord + class OrTest < ActiveRecord::TestCase + fixtures :posts + + def test_or_with_relation + expected = Post.where('id = 1 or id = 2').to_a + assert_equal expected, Post.where('id = 1').or(Post.where('id = 2')).to_a + end + + def test_or_identity + expected = Post.where('id = 1').to_a + assert_equal expected, Post.where('id = 1').or(Post.where('id = 1')).to_a + end + + def test_or_with_null_left + expected = Post.where('id = 1').to_a + assert_equal expected, Post.none.or(Post.where('id = 1')).to_a + end + + def test_or_with_null_right + expected = Post.where('id = 1').to_a + assert_equal expected, Post.where('id = 1').or(Post.none).to_a + end + + def test_or_with_null_both + expected = Post.none.to_a + assert_equal expected, Post.none.or(Post.none).to_a + end + + def test_or_without_left_where + expected = Post.all.to_a + assert_equal expected, Post.or(Post.where('id = 1')).to_a + end + + def test_or_without_right_where + expected = Post.all.to_a + assert_equal expected, Post.where('id = 1').or(Post.all).to_a + end + + def test_or_preserves_other_querying_methods + expected = Post.where('id = 1 or id = 2 or id = 3').order('body asc').to_a + partial = Post.order('body asc') + assert_equal expected, partial.where('id = 1').or(partial.where(:id => [2, 3])).to_a + assert_equal expected, Post.order('body asc').where('id = 1').or(Post.order('body asc').where(:id => [2, 3])).to_a + end + + def test_or_with_incompatible_relations + assert_raises ArgumentError do + Post.order('body asc').where('id = 1').or(Post.order('id desc').where(:id => [2, 3])).to_a + end + end + + def test_or_when_grouping + groups = Post.where('id < 10').group('body').select('body, COUNT(*) AS c') + expected = groups.having("COUNT(*) > 1 OR body like 'Such%'").to_a.map {|o| [o.body, o.c] } + assert_equal expected, groups.having('COUNT(*) > 1').or(groups.having("body like 'Such%'")).to_a.map {|o| [o.body, o.c] } + end + + def test_or_with_named_scope + expected = Post.where("id = 1 or body LIKE '\%a\%'").to_a + assert_equal expected, Post.where('id = 1').or(Post.containing_the_letter_a) + end + + def test_or_inside_named_scope + expected = Post.where("body LIKE '\%a\%' OR title LIKE ?", "%'%").order('id DESC').to_a + assert_equal expected, Post.order(id: :desc).typographically_interesting + end + + def test_or_on_loaded_relation + expected = Post.where('id = 1 or id = 2').to_a + p = Post.where('id = 1') + p.load + assert_equal p.loaded?, true + assert_equal expected, p.or(Post.where('id = 2')).to_a + end + + end +end diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 7b637c9e3f..052b1c9690 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -18,6 +18,7 @@ class Post < ActiveRecord::Base end scope :containing_the_letter_a, -> { where("body LIKE '%a%'") } + scope :titled_with_an_apostrophe, -> { where("title LIKE '%''%'") } scope :ranked_by_comments, -> { order("comments_count DESC") } scope :limit_by, lambda {|l| limit(l) } @@ -43,6 +44,8 @@ class Post < ActiveRecord::Base scope :tagged_with, ->(id) { joins(:taggings).where(taggings: { tag_id: id }) } scope :tagged_with_comment, ->(comment) { joins(:taggings).where(taggings: { comment: comment }) } + scope :typographically_interesting, -> { containing_the_letter_a.or(titled_with_an_apostrophe) } + has_many :comments do def find_most_recent order("id DESC").first -- cgit v1.2.3 From ff45b9e9f7c4ff0fb4fdab8beb539913b876d63b Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Wed, 28 Jan 2015 14:04:26 -0700 Subject: Bring the implementation of Relation#or up to speed --- activerecord/test/cases/relation/or_test.rb | 9 ++++++--- .../test/cases/relation/where_clause_test.rb | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'activerecord/test') diff --git a/activerecord/test/cases/relation/or_test.rb b/activerecord/test/cases/relation/or_test.rb index f2115d8aa6..1515b9c454 100644 --- a/activerecord/test/cases/relation/or_test.rb +++ b/activerecord/test/cases/relation/or_test.rb @@ -25,18 +25,22 @@ module ActiveRecord assert_equal expected, Post.where('id = 1').or(Post.none).to_a end + def test_or_with_bind_params + assert_equal Post.find([1, 2]), Post.where(id: 1).or(Post.where(id: 2)).to_a + end + def test_or_with_null_both expected = Post.none.to_a assert_equal expected, Post.none.or(Post.none).to_a end def test_or_without_left_where - expected = Post.all.to_a + expected = Post.where('id = 1') assert_equal expected, Post.or(Post.where('id = 1')).to_a end def test_or_without_right_where - expected = Post.all.to_a + expected = Post.where('id = 1') assert_equal expected, Post.where('id = 1').or(Post.all).to_a end @@ -76,6 +80,5 @@ module ActiveRecord assert_equal p.loaded?, true assert_equal expected, p.or(Post.where('id = 2')).to_a end - end end diff --git a/activerecord/test/cases/relation/where_clause_test.rb b/activerecord/test/cases/relation/where_clause_test.rb index db18980e0b..7325aec0a9 100644 --- a/activerecord/test/cases/relation/where_clause_test.rb +++ b/activerecord/test/cases/relation/where_clause_test.rb @@ -145,6 +145,26 @@ class ActiveRecord::Relation assert_equal where_clause.ast, where_clause_with_empty.ast end + test "or joins the two clauses using OR" do + where_clause = WhereClause.new([table["id"].eq(bind_param)], [attribute("id", 1)]) + other_clause = WhereClause.new([table["name"].eq(bind_param)], [attribute("name", "Sean")]) + expected_ast = + Arel::Nodes::Grouping.new( + Arel::Nodes::Or.new(table["id"].eq(bind_param), table["name"].eq(bind_param)) + ) + expected_binds = where_clause.binds + other_clause.binds + + assert_equal expected_ast.to_sql, where_clause.or(other_clause).ast.to_sql + assert_equal expected_binds, where_clause.or(other_clause).binds + end + + test "or does nothing with an empty where clause" do + where_clause = WhereClause.new([table["id"].eq(bind_param)], [attribute("id", 1)]) + + assert_equal where_clause, where_clause.or(WhereClause.empty) + assert_equal where_clause, WhereClause.empty.or(where_clause) + end + private def table -- cgit v1.2.3