finder_test.rb 43.4 KB
Newer Older
1
require "cases/helper"
2
require 'models/post'
J
Jeremy Kemper 已提交
3
require 'models/author'
4
require 'models/categorization'
J
Jeremy Kemper 已提交
5 6 7 8 9
require 'models/comment'
require 'models/company'
require 'models/topic'
require 'models/reply'
require 'models/entrant'
10
require 'models/project'
J
Jeremy Kemper 已提交
11
require 'models/developer'
12
require 'models/customer'
13
require 'models/toy'
D
David Heinemeier Hansson 已提交
14

15
class FinderTest < ActiveRecord::TestCase
16
  fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers, :categories, :categorizations
D
David Heinemeier Hansson 已提交
17 18

  def test_find
19
    assert_equal(topics(:first).title, Topic.find(1).title)
D
David Heinemeier Hansson 已提交
20
  end
21

22 23 24 25 26
  # find should handle strings that come from URLs
  # (example: Category.find(params[:id]))
  def test_find_with_string
    assert_equal(Topic.find(1).title,Topic.find("1").title)
  end
27

D
David Heinemeier Hansson 已提交
28
  def test_exists
29 30 31 32 33 34
    assert Topic.exists?(1)
    assert Topic.exists?("1")
    assert Topic.exists?(:author_name => "David")
    assert Topic.exists?(:author_name => "Mary", :approved => true)
    assert Topic.exists?(["parent_id = ?", 1])
    assert !Topic.exists?(45)
35 36 37 38 39 40 41 42 43

    begin
      assert !Topic.exists?("foo")
    rescue ActiveRecord::StatementInvalid
      # PostgreSQL complains about string comparison with integer field
    rescue Exception
      flunk
    end

44
    assert_raise(NoMethodError) { Topic.exists?([1,2]) }
D
David Heinemeier Hansson 已提交
45
  end
46

47 48 49
  def test_exists_returns_true_with_one_record_and_no_args
    assert Topic.exists?
  end
50

51 52 53 54 55 56 57 58 59
  # 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
    assert !Topic.exists?(nil)
    assert Topic.exists?
    assert !Topic.first.replies.exists?(nil)
    assert Topic.first.replies.exists?
  end

60 61 62 63 64
  # ensures +exists?+ runs valid SQL by excluding order value
  def test_exists_with_order
    assert Topic.order(:id).uniq.exists?
  end

65 66 67 68
  def test_does_not_exist_with_empty_table_and_no_args_given
    Topic.delete_all
    assert !Topic.exists?
  end
