ibm_db 0.9.5 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGES +5 -0
  2. data/README +63 -97
  3. data/ext/ibm_db.c +20 -4
  4. data/ext/ruby_ibm_db.h +10 -0
  5. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2 -4
  6. data/test/{adapter_test.rb → cases/adapter_test.rb} +39 -14
  7. data/test/cases/associations/cascaded_eager_loading_test.rb +113 -0
  8. data/test/{associations → cases/associations}/eager_test.rb +231 -65
  9. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +686 -0
  10. data/test/cases/associations/join_model_test.rb +797 -0
  11. data/test/{base_test.rb → cases/base_test.rb} +605 -385
  12. data/test/cases/calculations_test.rb +275 -0
  13. data/test/cases/finder_test.rb +885 -0
  14. data/test/cases/fixtures_test.rb +630 -0
  15. data/test/{migration_test.rb → cases/migration_test.rb} +530 -146
  16. data/test/cases/query_cache_test.rb +127 -0
  17. data/test/cases/validations_test.rb +1509 -0
  18. data/test/connections/native_ibm_db/connection.rb +1 -1
  19. data/test/models/warehouse_thing.rb +5 -0
  20. data/test/schema/i5/ibm_db_specific_schema.rb +133 -0
  21. data/test/schema/ids/ibm_db_specific_schema.rb +136 -0
  22. data/test/schema/luw/ibm_db_specific_schema.rb +133 -0
  23. data/test/schema/schema.rb +432 -0
  24. data/test/schema/zOS/ibm_db_specific_schema.rb +204 -0
  25. metadata +29 -33
  26. data/test/associations_test.rb +0 -2151
  27. data/test/fixtures/db_definitions/i5/ibm_db.drop.sql +0 -33
  28. data/test/fixtures/db_definitions/i5/ibm_db.sql +0 -236
  29. data/test/fixtures/db_definitions/i5/ibm_db2.drop.sql +0 -2
  30. data/test/fixtures/db_definitions/i5/ibm_db2.sql +0 -5
  31. data/test/fixtures/db_definitions/ids/ibm_db.drop.sql +0 -33
  32. data/test/fixtures/db_definitions/ids/ibm_db.sql +0 -237
  33. data/test/fixtures/db_definitions/ids/ibm_db2.drop.sql +0 -2
  34. data/test/fixtures/db_definitions/ids/ibm_db2.sql +0 -5
  35. data/test/fixtures/db_definitions/luw/ibm_db.drop.sql +0 -33
  36. data/test/fixtures/db_definitions/luw/ibm_db.sql +0 -236
  37. data/test/fixtures/db_definitions/luw/ibm_db2.drop.sql +0 -2
  38. data/test/fixtures/db_definitions/luw/ibm_db2.sql +0 -5
  39. data/test/fixtures/db_definitions/schema.rb +0 -361
  40. data/test/fixtures/db_definitions/zOS/ibm_db.drop.sql +0 -33
  41. data/test/fixtures/db_definitions/zOS/ibm_db.sql +0 -288
  42. data/test/fixtures/db_definitions/zOS/ibm_db2.drop.sql +0 -2
  43. data/test/fixtures/db_definitions/zOS/ibm_db2.sql +0 -7
  44. data/test/locking_test.rb +0 -282
