finder_test.rb 45.0 KB
Newer Older
1
require "cases/helper"
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
require "models/post"
require "models/author"
require "models/categorization"
require "models/comment"
require "models/company"
require "models/tagging"
require "models/topic"
require "models/reply"
require "models/entrant"
require "models/project"
require "models/developer"
require "models/computer"
require "models/customer"
require "models/toy"
require "models/matey"
require "models/dog"
require "models/car"
require "models/tyre"
D
David Heinemeier Hansson 已提交
20

21
class FinderTest < ActiveRecord::TestCase
R
Fix...  
Ryuta Kamizono 已提交
22
  fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :author_addresses, :customers, :categories, :categorizations, :cars
D
David Heinemeier Hansson 已提交
23

24
  def test_find_by_id_with_hash
25
    assert_nothing_raised do
26
      Post.find_by_id(limit: 1)
27 28 29 30
    end
  end

  def test_find_by_title_and_id_with_hash
31
    assert_nothing_raised do
32
      Post.find_by_title_and_id("foo", limit: 1)
33 34 35
    end
  end

D
David Heinemeier Hansson 已提交
36
  def test_find
37
    assert_equal(topics(:first).title, Topic.find(1).title)
D
David Heinemeier Hansson 已提交
38
  end
39

40
  def test_find_with_proc_parameter_and_block
S
Sean Griffin 已提交
41
    exception = assert_raises(RuntimeError) do
42 43
      Topic.all.find(-> { raise "should happen" }) { |e| e.title == "non-existing-title" }
    end
S
Sean Griffin 已提交
44
    assert_equal "should happen", exception.message
45

46
    assert_nothing_raised do
47 48 49 50
      Topic.all.find(-> { raise "should not happen" }) { |e| e.title == topics(:first).title }
    end
  end

51
  def test_find_with_ids_returning_ordered
52
    records = Topic.find([4, 2, 5])
53 54 55
    assert_equal "The Fourth Topic of the day", records[0].title
    assert_equal "The Second Topic of the day", records[1].title
    assert_equal "The Fifth Topic of the day", records[2].title
56

57
    records = Topic.find(4, 2, 5)
58 59 60
    assert_equal "The Fourth Topic of the day", records[0].title
    assert_equal "The Second Topic of the day", records[1].title
    assert_equal "The Fifth Topic of the day", records[2].title
61

62
    records = Topic.find(["4", "2", "5"])
63 64 65
    assert_equal "The Fourth Topic of the day", records[0].title
    assert_equal "The Second Topic of the day", records[1].title
    assert_equal "The Fifth Topic of the day", records[2].title
66

67
    records = Topic.find("4", "2", "5")
68 69 70
    assert_equal "The Fourth Topic of the day", records[0].title
    assert_equal "The Second Topic of the day", records[1].title
    assert_equal "The Fifth Topic of the day", records[2].title
71 72 73 74
  end

  def test_find_with_ids_and_order_clause
    # The order clause takes precedence over the informed ids
75
    records = Topic.order(:author_name).find([5, 3, 1])
76 77 78
    assert_equal "The Third Topic of the day", records[0].title
    assert_equal "The First Topic",            records[1].title
    assert_equal "The Fifth Topic of the day", records[2].title
79

80
    records = Topic.order(:id).find([5, 3, 1])
81 82 83
    assert_equal "The First Topic",            records[0].title
    assert_equal "The Third Topic of the day", records[1].title
    assert_equal "The Fifth Topic of the day", records[2].title
84 85
  end

86 87
  def test_find_with_ids_with_limit_and_order_clause
    # The order clause takes precedence over the informed ids
88
    records = Topic.limit(2).order(:id).find([5, 3, 1])
89
    assert_equal 2, records.size
90 91
    assert_equal "The First Topic",            records[0].title
    assert_equal "The Third Topic of the day", records[1].title
92 93 94
  end

  def test_find_with_ids_and_limit
95
    records = Topic.limit(3).find([3, 2, 5, 1, 4])
96
    assert_equal 3, records.size
97 98 99
    assert_equal "The Third Topic of the day",  records[0].title
    assert_equal "The Second Topic of the day", records[1].title
    assert_equal "The Fifth Topic of the day",  records[2].title
100 101
  end

102 103
  def test_find_with_ids_where_and_limit
    # Please note that Topic 1 is the only not approved so
104
    # if it were among the first 3 it would raise an ActiveRecord::RecordNotFound
105
    records = Topic.where(approved: true).limit(3).find([3, 2, 5, 1, 4])
106
    assert_equal 3, records.size
107 108 109
    assert_equal "The Third Topic of the day",  records[0].title
    assert_equal "The Second Topic of the day", records[1].title
    assert_equal "The Fifth Topic of the day",  records[2].title
110 111
  end

112
  def test_find_with_ids_and_offset
113
    records = Topic.offset(2).find([3, 2, 5, 1, 4])
114
    assert_equal 3, records.size
115 116 117
    assert_equal "The Fifth Topic of the day",  records[0].title
    assert_equal "The First Topic",             records[1].title
    assert_equal "The Fourth Topic of the day", records[2].title
118 119
  end

120
  def test_find_passing_active_record_object_is_not_permitted
121
    assert_raises(ArgumentError) do
122 123 124 125
      Topic.find(Topic.last)
    end
  end

126
  def test_symbols_table_ref
127
    gc_disabled = GC.disable
128
    Post.where("author_id" => nil)  # warm up
129
    x = Symbol.all_symbols.count
130
    Post.where("title" => { "xxxqqqq" => "bar" })
131
    assert_equal x, Symbol.all_symbols.count
R
Ryuta Kamizono 已提交
132 133
  ensure
    GC.enable if gc_disabled == false
134 135
  end