69

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
  def test_exists_with_aggregate_having_three_mappings
    existing_address = customers(:david).address
    assert Customer.exists?(:address => existing_address)
  end

  def test_exists_with_aggregate_having_three_mappings_with_one_difference
    existing_address = customers(:david).address
    assert !Customer.exists?(:address =>
      Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
    assert !Customer.exists?(:address =>
      Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
    assert !Customer.exists?(:address =>
      Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
  end

85 86 87 88 89
  def test_exists_does_not_instantiate_records
    Developer.expects(:instantiate).never
    Developer.exists?
  end

D
David Heinemeier Hansson 已提交
90 91 92 93
  def test_find_by_array_of_one_id
    assert_kind_of(Array, Topic.find([ 1 ]))
    assert_equal(1, Topic.find([ 1 ]).length)
  end
94

D
David Heinemeier Hansson 已提交
95
  def test_find_by_ids
96 97 98 99 100
    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
J
Jon Leighton 已提交
101 102
    assert_equal 2, Entrant.scoped(:limit => 2).find([1,3,2]).size
    assert_equal 1, Entrant.scoped(:limit => 3, :offset => 2).find([1,3,2]).size
103 104 105 106

    # 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.
107
    devs = Developer.all
J
Jon Leighton 已提交
108
    last_devs = Developer.scoped(:limit => 3, :offset => 9).find devs.map(&:id)
109
    assert_equal 2, last_devs.size
D
David Heinemeier Hansson 已提交
110 111
  end

112 113 114 115
  def test_find_an_empty_array
    assert_equal [], Topic.find([])
  end

D
David Heinemeier Hansson 已提交
116
  def test_find_by_ids_missing_one
117
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
D
David Heinemeier Hansson 已提交
118
  end
119

120 121 122 123 124 125 126
  def test_find_with_group_and_sanitized_having_method
    developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select('salary').all
    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 已提交
127 128
  def test_find_with_entire_select_statement
    topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
129

D
David Heinemeier Hansson 已提交
130
    assert_equal(1, topics.size)
131
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
132
  end
133

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

D
David Heinemeier Hansson 已提交
137
    assert_equal(1, topics.size)
138
    assert_equal(topics(:second).title, topics.first.title)
D
David Heinemeier Hansson 已提交
139
  end
140

141 142 143 144
  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
145

146
  def test_first
147
    assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
148
  end
149

150
  def test_first_failing
151
    assert_nil Topic.where("title = 'The Second Topic of the day!'").first
152
  end
D
David Heinemeier Hansson 已提交
153

154 155 156 157 158 159 160 161 162 163 164 165
  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
    assert_raises ActiveRecord::RecordNotFound do
      Topic.where("title = 'This title does not exist'").first!
    end
  end

166 167 168 169 170 171
  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

172
  def test_model_class_responds_to_first_bang
173 174
    assert Topic.first!
    Topic.delete_all
175 176 177 178 179
    assert_raises ActiveRecord::RecordNotFound do
      Topic.first!
    end
  end

180 181 182 183 184 185 186 187 188 189 190 191
  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
    assert_raises ActiveRecord::RecordNotFound do
      Topic.where("title = 'This title does not exist'").last!
    end
  end

192 193 194 195 196 197 198 199
  def test_model_class_responds_to_last_bang
    assert_equal topics(:fourth), Topic.last!
    assert_raises ActiveRecord::RecordNotFound do
      Topic.delete_all
      Topic.last!
    end
  end

200
  def test_first_and_last_with_integer_should_use_sql_limit
201 202
    assert_sql(/LIMIT 2|ROWNUM <= 2/) { Topic.first(2).entries }
    assert_sql(/LIMIT 5|ROWNUM <= 5/) { Topic.last(5).entries }
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
  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

  def test_last_with_integer_and_order_should_not_use_sql_limit
    query = assert_sql { Topic.order("title").last(5).entries }
    assert_equal 1, query.length
    assert_no_match(/LIMIT/, query.first)
  end

  def test_last_with_integer_and_reorder_should_not_use_sql_limit
    query = assert_sql { Topic.reorder("title").last(5).entries }
    assert_equal 1, query.length
    assert_no_match(/LIMIT/, query.first)
219 220 221 222 223 224 225
  end

  def test_first_and_last_with_integer_should_return_an_array
    assert_kind_of Array, Topic.first(5)
    assert_kind_of Array, Topic.last(5)
  end

D
David Heinemeier Hansson 已提交
226
  def test_unexisting_record_exception_handling
227
    assert_raise(ActiveRecord::RecordNotFound) {
D
David Heinemeier Hansson 已提交
228 229
      Topic.find(1).parent
    }
230

231
    Topic.find(2).topic
D
David Heinemeier Hansson 已提交
232
  end
233

234
  def test_find_only_some_columns
J
Jon Leighton 已提交
235
    topic = Topic.scoped(:select => "author_name").find(1)
236
    assert_raise(ActiveModel::MissingAttributeError) {topic.title}
237
    assert_nil topic.read_attribute("title")
238 239
    assert_equal "David", topic.author_name
    assert !topic.attribute_present?("title")
240
    assert !topic.attribute_present?(:title)
241
    assert topic.attribute_present?("author_name")
242
    assert_respond_to topic, "author_name"
243
  end
J
Jeremy Kemper 已提交
244

245
  def test_find_on_array_conditions
J
Jon Leighton 已提交
246 247
    assert Topic.scoped(:where => ["approved = ?", false]).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => ["approved = ?", true]).find(1) }
D
David Heinemeier Hansson 已提交
248
  end
249

250
  def test_find_on_hash_conditions
J
Jon Leighton 已提交
251 252
    assert Topic.scoped(:where => { :approved => false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :approved => true }).find(1) }
253
  end
254

255
  def test_find_on_hash_conditions_with_explicit_table_name
J
Jon Leighton 已提交
256 257
    assert Topic.scoped(:where => { 'topics.approved' => false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { 'topics.approved' => true }).find(1) }
258 259
  end

260
  def test_find_on_hash_conditions_with_hashed_table_name
J
Jon Leighton 已提交
261 262
    assert Topic.scoped(:where => {:topics => { :approved => false }}).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => {:topics => { :approved => true }}).find(1) }
263 264 265
  end

  def test_find_with_hash_conditions_on_joined_table
266
    firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 })
267 268 269 270 271
    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
J
Jon Leighton 已提交
272
    firms = DependentFirm.scoped :joins => :account, :where => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
273 274 275 276
    assert_equal 1, firms.size
    assert_equal companies(:rails_core), firms.first
  end

277 278
  def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
    david = customers(:david)
J
Jon Leighton 已提交
279
    assert Customer.scoped(:where => { 'customers.name' => david.name, :address => david.address }).find(david.id)
280
    assert_raise(ActiveRecord::RecordNotFound) {
J
Jon Leighton 已提交
281
      Customer.scoped(:where => { 'customers.name' => david.name + "1", :address => david.address }).find(david.id)
282 283 284
    }
  end

285
  def test_find_on_association_proxy_conditions
286
    assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort
287 288
  end

289
  def test_find_on_hash_conditions_with_range
J
Jon Leighton 已提交
290
    assert_equal [1,2], Topic.scoped(:where => { :id => 1..2 }).all.map(&:id).sort
J
Jon Leighton 已提交
291
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :id => 2..3 }).find(1) }
292
  end
293

294
  def test_find_on_hash_conditions_with_end_exclusive_range
J
Jon Leighton 已提交
295 296
    assert_equal [1,2,3], Topic.scoped(:where => { :id => 1..3 }).all.map(&:id).sort
    assert_equal [1,2], Topic.scoped(:where => { :id => 1...3 }).all.map(&:id).sort
