diff options
Diffstat (limited to 'activerecord/test/cases/finder_test.rb')
-rw-r--r-- | activerecord/test/cases/finder_test.rb | 172 |
1 files changed, 138 insertions, 34 deletions
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 89d8a8bdca..4769ffd64d 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cases/helper" require "models/post" require "models/author" @@ -7,6 +9,7 @@ require "models/company" require "models/tagging" require "models/topic" require "models/reply" +require "models/rating" require "models/entrant" require "models/project" require "models/developer" @@ -117,6 +120,21 @@ class FinderTest < ActiveRecord::TestCase assert_equal "The Fourth Topic of the day", records[2].title end + def test_find_with_ids_with_no_id_passed + exception = assert_raises(ActiveRecord::RecordNotFound) { Topic.find } + assert_equal exception.model, "Topic" + assert_equal exception.primary_key, "id" + end + + def test_find_with_ids_with_id_out_of_range + exception = assert_raises(ActiveRecord::RecordNotFound) do + Topic.find("9999999999999999999999999999999") + end + + assert_equal exception.model, "Topic" + assert_equal exception.primary_key, "id" + end + def test_find_passing_active_record_object_is_not_permitted assert_raises(ArgumentError) do Topic.find(Topic.last) @@ -154,6 +172,32 @@ class FinderTest < ActiveRecord::TestCase assert_raise(NoMethodError) { Topic.exists?([1, 2]) } end + def test_exists_with_scope + davids = Author.where(name: "David") + assert_equal true, davids.exists? + assert_equal true, davids.exists?(authors(:david).id) + assert_equal false, davids.exists?(authors(:mary).id) + assert_equal false, davids.exists?("42") + assert_equal false, davids.exists?(42) + assert_equal false, davids.exists?(davids.new.id) + + fake = Author.where(name: "fake author") + assert_equal false, fake.exists? + assert_equal false, fake.exists?(authors(:david).id) + end + + def test_exists_uses_existing_scope + post = authors(:david).posts.first + authors = Author.includes(:posts).where(name: "David", posts: { id: post.id }) + assert_equal true, authors.exists?(authors(:david).id) + end + + def test_any_with_scope_on_hash_includes + post = authors(:david).posts.first + categories = Categorization.includes(author: :posts).where(posts: { id: post.id }) + assert_equal true, categories.exists? + end + def test_exists_with_polymorphic_relation post = Post.create!(title: "Post", body: "default", taggings: [Tagging.new(comment: "tagging comment")]) relation = Post.tagged_with_comment("tagging comment") @@ -202,26 +246,51 @@ class FinderTest < ActiveRecord::TestCase assert_equal true, Topic.first.replies.exists? end - # ensures +exists?+ runs valid SQL by excluding order value - def test_exists_with_order + # Ensure +exists?+ runs without an error by excluding distinct value. + # See https://github.com/rails/rails/pull/26981. + def test_exists_with_order_and_distinct assert_equal true, Topic.order(:id).distinct.exists? end + # Ensure +exists?+ runs without an error by excluding order value. + def test_exists_with_order + assert_equal true, Topic.order(Arel.sql("invalid sql here")).exists? + end + + def test_exists_with_joins + assert_equal true, Topic.joins(:replies).where(replies_topics: { approved: true }).order("replies_topics.created_at DESC").exists? + end + + def test_exists_with_left_joins + assert_equal true, Topic.left_joins(:replies).where(replies_topics: { approved: true }).order("replies_topics.created_at DESC").exists? + end + + def test_exists_with_eager_load + assert_equal true, Topic.eager_load(:replies).where(replies_topics: { approved: true }).order("replies_topics.created_at DESC").exists? + end + def test_exists_with_includes_limit_and_empty_result - assert_equal false, Topic.includes(:replies).limit(0).exists? - assert_equal false, Topic.includes(:replies).limit(1).where("0 = 1").exists? + assert_no_queries { assert_equal false, Topic.includes(:replies).limit(0).exists? } + assert_queries(1) { assert_equal false, Topic.includes(:replies).limit(1).where("0 = 1").exists? } end def test_exists_with_distinct_association_includes_and_limit author = Author.first - assert_equal false, author.unique_categorized_posts.includes(:special_comments).limit(0).exists? - assert_equal true, author.unique_categorized_posts.includes(:special_comments).limit(1).exists? + unique_categorized_posts = author.unique_categorized_posts.includes(:special_comments) + assert_no_queries { assert_equal false, unique_categorized_posts.limit(0).exists? } + assert_queries(1) { assert_equal true, unique_categorized_posts.limit(1).exists? } end def test_exists_with_distinct_association_includes_limit_and_order author = Author.first - assert_equal false, author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC").limit(0).exists? - assert_equal true, author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC").limit(1).exists? + unique_categorized_posts = author.unique_categorized_posts.includes(:special_comments).order("comments.tags_count DESC") + assert_no_queries { assert_equal false, unique_categorized_posts.limit(0).exists? } + assert_queries(1) { assert_equal true, unique_categorized_posts.limit(1).exists? } + end + + def test_exists_should_reference_correct_aliases_while_joining_tables_of_has_many_through_association + ratings = developers(:david).ratings.includes(comment: :post).where(posts: { id: 1 }) + assert_queries(1) { assert_not_predicate ratings.limit(1), :exists? } end def test_exists_with_empty_table_and_no_args_given @@ -236,9 +305,9 @@ class FinderTest < ActiveRecord::TestCase def test_exists_with_aggregate_having_three_mappings_with_one_difference existing_address = customers(:david).address - assert_equal false, Customer.exists?(address: Address.new(existing_address.street, existing_address.city, existing_address.country + "1")) - assert_equal false, Customer.exists?(address: Address.new(existing_address.street, existing_address.city + "1", existing_address.country)) - assert_equal false, Customer.exists?(address: Address.new(existing_address.street + "1", existing_address.city, existing_address.country)) + assert_equal false, Customer.exists?(address: Address.new(existing_address.street, existing_address.city, existing_address.country + "1")) + assert_equal false, Customer.exists?(address: Address.new(existing_address.street, existing_address.city + "1", existing_address.country)) + assert_equal false, Customer.exists?(address: Address.new(existing_address.street + "1", existing_address.city, existing_address.country)) end def test_exists_does_not_instantiate_records @@ -496,7 +565,7 @@ class FinderTest < ActiveRecord::TestCase assert_nil Topic.offset(4).second_to_last assert_nil Topic.offset(5).second_to_last - #test with limit + # test with limit assert_nil Topic.limit(1).second assert_nil Topic.limit(1).second_to_last end @@ -598,7 +667,7 @@ class FinderTest < ActiveRecord::TestCase def test_last_with_irreversible_order assert_raises(ActiveRecord::IrreversibleOrderError) do - Topic.order("coalesce(author_name, title)").last + Topic.order(Arel.sql("coalesce(author_name, title)")).last end end @@ -610,12 +679,34 @@ class FinderTest < ActiveRecord::TestCase assert_equal comments.limit(2).to_a.last(2), comments.limit(2).last(2) assert_equal comments.limit(2).to_a.last(3), comments.limit(2).last(3) + assert_equal comments.offset(2).to_a.last, comments.offset(2).last + assert_equal comments.offset(2).to_a.last(2), comments.offset(2).last(2) + assert_equal comments.offset(2).to_a.last(3), comments.offset(2).last(3) + comments = comments.offset(1) assert_equal comments.limit(2).to_a.last, comments.limit(2).last assert_equal comments.limit(2).to_a.last(2), comments.limit(2).last(2) assert_equal comments.limit(2).to_a.last(3), comments.limit(2).last(3) end + def test_first_on_relation_with_limit_and_offset + post = posts("sti_comments") + + comments = post.comments.order(id: :asc) + assert_equal comments.limit(2).to_a.first, comments.limit(2).first + assert_equal comments.limit(2).to_a.first(2), comments.limit(2).first(2) + assert_equal comments.limit(2).to_a.first(3), comments.limit(2).first(3) + + assert_equal comments.offset(2).to_a.first, comments.offset(2).first + assert_equal comments.offset(2).to_a.first(2), comments.offset(2).first(2) + assert_equal comments.offset(2).to_a.first(3), comments.offset(2).first(3) + + comments = comments.offset(1) + assert_equal comments.limit(2).to_a.first, comments.limit(2).first + assert_equal comments.limit(2).to_a.first(2), comments.limit(2).first(2) + assert_equal comments.limit(2).to_a.first(3), comments.limit(2).first(3) + end + def test_take_and_first_and_last_with_integer_should_return_an_array assert_kind_of Array, Topic.take(5) assert_kind_of Array, Topic.first(5) @@ -725,7 +816,6 @@ class FinderTest < ActiveRecord::TestCase assert Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: false).find(1) assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) } assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "HHC", replies_count: 1, approved: false).find(1) } - assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) } end def test_condition_interpolation @@ -983,14 +1073,6 @@ class FinderTest < ActiveRecord::TestCase assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") } end - def test_find_last_with_offset - devs = Developer.order("id") - - assert_equal devs[2], Developer.offset(2).first - assert_equal devs[-3], Developer.offset(2).last - assert_equal devs[-3], Developer.offset(2).order("id DESC").first - end - def test_find_by_nil_attribute topic = Topic.find_by_last_read nil assert_not_nil topic @@ -1006,16 +1088,6 @@ class FinderTest < ActiveRecord::TestCase assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" } end - def test_find_all_with_join - developers_on_project_one = Developer. - joins("LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id"). - where("project_id=1").to_a - assert_equal 3, developers_on_project_one.length - developer_names = developers_on_project_one.map(&:name) - assert_includes developer_names, "David" - assert_includes developer_names, "Jamis" - end - def test_joins_dont_clobber_id first = Firm. joins("INNER JOIN companies clients ON clients.firm_id = companies.id"). @@ -1144,7 +1216,7 @@ class FinderTest < ActiveRecord::TestCase e = assert_raises(ActiveRecord::RecordNotFound) do model.find "Hello", "World!" end - assert_equal "Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2)", e.message + assert_equal "Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2).", e.message end end @@ -1170,13 +1242,17 @@ class FinderTest < ActiveRecord::TestCase assert_equal posts(:eager_other), Post.find_by("id = ?", posts(:eager_other).id) end + test "find_by with range conditions returns the first matching record" do + assert_equal posts(:eager_other), Post.find_by(id: posts(:eager_other).id...posts(:misc_by_bob).id) + end + test "find_by returns nil if the record is missing" do assert_nil Post.find_by("1 = 0") end test "find_by with associations" do assert_equal authors(:david), Post.find_by(author: authors(:david)).author - assert_equal authors(:mary) , Post.find_by(author: authors(:mary)).author + assert_equal authors(:mary), Post.find_by(author: authors(:mary)).author end test "find_by doesn't have implicit ordering" do @@ -1225,6 +1301,34 @@ class FinderTest < ActiveRecord::TestCase assert_equal tyre2, zyke.tyres.custom_find_by(id: tyre2.id) end + test "#skip_query_cache! for #exists?" do + Topic.cache do + assert_queries(1) do + Topic.exists? + Topic.exists? + end + + assert_queries(2) do + Topic.all.skip_query_cache!.exists? + Topic.all.skip_query_cache!.exists? + end + end + end + + test "#skip_query_cache! for #exists? with a limited eager load" do + Topic.cache do + assert_queries(1) do + Topic.eager_load(:replies).limit(1).exists? + Topic.eager_load(:replies).limit(1).exists? + end + + assert_queries(2) do + Topic.eager_load(:replies).limit(1).skip_query_cache!.exists? + Topic.eager_load(:replies).limit(1).skip_query_cache!.exists? + end + end + end + private def table_with_custom_primary_key yield(Class.new(Toy) do |