136 137 138
  # find should handle strings that come from URLs
  # (example: Category.find(params[:id]))
  def test_find_with_string
139
    assert_equal(Topic.find(1).title, Topic.find("1").title)
140
  end
141

D
David Heinemeier Hansson 已提交
142
  def test_exists
143 144 145 146
    assert_equal true, Topic.exists?(1)
    assert_equal true, Topic.exists?("1")
    assert_equal true, Topic.exists?(title: "The First Topic")
    assert_equal true, Topic.exists?(heading: "The First Topic")
147
    assert_equal true, Topic.exists?(author_name: "Mary", approved: true)
148
    assert_equal true, Topic.exists?(["parent_id = ?", 1])
149
    assert_equal true, Topic.exists?(id: [1, 9999])
150 151

    assert_equal false, Topic.exists?(45)
152
    assert_equal false, Topic.exists?(Topic.new.id)
153

154
    assert_raise(NoMethodError) { Topic.exists?([1, 2]) }
155 156
  end

157
  def test_exists_with_polymorphic_relation
158 159
    post = Post.create!(title: "Post", body: "default", taggings: [Tagging.new(comment: "tagging comment")])
    relation = Post.tagged_with_comment("tagging comment")
160

161 162
    assert_equal true, relation.exists?(title: ["Post"])
    assert_equal true, relation.exists?(["title LIKE ?", "Post%"])
163 164 165 166 167 168 169
    assert_equal true, relation.exists?
    assert_equal true, relation.exists?(post.id)
    assert_equal true, relation.exists?(post.id.to_s)

    assert_equal false, relation.exists?(false)
  end

170
  def test_exists_passing_active_record_object_is_not_permitted
171
    assert_raises(ArgumentError) do
172 173 174 175
      Topic.exists?(Topic.new)
    end
  end

176
  def test_exists_returns_false_when_parameter_has_invalid_type
177
    assert_equal false, Topic.exists?("foo")
178
    assert_equal false, Topic.exists?(("9" * 53).to_i) # number that's bigger than int
D
David Heinemeier Hansson 已提交
179
  end
180

181
  def test_exists_does_not_select_columns_without_alias