J
Jon Leighton 已提交
297
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :id => 2...3 }).find(3) }
298 299
  end

300
  def test_find_on_hash_conditions_with_multiple_ranges
J
Jon Leighton 已提交
301 302
    assert_equal [1,2,3], Comment.scoped(:where => { :id => 1..3, :post_id => 1..2 }).all.map(&:id).sort
    assert_equal [1], Comment.scoped(:where => { :id => 1..1, :post_id => 1..10 }).all.map(&:id).sort
303
  end
304

305
  def test_find_on_hash_conditions_with_array_of_integers_and_ranges
J
Jon Leighton 已提交
306
    assert_equal [1,2,3,5,6,7,8,9], Comment.scoped(:where => {:id => [1..2, 3, 5, 6..8, 9]}).all.map(&:id).sort
307 308
  end

309
  def test_find_on_multiple_hash_conditions
J
Jon Leighton 已提交
310 311 312 313
    assert Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false }).find(1)
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }).find(1) }
    assert_raise(ActiveRecord::RecordNotFound) { Topic.scoped(:where => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }).find(1) }
314
  end
315

316
  def test_condition_interpolation
317
    assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
J
Jon Leighton 已提交
318 319 320
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!"]).first
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = %d", 1]).first.written_on
321 322
  end

323
  def test_condition_array_interpolation
J
Jon Leighton 已提交
324 325 326 327
    assert_kind_of Firm, Company.scoped(:where => ["name = '%s'", "37signals"]).first
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!"]).first
    assert_nil Company.scoped(:where => ["name = '%s'", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = %d", 1]).first.written_on
D
David Heinemeier Hansson 已提交
328
  end
329

330
  def test_condition_hash_interpolation
J
Jon Leighton 已提交
331 332 333
    assert_kind_of Firm, Company.scoped(:where => { :name => "37signals"}).first
    assert_nil Company.scoped(:where => { :name => "37signals!"}).first
    assert_kind_of Time, Topic.scoped(:where => {:id => 1}).first.written_on
334
  end
335

336
  def test_hash_condition_find_malformed
337
    assert_raise(ActiveRecord::StatementInvalid) {
J
Jon Leighton 已提交
338
      Company.scoped(:where => { :id => 2, :dhh => true }).first
339 340
    }
  end
341

342 343
  def test_hash_condition_find_with_escaped_characters
    Company.create("name" => "Ain't noth'n like' \#stuff")
J
Jon Leighton 已提交
344
    assert Company.scoped(:where => { :name => "Ain't noth'n like' \#stuff" }).first
345 346 347
  end

  def test_hash_condition_find_with_array
348
    p1, p2 = Post.scoped(:limit => 2, :order => 'id asc').all
J
Jon Leighton 已提交
349 350
    assert_equal [p1, p2], Post.scoped(:where => { :id => [p1, p2] }, :order => 'id asc').all
    assert_equal [p1, p2], Post.scoped(:where => { :id => [p1, p2.id] }, :order => 'id asc').all
351 352 353
  end

  def test_hash_condition_find_with_nil
J
Jon Leighton 已提交
354
    topic = Topic.scoped(:where => { :last_read => nil } ).first
355 356
    assert_not_nil topic
    assert_nil topic.last_read
357
  end
D
David Heinemeier Hansson 已提交
358

359 360 361
  def test_hash_condition_find_with_aggregate_having_one_mapping
    balance = customers(:david).balance
    assert_kind_of Money, balance
J
Jon Leighton 已提交
362
    found_customer = Customer.scoped(:where => {:balance => balance}).first
363 364 365 366 367 368
    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
J
Jon Leighton 已提交
369
    found_customer = Customer.scoped(:where => {:gps_location => gps_location}).first
370 371 372 373 374 375
    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
J
Jon Leighton 已提交
376
    found_customer = Customer.scoped(:where => {:balance => balance.amount}).first
377 378 379 380 381 382
    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
J
Jon Leighton 已提交
383
    found_customer = Customer.scoped(:where => {:gps_location => gps_location.gps_location}).first
384 385 386 387 388 389
    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
J
Jon Leighton 已提交
390
    found_customer = Customer.scoped(:where => {:address => address}).first
391 392 393 394 395 396
    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
J
Jon Leighton 已提交
397
    found_customer = Customer.scoped(:where => {:address => address, :name => customers(:david).name}).first
398 399 400
    assert_equal customers(:david), found_customer
  end

401 402 403 404
  def test_condition_utc_time_interpolation_with_default_timezone_local
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :local do
        topic = Topic.first
J
Jon Leighton 已提交
405
        assert_equal topic, Topic.scoped(:where => ['written_on = ?', topic.written_on.getutc]).first
406 407 408 409 410 411 412 413
      end
    end
  end

  def test_hash_condition_utc_time_interpolation_with_default_timezone_local
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :local do
        topic = Topic.first
J
Jon Leighton 已提交
414
        assert_equal topic, Topic.scoped(:where => {:written_on => topic.written_on.getutc}).first
415 416 417 418 419 420 421 422
      end
    end
  end

  def test_condition_local_time_interpolation_with_default_timezone_utc
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :utc do
        topic = Topic.first
J
Jon Leighton 已提交
423
        assert_equal topic, Topic.scoped(:where => ['written_on = ?', topic.written_on.getlocal]).first
424 425 426 427 428 429 430 431
      end
    end
  end

  def test_hash_condition_local_time_interpolation_with_default_timezone_utc
    with_env_tz 'America/New_York' do
      with_active_record_default_timezone :utc do
        topic = Topic.first
J
Jon Leighton 已提交
432
        assert_equal topic, Topic.scoped(:where => {:written_on => topic.written_on.getlocal}).first
433 434 435 436
      end
    end
  end

D
David Heinemeier Hansson 已提交
437
  def test_bind_variables
J
Jon Leighton 已提交
438 439 440 441
    assert_kind_of Firm, Company.scoped(:where => ["name = ?", "37signals"]).first
    assert_nil Company.scoped(:where => ["name = ?", "37signals!"]).first
    assert_nil Company.scoped(:where => ["name = ?", "37signals!' OR 1=1"]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = ?", 1]).first.written_on
442
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
J
Jon Leighton 已提交
443
      Company.scoped(:where => ["id=? AND name = ?", 2]).first
D
David Heinemeier Hansson 已提交
444
    }
445
    assert_raise(ActiveRecord::PreparedStatementInvalid) {
J
Jon Leighton 已提交
446
     Company.scoped(:where => ["id=?", 2, 3, 4]).first
D
David Heinemeier Hansson 已提交
447 448
    }
  end
449

D
David Heinemeier Hansson 已提交
450 451
  def test_bind_variables_with_quotes
    Company.create("name" => "37signals' go'es agains")
J
Jon Leighton 已提交
452
    assert Company.scoped(:where => ["name = ?", "37signals' go'es agains"]).first
D
David Heinemeier Hansson 已提交
453 454 455 456
  end

  def test_named_bind_variables_with_quotes
    Company.create("name" => "37signals' go'es agains")
J
Jon Leighton 已提交
457
    assert Company.scoped(:where => ["name = :name", {:name => "37signals' go'es agains"}]).first
D
David Heinemeier Hansson 已提交
458 459 460 461
  end

  def test_bind_arity
    assert_nothing_raised                                 { bind '' }
462
    assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
463

464
    assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' }
D
David Heinemeier Hansson 已提交
465
    assert_nothing_raised                                 { bind '?', 1 }
466
    assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1  }
D
David Heinemeier Hansson 已提交
467
  end
468

D
David Heinemeier Hansson 已提交
469 470 471
  def test_named_bind_variables
    assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
    assert_equal '1 1', bind(':a :a', :a => 1)  # ' ruby-mode
472

473
    assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
474

J
Jon Leighton 已提交
475 476 477 478
    assert_kind_of Firm, Company.scoped(:where => ["name = :name", { :name => "37signals" }]).first
    assert_nil Company.scoped(:where => ["name = :name", { :name => "37signals!" }]).first
    assert_nil Company.scoped(:where => ["name = :name", { :name => "37signals!' OR 1=1" }]).first
    assert_kind_of Time, Topic.scoped(:where => ["id = :id", { :id => 1 }]).first.written_on
D
David Heinemeier Hansson 已提交
479 480
  end

481 482 483 484 485 486 487 488 489 490 491 492
  class SimpleEnumerable
    include Enumerable

    def initialize(ary)
      @ary = ary
    end

    def each(&b)
      @ary.each(&b)
    end
  end

493
  def test_bind_enumerable
494 495
    quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})

