ibm_db 2.5.6-x86-mingw32

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