182
    assert_sql(/SELECT\W+1 AS one FROM ["`]topics["`]/i) do
183 184 185 186
      Topic.exists?
    end
  end

187
  def test_exists_returns_true_with_one_record_and_no_args
188
    assert_equal true, Topic.exists?
189
  end
190

E
Egor Lynko 已提交
191
  def test_exists_returns_false_with_false_arg
192
    assert_equal false, Topic.exists?(false)
E
Egor Lynko 已提交
193 194
  end

195 196 197
  # exists? should handle nil for id's that come from URLs and always return false
  # (example: Topic.exists?(params[:id])) where params[:id] is nil
  def test_exists_with_nil_arg
198 199 200 201 202
    assert_equal false, Topic.exists?(nil)
    assert_equal true, Topic.exists?

    assert_equal false, Topic.first.replies.exists?(nil)
    assert_equal true, Topic.first.replies.exists?
203 204
  end

R
Ryuta Kamizono 已提交
205 206 207
  # 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
208
    assert_equal true, Topic.order(:id).distinct.exists?
209 210
  end

R
Ryuta Kamizono 已提交
211 212 213 214 215 216 217 218 219 220 221 222
  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

223
  def test_exists_with_includes_limit_and_empty_result
224
    assert_equal false, Topic.includes(:replies).limit(0).exists?
225
    assert_equal false, Topic.includes(:replies).limit(1).where("0 = 1").exists?
226 227
  end

228 229
  def test_exists_with_distinct_association_includes_and_limit
    author = Author.first
230 231
    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?
232 233 234 235
  end

  def test_exists_with_distinct_association_includes_limit_and_order
    author = Author.first
236 237
    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?
238 239
  end

240
  def test_exists_with_empty_table_and_no_args_given
241
    Topic.delete_all
242
    assert_equal false, Topic.exists?
243
  end
244

245 246
  def test_exists_with_aggregate_having_three_mappings
    existing_address = customers(:david).address
247
    assert_equal true, Customer.exists?(address: existing_address)
248 249 250 251
  end

  def test_exists_with_aggregate_having_three_mappings_with_one_difference
    existing_address = customers(:david).address
R
Ryuta Kamizono 已提交
252 253 254
    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))
255 256
  end

257
  def test_exists_does_not_instantiate_records
258 259 260
    assert_not_called(Developer, :instantiate) do
      Developer.exists?
    end
261 262
  end

D
David Heinemeier Hansson 已提交
263 264 265 266
  def test_find_by_array_of_one_id
    assert_kind_of(Array, Topic.find([ 1 ]))
    assert_equal(1, Topic.find([ 1 ]).length)
  end
267

D
David Heinemeier Hansson 已提交
268
  def test_find_by_ids
269 270 271 272 273
    assert_equal 2, Topic.find(1, 2).size
    assert_equal topics(:second).title, Topic.find([2]).first.title
  end

  def test_find_by_ids_with_limit_and_offset
274 275
    assert_equal 2, Entrant.limit(2).find([1, 3, 2]).size
    entrants = Entrant.limit(3).offset(2).find([1, 3, 2])
276
    assert_equal 1, entrants.size
277
    assert_equal "Ruby Guru", entrants.first.name
278 279 280 281

    # Also test an edge case: If you have 11 results, and you set a
    #   limit of 3 and offset of 9, then you should find that there
    #   will be only 2 results, regardless of the limit.
J
Jon Leighton 已提交
282
    devs = Developer.all
283
    last_devs = Developer.limit(3).offset(9).find devs.map(&:id)
284
    assert_equal 2, last_devs.size
285 286
    assert_equal "fixture_10", last_devs[0].name
    assert_equal "Jamis", last_devs[1].name
D
David Heinemeier Hansson 已提交
287 288
  end

289
  def test_find_with_large_number
290
    assert_raises(ActiveRecord::RecordNotFound) { Topic.find("9999999999999999999999999999999") }
291 292 293
  end

  def test_find_by_with_large_number
294
    assert_nil Topic.find_by(id: "9999999999999999999999999999999")
295 296 297
  end

  def test_find_by_id_with_large_number
298
    assert_nil Topic.find_by_id("9999999999999999999999999999999")
299 300
  end

301
  def test_find_on_relation_with_large_number
302
    assert_nil Topic.where("1=1").find_by(id: 9999999999999999999999999999999)
303 304 305 306
  end

  def test_find_by_bang_on_relation_with_large_number
    assert_raises(ActiveRecord::RecordNotFound) do
307
      Topic.where("1=1").find_by!(id: 9999999999999999999999999999999)
308 309 310
    end
  end

311 312 313 314
  def test_find_an_empty_array
    assert_equal [], Topic.find([])
  end

315 316 317 318
  def test_find_doesnt_have_implicit_ordering
    assert_sql(/^((?!ORDER).)*$/) { Topic.find(1) }
  end

D
David Heinemeier Hansson 已提交
319
  def test_find_by_ids_missing_one
320
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
D
David Heinemeier Hansson 已提交
321
  end
322

323
  def test_find_with_group_and_sanitized_having_method
324
    developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select("salary").to_a
325 326 327 328 329
    assert_equal 3, developers.size
    assert_equal 3, developers.map(&:salary).uniq.size
    assert developers.all? { |developer| developer.salary > 10000 }
  end

D
David Heinemeier Hansson 已提交
330 331
  def test_find_with_entire_select_statement
    topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
332

D
David Heinemeier Hansson 已提交
333
    assert_equal(1, topics.size)
334
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
335
  end
336

D
David Heinemeier Hansson 已提交
337 338
  def test_find_with_prepared_select_statement
    topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
339

D
David Heinemeier Hansson 已提交
340
    assert_equal(1, topics.size)
341
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
342
  end
343

344 345 346 347
  def test_find_by_sql_with_sti_on_joined_table
    accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
    assert_equal [Account], accounts.collect(&:class).uniq
  end
348

349 350 351 352 353 354
  def test_find_by_association_subquery
    author = authors(:david)
    assert_equal author.post, Post.find_by(author: Author.where(id: author))
    assert_equal author.post, Post.find_by(author_id: Author.where(id: author))
  end

355 356 357 358 359
  def test_find_by_and_where_consistency_with_active_record_instance
    author = authors(:david)
    assert_equal Post.where(author_id: author).take, Post.find_by(author_id: author)
  end

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
  def test_take
    assert_equal topics(:first), Topic.take
  end

  def test_take_failing
    assert_nil Topic.where("title = 'This title does not exist'").take
  end

  def test_take_bang_present
    assert_nothing_raised do
      assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").take!
    end
  end

  def test_take_bang_missing
375
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
376 377 378 379
      Topic.where("title = 'This title does not exist'").take!
    end
  end

380
  def test_first
381
    assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
382
  end
383

384
  def test_first_failing
385
    assert_nil Topic.where("title = 'The Second Topic of the day!'").first
386
  end
D
David Heinemeier Hansson 已提交
387

388 389 390 391 392 393 394
  def test_first_bang_present
    assert_nothing_raised do
      assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").first!
    end
  end

  def test_first_bang_missing
395
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
396 397 398 399
      Topic.where("title = 'This title does not exist'").first!
    end
  end

400 401 402 403 404 405
  def test_first_have_primary_key_order_by_default
    expected = topics(:first)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.first
  end

406
  def test_model_class_responds_to_first_bang
407 408
    assert Topic.first!
    Topic.delete_all
409
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
410 411 412 413
      Topic.first!
    end
  end

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
  def test_second
    assert_equal topics(:second).title, Topic.second.title
  end

  def test_second_with_offset
    assert_equal topics(:fifth), Topic.offset(3).second
  end

  def test_second_have_primary_key_order_by_default
    expected = topics(:second)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.second
  end

  def test_model_class_responds_to_second_bang
    assert Topic.second!
    Topic.delete_all
431
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
      Topic.second!
    end
  end

  def test_third
    assert_equal topics(:third).title, Topic.third.title
  end

  def test_third_with_offset
    assert_equal topics(:fifth), Topic.offset(2).third
  end

  def test_third_have_primary_key_order_by_default
    expected = topics(:third)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.third
  end

  def test_model_class_responds_to_third_bang
    assert Topic.third!
    Topic.delete_all
453
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
      Topic.third!
    end
  end

  def test_fourth
    assert_equal topics(:fourth).title, Topic.fourth.title
  end

  def test_fourth_with_offset
    assert_equal topics(:fifth), Topic.offset(1).fourth
  end

  def test_fourth_have_primary_key_order_by_default
    expected = topics(:fourth)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.fourth
  end

  def test_model_class_responds_to_fourth_bang
    assert Topic.fourth!
    Topic.delete_all
475
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
      Topic.fourth!
    end
  end

  def test_fifth
    assert_equal topics(:fifth).title, Topic.fifth.title
  end

  def test_fifth_with_offset
    assert_equal topics(:fifth), Topic.offset(0).fifth
  end

  def test_fifth_have_primary_key_order_by_default
    expected = topics(:fifth)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.fifth
  end

  def test_model_class_responds_to_fifth_bang
    assert Topic.fifth!
    Topic.delete_all
497
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
498 499 500 501
      Topic.fifth!
    end
  end

502 503
  def test_second_to_last
    assert_equal topics(:fourth).title, Topic.second_to_last.title
504 505 506

    # test with offset
    assert_equal topics(:fourth), Topic.offset(1).second_to_last
507 508
    assert_equal topics(:fourth), Topic.offset(2).second_to_last
    assert_equal topics(:fourth), Topic.offset(3).second_to_last
509 510
    assert_nil Topic.offset(4).second_to_last
    assert_nil Topic.offset(5).second_to_last
511 512

    #test with limit
513
    assert_nil Topic.limit(1).second
514
    assert_nil Topic.limit(1).second_to_last
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
  end

  def test_second_to_last_have_primary_key_order_by_default
    expected = topics(:fourth)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.second_to_last
  end

  def test_model_class_responds_to_second_to_last_bang
    assert Topic.second_to_last!
    Topic.delete_all
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
      Topic.second_to_last!
    end
  end

  def test_third_to_last
    assert_equal topics(:third).title, Topic.third_to_last.title
533 534 535

    # test with offset
    assert_equal topics(:third), Topic.offset(1).third_to_last
536
    assert_equal topics(:third), Topic.offset(2).third_to_last
537 538 539
    assert_nil Topic.offset(3).third_to_last
    assert_nil Topic.offset(4).third_to_last
    assert_nil Topic.offset(5).third_to_last
540 541

    # test with limit
542
    assert_nil Topic.limit(1).third
543
    assert_nil Topic.limit(1).third_to_last
544
    assert_nil Topic.limit(2).third
545
    assert_nil Topic.limit(2).third_to_last
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
  end

  def test_third_to_last_have_primary_key_order_by_default
    expected = topics(:third)
    expected.touch # PostgreSQL changes the default order if no order clause is used
    assert_equal expected, Topic.third_to_last
  end

  def test_model_class_responds_to_third_to_last_bang
    assert Topic.third_to_last!
    Topic.delete_all
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
      Topic.third_to_last!
    end
  end

562 563 564 565 566 567 568
  def test_last_bang_present
    assert_nothing_raised do
      assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").last!
    end
  end

  def test_last_bang_missing
569
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
570 571 572 573
      Topic.where("title = 'This title does not exist'").last!
    end
  end

574
  def test_model_class_responds_to_last_bang
575
    assert_equal topics(:fifth), Topic.last!
576
    assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
577 578 579 580 581
      Topic.delete_all
      Topic.last!
    end
  end

582
  def test_take_and_first_and_last_with_integer_should_use_sql_limit
583 584 585
    assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.take(3).entries }
    assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.first(2).entries }
    assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.last(5).entries }
586 587 588 589 590 591
  end

  def test_last_with_integer_and_order_should_keep_the_order
    assert_equal Topic.order("title").to_a.last(2), Topic.order("title").last(2)
  end

592 593 594 595
  def test_last_with_integer_and_order_should_use_sql_limit
    relation = Topic.order("title")
    assert_queries(1) { relation.last(5) }
    assert !relation.loaded?
596 597
  end

598 599 600 601 602 603 604
  def test_last_with_integer_and_reorder_should_use_sql_limit
    relation = Topic.reorder("title")
    assert_queries(1) { relation.last(5) }
    assert !relation.loaded?
  end

  def test_last_on_loaded_relation_should_not_use_sql
605
    relation = Topic.limit(10).load
606 607 608 609 610 611 612
    assert_no_queries do
      relation.last
      relation.last(2)
    end
  end

  def test_last_with_irreversible_order
613
    assert_raises(ActiveRecord::IrreversibleOrderError) do
614 615
      Topic.order("coalesce(author_name, title)").last
    end
616
  end
617 618

  def test_last_on_relation_with_limit_and_offset
619
    post = posts("sti_comments")
620 621 622 623 624 625 626 627 628 629

    comments = post.comments.order(id: :asc)
    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)

    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)
630 631
  end

632 633
  def test_take_and_first_and_last_with_integer_should_return_an_array
    assert_kind_of Array, Topic.take(5)
634 635 636 637
    assert_kind_of Array, Topic.first(5)
    assert_kind_of Array, Topic.last(5)
  end

D
David Heinemeier Hansson 已提交
638
  def test_unexisting_record_exception_handling
639
    assert_raise(ActiveRecord::RecordNotFound) {
D
David Heinemeier Hansson 已提交
640 641
      Topic.find(1).parent
    }
642

643
    Topic.find(2).topic
D
David Heinemeier Hansson 已提交
644
  end
645

646
  def test_find_only_some_columns
647
    topic = Topic.select("author_name").find(1)
648 649
    assert_raise(ActiveModel::MissingAttributeError) { topic.title }
    assert_raise(ActiveModel::MissingAttributeError) { topic.title? }
650
    assert_nil topic.read_attribute("title")
651 652
    assert_equal "David", topic.author_name
    assert !topic.attribute_present?("title")
653
    assert !topic.attribute_present?(:title)
654
    assert topic.attribute_present?("author_name")
655
    assert_respond_to topic, "author_name"
656
  end
J
Jeremy Kemper 已提交
657

658
  def test_find_on_array_conditions
659 660
    assert Topic.where(["approved = ?", false]).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(["approved = ?", true]).find(1) }
D
David Heinemeier Hansson 已提交
661
  end
662

663
  def test_find_on_hash_conditions
664 665
    assert Topic.where(approved: false).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(approved: true).find(1) }
666
  end
667

668
  def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_string
669 670
    assert Topic.where("topics.approved" => false).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where("topics.approved" => true).find(1) }
671 672
  end

673 674 675 676 677
  def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_symbol
    assert Topic.where('topics.approved': false).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved': true).find(1) }
  end

678
  def test_find_on_hash_conditions_with_hashed_table_name
679 680
    assert Topic.where(topics: { approved: false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(topics: { approved: true }).find(1) }
681 682
  end

683
  def test_find_on_combined_explicit_and_hashed_table_names
684 685 686
    assert Topic.where("topics.approved" => false, topics: { author_name: "David" }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where("topics.approved" => true, topics: { author_name: "David" }).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where("topics.approved" => false, topics: { author_name: "Melanie" }).find(1) }
687 688
  end

689
  def test_find_with_hash_conditions_on_joined_table
690
    firms = Firm.joins(:account).where(accounts: { credit_limit: 50 })
691 692 693 694 695
    assert_equal 1, firms.size
    assert_equal companies(:first_firm), firms.first
  end

  def test_find_with_hash_conditions_on_joined_table_and_with_range
696
    firms = DependentFirm.joins(:account).where(name: "RailsCore", accounts: { credit_limit: 55..60 })
697 698 699 700
    assert_equal 1, firms.size
    assert_equal companies(:rails_core), firms.first
  end

701 702
  def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
    david = customers(:david)
703
    assert Customer.where("customers.name" => david.name, :address => david.address).find(david.id)
704
    assert_raise(ActiveRecord::RecordNotFound) {
705
      Customer.where("customers.name" => david.name + "1", :address => david.address).find(david.id)
706 707 708
    }
  end

709
  def test_find_on_association_proxy_conditions
J
Jon Leighton 已提交
710
    assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.where(post_id: authors(:david).posts).map(&:id).sort
711 712
  end

713
  def test_find_on_hash_conditions_with_range
714
    assert_equal [1, 2], Topic.where(id: 1..2).to_a.map(&:id).sort
715
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2..3).find(1) }
716
  end
717

718
  def test_find_on_hash_conditions_with_end_exclusive_range
719 720
    assert_equal [1, 2, 3], Topic.where(id: 1..3).to_a.map(&:id).sort
    assert_equal [1, 2], Topic.where(id: 1...3).to_a.map(&:id).sort
721
    assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2...3).find(3) }
722 723
  end

724
  def test_find_on_hash_conditions_with_multiple_ranges
725
    assert_equal [1, 2, 3], Comment.where(id: 1..3, post_id: 1..2).to_a.map(&:id).sort
726
    assert_equal [1], Comment.where(id: 1..1, post_id: 1..10).to_a.map(&:id).sort
727
  end
728

729
  def test_find_on_hash_conditions_with_array_of_integers_and_ranges
730
    assert_equal [1, 2, 3, 5, 6, 7, 8, 9], Comment.where(id: [1..2, 3, 5, 6..8, 9]).to_a.map(&:id).sort
731 732
  end

733
  def test_find_on_hash_conditions_with_array_of_ranges
734
    assert_equal [1, 2, 6, 7, 8], Comment.where(id: [1..2, 6..8]).to_a.map(&:id).sort
735 736
  end

737
  def test_find_on_multiple_hash_conditions
738 739 740 741
    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) }
742
  end
743

744
  def test_condition_interpolation
745
    assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
746 747 748
    assert_nil Company.where(["name = '%s'", "37signals!"]).first
    assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
749 750
  end

751
  def test_condition_array_interpolation
752 753 754 755
    assert_kind_of Firm, Company.where(["name = '%s'", "37signals"]).first
    assert_nil Company.where(["name = '%s'", "37signals!"]).first
    assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
D
David Heinemeier Hansson 已提交
756
  end
757

758
  def test_condition_hash_interpolation
759 760 761
    assert_kind_of Firm, Company.where(name: "37signals").first
    assert_nil Company.where(name: "37signals!").first
    assert_kind_of Time, Topic.where(id: 1).first.written_on
762
  end
763

764
  def test_hash_condition_find_malformed
765
    assert_raise(ActiveRecord::StatementInvalid) {
766
      Company.where(id: 2, dhh: true).first
767 768
    }
  end
769

770 771
  def test_hash_condition_find_with_escaped_characters
    Company.create("name" => "Ain't noth'n like' \#stuff")
772
    assert Company.where(name: "Ain't noth'n like' \#stuff").first
773 774 775
  end

  def test_hash_condition_find_with_array
776 777 778
    p1, p2 = Post.limit(2).order("id asc").to_a
    assert_equal [p1, p2], Post.where(id: [p1, p2]).order("id asc").to_a
    assert_equal [p1, p2], Post.where(id: [p1, p2.id]).order("id asc").to_a
779 780 781
  end

  def test_hash_condition_find_with_nil
782
    topic = Topic.where(last_read: nil).first
783 784
    assert_not_nil topic
    assert_nil topic.last_read
785
  end
D
David Heinemeier Hansson 已提交
786

787 788 789
  def test_hash_condition_find_with_aggregate_having_one_mapping
    balance = customers(:david).balance
    assert_kind_of Money, balance
790
    found_customer = Customer.where(balance: balance).first
791 792 793 794 795 796
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
    gps_location = customers(:david).gps_location
    assert_kind_of GpsLocation, gps_location
797
    found_customer = Customer.where(gps_location: gps_location).first
798 799 800 801 802 803
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
    balance = customers(:david).balance
    assert_kind_of Money, balance
804
    found_customer = Customer.where(balance: balance.amount).first
805 806 807 808 809 810
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
    gps_location = customers(:david).gps_location
    assert_kind_of GpsLocation, gps_location
811
    found_customer = Customer.where(gps_location: gps_location.gps_location).first
812 813 814 815 816 817
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_aggregate_having_three_mappings
    address = customers(:david).address
    assert_kind_of Address, address
818
    found_customer = Customer.where(address: address).first
819 820 821 822 823 824
    assert_equal customers(:david), found_customer
  end

  def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
    address = customers(:david).address
    assert_kind_of Address, address
825
    found_customer = Customer.where(address: address, name: customers(:david).name).first
826 827 828
    assert_equal customers(:david), found_customer
  end

829
  def test_condition_utc_time_interpolation_with_default_timezone_local
830
    with_env_tz "America/New_York" do
831
      with_timezone_config default: :local do
832
        topic = Topic.first
833
        assert_equal topic, Topic.where(["written_on = ?", topic.written_on.getutc]).first
834 835 836 837 838
      end
    end
  end

  def test_hash_condition_utc_time_interpolation_with_default_timezone_local
839
    with_env_tz "America/New_York" do
840
      with_timezone_config default: :local do
841
        topic = Topic.first
842
        assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
843 844 845 846 847
      end
    end
  end

  def test_condition_local_time_interpolation_with_default_timezone_utc
848
    with_env_tz "America/New_York" do
849
      with_timezone_config default: :utc do
850
        topic = Topic.first
851
        assert_equal topic, Topic.where(["written_on = ?", topic.written_on.getlocal]).first
852 853 854 855 856
      end
    end
  end

  def test_hash_condition_local_time_interpolation_with_default_timezone_utc
857
    with_env_tz "America/New_York" do
858
      with_timezone_config default: :utc do
859
        topic = Topic.first
860
        assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
861 862 863 864
      end
    end
  end

D
David Heinemeier Hansson 已提交
865
  def test_bind_variables
866 867 868 869
    assert_kind_of Firm, Company.where(["name = ?", "37signals"]).first
    assert_nil Company.where(["name = ?", "37signals!"]).first
    assert_nil Company.where(["name = ?", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.where(["id = ?", 1]).first.written_on
870
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
871
      Company.where(["id=? AND name = ?", 2]).first
D
David Heinemeier Hansson 已提交
872
    }
873
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
874
      Company.where(["id=?", 2, 3, 4]).first
D
David Heinemeier Hansson 已提交
875 876
    }
  end
877

D
David Heinemeier Hansson 已提交
878
  def test_bind_variables_with_quotes
B
Benjamin Fleischer 已提交
879 880
    Company.create("name" => "37signals' go'es against")
    assert Company.where(["name = ?", "37signals' go'es against"]).first
D
David Heinemeier Hansson 已提交
881 882 883
  end

  def test_named_bind_variables_with_quotes
B
Benjamin Fleischer 已提交
884 885
    Company.create("name" => "37signals' go'es against")
    assert Company.where(["name = :name", { name: "37signals' go'es against" }]).first
D
David Heinemeier Hansson 已提交
886 887 888
  end

  def test_named_bind_variables
889 890 891 892
    assert_kind_of Firm, Company.where(["name = :name", { name: "37signals" }]).first
    assert_nil Company.where(["name = :name", { name: "37signals!" }]).first
    assert_nil Company.where(["name = :name", { name: "37signals!' OR 1=1" }]).first
    assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on
D
David Heinemeier Hansson 已提交
893 894 895 896 897 898 899 900 901
  end

  def test_count_by_sql
    assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
    assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
    assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
  end

  def test_find_by_one_attribute
902
    assert_equal topics(:first), Topic.find_by_title("The First Topic")
D
David Heinemeier Hansson 已提交
903 904
    assert_nil Topic.find_by_title("The First Topic!")
  end
J
Jeremy Kemper 已提交
905

906 907
  def test_find_by_one_attribute_bang
    assert_equal topics(:first), Topic.find_by_title!("The First Topic")
908 909 910
    assert_raises_with_message(ActiveRecord::RecordNotFound, "Couldn't find Topic") do
      Topic.find_by_title!("The First Topic!")
    end
911 912
  end

913
  def test_find_by_on_attribute_that_is_a_reserved_word
914
    dog_alias = "Dog"
915 916 917 918 919
    dog = Dog.create(alias: dog_alias)

    assert_equal dog, Dog.find_by_alias(dog_alias)
  end

920 921 922 923 924
  def test_find_by_one_attribute_that_is_an_alias
    assert_equal topics(:first), Topic.find_by_heading("The First Topic")
    assert_nil Topic.find_by_heading("The First Topic!")
  end

N
Nikita Afanasenko 已提交
925
  def test_find_by_one_attribute_bang_with_blank_defined
926 927
    blank_topic = BlankTopic.create(title: "The Blank One")
    assert_equal blank_topic, BlankTopic.find_by_title!("The Blank One")
N
Nikita Afanasenko 已提交
928 929
  end

930
  def test_find_by_one_attribute_with_conditions
931
    assert_equal accounts(:rails_core_account), Account.where("firm_id = ?", 6).find_by_credit_limit(50)
932 933
  end

934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
  def test_find_by_one_attribute_that_is_an_aggregate
    address = customers(:david).address
    assert_kind_of Address, address
    found_customer = Customer.find_by_address(address)
    assert_equal customers(:david), found_customer
  end

  def test_find_by_one_attribute_that_is_an_aggregate_with_one_attribute_difference
    address = customers(:david).address
    assert_kind_of Address, address
    missing_address = Address.new(address.street, address.city, address.country + "1")
    assert_nil Customer.find_by_address(missing_address)
    missing_address = Address.new(address.street, address.city + "1", address.country)
    assert_nil Customer.find_by_address(missing_address)
    missing_address = Address.new(address.street + "1", address.city, address.country)
    assert_nil Customer.find_by_address(missing_address)
  end

  def test_find_by_two_attributes_that_are_both_aggregates
    balance = customers(:david).balance
    address = customers(:david).address
    assert_kind_of Money, balance
    assert_kind_of Address, address
    found_customer = Customer.find_by_balance_and_address(balance, address)
    assert_equal customers(:david), found_customer
  end

  def test_find_by_two_attributes_with_one_being_an_aggregate
    balance = customers(:david).balance
    assert_kind_of Money, balance
    found_customer = Customer.find_by_balance_and_name(balance, customers(:david).name)
    assert_equal customers(:david), found_customer
  end

968 969
  def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
    # ensure this test can run independently of order
A
Akira Matsuda 已提交
970
    class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.include?(:find_by_credit_limit)
971 972
    a = Account.where("firm_id = ?", 6).find_by_credit_limit(50)
    assert_equal a, Account.where("firm_id = ?", 6).find_by_credit_limit(50) # find_by_credit_limit has been cached
973 974
  end

975
  def test_find_by_one_attribute_with_several_options
976
    assert_equal accounts(:unknown), Account.order("id DESC").where("id != ?", 3).find_by_credit_limit(50)
977
  end
978

D
David Heinemeier Hansson 已提交
979
  def test_find_by_one_missing_attribute
980
    assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
D
David Heinemeier Hansson 已提交
981
  end
982

983
  def test_find_by_invalid_method_syntax
984 985 986 987
    assert_raise(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
    assert_raise(NoMethodError) { Topic.find_by_title?("The First Topic") }
    assert_raise(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
    assert_raise(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
988
  end
D
David Heinemeier Hansson 已提交
989 990

  def test_find_by_two_attributes
991
    assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
D
David Heinemeier Hansson 已提交
992 993 994
    assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
  end

995 996 997 998
  def test_find_by_two_attributes_but_passing_only_one
    assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") }
  end

L
Lauro Caetano 已提交
999
  def test_find_last_with_offset
1000
    devs = Developer.order("id")
L
Lauro Caetano 已提交
1001 1002 1003

    assert_equal devs[2], Developer.offset(2).first
    assert_equal devs[-3], Developer.offset(2).last
1004
    assert_equal devs[-3], Developer.offset(2).order("id DESC").first
L
Lauro Caetano 已提交
1005 1006
  end

D
David Heinemeier Hansson 已提交
1007 1008 1009 1010 1011
  def test_find_by_nil_attribute
    topic = Topic.find_by_last_read nil
    assert_not_nil topic
    assert_nil topic.last_read
  end
1012

D
David Heinemeier Hansson 已提交
1013 1014 1015 1016 1017 1018
  def test_find_by_nil_and_not_nil_attributes
    topic = Topic.find_by_last_read_and_author_name nil, "Mary"
    assert_equal "Mary", topic.author_name
  end

  def test_find_with_bad_sql
1019
    assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
D
David Heinemeier Hansson 已提交
1020 1021
  end

1022
  def test_find_all_with_join
1023
    developers_on_project_one = Developer.
1024 1025
      joins("LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id").
      where("project_id=1").to_a
1026
    assert_equal 3, developers_on_project_one.length
1027
    developer_names = developers_on_project_one.map(&:name)
1028 1029
    assert_includes developer_names, "David"
    assert_includes developer_names, "Jamis"
1030
  end
1031

1032
  def test_joins_dont_clobber_id
1033
    first = Firm.
1034 1035
      joins("INNER JOIN companies clients ON clients.firm_id = companies.id").
      where("companies.id = 1").first
1036 1037 1038
    assert_equal 1, first.id
  end

1039
  def test_joins_with_string_array
1040 1041 1042 1043
    person_with_reader_and_post = Post.
      joins(["INNER JOIN categorizations ON categorizations.post_id = posts.id",
             "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
            ])
1044 1045 1046
    assert_equal 1, person_with_reader_and_post.size
  end

1047 1048
  def test_find_by_id_with_conditions_with_or
    assert_nothing_raised do
1049
      Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1, 2, 3])
1050 1051
    end
  end
1052

1053
  def test_find_ignores_previously_inserted_record
1054
    Post.create!(title: "test", body: "it out")
J
Jon Leighton 已提交
1055
    assert_equal [], Post.where(id: nil)
1056 1057
  end

1058 1059 1060 1061 1062
  def test_find_by_empty_ids
    assert_equal [], Post.find([])
  end

  def test_find_by_empty_in_condition
1063
    assert_equal [], Post.where("id in (?)", [])
1064 1065 1066
  end

  def test_find_by_records
1067 1068 1069
    p1, p2 = Post.limit(2).order("id asc").to_a
    assert_equal [p1, p2], Post.where(["id in (?)", [p1, p2]]).order("id asc")
    assert_equal [p1, p2], Post.where(["id in (?)", [p1, p2.id]]).order("id asc")
1070 1071
  end

1072 1073 1074 1075 1076 1077 1078 1079 1080
  def test_select_value
    assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
    assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
    # make sure we didn't break count...
    assert_equal 0, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = 'Halliburton'")
    assert_equal 1, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = '37signals'")
  end

  def test_select_values
1081 1082
    assert_equal ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map!(&:to_s)
    assert_equal ["37signals", "Summit", "Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux", "Apex"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
1083 1084
  end

1085 1086
  def test_select_rows
    assert_equal(
1087
      [["1", "1", nil, "37signals"],
1088 1089
       ["2", "1", "2", "Summit"],
       ["3", "1", "1", "Microsoft"]],
1090
      Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! { |i| i.map! { |j| j.to_s unless j.nil? } })
1091
    assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
1092
      Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! { |i| i.map! { |j| j.to_s unless j.nil? } }
1093 1094
  end

1095
  def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
R
Fix...  
Ryuta Kamizono 已提交
1096 1097
    assert_equal 2, Post.includes(authors: :author_address).
      where.not(author_addresses: { id: nil }).
1098
      order("author_addresses.id DESC").limit(2).to_a.size
1099

1100
    assert_equal 3, Post.includes(author: :author_address, authors: :author_address).
R
Fix...  
Ryuta Kamizono 已提交
1101
      where.not(author_addresses_authors: { id: nil }).
1102
      order("author_addresses_authors.id DESC").limit(3).to_a.size
1103 1104
  end

1105
  def test_find_with_nil_inside_set_passed_for_one_attribute
1106 1107
    client_of = Company.
      where(client_of: [2, 1, nil],
1108 1109
            name: ["37signals", "Summit", "Microsoft"]).
      order("client_of DESC").
1110
      map(&:client_of)
1111

1112
    assert_includes client_of, nil
1113
    assert_equal [2, 1].sort, client_of.compact.sort
1114 1115
  end

1116
  def test_find_with_nil_inside_set_passed_for_attribute
1117 1118
    client_of = Company.
      where(client_of: [nil]).
1119
      order("client_of DESC").
1120
      map(&:client_of)
1121 1122 1123 1124

    assert_equal [], client_of.compact
  end

1125
  def test_with_limiting_with_custom_select
1126
    posts = Post.references(:authors).merge(
1127 1128
      includes: :author, select: 'posts.*, authors.id as "author_id"',
      limit: 3, order: "posts.id"
1129
    ).to_a
1130 1131
    assert_equal 3, posts.size
    assert_equal [0, 1, 1], posts.map(&:author_id).sort
1132
  end
1133

1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
  def test_find_one_message_on_primary_key
    e = assert_raises(ActiveRecord::RecordNotFound) do
      Car.find(0)
    end
    assert_equal 0, e.id
    assert_equal "id", e.primary_key
    assert_equal "Car", e.model
    assert_equal "Couldn't find Car with 'id'=0", e.message
  end

1144
  def test_find_one_message_with_custom_primary_key
1145 1146 1147
    table_with_custom_primary_key do |model|
      model.primary_key = :name
      e = assert_raises(ActiveRecord::RecordNotFound) do
1148
        model.find "Hello World!"
1149
      end
1150
      assert_equal "Couldn't find MercedesCar with 'name'=Hello World!", e.message
1151 1152 1153 1154 1155 1156 1157
    end
  end

  def test_find_some_message_with_custom_primary_key
    table_with_custom_primary_key do |model|
      model.primary_key = :name
      e = assert_raises(ActiveRecord::RecordNotFound) do
1158
        model.find "Hello", "World!"
1159
      end
1160
      assert_equal "Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2)", e.message
1161 1162 1163
    end
  end

1164 1165 1166 1167 1168 1169
  def test_find_without_primary_key
    assert_raises(ActiveRecord::UnknownPrimaryKey) do
      Matey.find(1)
    end
  end

1170
  def test_finder_with_offset_string
1171
    assert_nothing_raised { Topic.offset("3").to_a }
1172 1173
  end

1174 1175 1176 1177 1178 1179 1180 1181 1182
  test "find_by with hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by(id: posts(:eager_other).id)
  end

  test "find_by with non-hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by("id = #{posts(:eager_other).id}")
  end

  test "find_by with multi-arg conditions returns the first matching record" do
1183
    assert_equal posts(:eager_other), Post.find_by("id = ?", posts(:eager_other).id)
1184 1185 1186
  end

  test "find_by returns nil if the record is missing" do
1187
    assert_nil Post.find_by("1 = 0")
1188 1189
  end

1190 1191
  test "find_by with associations" do
    assert_equal authors(:david), Post.find_by(author: authors(:david)).author
1192
    assert_equal authors(:mary) , Post.find_by(author: authors(:mary)).author
1193 1194
  end

1195 1196 1197 1198
  test "find_by doesn't have implicit ordering" do
    assert_sql(/^((?!ORDER).)*$/) { Post.find_by(id: posts(:eager_other).id) }
  end

1199 1200 1201 1202 1203 1204 1205 1206 1207
  test "find_by! with hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by!(id: posts(:eager_other).id)
  end

  test "find_by! with non-hash conditions returns the first matching record" do
    assert_equal posts(:eager_other), Post.find_by!("id = #{posts(:eager_other).id}")
  end

  test "find_by! with multi-arg conditions returns the first matching record" do
1208
    assert_equal posts(:eager_other), Post.find_by!("id = ?", posts(:eager_other).id)
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
  end

  test "find_by! doesn't have implicit ordering" do
    assert_sql(/^((?!ORDER).)*$/) { Post.find_by!(id: posts(:eager_other).id) }
  end

  test "find_by! raises RecordNotFound if the record is missing" do
    assert_raises(ActiveRecord::RecordNotFound) do
      Post.find_by!("1 = 0")
    end
  end

1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
  test "find on a scope does not perform statement caching" do
    honda = cars(:honda)
    zyke = cars(:zyke)
    tyre = honda.tyres.create!
    tyre2 = zyke.tyres.create!

    assert_equal tyre, honda.tyres.custom_find(tyre.id)
    assert_equal tyre2, zyke.tyres.custom_find(tyre2.id)
  end

  test "find_by on a scope does not perform statement caching" do
    honda = cars(:honda)
    zyke = cars(:zyke)
    tyre = honda.tyres.create!
    tyre2 = zyke.tyres.create!

    assert_equal tyre, honda.tyres.custom_find_by(id: tyre.id)
    assert_equal tyre2, zyke.tyres.custom_find_by(id: tyre2.id)
  end

1241
  private
1242 1243 1244
    def table_with_custom_primary_key
      yield(Class.new(Toy) do
        def self.name
1245
          "MercedesCar"
1246 1247 1248
        end
      end)
    end
1249 1250 1251 1252 1253

    def assert_raises_with_message(exception_class, message, &block)
      err = assert_raises(exception_class) { block.call }
      assert_match message, err.message
    end
D
David Heinemeier Hansson 已提交
1254
end