D
David Heinemeier Hansson 已提交
496
    assert_equal '1,2,3', bind('?', [1, 2, 3])
497
    assert_equal quoted_abc, bind('?', %w(a b c))
D
David Heinemeier Hansson 已提交
498 499

    assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
500
    assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
501

502 503
    assert_equal '1,2,3', bind('?', SimpleEnumerable.new([1, 2, 3]))
    assert_equal quoted_abc, bind('?', SimpleEnumerable.new(%w(a b c)))
504

505 506
    assert_equal '1,2,3', bind(':a', :a => SimpleEnumerable.new([1, 2, 3]))
    assert_equal quoted_abc, bind(':a', :a => SimpleEnumerable.new(%w(a b c))) # '
D
David Heinemeier Hansson 已提交
507 508
  end

509 510 511 512 513 514 515
  def test_bind_empty_enumerable
    quoted_nil = ActiveRecord::Base.connection.quote(nil)
    assert_equal quoted_nil, bind('?', [])
    assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
    assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
  end

J
Jeremy Kemper 已提交
516 517 518
  def test_bind_empty_string
    quoted_empty = ActiveRecord::Base.connection.quote('')
    assert_equal quoted_empty, bind('?', '')
519 520
  end

521 522 523 524 525
  def test_bind_chars
    quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
    quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
    assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
    assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
526 527
    assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
    assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
528 529
  end

530 531 532 533 534 535 536 537
  def test_bind_record
    o = Struct.new(:quoted_id).new(1)
    assert_equal '1', bind('?', o)

    os = [o] * 3
    assert_equal '1,1,1', bind('?', os)
  end

