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,797 @@
1
+ require "cases/helper"
2
+ require 'models/tag'
3
+ require 'models/tagging'
4
+ require 'models/post'
5
+ require 'models/item'
6
+ require 'models/comment'
7
+ require 'models/author'
8
+ require 'models/category'
9
+ require 'models/categorization'
10
+ require 'models/vertex'
11
+ require 'models/edge'
12
+ require 'models/book'
13
+ require 'models/citation'
14
+
15
+ class AssociationsJoinModelTest < ActiveRecord::TestCase
16
+ self.use_transactional_fixtures = false
17
+ fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
18
+
19
+ def test_has_many
20
+ assert authors(:david).categories.include?(categories(:general))
21
+ end
22
+
23
+ def test_has_many_inherited
24
+ assert authors(:mary).categories.include?(categories(:sti_test))
25
+ end
26
+
27
+ def test_inherited_has_many
28
+ assert categories(:sti_test).authors.include?(authors(:mary))
29
+ end
30
+
31
+ def test_has_many_uniq_through_join_model
32
+ assert_equal 2, authors(:mary).categorized_posts.size
33
+ assert_equal 1, authors(:mary).unique_categorized_posts.size
34
+ end
35
+
36
+ def test_has_many_uniq_through_count
37
+ author = authors(:mary)
38
+ assert !authors(:mary).unique_categorized_posts.loaded?
39
+ assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
40
+ assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
41
+ assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
42
+ assert !authors(:mary).unique_categorized_posts.loaded?
43
+ end
44
+
45
+ unless current_adapter?(:IBM_DBAdapter)
46
+ def test_has_many_uniq_through_find
47
+ assert_equal 1, authors(:mary).unique_categorized_posts.find(:all).size
48
+ end
49
+
50
+ def test_has_many_uniq_through_dynamic_find
51
+ assert_equal 1, authors(:mary).unique_categorized_posts.find_all_by_title("So I was thinking").size
52
+ end
53
+ # LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
54
+ # An expression in the ORDER BY clause in the following position,
55
+ # or starting with "DEVELOPERS" in the "ORDER BY" clause is not valid.
56
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
57
+ # SELECT DISTINCT projects.id FROM projects
58
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
59
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
60
+ # ORDER BY developers.created_at
61
+ #
62
+ # i5: [IBM][CLI Driver][AS] SQL0214N
63
+ # An expression in the ORDER BY clause in the following position,
64
+ # or starting with "1" in the "CREATED_AT" clause is not valid.
65
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
66
+ # SELECT DISTINCT projects.id FROM projects
67
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
68
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
69
+ # ORDER BY developers.created_at
70
+ #
71
+ # zOS 9:[IBM][CLI Driver][DB2] SQL0214N
72
+ # An expression in the ORDER BY clause in the following position,
73
+ # or starting with "CREATED_AT" in the "ORDER BY" clause is not valid.
74
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
75
+ # SELECT DISTINCT projects.id FROM projects
76
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
77
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
78
+ # ORDER BY developers.created_at
79
+ #
80
+ end
81
+
82
+ def test_polymorphic_has_many
83
+ assert posts(:welcome).taggings.include?(taggings(:welcome_general))
84
+ end
85
+
86
+ def test_polymorphic_has_one
87
+ assert_equal taggings(:welcome_general), posts(:welcome).tagging
88
+ end
89
+
90
+ def test_polymorphic_belongs_to
91
+ assert_equal posts(:welcome), posts(:welcome).taggings.first.taggable
92
+ end
93
+
94
+ def test_polymorphic_has_many_going_through_join_model
95
+ assert_equal tags(:general), tag = posts(:welcome).tags.first
96
+ assert_no_queries do
97
+ tag.tagging
98
+ end
99
+ end
100
+
101
+ def test_count_polymorphic_has_many
102
+ assert_equal 1, posts(:welcome).taggings.count
103
+ assert_equal 1, posts(:welcome).tags.count
104
+ end
105
+
106
+ def test_polymorphic_has_many_going_through_join_model_with_find
107
+ assert_equal tags(:general), tag = posts(:welcome).tags.find(:first)
108
+ assert_no_queries do
109
+ tag.tagging
110
+ end
111
+ end
112
+
113
+ def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection
114
+ assert_equal tags(:general), tag = posts(:welcome).funky_tags.first
115
+ assert_no_queries do
116
+ tag.tagging
117
+ end
118
+ end
119
+
120
+ def test_polymorphic_has_many_going_through_join_model_with_include_on_source_reflection_with_find
121
+ assert_equal tags(:general), tag = posts(:welcome).funky_tags.find(:first)
122
+ assert_no_queries do
123
+ tag.tagging
124
+ end
125
+ end
126
+
127
+ def test_polymorphic_has_many_going_through_join_model_with_disabled_include
128
+ assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
129
+ assert_queries 1 do
130
+ tag.tagging
131
+ end
132
+ end
133
+
134
+ def test_polymorphic_has_many_going_through_join_model_with_custom_select_and_joins
135
+ assert_equal tags(:general), tag = posts(:welcome).tags.add_joins_and_select.first
136
+ tag.author_id
137
+ end
138
+
139
+ def test_polymorphic_has_many_going_through_join_model_with_custom_foreign_key
140
+ assert_equal tags(:misc), taggings(:welcome_general).super_tag
141
+ assert_equal tags(:misc), posts(:welcome).super_tags.first
142
+ end
143
+
144
+ def test_polymorphic_has_many_create_model_with_inheritance_and_custom_base_class
145
+ post = SubStiPost.create :title => 'SubStiPost', :body => 'SubStiPost body'
146
+ assert_instance_of SubStiPost, post
147
+
148
+ tagging = tags(:misc).taggings.create(:taggable => post)
149
+ assert_equal "SubStiPost", tagging.taggable_type
150
+ end
151
+
152
+ def test_polymorphic_has_many_going_through_join_model_with_inheritance
153
+ assert_equal tags(:general), posts(:thinking).tags.first
154
+ end
155
+
156
+ def test_polymorphic_has_many_going_through_join_model_with_inheritance_with_custom_class_name
157
+ assert_equal tags(:general), posts(:thinking).funky_tags.first
158
+ end
159
+
160
+ def test_polymorphic_has_many_create_model_with_inheritance
161
+ post = posts(:thinking)
162
+ assert_instance_of SpecialPost, post
163
+
164
+ tagging = tags(:misc).taggings.create(:taggable => post)
165
+ assert_equal "Post", tagging.taggable_type
166
+ end
167
+
168
+ def test_polymorphic_has_one_create_model_with_inheritance
169
+ tagging = tags(:misc).create_tagging(:taggable => posts(:thinking))
170
+ assert_equal "Post", tagging.taggable_type
171
+ end
172
+
173
+ def test_set_polymorphic_has_many
174
+ tagging = tags(:misc).taggings.create
175
+ posts(:thinking).taggings << tagging
176
+ assert_equal "Post", tagging.taggable_type
177
+ end
178
+
179
+ def test_set_polymorphic_has_one
180
+ tagging = tags(:misc).taggings.create
181
+ posts(:thinking).tagging = tagging
182
+ assert_equal "Post", tagging.taggable_type
183
+ end
184
+
185
+ def test_create_polymorphic_has_many_with_scope
186
+ old_count = posts(:welcome).taggings.count
187
+ tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
188
+ assert_equal "Post", tagging.taggable_type
189
+ assert_equal old_count+1, posts(:welcome).taggings.count
190
+ end
191
+
192
+ def test_create_bang_polymorphic_with_has_many_scope
193
+ old_count = posts(:welcome).taggings.count
194
+ tagging = posts(:welcome).taggings.create!(:tag => tags(:misc))
195
+ assert_equal "Post", tagging.taggable_type
196
+ assert_equal old_count+1, posts(:welcome).taggings.count
197
+ end
198
+
199
+ def test_create_polymorphic_has_one_with_scope
200
+ old_count = Tagging.count
201
+ tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
202
+ assert_equal "Post", tagging.taggable_type
203
+ assert_equal old_count+1, Tagging.count
204
+ end
205
+
206
+ def test_delete_polymorphic_has_many_with_delete_all
207
+ assert_equal 1, posts(:welcome).taggings.count
208
+ posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDeleteAll'
209
+ post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
210
+
211
+ old_count = Tagging.count
212
+ post.destroy
213
+ assert_equal old_count-1, Tagging.count
214
+ assert_equal 0, posts(:welcome).taggings.count
215
+ end
216
+
217
+ def test_delete_polymorphic_has_many_with_destroy
218
+ assert_equal 1, posts(:welcome).taggings.count
219
+ posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDestroy'
220
+ post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
221
+
222
+ old_count = Tagging.count
223
+ post.destroy
224
+ assert_equal old_count-1, Tagging.count
225
+ assert_equal 0, posts(:welcome).taggings.count
226
+ end
227
+
228
+ def test_delete_polymorphic_has_many_with_nullify
229
+ assert_equal 1, posts(:welcome).taggings.count
230
+ posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyNullify'
231
+ post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
232
+
233
+ old_count = Tagging.count
234
+ post.destroy
235
+ assert_equal old_count, Tagging.count
236
+ assert_equal 0, posts(:welcome).taggings.count
237
+ end
238
+
239
+ def test_delete_polymorphic_has_one_with_destroy
240
+ assert posts(:welcome).tagging
241
+ posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneDestroy'
242
+ post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
243
+
244
+ old_count = Tagging.count
245
+ post.destroy
246
+ assert_equal old_count-1, Tagging.count
247
+ assert_nil posts(:welcome).tagging(true)
248
+ end
249
+
250
+ def test_delete_polymorphic_has_one_with_nullify
251
+ assert posts(:welcome).tagging
252
+ posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneNullify'
253
+ post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
254
+
255
+ old_count = Tagging.count
256
+ post.destroy
257
+ assert_equal old_count, Tagging.count
258
+ assert_nil posts(:welcome).tagging(true)
259
+ end
260
+
261
+ def test_has_many_with_piggyback
262
+ assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
263
+ end
264
+
265
+ def test_include_has_many_through
266
+ posts = Post.find(:all, :order => 'posts.id')
267
+ posts_with_authors = Post.find(:all, :include => :authors, :order => 'posts.id')
268
+ assert_equal posts.length, posts_with_authors.length
269
+ posts.length.times do |i|
270
+ assert_equal posts[i].authors.length, assert_no_queries { posts_with_authors[i].authors.length }
271
+ end
272
+ end
273
+
274
+ def test_include_polymorphic_has_one
275
+ post = Post.find_by_id(posts(:welcome).id, :include => :tagging)
276
+ tagging = taggings(:welcome_general)
277
+ assert_no_queries do
278
+ assert_equal tagging, post.tagging
279
+ end
280
+ end
281
+
282
+ def test_include_polymorphic_has_one_defined_in_abstract_parent
283
+ item = Item.find_by_id(items(:dvd).id, :include => :tagging)
284
+ tagging = taggings(:godfather)
285
+ assert_no_queries do
286
+ assert_equal tagging, item.tagging
287
+ end
288
+ end
289
+
290
+ def test_include_polymorphic_has_many_through
291
+ posts = Post.find(:all, :order => 'posts.id')
292
+ posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
293
+ assert_equal posts.length, posts_with_tags.length
294
+ posts.length.times do |i|
295
+ assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
296
+ end
297
+ end
298
+
299
+ def test_include_polymorphic_has_many
300
+ posts = Post.find(:all, :order => 'posts.id')
301
+ posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
302
+ assert_equal posts.length, posts_with_taggings.length
303
+ posts.length.times do |i|
304
+ assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
305
+ end
306
+ end
307
+
308
+ def test_has_many_find_all
309
+ assert_equal [categories(:general)], authors(:david).categories.find(:all)
310
+ end
311
+
312
+ def test_has_many_find_first
313
+ assert_equal categories(:general), authors(:david).categories.find(:first)
314
+ end
315
+
316
+ def test_has_many_with_hash_conditions
317
+ assert_equal categories(:general), authors(:david).categories_like_general.find(:first)
318
+ end
319
+
320
+ def test_has_many_find_conditions
321
+ assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
322
+ assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
323
+ end
324
+
325
+ def test_has_many_class_methods_called_by_method_missing
326
+ assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
327
+ assert_equal nil, authors(:david).categories.find_by_name('Technology')
328
+ end
329
+
330
+ def test_has_many_array_methods_called_by_method_missing
331
+ assert true, authors(:david).categories.any? { |category| category.name == 'General' }
332
+ assert_nothing_raised { authors(:david).categories.sort }
333
+ end
334
+
335
+ def test_has_many_going_through_join_model_with_custom_foreign_key
336
+ assert_equal [], posts(:thinking).authors
337
+ assert_equal [authors(:mary)], posts(:authorless).authors
338
+ end
339
+
340
+ def test_both_scoped_and_explicit_joins_should_be_respected
341
+ assert_nothing_raised do
342
+ Post.send(:with_scope, :find => {:joins => "left outer join comments on comments.id = posts.id"}) do
343
+ Post.find :all, :select => "comments.id, authors.id", :joins => "left outer join authors on authors.id = posts.author_id"
344
+ end
345
+ end
346
+ end
347
+
348
+ def test_belongs_to_polymorphic_with_counter_cache
349
+ assert_equal 0, posts(:welcome)[:taggings_count]
350
+ tagging = posts(:welcome).taggings.create(:tag => tags(:general))
351
+ assert_equal 1, posts(:welcome, :reload)[:taggings_count]
352
+ tagging.destroy
353
+ assert posts(:welcome, :reload)[:taggings_count].zero?
354
+ end
355
+
356
+ def test_unavailable_through_reflection
357
+ assert_raise(ActiveRecord::HasManyThroughAssociationNotFoundError) { authors(:david).nothings }
358
+ end
359
+
360
+ def test_has_many_through_join_model_with_conditions
361
+ assert_equal [], posts(:welcome).invalid_taggings
362
+ assert_equal [], posts(:welcome).invalid_tags
363
+ end
364
+
365
+ def test_has_many_polymorphic
366
+ assert_raise ActiveRecord::HasManyThroughAssociationPolymorphicError do
367
+ assert_equal posts(:welcome, :thinking), tags(:general).taggables
368
+ end
369
+ assert_raise ActiveRecord::EagerLoadPolymorphicError do
370
+ assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable, :conditions => 'bogus_table.column = 1')
371
+ end
372
+ end
373
+
374
+ def test_has_many_polymorphic_with_source_type
375
+ assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
376
+ end
377
+
378
+ def test_eager_has_many_polymorphic_with_source_type
379
+ tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
380
+ desired = posts(:welcome, :thinking)
381
+ assert_no_queries do
382
+ assert_equal desired, tag_with_include.tagged_posts
383
+ end
384
+ assert_equal 5, tag_with_include.taggings.length
385
+ end
386
+
387
+ def test_has_many_through_has_many_find_all
388
+ assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
389
+ end
390
+
391
+ def test_has_many_through_has_many_find_all_with_custom_class
392
+ assert_equal comments(:greetings), authors(:david).funky_comments.find(:all, :order => 'comments.id').first
393
+ end
394
+
395
+ def test_has_many_through_has_many_find_first
396
+ assert_equal comments(:greetings), authors(:david).comments.find(:first, :order => 'comments.id')
397
+ end
398
+
399
+ def test_has_many_through_has_many_find_conditions
400
+ options = { :conditions => "comments.#{QUOTED_TYPE}='SpecialComment'", :order => 'comments.id' }
401
+ assert_equal comments(:does_it_hurt), authors(:david).comments.find(:first, options)
402
+ end
403
+
404
+ def test_has_many_through_has_many_find_by_id
405
+ assert_equal comments(:more_greetings), authors(:david).comments.find(2)
406
+ end
407
+
408
+ def test_has_many_through_polymorphic_has_one
409
+ assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tagging }
410
+ end
411
+
412
+ def test_has_many_through_polymorphic_has_many
413
+ assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
414
+ end
415
+
416
+ def test_include_has_many_through_polymorphic_has_many
417
+ author = Author.find_by_id(authors(:david).id, :include => :taggings)
418
+ expected_taggings = taggings(:welcome_general, :thinking_general)
419
+ assert_no_queries do
420
+ assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
421
+ end
422
+ end
423
+
424
+ def test_has_many_through_has_many_through
425
+ assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).tags }
426
+ end
427
+
428
+ def test_has_many_through_habtm
429
+ assert_raise(ActiveRecord::HasManyThroughSourceAssociationMacroError) { authors(:david).post_categories }
430
+ end
431
+
432
+ unless current_adapter?(:IBM_DBAdapter)
433
+ def test_eager_load_has_many_through_has_many
434
+ author = Author.find :first, :conditions => ['name = ?', 'David'], :include => :comments, :order => 'comments.id'
435
+ SpecialComment.new; VerySpecialComment.new
436
+ assert_no_queries do
437
+ assert_equal [1,2,3,5,6,7,8,9,10], author.comments.collect(&:id)
438
+ end
439
+ end
440
+ # LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
441
+ # An expression in the ORDER BY clause in the following position,
442
+ # or starting with "DEVELOPERS" in the "ORDER BY" clause is not valid.
443
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
444
+ # SELECT DISTINCT projects.id FROM projects
445
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
446
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
447
+ # ORDER BY developers.created_at
448
+ #
449
+ # i5: [IBM][CLI Driver][AS] SQL0214N
450
+ # An expression in the ORDER BY clause in the following position,
451
+ # or starting with "1" in the "CREATED_AT" clause is not valid.
452
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
453
+ # SELECT DISTINCT projects.id FROM projects
454
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
455
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
456
+ # ORDER BY developers.created_at
457
+ #
458
+ # zOS 9:[IBM][CLI Driver][DB2] SQL0214N
459
+ # An expression in the ORDER BY clause in the following position,
460
+ # or starting with "CREATED_AT" in the "ORDER BY" clause is not valid.
461
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
462
+ # SELECT DISTINCT projects.id FROM projects
463
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
464
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
465
+ # ORDER BY developers.created_at
466
+ #
467
+ end
468
+
469
+ def test_eager_load_has_many_through_has_many_with_conditions
470
+ post = Post.find(:first, :include => :invalid_tags)
471
+ assert_no_queries do
472
+ post.invalid_tags
473
+ end
474
+ end
475
+
476
+ def test_eager_belongs_to_and_has_one_not_singularized
477
+ assert_nothing_raised do
478
+ Author.find(:first, :include => :author_address)
479
+ AuthorAddress.find(:first, :include => :author)
480
+ end
481
+ end
482
+
483
+ def test_self_referential_has_many_through
484
+ assert_equal [authors(:mary)], authors(:david).favorite_authors
485
+ assert_equal [], authors(:mary).favorite_authors
486
+ end
487
+
488
+ def test_add_to_self_referential_has_many_through
489
+ new_author = Author.create(:name => "Bob")
490
+ authors(:david).author_favorites.create :favorite_author => new_author
491
+ assert_equal new_author, authors(:david).reload.favorite_authors.first
492
+ end
493
+
494
+ def test_has_many_through_uses_conditions_specified_on_the_has_many_association
495
+ author = Author.find(:first)
496
+ assert !author.comments.blank?
497
+ assert author.nonexistant_comments.blank?
498
+ end
499
+
500
+ def test_has_many_through_uses_correct_attributes
501
+ assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
502
+ end
503
+
504
+ def test_associating_unsaved_records_with_has_many_through
505
+ saved_post = posts(:thinking)
506
+ new_tag = Tag.new(:name => "new")
507
+
508
+ saved_post.tags << new_tag
509
+ assert !new_tag.new_record? #consistent with habtm!
510
+ assert !saved_post.new_record?
511
+ assert saved_post.tags.include?(new_tag)
512
+
513
+ assert !new_tag.new_record?
514
+ assert saved_post.reload.tags(true).include?(new_tag)
515
+
516
+
517
+ new_post = Post.new(:title => "Association replacmenet works!", :body => "You best believe it.")
518
+ saved_tag = tags(:general)
519
+
520
+ new_post.tags << saved_tag
521
+ assert new_post.new_record?
522
+ assert !saved_tag.new_record?
523
+ assert new_post.tags.include?(saved_tag)
524
+
525
+ new_post.save!
526
+ assert !new_post.new_record?
527
+ assert new_post.reload.tags(true).include?(saved_tag)
528
+
529
+ assert posts(:thinking).tags.build.new_record?
530
+ assert posts(:thinking).tags.new.new_record?
531
+ end
532
+
533
+ def test_create_associate_when_adding_to_has_many_through
534
+ count = posts(:thinking).tags.count
535
+ push = Tag.create!(:name => 'pushme')
536
+ post_thinking = posts(:thinking)
537
+ assert_nothing_raised { post_thinking.tags << push }
538
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
539
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
540
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
541
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
542
+ assert_equal(count + 1, post_thinking.tags.size)
543
+ assert_equal(count + 1, post_thinking.tags(true).size)
544
+
545
+ assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
546
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
547
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
548
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
549
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
550
+ assert_equal(count + 2, post_thinking.tags.size)
551
+ assert_equal(count + 2, post_thinking.tags(true).size)
552
+
553
+ assert_nothing_raised { post_thinking.tags.concat(Tag.create!(:name => 'abc'), Tag.create!(:name => 'def')) }
554
+ assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
555
+ message = "Expected a Tag in tags collection, got #{wrong.class}.")
556
+ assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
557
+ message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
558
+ assert_equal(count + 4, post_thinking.tags.size)
559
+ assert_equal(count + 4, post_thinking.tags(true).size)
560
+
561
+ # Raises if the wrong reflection name is used to set the Edge belongs_to
562
+ assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
563
+ end
564
+
565
+ def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
566
+ author = authors(:david)
567
+ assert_equal 9, author.comments.size
568
+ assert !author.comments.loaded?
569
+ end
570
+
571
+ uses_mocha('has_many_through_collection_size_uses_counter_cache_if_it_exists') do
572
+ def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
573
+ author = authors(:david)
574
+ author.stubs(:read_attribute).with('comments_count').returns(100)
575
+ assert_equal 100, author.comments.size
576
+ assert !author.comments.loaded?
577
+ end
578
+ end
579
+
580
+ def test_adding_junk_to_has_many_through_should_raise_type_mismatch
581
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
582
+ end
583
+
584
+ def test_adding_to_has_many_through_should_return_self
585
+ tags = posts(:thinking).tags
586
+ assert_equal tags, posts(:thinking).tags.push(tags(:general))
587
+ end
588
+
589
+ def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
590
+ count = books(:awdr).references.count
591
+ references_before = books(:awdr).references
592
+ book = Book.create!(:name => 'Getting Real')
593
+ book_awdr = books(:awdr)
594
+ book_awdr.references << book
595
+ assert_equal(count + 1, book_awdr.references(true).size)
596
+
597
+ assert_nothing_raised { book_awdr.references.delete(book) }
598
+ assert_equal(count, book_awdr.references.size)
599
+ assert_equal(count, book_awdr.references(true).size)
600
+ assert_equal(references_before.sort, book_awdr.references.sort)
601
+ end
602
+
603
+ def test_delete_associate_when_deleting_from_has_many_through
604
+ count = posts(:thinking).tags.count
605
+ tags_before = posts(:thinking).tags
606
+ tag = Tag.create!(:name => 'doomed')
607
+ post_thinking = posts(:thinking)
608
+ post_thinking.tags << tag
609
+ assert_equal(count + 1, post_thinking.taggings(true).size)
610
+ assert_equal(count + 1, post_thinking.tags(true).size)
611
+
612
+ assert_nothing_raised { post_thinking.tags.delete(tag) }
613
+ assert_equal(count, post_thinking.tags.size)
614
+ assert_equal(count, post_thinking.tags(true).size)
615
+ assert_equal(count, post_thinking.taggings(true).size)
616
+ assert_equal(tags_before.sort, post_thinking.tags.sort)
617
+ end
618
+
619
+ def test_delete_associate_when_deleting_from_has_many_through_with_multiple_tags
620
+ count = posts(:thinking).tags.count
621
+ tags_before = posts(:thinking).tags
622
+ doomed = Tag.create!(:name => 'doomed')
623
+ doomed2 = Tag.create!(:name => 'doomed2')
624
+ quaked = Tag.create!(:name => 'quaked')
625
+ post_thinking = posts(:thinking)
626
+ post_thinking.tags << doomed << doomed2
627
+ assert_equal(count + 2, post_thinking.tags(true).size)
628
+
629
+ assert_nothing_raised { post_thinking.tags.delete(doomed, doomed2, quaked) }
630
+ assert_equal(count, post_thinking.tags.size)
631
+ assert_equal(count, post_thinking.tags(true).size)
632
+ assert_equal(tags_before.sort, post_thinking.tags.sort)
633
+ end
634
+
635
+ def test_deleting_junk_from_has_many_through_should_raise_type_mismatch
636
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags.delete("Uhh what now?") }
637
+ end
638
+
639
+ def test_has_many_through_sum_uses_calculations
640
+ assert_nothing_raised { authors(:david).comments.sum(:post_id) }
641
+ end
642
+
643
+ def test_calculations_on_has_many_through_should_disambiguate_fields
644
+ assert_nothing_raised { authors(:david).categories.maximum(:id) }
645
+ end
646
+
647
+ def test_calculations_on_has_many_through_should_not_disambiguate_fields_unless_necessary
648
+ assert_nothing_raised { authors(:david).categories.maximum("categories.id") }
649
+ end
650
+
651
+ def test_has_many_through_has_many_with_sti
652
+ assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
653
+ end
654
+
655
+ def test_uniq_has_many_through_should_retain_order
656
+ comment_ids = authors(:david).comments.map(&:id)
657
+ assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
658
+
659
+ unless current_adapter?(:IBM_DBAdapter)
660
+ assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
661
+ # LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
662
+ # An expression in the ORDER BY clause in the following position,
663
+ # or starting with "DEVELOPERS" in the "ORDER BY" clause is not valid.
664
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
665
+ # SELECT DISTINCT projects.id FROM projects
666
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
667
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
668
+ # ORDER BY developers.created_at
669
+ #
670
+ # i5: [IBM][CLI Driver][AS] SQL0214N
671
+ # An expression in the ORDER BY clause in the following position,
672
+ # or starting with "1" in the "CREATED_AT" clause is not valid.
673
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
674
+ # SELECT DISTINCT projects.id FROM projects
675
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
676
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
677
+ # ORDER BY developers.created_at
678
+ #
679
+ # zOS 9:[IBM][CLI Driver][DB2] SQL0214N
680
+ # An expression in the ORDER BY clause in the following position,
681
+ # or starting with "CREATED_AT" in the "ORDER BY" clause is not valid.
682
+ # Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
683
+ # SELECT DISTINCT projects.id FROM projects
684
+ # LEFT OUTER JOIN developers_projects ON developers_projects.project_id = projects.id
685
+ # LEFT OUTER JOIN developers ON developers.id = developers_projects.developer_id
686
+ # ORDER BY developers.created_at
687
+ #
688
+ end
689
+ end
690
+
691
+ def test_polymorphic_has_many
692
+ expected = taggings(:welcome_general)
693
+ p = Post.find(posts(:welcome).id, :include => :taggings)
694
+ assert_no_queries {assert p.taggings.include?(expected)}
695
+ assert posts(:welcome).taggings.include?(taggings(:welcome_general))
696
+ end
697
+
698
+ def test_polymorphic_has_one
699
+ expected = posts(:welcome)
700
+
701
+ tagging = Tagging.find(taggings(:welcome_general).id, :include => :taggable)
702
+ assert_no_queries { assert_equal expected, tagging.taggable}
703
+ end
704
+
705
+ def test_polymorphic_belongs_to
706
+ p = Post.find(posts(:welcome).id, :include => {:taggings => :taggable})
707
+ assert_no_queries {assert_equal posts(:welcome), p.taggings.first.taggable}
708
+ end
709
+
710
+ def test_preload_polymorphic_has_many_through
711
+ posts = Post.find(:all, :order => 'posts.id')
712
+ posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
713
+ assert_equal posts.length, posts_with_tags.length
714
+ posts.length.times do |i|
715
+ assert_equal posts[i].tags.length, assert_no_queries { posts_with_tags[i].tags.length }
716
+ end
717
+ end
718
+
719
+ def test_preload_polymorph_many_types
720
+ taggings = Tagging.find :all, :include => :taggable, :conditions => ['taggable_type != ?', 'FakeModel']
721
+ assert_no_queries do
722
+ taggings.first.taggable.id
723
+ taggings[1].taggable.id
724
+ end
725
+
726
+ taggables = taggings.map(&:taggable)
727
+ assert taggables.include?(items(:dvd))
728
+ assert taggables.include?(posts(:welcome))
729
+ end
730
+
731
+ def test_preload_nil_polymorphic_belongs_to
732
+ assert_nothing_raised do
733
+ taggings = Tagging.find(:all, :include => :taggable, :conditions => ['taggable_type IS NULL'])
734
+ end
735
+ end
736
+
737
+ def test_preload_polymorphic_has_many
738
+ posts = Post.find(:all, :order => 'posts.id')
739
+ posts_with_taggings = Post.find(:all, :include => :taggings, :order => 'posts.id')
740
+ assert_equal posts.length, posts_with_taggings.length
741
+ posts.length.times do |i|
742
+ assert_equal posts[i].taggings.length, assert_no_queries { posts_with_taggings[i].taggings.length }
743
+ end
744
+ end
745
+
746
+ def test_belongs_to_shared_parent
747
+ comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 1')
748
+ assert_no_queries do
749
+ assert_equal comments.first.post, comments[1].post
750
+ end
751
+ end
752
+
753
+ def test_has_many_through_include_uses_array_include_after_loaded
754
+ david = authors(:david)
755
+ david.categories.class # force load target
756
+
757
+ category = david.categories.first
758
+
759
+ assert_no_queries do
760
+ assert david.categories.loaded?
761
+ assert david.categories.include?(category)
762
+ end
763
+ end
764
+
765
+ def test_has_many_through_include_checks_if_record_exists_if_target_not_loaded
766
+ david = authors(:david)
767
+ category = david.categories.first
768
+
769
+ david.reload
770
+ assert ! david.categories.loaded?
771
+ assert_queries(1) do
772
+ assert david.categories.include?(category)
773
+ end
774
+ assert ! david.categories.loaded?
775
+ end
776
+
777
+ unless current_adapter?(:IBM_DBAdapter) #works fine stand alone, however when run as part of whole suite it breaks unique constraint
778
+ def test_has_many_through_include_returns_false_for_non_matching_record_to_verify_scoping
779
+ david = authors(:david)
780
+ category = Category.create!(:name => 'Not Associated')
781
+
782
+ assert ! david.categories.loaded?
783
+ assert ! david.categories.include?(category)
784
+ end
785
+ end
786
+
787
+ private
788
+ # create dynamic Post models to allow different dependency options
789
+ def find_post_with_dependency(post_id, association, association_name, dependency)
790
+ class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
791
+ Post.find(post_id).update_attribute :type, class_name
792
+ klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
793
+ klass.set_table_name 'posts'
794
+ klass.send(association, association_name, :as => :taggable, :dependent => dependency)
795
+ klass.find(post_id)
796
+ end
797
+ end