ibm_db 0.9.5 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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