538 539 540 541 542 543
  def test_named_bind_with_postgresql_type_casts
    l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
    assert_nothing_raised(&l)
    assert_equal "#{ActiveRecord::Base.quote_value('10')}::integer '2009-01-01'::date", l.call
  end

D
David Heinemeier Hansson 已提交
544
  def test_string_sanitation
545 546
    assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
    assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
D
David Heinemeier Hansson 已提交
547 548 549 550 551 552 553 554 555
  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
556
    assert_equal topics(:first), Topic.find_by_title("The First Topic")
D
David Heinemeier Hansson 已提交
557 558
    assert_nil Topic.find_by_title("The First Topic!")
  end
J
Jeremy Kemper 已提交
559

560 561
  def test_find_by_one_attribute_bang
    assert_equal topics(:first), Topic.find_by_title!("The First Topic")
562
    assert_raise(ActiveRecord::RecordNotFound) { Topic.find_by_title!("The First Topic!") }
563 564
  end

565
  def test_find_by_one_attribute_with_order_option
566
    assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id')
567 568 569 570
    assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC')
  end

  def test_find_by_one_attribute_with_conditions
J
Jon Leighton 已提交
571
    assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50)
572 573
  end

574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
  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

608 609
  def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
    # ensure this test can run independently of order
610
    class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
J
Jon Leighton 已提交
611 612
    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
613 614
  end

615
  def test_find_by_one_attribute_with_several_options
J
Jon Leighton 已提交
616
    assert_equal accounts(:unknown), Account.order('id DESC').where('id != ?', 3).find_by_credit_limit(50)
617
  end
618

D
David Heinemeier Hansson 已提交
619
  def test_find_by_one_missing_attribute
620
    assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
D
David Heinemeier Hansson 已提交
621
  end
622

623
  def test_find_by_invalid_method_syntax
624 625 626 627
    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") }
628
  end
D
David Heinemeier Hansson 已提交
629 630

  def test_find_by_two_attributes
631
    assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
D
David Heinemeier Hansson 已提交
632 633 634
    assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
  end

635 636 637 638
  def test_find_by_two_attributes_but_passing_only_one
    assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") }
  end

639 640 641 642 643 644
  def test_find_last_by_one_attribute
    assert_equal Topic.last, Topic.find_last_by_title(Topic.last.title)
    assert_nil Topic.find_last_by_title("A title with no matches")
  end

  def test_find_last_by_invalid_method_syntax
645 646
    assert_raise(NoMethodError) { Topic.fail_to_find_last_by_title("The First Topic") }
    assert_raise(NoMethodError) { Topic.find_last_by_title?("The First Topic") }
647 648 649
  end

  def test_find_last_by_one_attribute_with_several_options
J
Jon Leighton 已提交
650
    assert_equal accounts(:signals37), Account.order('id DESC').where('id != ?', 3).find_last_by_credit_limit(50)
651 652 653
  end

  def test_find_last_by_one_missing_attribute
654
    assert_raise(NoMethodError) { Topic.find_last_by_undertitle("The Last Topic!") }
655 656 657 658 659 660 661 662
  end

  def test_find_last_by_two_attributes
    topic = Topic.last
    assert_equal topic, Topic.find_last_by_title_and_author_name(topic.title, topic.author_name)
    assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous")
  end

N
Nick Howard 已提交
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
  def test_find_last_with_limit_gives_same_result_when_loaded_and_unloaded
    scope = Topic.limit(2)
    unloaded_last = scope.last
    loaded_last = scope.all.last
    assert_equal loaded_last, unloaded_last
  end

  def test_find_last_with_limit_and_offset_gives_same_result_when_loaded_and_unloaded
    scope = Topic.offset(2).limit(2)
    unloaded_last = scope.last
    loaded_last = scope.all.last
    assert_equal loaded_last, unloaded_last
  end

  def test_find_last_with_offset_gives_same_result_when_loaded_and_unloaded
    scope = Topic.offset(3)
    unloaded_last = scope.last
    loaded_last = scope.all.last
    assert_equal loaded_last, unloaded_last
  end

D
David Heinemeier Hansson 已提交
684 685 686
  def test_find_all_by_one_attribute
    topics = Topic.find_all_by_content("Have a nice day")
    assert_equal 2, topics.size
687
    assert topics.include?(topics(:first))
D
David Heinemeier Hansson 已提交
688 689 690

    assert_equal [], Topic.find_all_by_title("The First Topic!!")
  end
691

692 693 694 695 696 697 698 699
  def test_find_all_by_one_attribute_which_is_a_symbol
    topics = Topic.find_all_by_content("Have a nice day".to_sym)
    assert_equal 2, topics.size
    assert topics.include?(topics(:first))

    assert_equal [], Topic.find_all_by_title("The First Topic!!")
  end

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
  def test_find_all_by_one_attribute_that_is_an_aggregate
    balance = customers(:david).balance
    assert_kind_of Money, balance
    found_customers = Customer.find_all_by_balance(balance)
    assert_equal 1, found_customers.size
    assert_equal customers(:david), found_customers.first
  end

  def test_find_all_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_customers = Customer.find_all_by_balance_and_address(balance, address)
    assert_equal 1, found_customers.size
    assert_equal customers(:david), found_customers.first
  end

  def test_find_all_by_two_attributes_with_one_being_an_aggregate
    balance = customers(:david).balance
    assert_kind_of Money, balance
    found_customers = Customer.find_all_by_balance_and_name(balance, customers(:david).name)
    assert_equal 1, found_customers.size
    assert_equal customers(:david), found_customers.first
  end