@@ -0,0 +1,275 @@
1
+ require "cases/helper"
2
+ require 'models/company'
3
+ require 'models/topic'
4
+
5
+ Company.has_many :accounts
6
+
7
+ class NumericData < ActiveRecord::Base
8
+ self.table_name = 'numeric_data'
9
+ end
10
+
11
+ class CalculationsTest < ActiveRecord::TestCase
12
+ fixtures :companies, :accounts, :topics
13
+
14
+ def test_should_sum_field
15
+ assert_equal 318, Account.sum(:credit_limit)
16
+ end
17
+
18
+ def test_should_average_field
19
+ value = Account.average(:credit_limit)
20
+ assert_kind_of Float, value
21
+ assert_in_delta 53.0, value, 0.001
22
+ end
23
+
24
+ def test_should_return_nil_as_average
25
+ assert_nil NumericData.average(:bank_balance)
26
+ end
27
+
28
+ def test_should_get_maximum_of_field
29
+ assert_equal 60, Account.maximum(:credit_limit)
30
+ end
31
+
32
+ def test_should_get_maximum_of_field_with_include
33
+ assert_equal 50, Account.maximum(:credit_limit, :include => :firm, :conditions => "companies.name != 'Summit'")
34
+ end
35
+
36
+ def test_should_get_maximum_of_field_with_scoped_include
37
+ Account.with_scope :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do
38
+ assert_equal 50, Account.maximum(:credit_limit)
39
+ end
40
+ end
41
+
42
+ def test_should_get_minimum_of_field
43
+ assert_equal 50, Account.minimum(:credit_limit)
44
+ end
45
+
46
+ def test_should_group_by_field
47
+ c = Account.sum(:credit_limit, :group => :firm_id)
48
+ [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
49
+ end
50
+
51
+ def test_should_group_by_summed_field
52
+ c = Account.sum(:credit_limit, :group => :firm_id)
53
+ assert_equal 50, c[1]
54
+ assert_equal 105, c[6]
55
+ assert_equal 60, c[2]
56
+ end
57
+
58
+ def test_should_order_by_grouped_field
59
+ c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
60
+ assert_equal [1, 2, 6, 9], c.keys.compact
61
+ end
62
+
63
+ def test_should_order_by_calculation
64
+ c = Account.sum(:credit_limit, :group => :firm_id, :order => "sum_credit_limit desc, firm_id")
65
+ assert_equal [105, 60, 53, 50, 50], c.keys.collect { |k| c[k] }
66
+ assert_equal [6, 2, 9, 1], c.keys.compact
67
+ end
68
+
69
+ def test_should_limit_calculation
70
+ c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
71
+ :group => :firm_id, :order => "firm_id", :limit => 2)
72
+ assert_equal [1, 2], c.keys.compact
73
+ end
74
+
75
+ def test_should_limit_calculation_with_offset
76
+ c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
77
+ :group => :firm_id, :order => "firm_id", :limit => 2, :offset => 1)
78
+ assert_equal [2, 6], c.keys.compact
79
+ end
80
+
81
+ def test_should_group_by_summed_field_having_condition
82
+ c = Account.sum(:credit_limit, :group => :firm_id,
83
+ :having => 'sum(credit_limit) > 50')
84
+ assert_nil c[1]
85
+ assert_equal 105, c[6]
86
+ assert_equal 60, c[2]
87
+ end
88
+
89
+ def test_should_group_by_summed_association
90
+ c = Account.sum(:credit_limit, :group => :firm)
91
+ assert_equal 50, c[companies(:first_firm)]
92
+ assert_equal 105, c[companies(:rails_core)]
93
+ assert_equal 60, c[companies(:first_client)]
94
+ end
95
+
96
+ def test_should_sum_field_with_conditions
97
+ assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
98
+ end
99
+
100
+ def test_should_return_zero_if_sum_conditions_return_nothing
101
+ assert_equal 0, Account.sum(:credit_limit, :conditions => '1 = 2')
102
+ end
103
+
104
+ def test_should_group_by_summed_field_with_conditions
105
+ c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
106
+ :group => :firm_id)
107
+ assert_nil c[1]
108
+ assert_equal 105, c[6]
109
+ assert_equal 60, c[2]
110
+ end
111
+
112
+ def test_should_group_by_summed_field_with_conditions_and_having
113
+ c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
114
+ :group => :firm_id,
115
+ :having => 'sum(credit_limit) > 60')
116
+ assert_nil c[1]
117
+ assert_equal 105, c[6]
118
+ assert_nil c[2]
119
+ end
120
+
121
+ def test_should_group_by_fields_with_table_alias
122
+ c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
123
+ assert_equal 50, c[1]
124
+ assert_equal 105, c[6]
125
+ assert_equal 60, c[2]
126
+ end
127
+
128
+ def test_should_calculate_with_invalid_field
129
+ assert_equal 6, Account.calculate(:count, '*')
130
+ assert_equal 6, Account.calculate(:count, :all)
131
+ end
132
+
133
+ def test_should_calculate_grouped_with_invalid_field
134
+ c = Account.count(:all, :group => 'accounts.firm_id')
135
+ assert_equal 1, c[1]
136
+ assert_equal 2, c[6]
137
+ assert_equal 1, c[2]
138
+ end
139
+
140
+ def test_should_calculate_grouped_association_with_invalid_field
141
+ c = Account.count(:all, :group => :firm)
142
+ assert_equal 1, c[companies(:first_firm)]
143
+ assert_equal 2, c[companies(:rails_core)]
144
+ assert_equal 1, c[companies(:first_client)]
145
+ end
146
+
147
+ uses_mocha 'group_by_non_numeric_foreign_key_association' do
148
+ def test_should_group_by_association_with_non_numeric_foreign_key
149
+ ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
150
+
151
+ firm = mock()
152
+ firm.expects(:id).returns("ABC")
153
+ firm.expects(:class).returns(Firm)
154
+ Company.expects(:find).with(["ABC"]).returns([firm])
155
+
156
+ column = mock()
157
+ column.expects(:name).at_least_once.returns(:firm_id)
158
+ column.expects(:type_cast).with("ABC").returns("ABC")
159
+ Account.expects(:columns).at_least_once.returns([column])
160
+
161
+ c = Account.count(:all, :group => :firm)
162
+ assert_equal Firm, c.first.first.class
163
+ assert_equal 1, c.first.last
164
+ end
165
+ end
166
+
167
+ def test_should_calculate_grouped_association_with_foreign_key_option
168
+ Account.belongs_to :another_firm, :class_name => 'Firm', :foreign_key => 'firm_id'
169
+ c = Account.count(:all, :group => :another_firm)
170
+ assert_equal 1, c[companies(:first_firm)]
171
+ assert_equal 2, c[companies(:rails_core)]
172
+ assert_equal 1, c[companies(:first_client)]
173
+ end
174
+
175
+ def test_should_not_modify_options_when_using_includes
176
+ options = {:conditions => 'companies.id > 1', :include => :firm}
177
+ options_copy = options.dup
178
+
179
+ Account.count(:all, options)
180
+ assert_equal options_copy, options
181
+ end
182
+
183
+ def test_should_calculate_grouped_by_function
184
+ c = Company.count(:all, :group => "UPPER(#{QUOTED_TYPE})")
185
+ assert_equal 2, c[nil]
186
+ assert_equal 1, c['DEPENDENTFIRM']
187
+ assert_equal 3, c['CLIENT']
188
+ assert_equal 2, c['FIRM']
189
+ end
190
+
191
+ def test_should_calculate_grouped_by_function_with_table_alias
192
+ c = Company.count(:all, :group => "UPPER(companies.#{QUOTED_TYPE})")
193
+ assert_equal 2, c[nil]
194
+ assert_equal 1, c['DEPENDENTFIRM']
195
+ assert_equal 3, c['CLIENT']
196
+ assert_equal 2, c['FIRM']
197
+ end
198
+
199
+ def test_should_not_overshadow_enumerable_sum
200
+ assert_equal 6, [1, 2, 3].sum(&:abs)
201
+ end
202
+
203
+ def test_should_sum_scoped_field
204
+ assert_equal 15, companies(:rails_core).companies.sum(:id)
205
+ end
206
+
207
+ def test_should_sum_scoped_field_with_conditions
208
+ assert_equal 8, companies(:rails_core).companies.sum(:id, :conditions => 'id > 7')
209
+ end
210
+
211
+ def test_should_group_by_scoped_field
212
+ c = companies(:rails_core).companies.sum(:id, :group => :name)
213
+ assert_equal 7, c['Leetsoft']
214
+ assert_equal 8, c['Jadedpixel']
215
+ end
216
+
217
+ def test_should_group_by_summed_field_with_conditions_and_having
218
+ c = companies(:rails_core).companies.sum(:id, :group => :name,
219
+ :having => 'sum(id) > 7')
220
+ assert_nil c['Leetsoft']
221
+ assert_equal 8, c['Jadedpixel']
222
+ end
223
+
224
+ def test_should_reject_invalid_options
225
+ assert_nothing_raised do
226
+ [:count, :sum].each do |func|
227
+ # empty options are valid
228
+ Company.send(:validate_calculation_options, func)
229
+ # these options are valid for all calculations
230
+ [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
231
+ Company.send(:validate_calculation_options, func, opt => true)
232
+ end
233
+ end
234
+
235
+ # :include is only valid on :count
236
+ Company.send(:validate_calculation_options, :count, :include => true)
237
+ end
238
+
239
+ assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) }
240
+ assert_raises(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
241
+ end
242
+
243
+ def test_should_count_selected_field_with_include
244
+ assert_equal 6, Account.count(:distinct => true, :include => :firm)
245
+ assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
246
+ end
247
+
248
+ def test_should_count_manual_select_with_include
249
+ assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm)
250
+ end
251
+
252
+ def test_count_with_column_parameter
253
+ assert_equal 5, Account.count(:firm_id)
254
+ end
255
+
256
+ def test_count_with_column_and_options_parameter
257
+ assert_equal 2, Account.count(:firm_id, :conditions => "credit_limit = 50")
258
+ end
259
+
260
+ def test_count_with_no_parameters_isnt_deprecated
261
+ assert_not_deprecated { Account.count }
262
+ end
263
+
264
+ def test_count_with_too_many_parameters_raises
265
+ assert_raise(ArgumentError) { Account.count(1, 2, 3) }
266
+ end
267
+
268
+ def test_should_sum_expression
269
+ if current_adapter?(:IBM_DBAdapter) && !ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
270
+ assert_equal 636, Account.sum("2 * credit_limit")
271
+ else
272
+ assert_equal "636", Account.sum("2 * credit_limit")
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,885 @@
1
+ require "cases/helper"
2
+ require 'models/author'
3
+ require 'models/comment'
4
+ require 'models/company'
5
+ require 'models/topic'
6
+ require 'models/reply'
7
+ require 'models/entrant'
8
+ require 'models/developer'
9
+ require 'models/post'
10
+ require 'models/customer'
11
+ require 'models/job'
12
+ require 'models/categorization'
13
+
14
+ class FinderTest < ActiveRecord::TestCase
15
+ fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers
16
+
17
+ def test_find
18
+ assert_equal(topics(:first).title, Topic.find(1).title)
19
+ end
20
+
21
+ # find should handle strings that come from URLs
22
+ # (example: Category.find(params[:id]))
23
+ def test_find_with_string
24
+ assert_equal(Topic.find(1).title,Topic.find("1").title)
25
+ end
26
+
27
+ def test_exists
28
+ assert Topic.exists?(1)
29
+ assert Topic.exists?("1")
30
+ assert Topic.exists?(:author_name => "David")
31
+ assert Topic.exists?(:author_name => "Mary", :approved => true)
32
+ assert Topic.exists?(["parent_id = ?", 1])
33
+ assert !Topic.exists?(45)
34
+
35
+ begin
36
+ assert !Topic.exists?("foo")
37
+ rescue ActiveRecord::StatementInvalid
38
+ # PostgreSQL complains about string comparison with integer field
39
+ rescue Exception
40
+ flunk
41
+ end
42
+
43
+ assert_raise(NoMethodError) { Topic.exists?([1,2]) }
44
+ end
45
+
46
+ def test_exists_with_aggregate_having_three_mappings
47
+ existing_address = customers(:david).address
48
+ assert Customer.exists?(:address => existing_address)
49
+ end
50
+
51
+ def test_exists_with_aggregate_having_three_mappings_with_one_difference
52
+ existing_address = customers(:david).address
53
+ assert !Customer.exists?(:address =>
54
+ Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
55
+ assert !Customer.exists?(:address =>
56
+ Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
57
+ assert !Customer.exists?(:address =>
58
+ Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
59
+ end
60
+
61
+ def test_find_by_array_of_one_id
62
+ assert_kind_of(Array, Topic.find([ 1 ]))
63
+ assert_equal(1, Topic.find([ 1 ]).length)
64
+ end
65
+
66
+ def test_find_by_ids
67
+ assert_equal 2, Topic.find(1, 2).size
68
+ assert_equal topics(:second).title, Topic.find([2]).first.title
69
+ end
70
+
71
+ def test_find_by_ids_with_limit_and_offset
72
+ assert_equal 2, Entrant.find([1,3,2], :limit => 2).size
73
+ assert_equal 1, Entrant.find([1,3,2], :limit => 3, :offset => 2).size
74
+
75
+ # Also test an edge case: If you have 11 results, and you set a
76
+ # limit of 3 and offset of 9, then you should find that there
77
+ # will be only 2 results, regardless of the limit.
78
+ devs = Developer.find :all
79
+ last_devs = Developer.find devs.map(&:id), :limit => 3, :offset => 9
80
+ assert_equal 2, last_devs.size
81
+ end
82
+
83
+ def test_find_an_empty_array
84
+ assert_equal [], Topic.find([])
85
+ end
86
+
87
+ def test_find_by_ids_missing_one
88
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
89
+ end
90
+
91
+ def test_find_all_with_limit
92
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2)
93
+
94
+ assert_equal(2, entrants.size)
95
+ assert_equal(entrants(:first).name, entrants.first.name)
96
+ end
97
+
98
+ def test_find_all_with_prepared_limit_and_offset
99
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 1)
100
+
101
+ assert_equal(2, entrants.size)
102
+ assert_equal(entrants(:second).name, entrants.first.name)
103
+
104
+ entrants = Entrant.find(:all, :order => "id ASC", :limit => 2, :offset => 2)
105
+ assert_equal(1, entrants.size)
106
+ assert_equal(entrants(:third).name, entrants.first.name)
107
+ end
108
+
109
+ def test_find_all_with_limit_and_offset_and_multiple_orderings
110
+ developers = Developer.find(:all, :order => "salary ASC, id DESC", :limit => 3, :offset => 1)
111
+ assert_equal ["David", "fixture_10", "fixture_9"], developers.collect {|d| d.name}
112
+ end
113
+
114
+ def test_find_with_limit_and_condition
115
+ developers = Developer.find(:all, :order => "id DESC", :conditions => "salary = 100000", :limit => 3, :offset =>7)
116
+ assert_equal(1, developers.size)
117
+ assert_equal("fixture_3", developers.first.name)
118
+ end
119
+
120
+ def test_find_with_entire_select_statement
121
+ topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
122
+
123
+ assert_equal(1, topics.size)
124
+ assert_equal(topics(:second).title, topics.first.title)
125
+ end
126
+
127
+ def test_find_with_prepared_select_statement
128
+ topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
129
+
130
+ assert_equal(1, topics.size)
131
+ assert_equal(topics(:second).title, topics.first.title)
132
+ end
133
+
134
+ def test_find_by_sql_with_sti_on_joined_table
135
+ accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
136
+ assert_equal [Account], accounts.collect(&:class).uniq
137
+ end
138
+
139
+ def test_find_first
140
+ first = Topic.find(:first, :conditions => "title = 'The First Topic'")
141
+ assert_equal(topics(:first).title, first.title)
142
+ end
143
+
144
+ def test_find_first_failing
145
+ first = Topic.find(:first, :conditions => "title = 'The First Topic!'")
146
+ assert_nil(first)
147
+ end
148
+
149
+ def test_first
150
+ assert_equal topics(:second).title, Topic.first(:conditions => "title = 'The Second Topic of the day'").title
151
+ end
152
+
153
+ def test_first_failing
154
+ assert_nil Topic.first(:conditions => "title = 'The Second Topic of the day!'")
155
+ end
156
+
157
+ def test_unexisting_record_exception_handling
158
+ assert_raises(ActiveRecord::RecordNotFound) {
159
+ Topic.find(1).parent
160
+ }
161
+
162
+ Topic.find(2).topic
163
+ end
164
+
165
+ def test_find_only_some_columns
166
+ topic = Topic.find(1, :select => "author_name")
167
+ assert_raises(ActiveRecord::MissingAttributeError) {topic.title}
168
+ assert_equal "David", topic.author_name
169
+ assert !topic.attribute_present?("title")
170
+ #assert !topic.respond_to?("title")
171
+ assert topic.attribute_present?("author_name")
172
+ assert topic.respond_to?("author_name")
173
+ end
174
+
175
+ def test_find_on_blank_conditions
176
+ [nil, " ", [], {}].each do |blank|
177
+ assert_nothing_raised { Topic.find(:first, :conditions => blank) }
178
+ end
179
+ end
180
+
181
+ def test_find_on_blank_bind_conditions
182
+ [ [""], ["",{}] ].each do |blank|
183
+ assert_nothing_raised { Topic.find(:first, :conditions => blank) }
184
+ end
185
+ end
186
+
187
+ def test_find_on_array_conditions
188
+ assert Topic.find(1, :conditions => ["approved = ?", false])
189
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) }
190
+ end
191
+
192
+ def test_find_on_hash_conditions
193
+ assert Topic.find(1, :conditions => { :approved => false })
194
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) }
195
+ end
196
+
197
+ def test_find_on_hash_conditions_with_explicit_table_name
198
+ assert Topic.find(1, :conditions => { 'topics.approved' => false })
199
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
200
+ end
201
+
202
+ def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
203
+ david = customers(:david)
204
+ assert Customer.find(david.id, :conditions => { 'customers.name' => david.name, :address => david.address })
205
+ assert_raises(ActiveRecord::RecordNotFound) {
206
+ Customer.find(david.id, :conditions => { 'customers.name' => david.name + "1", :address => david.address })
207
+ }
208
+ end
209
+
210
+ def test_find_on_association_proxy_conditions
211
+ assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10], Comment.find_all_by_post_id(authors(:david).posts).map(&:id).sort
212
+ end
213
+
214
+ def test_find_on_hash_conditions_with_range
215
+ assert_equal [1,2], Topic.find(:all, :conditions => { :id => 1..2 }).map(&:id).sort
216
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :id => 2..3 }) }
217
+ end
218
+
219
+ def test_find_on_hash_conditions_with_multiple_ranges
220
+ assert_equal [1,2,3], Comment.find(:all, :conditions => { :id => 1..3, :post_id => 1..2 }).map(&:id).sort
221
+ assert_equal [1], Comment.find(:all, :conditions => { :id => 1..1, :post_id => 1..10 }).map(&:id).sort
222
+ end
223
+
224
+ def test_find_on_multiple_hash_conditions
225
+ assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false })
226
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
227
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) }
228
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) }
229
+ end
230
+
231
+
232
+ def test_condition_interpolation
233
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
234
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
235
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
236
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
237
+ end
238
+
239
+ def test_condition_array_interpolation
240
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"])
241
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"])
242
+ assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"])
243
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on
244
+ end
245
+
246
+ def test_condition_hash_interpolation
247
+ assert_kind_of Firm, Company.find(:first, :conditions => { :name => "37signals"})
248
+ assert_nil Company.find(:first, :conditions => { :name => "37signals!"})
249
+ assert_kind_of Time, Topic.find(:first, :conditions => {:id => 1}).written_on
250
+ end
251
+
252
+ def test_hash_condition_find_malformed
253
+ assert_raises(ActiveRecord::StatementInvalid) {
254
+ Company.find(:first, :conditions => { :id => 2, :dhh => true })
255
+ }
256
+ end
257
+
258
+ def test_hash_condition_find_with_escaped_characters
259
+ Company.create("name" => "Ain't noth'n like' \#stuff")
260
+ assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
261
+ end
262
+
263
+ def test_hash_condition_find_with_array
264
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
265
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
266
+ assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
267
+ end
268
+
269
+ def test_hash_condition_find_with_nil
270
+ topic = Topic.find(:first, :conditions => { :last_read => nil } )
271
+ assert_not_nil topic
272
+ assert_nil topic.last_read
273
+ end
274
+
275
+ def test_hash_condition_find_with_aggregate_having_one_mapping
276
+ balance = customers(:david).balance
277
+ assert_kind_of Money, balance
278
+ found_customer = Customer.find(:first, :conditions => {:balance => balance})
279
+ assert_equal customers(:david), found_customer
280
+ end
281
+
282
+ def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
283
+ gps_location = customers(:david).gps_location
284
+ assert_kind_of GpsLocation, gps_location
285
+ found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location})
286
+ assert_equal customers(:david), found_customer
287
+ end
288
+
289
+ def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
290
+ balance = customers(:david).balance
291
+ assert_kind_of Money, balance
292
+ found_customer = Customer.find(:first, :conditions => {:balance => balance.amount})
293
+ assert_equal customers(:david), found_customer
294
+ end
295
+
296
+ def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
297
+ gps_location = customers(:david).gps_location
298
+ assert_kind_of GpsLocation, gps_location
299
+ found_customer = Customer.find(:first, :conditions => {:gps_location => gps_location.gps_location})
300
+ assert_equal customers(:david), found_customer
301
+ end
302
+
303
+ def test_hash_condition_find_with_aggregate_having_three_mappings
304
+ address = customers(:david).address
305
+ assert_kind_of Address, address
306
+ found_customer = Customer.find(:first, :conditions => {:address => address})
307
+ assert_equal customers(:david), found_customer
308
+ end
309
+
310
+ def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
311
+ address = customers(:david).address
312
+ assert_kind_of Address, address
313
+ found_customer = Customer.find(:first, :conditions => {:address => address, :name => customers(:david).name})
314
+ assert_equal customers(:david), found_customer
315
+ end
316
+
317
+ def test_bind_variables
318
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = ?", "37signals"])
319
+ assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!"])
320
+ assert_nil Company.find(:first, :conditions => ["name = ?", "37signals!' OR 1=1"])
321
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = ?", 1]).written_on
322
+ assert_raises(ActiveRecord::PreparedStatementInvalid) {
323
+ Company.find(:first, :conditions => ["id=? AND name = ?", 2])
324
+ }
325
+ assert_raises(ActiveRecord::PreparedStatementInvalid) {
326
+ Company.find(:first, :conditions => ["id=?", 2, 3, 4])
327
+ }
328
+ end
329
+
330
+ def test_bind_variables_with_quotes
331
+ Company.create("name" => "37signals' go'es agains")
332
+ assert Company.find(:first, :conditions => ["name = ?", "37signals' go'es agains"])
333
+ end
334
+
335
+ def test_named_bind_variables_with_quotes
336
+ Company.create("name" => "37signals' go'es agains")
337
+ assert Company.find(:first, :conditions => ["name = :name", {:name => "37signals' go'es agains"}])
338
+ end
339
+
340
+ def test_bind_arity
341
+ assert_nothing_raised { bind '' }
342
+ assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
343
+
344
+ assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?' }
345
+ assert_nothing_raised { bind '?', 1 }
346
+ assert_raises(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 }
347
+ end
348
+
349
+ def test_named_bind_variables
350
+ assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
351
+ assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
352
+
353
+ assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
354
+
355
+ assert_kind_of Firm, Company.find(:first, :conditions => ["name = :name", { :name => "37signals" }])
356
+ assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!" }])
357
+ assert_nil Company.find(:first, :conditions => ["name = :name", { :name => "37signals!' OR 1=1" }])
358
+ assert_kind_of Time, Topic.find(:first, :conditions => ["id = :id", { :id => 1 }]).written_on
359
+ end
360
+
361
+ def test_bind_enumerable
362
+ quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})
363
+
364
+ assert_equal '1,2,3', bind('?', [1, 2, 3])
365
+ assert_equal quoted_abc, bind('?', %w(a b c))
366
+
367
+ assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
368
+ assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
369
+
370
+ require 'set'
371
+ assert_equal '1,2,3', bind('?', Set.new([1, 2, 3]))
372
+ assert_equal quoted_abc, bind('?', Set.new(%w(a b c)))
373
+
374
+ assert_equal '1,2,3', bind(':a', :a => Set.new([1, 2, 3]))
375
+ assert_equal quoted_abc, bind(':a', :a => Set.new(%w(a b c))) # '
376
+ end
377
+
378
+ def test_bind_empty_enumerable
379
+ quoted_nil = ActiveRecord::Base.connection.quote(nil)
380
+ assert_equal quoted_nil, bind('?', [])
381
+ assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
382
+ assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
383
+ end
384
+
385
+ def test_bind_string
386
+ assert_equal ActiveRecord::Base.connection.quote(''), bind('?', '')
387
+ end
388
+
389
+ def test_bind_record
390
+ o = Struct.new(:quoted_id).new(1)
391
+ assert_equal '1', bind('?', o)
392
+
393
+ os = [o] * 3
394
+ assert_equal '1,1,1', bind('?', os)
395
+ end
396
+
397
+ def test_string_sanitation
398
+ assert_not_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
399
+ assert_equal "#{ActiveRecord::Base.connection.quoted_string_prefix}'something; select table'", ActiveRecord::Base.sanitize("something; select table")
400
+ end
401
+
402
+ def test_count
403
+ assert_equal(0, Entrant.count(:conditions => "id > 3"))
404
+ assert_equal(1, Entrant.count(:conditions => ["id > ?", 2]))
405
+ assert_equal(2, Entrant.count(:conditions => ["id > ?", 1]))
406
+ end
407
+
408
+ def test_count_by_sql
409
+ assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
410
+ assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
411
+ assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
412
+ end
413
+
414
+ def test_find_by_one_attribute
415
+ assert_equal topics(:first), Topic.find_by_title("The First Topic")
416
+ assert_nil Topic.find_by_title("The First Topic!")
417
+ end
418
+
419
+ def test_find_by_one_attribute_caches_dynamic_finder
420
+ # ensure this test can run independently of order
421
+ class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
422
+ assert !Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
423
+ t = Topic.find_by_title("The First Topic")
424
+ assert Topic.public_methods.any? { |m| m.to_s == 'find_by_title' }
425
+ end
426
+
427
+ def test_dynamic_finder_returns_same_results_after_caching
428
+ # ensure this test can run independently of order
429
+ class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.public_method_defined?(:find_by_title)
430
+ t = Topic.find_by_title("The First Topic")
431
+ assert_equal t, Topic.find_by_title("The First Topic") # find_by_title has been cached
432
+ end
433
+
434
+ def test_find_by_one_attribute_with_order_option
435
+ assert_equal accounts(:signals37), Account.find_by_credit_limit(50, :order => 'id')
436
+ assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :order => 'id DESC')
437
+ end
438
+
439
+ def test_find_by_one_attribute_with_conditions
440
+ assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
441
+ end
442
+
443
+ def test_find_by_one_attribute_that_is_an_aggregate
444
+ address = customers(:david).address
445
+ assert_kind_of Address, address
446
+ found_customer = Customer.find_by_address(address)
447
+ assert_equal customers(:david), found_customer
448
+ end
449
+
450
+ def test_find_by_one_attribute_that_is_an_aggregate_with_one_attribute_difference
451
+ address = customers(:david).address
452
+ assert_kind_of Address, address
453
+ missing_address = Address.new(address.street, address.city, address.country + "1")
454
+ assert_nil Customer.find_by_address(missing_address)
455
+ missing_address = Address.new(address.street, address.city + "1", address.country)
456
+ assert_nil Customer.find_by_address(missing_address)
457
+ missing_address = Address.new(address.street + "1", address.city, address.country)
458
+ assert_nil Customer.find_by_address(missing_address)
459
+ end
460
+
461
+ def test_find_by_two_attributes_that_are_both_aggregates
462
+ balance = customers(:david).balance
463
+ address = customers(:david).address
464
+ assert_kind_of Money, balance
465
+ assert_kind_of Address, address
466
+ found_customer = Customer.find_by_balance_and_address(balance, address)
467
+ assert_equal customers(:david), found_customer
468
+ end
469
+
470
+ def test_find_by_two_attributes_with_one_being_an_aggregate
471
+ balance = customers(:david).balance
472
+ assert_kind_of Money, balance
473
+ found_customer = Customer.find_by_balance_and_name(balance, customers(:david).name)
474
+ assert_equal customers(:david), found_customer
475
+ end
476
+
477
+ def test_dynamic_finder_on_one_attribute_with_conditions_caches_method
478
+ # ensure this test can run independently of order
479
+ class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
480
+ assert !Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
481
+ a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
482
+ assert Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
483
+ end
484
+
485
+ def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
486
+ # ensure this test can run independently of order
487
+ class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.any? { |m| m.to_s == 'find_by_credit_limit' }
488
+ a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6])
489
+ assert_equal a, Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) # find_by_credit_limit has been cached
490
+ end
491
+
492
+ def test_find_by_one_attribute_with_several_options
493
+ assert_equal accounts(:unknown), Account.find_by_credit_limit(50, :order => 'id DESC', :conditions => ['id != ?', 3])
494
+ end
495
+
496
+ def test_find_by_one_missing_attribute
497
+ assert_raises(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
498
+ end
499
+
500
+ def test_find_by_invalid_method_syntax
501
+ assert_raises(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
502
+ assert_raises(NoMethodError) { Topic.find_by_title?("The First Topic") }
503
+ assert_raises(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
504
+ assert_raises(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
505
+ end
506
+
507
+ def test_find_by_two_attributes
508
+ assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
509
+ assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
510
+ end
511
+
512
+ def test_find_all_by_one_attribute
513
+ topics = Topic.find_all_by_content("Have a nice day")
514
+ assert_equal 2, topics.size
515
+ assert topics.include?(topics(:first))
516
+
517
+ assert_equal [], Topic.find_all_by_title("The First Topic!!")
518
+ end
519
+
520
+ def test_find_all_by_one_attribute_that_is_an_aggregate
521
+ balance = customers(:david).balance
522
+ assert_kind_of Money, balance
523
+ found_customers = Customer.find_all_by_balance(balance)
524
+ assert_equal 1, found_customers.size
525
+ assert_equal customers(:david), found_customers.first
526
+ end
527
+
528
+ def test_find_all_by_two_attributes_that_are_both_aggregates
529
+ balance = customers(:david).balance
530
+ address = customers(:david).address
531
+ assert_kind_of Money, balance
532
+ assert_kind_of Address, address
533
+ found_customers = Customer.find_all_by_balance_and_address(balance, address)
534
+ assert_equal 1, found_customers.size
535
+ assert_equal customers(:david), found_customers.first
536
+ end
537
+
538
+ def test_find_all_by_two_attributes_with_one_being_an_aggregate
539
+ balance = customers(:david).balance
540
+ assert_kind_of Money, balance
541
+ found_customers = Customer.find_all_by_balance_and_name(balance, customers(:david).name)
542
+ assert_equal 1, found_customers.size
543
+ assert_equal customers(:david), found_customers.first
544
+ end
545
+
546
+ def test_find_all_by_one_attribute_with_options
547
+ topics = Topic.find_all_by_content("Have a nice day", :order => "id DESC")
548
+ assert topics(:first), topics.last
549
+
550
+ topics = Topic.find_all_by_content("Have a nice day", :order => "id")
551
+ assert topics(:first), topics.first
552
+ end
553
+
554
+ def test_find_all_by_array_attribute
555
+ assert_equal 2, Topic.find_all_by_title(["The First Topic", "The Second Topic of the day"]).size
556
+ end
557
+
558
+ def test_find_all_by_boolean_attribute
559
+ topics = Topic.find_all_by_approved(false)
560
+ assert_equal 1, topics.size
561
+ assert topics.include?(topics(:first))
562
+
563
+ topics = Topic.find_all_by_approved(true)
564
+ assert_equal 3, topics.size
565
+ assert topics.include?(topics(:second))
566
+ end
567
+
568
+ def test_find_by_nil_attribute
569
+ topic = Topic.find_by_last_read nil
570
+ assert_not_nil topic
571
+ assert_nil topic.last_read
572
+ end
573
+
574
+ def test_find_all_by_nil_attribute
575
+ topics = Topic.find_all_by_last_read nil
576
+ assert_equal 3, topics.size
577
+ assert topics.collect(&:last_read).all?(&:nil?)
578
+ end
579
+
580
+ def test_find_by_nil_and_not_nil_attributes
581
+ topic = Topic.find_by_last_read_and_author_name nil, "Mary"
582
+ assert_equal "Mary", topic.author_name
583
+ end
584
+
585
+ def test_find_all_by_nil_and_not_nil_attributes
586
+ topics = Topic.find_all_by_last_read_and_author_name nil, "Mary"
587
+ assert_equal 1, topics.size
588
+ assert_equal "Mary", topics[0].author_name
589
+ end
590
+
591
+ def test_find_or_create_from_one_attribute
592
+ number_of_companies = Company.count
593
+ sig38 = Company.find_or_create_by_name("38signals")
594
+ assert_equal number_of_companies + 1, Company.count
595
+ assert_equal sig38, Company.find_or_create_by_name("38signals")
596
+ assert !sig38.new_record?
597
+ end
598
+
599
+ def test_find_or_create_from_two_attributes
600
+ number_of_topics = Topic.count
601
+ another = Topic.find_or_create_by_title_and_author_name("Another topic","John")
602
+ assert_equal number_of_topics + 1, Topic.count
603
+ assert_equal another, Topic.find_or_create_by_title_and_author_name("Another topic", "John")
604
+ assert !another.new_record?
605
+ end
606
+
607
+ def test_find_or_create_from_two_attributes_with_one_being_an_aggregate
608
+ number_of_customers = Customer.count
609
+ created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth")
610
+ assert_equal number_of_customers + 1, Customer.count
611
+ assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123), "Elizabeth")
612
+ assert !created_customer.new_record?
613
+ end
614
+
615
+ def test_find_or_create_from_one_attribute_and_hash
616
+ number_of_companies = Company.count
617
+ sig38 = Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
618
+ assert_equal number_of_companies + 1, Company.count
619
+ assert_equal sig38, Company.find_or_create_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
620
+ assert !sig38.new_record?
621
+ assert_equal "38signals", sig38.name
622
+ assert_equal 17, sig38.firm_id
623
+ assert_equal 23, sig38.client_of
624
+ end
625
+
626
+ def test_find_or_create_from_one_aggregate_attribute
627
+ number_of_customers = Customer.count
628
+ created_customer = Customer.find_or_create_by_balance(Money.new(123))
629
+ assert_equal number_of_customers + 1, Customer.count
630
+ assert_equal created_customer, Customer.find_or_create_by_balance(Money.new(123))
631
+ assert !created_customer.new_record?
632
+ end
633
+
634
+ def test_find_or_create_from_one_aggregate_attribute_and_hash
635
+ number_of_customers = Customer.count
636
+ balance = Money.new(123)
637
+ name = "Elizabeth"
638
+ created_customer = Customer.find_or_create_by_balance({:balance => balance, :name => name})
639
+ assert_equal number_of_customers + 1, Customer.count
640
+ assert_equal created_customer, Customer.find_or_create_by_balance({:balance => balance, :name => name})
641
+ assert !created_customer.new_record?
642
+ assert_equal balance, created_customer.balance
643
+ assert_equal name, created_customer.name
644
+ end
645
+
646
+ def test_find_or_initialize_from_one_attribute
647
+ sig38 = Company.find_or_initialize_by_name("38signals")
648
+ assert_equal "38signals", sig38.name
649
+ assert sig38.new_record?
650
+ end
651
+
652
+ def test_find_or_initialize_from_one_aggregate_attribute
653
+ new_customer = Customer.find_or_initialize_by_balance(Money.new(123))
654
+ assert_equal 123, new_customer.balance.amount
655
+ assert new_customer.new_record?
656
+ end
657
+
658
+ def test_find_or_initialize_from_one_attribute_should_not_set_attribute_even_when_protected
659
+ c = Company.find_or_initialize_by_name({:name => "Fortune 1000", :rating => 1000})
660
+ assert_equal "Fortune 1000", c.name
661
+ assert_not_equal 1000, c.rating
662
+ assert c.valid?
663
+ assert c.new_record?
664
+ end
665
+
666
+ def test_find_or_create_from_one_attribute_should_set_not_attribute_even_when_protected
667
+ c = Company.find_or_create_by_name({:name => "Fortune 1000", :rating => 1000})
668
+ assert_equal "Fortune 1000", c.name
669
+ assert_not_equal 1000, c.rating
670
+ assert c.valid?
671
+ assert !c.new_record?
672
+ end
673
+
674
+ def test_find_or_initialize_from_one_attribute_should_set_attribute_even_when_protected
675
+ c = Company.find_or_initialize_by_name_and_rating("Fortune 1000", 1000)
676
+ assert_equal "Fortune 1000", c.name
677
+ assert_equal 1000, c.rating
678
+ assert c.valid?
679
+ assert c.new_record?
680
+ end
681
+
682
+ def test_find_or_create_from_one_attribute_should_set_attribute_even_when_protected
683
+ c = Company.find_or_create_by_name_and_rating("Fortune 1000", 1000)
684
+ assert_equal "Fortune 1000", c.name
685
+ assert_equal 1000, c.rating
686
+ assert c.valid?
687
+ assert !c.new_record?
688
+ end
689
+
690
+ def test_find_or_initialize_should_set_protected_attributes_if_given_as_block
691
+ c = Company.find_or_initialize_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
692
+ assert_equal "Fortune 1000", c.name
693
+ assert_equal 1000.to_f, c.rating.to_f
694
+ assert c.valid?
695
+ assert c.new_record?
696
+ end
697
+
698
+ def test_find_or_create_should_set_protected_attributes_if_given_as_block
699
+ c = Company.find_or_create_by_name(:name => "Fortune 1000") { |f| f.rating = 1000 }
700
+ assert_equal "Fortune 1000", c.name
701
+ assert_equal 1000.to_f, c.rating.to_f
702
+ assert c.valid?
703
+ assert !c.new_record?
704
+ end
705
+
706
+ def test_dynamic_find_or_initialize_from_one_attribute_caches_method
707
+ class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
708
+ assert !Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
709
+ sig38 = Company.find_or_initialize_by_name("38signals")
710
+ assert Company.public_methods.any? { |m| m.to_s == 'find_or_initialize_by_name' }
711
+ end
712
+
713
+ def test_find_or_initialize_from_two_attributes
714
+ another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John")
715
+ assert_equal "Another topic", another.title
716
+ assert_equal "John", another.author_name
717
+ assert another.new_record?
718
+ end
719
+
720
+ def test_find_or_initialize_from_one_aggregate_attribute_and_one_not
721
+ new_customer = Customer.find_or_initialize_by_balance_and_name(Money.new(123), "Elizabeth")
722
+ assert_equal 123, new_customer.balance.amount
723
+ assert_equal "Elizabeth", new_customer.name
724
+ assert new_customer.new_record?
725
+ end
726
+
727
+ def test_find_or_initialize_from_one_attribute_and_hash
728
+ sig38 = Company.find_or_initialize_by_name({:name => "38signals", :firm_id => 17, :client_of => 23})
729
+ assert_equal "38signals", sig38.name
730
+ assert_equal 17, sig38.firm_id
731
+ assert_equal 23, sig38.client_of
732
+ assert sig38.new_record?
733
+ end
734
+
735
+ def test_find_or_initialize_from_one_aggregate_attribute_and_hash
736
+ balance = Money.new(123)
737
+ name = "Elizabeth"
738
+ new_customer = Customer.find_or_initialize_by_balance({:balance => balance, :name => name})
739
+ assert_equal balance, new_customer.balance
740
+ assert_equal name, new_customer.name
741
+ assert new_customer.new_record?
742
+ end
743
+
744
+ def test_find_with_bad_sql
745
+ assert_raises(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
746
+ end
747
+
748
+ def test_find_with_invalid_params
749
+ assert_raises(ArgumentError) { Topic.find :first, :join => "It should be `joins'" }
750
+ assert_raises(ArgumentError) { Topic.find :first, :conditions => '1 = 1', :join => "It should be `joins'" }
751
+ end
752
+
753
+ def test_dynamic_finder_with_invalid_params
754
+ assert_raises(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" }
755
+ end
756
+
757
+ def test_find_all_with_limit
758
+ first_five_developers = Developer.find :all, :order => 'id ASC', :limit => 5
759
+ assert_equal 5, first_five_developers.length
760
+ assert_equal 'David', first_five_developers.first.name
761
+ assert_equal 'fixture_5', first_five_developers.last.name
762
+
763
+ no_developers = Developer.find :all, :order => 'id ASC', :limit => 0
764
+ assert_equal 0, no_developers.length
765
+ end
766
+
767
+ def test_find_all_with_limit_and_offset
768
+ first_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 0
769
+ second_three_developers = Developer.find :all, :order => 'id ASC', :limit => 3, :offset => 3
770
+ last_two_developers = Developer.find :all, :order => 'id ASC', :limit => 2, :offset => 8
771
+
772
+ assert_equal 3, first_three_developers.length
773
+ assert_equal 3, second_three_developers.length
774
+ assert_equal 2, last_two_developers.length
775
+
776
+ assert_equal 'David', first_three_developers.first.name
777
+ assert_equal 'fixture_4', second_three_developers.first.name
778
+ assert_equal 'fixture_9', last_two_developers.first.name
779
+ end
780
+
781
+ def test_find_all_with_limit_and_offset_and_multiple_order_clauses
782
+ first_three_posts = Post.find :all, :order => 'author_id, id', :limit => 3, :offset => 0
783
+ second_three_posts = Post.find :all, :order => ' author_id,id ', :limit => 3, :offset => 3
784
+ last_posts = Post.find :all, :order => ' author_id, id ', :limit => 3, :offset => 6
785
+
786
+ assert_equal [[0,3],[1,1],[1,2]], first_three_posts.map { |p| [p.author_id, p.id] }
787
+ assert_equal [[1,4],[1,5],[1,6]], second_three_posts.map { |p| [p.author_id, p.id] }
788
+ assert_equal [[2,7]], last_posts.map { |p| [p.author_id, p.id] }
789
+ end
790
+
791
+ def test_find_all_with_join
792
+ developers_on_project_one = Developer.find(
793
+ :all,
794
+ :joins => 'LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id',
795
+ :conditions => 'project_id=1'
796
+ )
797
+ assert_equal 3, developers_on_project_one.length
798
+ developer_names = developers_on_project_one.map { |d| d.name }
799
+ assert developer_names.include?('David')
800
+ assert developer_names.include?('Jamis')
801
+ end
802
+
803
+ def test_joins_dont_clobber_id
804
+ first = Firm.find(
805
+ :first,
806
+ :joins => 'INNER JOIN companies AS clients ON clients.firm_id = companies.id',
807
+ :conditions => 'companies.id = 1'
808
+ )
809
+ assert_equal 1, first.id
810
+ end
811
+
812
+ def test_find_by_id_with_conditions_with_or
813
+ assert_nothing_raised do
814
+ Post.find([1,2,3],
815
+ :conditions => "posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'")
816
+ end
817
+ end
818
+
819
+ # http://dev.rubyonrails.org/ticket/6778
820
+ def test_find_ignores_previously_inserted_record
821
+ post = Post.create!(:title => 'test', :body => 'it out')
822
+ assert_equal [], Post.find_all_by_id(nil)
823
+ end
824
+
825
+ def test_find_by_empty_ids
826
+ assert_equal [], Post.find([])
827
+ end
828
+
829
+ def test_find_by_empty_in_condition
830
+ assert_equal [], Post.find(:all, :conditions => ['id in (?)', []])
831
+ end
832
+
833
+ def test_find_by_records
834
+ p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
835
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2]], :order => 'id asc')
836
+ assert_equal [p1, p2], Post.find(:all, :conditions => ['id in (?)', [p1, p2.id]], :order => 'id asc')
837
+ end
838
+
839
+ def test_select_value
840
+ assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
841
+ assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
842
+ # make sure we didn't break count...
843
+ assert_equal 0, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = 'Halliburton'")
844
+ assert_equal 1, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = '37signals'")
845
+ end
846
+
847
+ def test_select_values
848
+ assert_equal ["1","2","3","4","5","6","7","8","9"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map! { |i| i.to_s }
849
+ assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
850
+ end
851
+
852
+ def test_select_rows
853
+ assert_equal(
854
+ [["1", nil, nil, "37signals"],
855
+ ["2", "1", "2", "Summit"],
856
+ ["3", "1", "1", "Microsoft"]],
857
+ 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?}})
858
+ assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
859
+ 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?}}
860
+ end
861
+
862
+ unless current_adapter?(:IBM_DBAdapter)
863
+ def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
864
+ assert_equal 2, Post.find(:all, :include => { :authors => :author_address }, :order => ' author_addresses.id DESC ', :limit => 2).size
865
+
866
+ assert_equal 3, Post.find(:all, :include => { :author => :author_address, :authors => :author_address},
867
+ :order => ' author_addresses_authors.id DESC ', :limit => 3).size
868
+ end
869
+ end
870
+
871
+ def test_with_limiting_with_custom_select
872
+ posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3, :order => 'posts.id')
873
+ assert_equal 3, posts.size
874
+ assert_equal [0, 1, 1], posts.map(&:author_id).sort
875
+ end
876
+
877
+ protected
878
+ def bind(statement, *vars)
879
+ if vars.first.is_a?(Hash)
880
+ ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
881
+ else
882
+ ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
883
+ end
884
+ end
885
+ end