726 727
  def test_find_all_by_one_attribute_with_options
    topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC")
728
    assert_equal topics(:first), topics.last
729 730

    topics = Topic.find_all_by_content("Have a nice day", :order => "id")
731
    assert_equal topics(:first), topics.first
732
  end
D
David Heinemeier Hansson 已提交
733

734
  def test_find_all_by_array_attribute
735
    assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic of the day"]).size
736 737
  end

D
David Heinemeier Hansson 已提交
738 739 740
  def test_find_all_by_boolean_attribute
    topics = Topic.find_all_by_approved(false)
    assert_equal 1, topics.size
741
    assert topics.include?(topics(:first))
D
David Heinemeier Hansson 已提交
742 743

    topics = Topic.find_all_by_approved(true)
744
    assert_equal 3, topics.size
745
    assert topics.include?(topics(:second))
D
David Heinemeier Hansson 已提交
746
  end
747

D
David Heinemeier Hansson 已提交
748 749 750 751 752
  def test_find_by_nil_attribute
    topic = Topic.find_by_last_read nil
    assert_not_nil topic
    assert_nil topic.last_read
  end
753

D
David Heinemeier Hansson 已提交
754 755
  def test_find_all_by_nil_attribute
    topics = Topic.find_all_by_last_read nil
756 757
    assert_equal 3, topics.size
    assert topics.collect(&:last_read).all?(&:nil?)
D
David Heinemeier Hansson 已提交
758
  end
759

D
David Heinemeier Hansson 已提交
760 761 762 763 764 765 766 767 768 769 770
  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_all_by_nil_and_not_nil_attributes
    topics = Topic.find_all_by_last_read_and_author_name nil, "Mary"
    assert_equal 1, topics.size
    assert_equal "Mary", topics[0].author_name
  end

771 772 773 774 775
  def test_find_or_create_from_one_attribute
    number_of_companies = Company.count
    sig38 = Company.find_or_create_by_name("38signals")
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name("38signals")
776
    assert sig38.persisted?
777 778 779
  end

  def test_find_or_create_from_two_attributes
780 781 782 783
    number_of_topics = Topic.count
    another = Topic.find_or_create_by_title_and_author_name("Another topic","John")
    assert_equal number_of_topics + 1, Topic.count
    assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John")
784
    assert another.persisted?
785
  end
786

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
  def test_find_or_create_from_one_attribute_bang
    number_of_companies = Company.count
    assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name!("") }
    assert_equal number_of_companies, Company.count
    sig38 = Company.find_or_create_by_name!("38signals")
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name!("38signals")
    assert sig38.persisted?
  end

  def test_find_or_create_from_two_attributes_bang
    number_of_companies = Company.count
    assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name_and_firm_id!("", 17) }
    assert_equal number_of_companies, Company.count
    sig38 = Company.find_or_create_by_name_and_firm_id!("38signals", 17)
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name_and_firm_id!("38signals", 17)
    assert sig38.persisted?
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
  end

809 810 811 812 813
  def test_find_or_create_from_two_attributes_with_one_being_an_aggregate
    number_of_customers = Customer.count
    created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth")
    assert_equal number_of_customers + 1, Customer.count
    assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth")
814
    assert created_customer.persisted?
815 816
  end

817 818 819 820 821
  def test_find_or_create_from_one_attribute_and_hash
    number_of_companies = Company.count
    sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
822
    assert sig38.persisted?
823 824 825 826 827
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
    assert_equal 23, sig38.client_of
  end

P
Paul McMahon 已提交
828 829 830 831 832 833 834 835 836 837 838
  def test_find_or_create_from_two_attributes_and_hash
    number_of_companies = Company.count
    sig38 = Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert_equal number_of_companies + 1, Company.count
    assert_equal sig38, Company.find_or_create_by_name_and_firm_id({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert sig38.persisted?
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
    assert_equal 23, sig38.client_of
  end

839 840 841 842 843
  def test_find_or_create_from_one_aggregate_attribute
    number_of_customers = Customer.count
    created_customer = Customer.find_or_create_by_balance(Money.new(123))
    assert_equal number_of_customers + 1, Customer.count
    assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123))
844
    assert created_customer.persisted?
845 846 847 848 849 850 851 852 853
  end

  def test_find_or_create_from_one_aggregate_attribute_and_hash
    number_of_customers = Customer.count
    balance = Money.new(123)
    name = "Elizabeth"
    created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name})
    assert_equal number_of_customers + 1, Customer.count
    assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name})
854
    assert created_customer.persisted?
855 856 857 858
    assert_equal balance, created_customer.balance
    assert_equal name, created_customer.name
  end

859 860 861
  def test_find_or_initialize_from_one_attribute
    sig38 = Company.find_or_initialize_by_name("38signals")
    assert_equal "38signals", sig38.name
862
    assert !sig38.persisted?
863
  end
J
Jeremy Kemper 已提交
864

865 866 867
  def test_find_or_initialize_from_one_aggregate_attribute
    new_customer = Customer.find_or_initialize_by_balance(Money.new(123))
    assert_equal 123, new_customer.balance.amount
868
    assert !new_customer.persisted?
869 870
  end

871 872 873 874 875
  def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected
    c = Company.find_or_initialize_by_name({:name => "Fortune 1000", :rating => 1000})
    assert_equal "Fortune 1000", c.name
    assert_not_equal 1000, c.rating
    assert c.valid?
876
    assert !c.persisted?
877 878
  end

879
  def test_find_or_create_from_one_attribute_should_not_set_attribute_even_when_protected
880 881 882 883
    c = Company.find_or_create_by_name({:name => "Fortune 1000", :rating => 1000})
    assert_equal "Fortune 1000", c.name
    assert_not_equal 1000, c.rating
    assert c.valid?
884
    assert c.persisted?
885 886
  end

887 888 889 890 891
  def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected
    c = Company.find_or_initialize_by_name_and_rating("Fortune 1000", 1000)
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
892
    assert !c.persisted?
893 894 895 896 897 898 899
  end

  def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected
    c = Company.find_or_create_by_name_and_rating("Fortune 1000", 1000)
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
900
    assert c.persisted?
901
  end
902

903 904 905 906 907
  def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash
    c = Company.find_or_initialize_by_rating(1000, {:name => "Fortune 1000"})
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
908
    assert !c.persisted?
909 910 911 912 913 914 915
  end

  def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected_and_also_set_the_hash
    c = Company.find_or_create_by_rating(1000, {:name => "Fortune 1000"})
    assert_equal "Fortune 1000", c.name
    assert_equal 1000, c.rating
    assert c.valid?
916
    assert c.persisted?
917 918
  end

919 920 921 922 923
  def test_find_or_initialize_should_set_protected_attributes_if_given_as_block
    c = Company.find_or_initialize_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
    assert_equal "Fortune 1000", c.name
    assert_equal 1000.to_f, c.rating.to_f
    assert c.valid?
924
    assert !c.persisted?
925 926 927 928 929 930 931
  end

  def test_find_or_create_should_set_protected_attributes_if_given_as_block
    c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
    assert_equal "Fortune 1000", c.name
    assert_equal 1000.to_f, c.rating.to_f
    assert c.valid?
932
    assert c.persisted?
933
  end
934

935 936 937 938 939 940 941 942
  def test_find_or_create_should_work_with_block_on_first_call
	  class << Company
		undef_method(:find_or_create_by_name) if method_defined?(:find_or_create_by_name)
	  end
    c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
    assert_equal "Fortune 1000", c.name
    assert_equal 1000.to_f, c.rating.to_f
    assert c.valid?
943
    assert c.persisted?
944 945
  end

946 947 948 949
  def test_find_or_initialize_from_two_attributes
    another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
    assert_equal "Another topic", another.title
    assert_equal "John", another.author_name
950
    assert !another.persisted?
951
  end
952

953 954 955 956
  def test_find_or_initialize_from_two_attributes_but_passing_only_one
    assert_raise(ArgumentError) { Topic.find_or_initialize_by_title_and_author_name("Another topic") }
  end

957 958 959 960
  def test_find_or_initialize_from_one_aggregate_attribute_and_one_not
    new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth")
    assert_equal 123, new_customer.balance.amount
    assert_equal "Elizabeth", new_customer.name
961
    assert !new_customer.persisted?
962 963
  end

964 965 966 967 968
  def test_find_or_initialize_from_one_attribute_and_hash
    sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
    assert_equal "38signals", sig38.name
    assert_equal 17, sig38.firm_id
    assert_equal 23, sig38.client_of
969
    assert !sig38.persisted?
970
  end
971

972 973 974 975 976 977
  def test_find_or_initialize_from_one_aggregate_attribute_and_hash
    balance = Money.new(123)
    name = "Elizabeth"
    new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name})
    assert_equal balance, new_customer.balance
    assert_equal name, new_customer.name
978
    assert !new_customer.persisted?
979 980
  end

D
David Heinemeier Hansson 已提交
981
  def test_find_with_bad_sql
982
    assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
D
David Heinemeier Hansson 已提交
983 984
  end

985
  def test_dynamic_finder_with_invalid_params
986
    assert_raise(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
987 988
  end

989
  def test_find_all_with_join
J
Jon Leighton 已提交
990
    developers_on_project_one = Developer.scoped(
991
      :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
J
Jon Leighton 已提交
992 993
      :where => 'project_id=1'
    ).all
994
    assert_equal 3, developers_on_project_one.length
995 996 997
    developer_names = developers_on_project_one.map { |d| d.name }
    assert developer_names.include?('David')
    assert developer_names.include?('Jamis')
998
  end
999

1000
  def test_joins_dont_clobber_id
J
Jon Leighton 已提交
1001
    first = Firm.scoped(
1002
      :joins => 'INNER JOIN companies clients ON clients.firm_id = companies.id',
J
Jon Leighton 已提交
1003 1004
      :where => 'companies.id = 1'
    ).first
1005 1006 1007
    assert_equal 1, first.id
  end

1008
  def test_joins_with_string_array
J
Jon Leighton 已提交
1009
    person_with_reader_and_post = Post.scoped(
1010 1011 1012 1013 1014 1015 1016 1017
      :joins => [
        "INNER JOIN categorizations ON categorizations.post_id = posts.id",
        "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
      ]
    )
    assert_equal 1, person_with_reader_and_post.size
  end

1018 1019
  def test_find_by_id_with_conditions_with_or
    assert_nothing_raised do
J
Jon Leighton 已提交
1020
      Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1,2,3])
1021 1022
    end
  end
1023

1024 1025
  # http://dev.rubyonrails.org/ticket/6778
  def test_find_ignores_previously_inserted_record
A
Aaron Patterson 已提交
1026
    Post.create!(:title => 'test', :body => 'it out')
1027 1028 1029
    assert_equal [], Post.find_all_by_id(nil)
  end

1030 1031 1032 1033 1034
  def test_find_by_empty_ids
    assert_equal [], Post.find([])
  end

  def test_find_by_empty_in_condition
1035
    assert_equal [], Post.where('id in (?)', [])
1036 1037 1038
  end

  def test_find_by_records
1039
    p1, p2 = Post.scoped(:limit => 2, :order => 'id asc').all
J
Jon Leighton 已提交
1040 1041
    assert_equal [p1, p2], Post.scoped(:where => ['id in (?)', [p1, p2]], :order => 'id asc')
    assert_equal [p1, p2], Post.scoped(:where => ['id in (?)', [p1, p2.id]], :order => 'id asc')
1042 1043
  end

1044 1045 1046 1047 1048 1049 1050 1051 1052
  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
1053 1054
    assert_equal ["1","2","3","4","5","6","7","8","9", "10"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map! { |i| i.to_s }
    assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
1055 1056
  end

1057 1058
  def test_select_rows
    assert_equal(
1059
      [["1", "1", nil, "37signals"],
1060 1061
       ["2", "1", "2", "Summit"],
       ["3", "1", "1", "Microsoft"]],
1062
      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?}})
1063
    assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
1064
      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?}}
1065 1066
  end

1067
  def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
J
Jon Leighton 已提交
1068
    assert_equal 2, Post.scoped(:includes => { :authors => :author_address }, :order => 'author_addresses.id DESC ', :limit => 2).all.size
1069

J
Jon Leighton 已提交
1070
    assert_equal 3, Post.scoped(:includes => { :author => :author_address, :authors => :author_address},
1071
                              :order => 'author_addresses_authors.id DESC ', :limit => 3).all.size
1072 1073
  end

1074
  def test_find_with_nil_inside_set_passed_for_one_attribute
J
Jon Leighton 已提交
1075 1076
    client_of = Company.scoped(
      :where => {
1077 1078 1079 1080 1081
        :client_of => [2, 1, nil],
        :name => ['37signals', 'Summit', 'Microsoft'] },
      :order => 'client_of DESC'
    ).map { |x| x.client_of }

1082 1083
    assert client_of.include?(nil)
    assert_equal [2, 1].sort, client_of.compact.sort
1084 1085 1086
  end

  def test_find_with_nil_inside_set_passed_for_attribute
J
Jon Leighton 已提交
1087 1088
    client_of = Company.scoped(
      :where => { :client_of => [nil] },
1089 1090 1091
      :order => 'client_of DESC'
    ).map { |x| x.client_of }

1092
    assert_equal [], client_of.compact
1093 1094
  end

1095
  def test_with_limiting_with_custom_select
J
Jon Leighton 已提交
1096 1097
    posts = Post.references(:authors).scoped(
      :includes => :author, :select => ' posts.*, authors.id as "author_id"',
J
Jon Leighton 已提交
1098
      :limit => 3, :order => 'posts.id'
J
Jon Leighton 已提交
1099
    ).all
1100 1101
    assert_equal 3, posts.size
    assert_equal [0, 1, 1], posts.map(&:author_id).sort
1102
  end
1103

1104
  def test_find_one_message_with_custom_primary_key
1105
    Toy.primary_key = :name
1106 1107 1108 1109 1110 1111 1112
    begin
      Toy.find 'Hello World!'
    rescue ActiveRecord::RecordNotFound => e
      assert_equal 'Couldn\'t find Toy with name=Hello World!', e.message
    end
  end

1113
  def test_finder_with_offset_string
1114
    assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.scoped(:offset => "3").all }
1115 1116
  end

D
David Heinemeier Hansson 已提交
1117 1118 1119 1120 1121 1122 1123 1124
  protected
    def bind(statement, *vars)
      if vars.first.is_a?(Hash)
        ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
      else
        ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
      end
    end
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138

    def with_env_tz(new_tz = 'US/Eastern')
      old_tz, ENV['TZ'] = ENV['TZ'], new_tz
      yield
    ensure
      old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
    end

    def with_active_record_default_timezone(zone)
      old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone
      yield
    ensure
      ActiveRecord::Base.default_timezone = old_zone
    end
D
David Heinemeier Hansson 已提交
1139
end