activerecord 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (311) hide show
  1. data/CHANGELOG +4928 -3
  2. data/README +45 -46
  3. data/RUNNING_UNIT_TESTS +8 -11
  4. data/Rakefile +247 -0
  5. data/install.rb +8 -38
  6. data/lib/active_record/aggregations.rb +64 -49
  7. data/lib/active_record/associations/association_collection.rb +217 -47
  8. data/lib/active_record/associations/association_proxy.rb +159 -0
  9. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
  12. data/lib/active_record/associations/has_many_association.rb +145 -75
  13. data/lib/active_record/associations/has_many_through_association.rb +283 -0
  14. data/lib/active_record/associations/has_one_association.rb +96 -0
  15. data/lib/active_record/associations.rb +1537 -304
  16. data/lib/active_record/attribute_methods.rb +328 -0
  17. data/lib/active_record/base.rb +2001 -588
  18. data/lib/active_record/calculations.rb +269 -0
  19. data/lib/active_record/callbacks.rb +169 -165
  20. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
  21. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
  22. data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
  23. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  24. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
  25. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
  26. data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  30. data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
  31. data/lib/active_record/fixtures.rb +946 -100
  32. data/lib/active_record/locking/optimistic.rb +144 -0
  33. data/lib/active_record/locking/pessimistic.rb +77 -0
  34. data/lib/active_record/migration.rb +417 -0
  35. data/lib/active_record/observer.rb +142 -32
  36. data/lib/active_record/query_cache.rb +23 -0
  37. data/lib/active_record/reflection.rb +163 -70
  38. data/lib/active_record/schema.rb +58 -0
  39. data/lib/active_record/schema_dumper.rb +171 -0
  40. data/lib/active_record/serialization.rb +98 -0
  41. data/lib/active_record/serializers/json_serializer.rb +71 -0
  42. data/lib/active_record/serializers/xml_serializer.rb +315 -0
  43. data/lib/active_record/timestamp.rb +41 -0
  44. data/lib/active_record/transactions.rb +87 -57
  45. data/lib/active_record/validations.rb +909 -122
  46. data/lib/active_record/vendor/db2.rb +362 -0
  47. data/lib/active_record/vendor/mysql.rb +126 -29
  48. data/lib/active_record/version.rb +9 -0
  49. data/lib/active_record.rb +35 -7
  50. data/lib/activerecord.rb +1 -0
  51. data/test/aaa_create_tables_test.rb +72 -0
  52. data/test/abstract_unit.rb +73 -5
  53. data/test/active_schema_test_mysql.rb +43 -0
  54. data/test/adapter_test.rb +105 -0
  55. data/test/adapter_test_sqlserver.rb +95 -0
  56. data/test/aggregations_test.rb +110 -16
  57. data/test/all.sh +2 -2
  58. data/test/ar_schema_test.rb +33 -0
  59. data/test/association_inheritance_reload.rb +14 -0
  60. data/test/associations/ar_joins_test.rb +0 -0
  61. data/test/associations/callbacks_test.rb +147 -0
  62. data/test/associations/cascaded_eager_loading_test.rb +110 -0
  63. data/test/associations/eager_singularization_test.rb +145 -0
  64. data/test/associations/eager_test.rb +442 -0
  65. data/test/associations/extension_test.rb +47 -0
  66. data/test/associations/inner_join_association_test.rb +88 -0
  67. data/test/associations/join_model_test.rb +553 -0
  68. data/test/associations_test.rb +1930 -267
  69. data/test/attribute_methods_test.rb +146 -0
  70. data/test/base_test.rb +1316 -84
  71. data/test/binary_test.rb +32 -0
  72. data/test/calculations_test.rb +251 -0
  73. data/test/callbacks_test.rb +400 -0
  74. data/test/class_inheritable_attributes_test.rb +3 -4
  75. data/test/column_alias_test.rb +17 -0
  76. data/test/connection_test_firebird.rb +8 -0
  77. data/test/connection_test_mysql.rb +30 -0
  78. data/test/connections/native_db2/connection.rb +25 -0
  79. data/test/connections/native_firebird/connection.rb +26 -0
  80. data/test/connections/native_frontbase/connection.rb +27 -0
  81. data/test/connections/native_mysql/connection.rb +21 -18
  82. data/test/connections/native_openbase/connection.rb +21 -0
  83. data/test/connections/native_oracle/connection.rb +27 -0
  84. data/test/connections/native_postgresql/connection.rb +17 -18
  85. data/test/connections/native_sqlite/connection.rb +17 -16
  86. data/test/connections/native_sqlite3/connection.rb +25 -0
  87. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  88. data/test/connections/native_sybase/connection.rb +23 -0
  89. data/test/copy_table_test_sqlite.rb +69 -0
  90. data/test/datatype_test_postgresql.rb +203 -0
  91. data/test/date_time_test.rb +37 -0
  92. data/test/default_test_firebird.rb +16 -0
  93. data/test/defaults_test.rb +67 -0
  94. data/test/deprecated_finder_test.rb +30 -0
  95. data/test/finder_test.rb +607 -32
  96. data/test/fixtures/accounts.yml +28 -0
  97. data/test/fixtures/all/developers.yml +0 -0
  98. data/test/fixtures/all/people.csv +0 -0
  99. data/test/fixtures/all/tasks.yml +0 -0
  100. data/test/fixtures/author.rb +107 -0
  101. data/test/fixtures/author_favorites.yml +4 -0
  102. data/test/fixtures/authors.yml +7 -0
  103. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  104. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  105. data/test/fixtures/bad_fixtures/blank_line +3 -0
  106. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  107. data/test/fixtures/bad_fixtures/missing_value +1 -0
  108. data/test/fixtures/binaries.yml +132 -0
  109. data/test/fixtures/binary.rb +2 -0
  110. data/test/fixtures/book.rb +4 -0
  111. data/test/fixtures/books.yml +7 -0
  112. data/test/fixtures/categories/special_categories.yml +9 -0
  113. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  114. data/test/fixtures/categories.yml +14 -0
  115. data/test/fixtures/categories_ordered.yml +7 -0
  116. data/test/fixtures/categories_posts.yml +23 -0
  117. data/test/fixtures/categorization.rb +5 -0
  118. data/test/fixtures/categorizations.yml +17 -0
  119. data/test/fixtures/category.rb +26 -0
  120. data/test/fixtures/citation.rb +6 -0
  121. data/test/fixtures/comment.rb +23 -0
  122. data/test/fixtures/comments.yml +59 -0
  123. data/test/fixtures/companies.yml +55 -0
  124. data/test/fixtures/company.rb +81 -4
  125. data/test/fixtures/company_in_module.rb +32 -6
  126. data/test/fixtures/computer.rb +4 -0
  127. data/test/fixtures/computers.yml +4 -0
  128. data/test/fixtures/contact.rb +16 -0
  129. data/test/fixtures/courses.yml +7 -0
  130. data/test/fixtures/customer.rb +28 -3
  131. data/test/fixtures/customers.yml +17 -0
  132. data/test/fixtures/db_definitions/db2.drop.sql +33 -0
  133. data/test/fixtures/db_definitions/db2.sql +235 -0
  134. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  135. data/test/fixtures/db_definitions/db22.sql +5 -0
  136. data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
  137. data/test/fixtures/db_definitions/firebird.sql +310 -0
  138. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  139. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  140. data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
  141. data/test/fixtures/db_definitions/frontbase.sql +273 -0
  142. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  143. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  144. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  145. data/test/fixtures/db_definitions/openbase.sql +318 -0
  146. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  148. data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
  149. data/test/fixtures/db_definitions/oracle.sql +330 -0
  150. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  151. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  152. data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
  153. data/test/fixtures/db_definitions/postgresql.sql +217 -38
  154. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/postgresql2.sql +2 -2
  156. data/test/fixtures/db_definitions/schema.rb +354 -0
  157. data/test/fixtures/db_definitions/schema2.rb +11 -0
  158. data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
  159. data/test/fixtures/db_definitions/sqlite.sql +139 -5
  160. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  161. data/test/fixtures/db_definitions/sqlite2.sql +1 -0
  162. data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
  163. data/test/fixtures/db_definitions/sybase.sql +222 -0
  164. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  165. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  166. data/test/fixtures/developer.rb +70 -6
  167. data/test/fixtures/developers.yml +21 -0
  168. data/test/fixtures/developers_projects/david_action_controller +2 -1
  169. data/test/fixtures/developers_projects/david_active_record +2 -1
  170. data/test/fixtures/developers_projects.yml +17 -0
  171. data/test/fixtures/edge.rb +5 -0
  172. data/test/fixtures/edges.yml +6 -0
  173. data/test/fixtures/entrants.yml +14 -0
  174. data/test/fixtures/example.log +1 -0
  175. data/test/fixtures/fk_test_has_fk.yml +3 -0
  176. data/test/fixtures/fk_test_has_pk.yml +2 -0
  177. data/test/fixtures/flowers.jpg +0 -0
  178. data/test/fixtures/funny_jokes.yml +10 -0
  179. data/test/fixtures/item.rb +7 -0
  180. data/test/fixtures/items.yml +4 -0
  181. data/test/fixtures/joke.rb +3 -0
  182. data/test/fixtures/keyboard.rb +3 -0
  183. data/test/fixtures/legacy_thing.rb +3 -0
  184. data/test/fixtures/legacy_things.yml +3 -0
  185. data/test/fixtures/matey.rb +4 -0
  186. data/test/fixtures/mateys.yml +4 -0
  187. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  188. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  189. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  190. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  191. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  192. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  193. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  194. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  195. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  196. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  197. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  198. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  199. data/test/fixtures/minimalistic.rb +2 -0
  200. data/test/fixtures/minimalistics.yml +2 -0
  201. data/test/fixtures/mixed_case_monkey.rb +3 -0
  202. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  203. data/test/fixtures/mixins.yml +29 -0
  204. data/test/fixtures/movies.yml +7 -0
  205. data/test/fixtures/naked/csv/accounts.csv +1 -0
  206. data/test/fixtures/naked/yml/accounts.yml +1 -0
  207. data/test/fixtures/naked/yml/companies.yml +1 -0
  208. data/test/fixtures/naked/yml/courses.yml +1 -0
  209. data/test/fixtures/order.rb +4 -0
  210. data/test/fixtures/parrot.rb +13 -0
  211. data/test/fixtures/parrots.yml +27 -0
  212. data/test/fixtures/parrots_pirates.yml +7 -0
  213. data/test/fixtures/people.yml +3 -0
  214. data/test/fixtures/person.rb +4 -0
  215. data/test/fixtures/pirate.rb +5 -0
  216. data/test/fixtures/pirates.yml +9 -0
  217. data/test/fixtures/post.rb +59 -0
  218. data/test/fixtures/posts.yml +48 -0
  219. data/test/fixtures/project.rb +27 -2
  220. data/test/fixtures/projects.yml +7 -0
  221. data/test/fixtures/reader.rb +4 -0
  222. data/test/fixtures/readers.yml +4 -0
  223. data/test/fixtures/reply.rb +18 -2
  224. data/test/fixtures/reserved_words/distinct.yml +5 -0
  225. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  226. data/test/fixtures/reserved_words/group.yml +14 -0
  227. data/test/fixtures/reserved_words/select.yml +8 -0
  228. data/test/fixtures/reserved_words/values.yml +7 -0
  229. data/test/fixtures/ship.rb +3 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/subject.rb +4 -0
  232. data/test/fixtures/subscriber.rb +4 -3
  233. data/test/fixtures/tag.rb +7 -0
  234. data/test/fixtures/tagging.rb +10 -0
  235. data/test/fixtures/taggings.yml +25 -0
  236. data/test/fixtures/tags.yml +7 -0
  237. data/test/fixtures/task.rb +3 -0
  238. data/test/fixtures/tasks.yml +7 -0
  239. data/test/fixtures/topic.rb +20 -3
  240. data/test/fixtures/topics.yml +22 -0
  241. data/test/fixtures/treasure.rb +4 -0
  242. data/test/fixtures/treasures.yml +10 -0
  243. data/test/fixtures/vertex.rb +9 -0
  244. data/test/fixtures/vertices.yml +4 -0
  245. data/test/fixtures_test.rb +574 -8
  246. data/test/inheritance_test.rb +113 -27
  247. data/test/json_serialization_test.rb +180 -0
  248. data/test/lifecycle_test.rb +56 -29
  249. data/test/locking_test.rb +273 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +933 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_test.rb +95 -0
  254. data/test/modules_test.rb +23 -10
  255. data/test/multiple_db_test.rb +17 -3
  256. data/test/pk_test.rb +59 -15
  257. data/test/query_cache_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +124 -27
  260. data/test/reserved_word_test_mysql.rb +177 -0
  261. data/test/schema_authorization_test_postgresql.rb +75 -0
  262. data/test/schema_dumper_test.rb +131 -0
  263. data/test/schema_test_postgresql.rb +64 -0
  264. data/test/serialization_test.rb +47 -0
  265. data/test/synonym_test_oracle.rb +17 -0
  266. data/test/table_name_test_sqlserver.rb +23 -0
  267. data/test/threaded_connections_test.rb +48 -0
  268. data/test/transactions_test.rb +227 -29
  269. data/test/unconnected_test.rb +14 -6
  270. data/test/validations_test.rb +1293 -32
  271. data/test/xml_serialization_test.rb +202 -0
  272. metadata +347 -143
  273. data/dev-utils/eval_debugger.rb +0 -9
  274. data/examples/associations.rb +0 -87
  275. data/examples/shared_setup.rb +0 -15
  276. data/examples/validation.rb +0 -88
  277. data/lib/active_record/deprecated_associations.rb +0 -70
  278. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  279. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  280. data/lib/active_record/support/clean_logger.rb +0 -10
  281. data/lib/active_record/support/inflector.rb +0 -70
  282. data/lib/active_record/vendor/simple.rb +0 -702
  283. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  284. data/lib/active_record/wrappings.rb +0 -59
  285. data/rakefile +0 -122
  286. data/test/deprecated_associations_test.rb +0 -336
  287. data/test/fixtures/accounts/signals37 +0 -3
  288. data/test/fixtures/accounts/unknown +0 -2
  289. data/test/fixtures/companies/first_client +0 -6
  290. data/test/fixtures/companies/first_firm +0 -4
  291. data/test/fixtures/companies/second_client +0 -6
  292. data/test/fixtures/courses/java +0 -2
  293. data/test/fixtures/courses/ruby +0 -2
  294. data/test/fixtures/customers/david +0 -6
  295. data/test/fixtures/db_definitions/mysql.sql +0 -96
  296. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  297. data/test/fixtures/developers/david +0 -2
  298. data/test/fixtures/developers/jamis +0 -2
  299. data/test/fixtures/entrants/first +0 -3
  300. data/test/fixtures/entrants/second +0 -3
  301. data/test/fixtures/entrants/third +0 -3
  302. data/test/fixtures/fixture_database.sqlite +0 -0
  303. data/test/fixtures/fixture_database_2.sqlite +0 -0
  304. data/test/fixtures/movies/first +0 -2
  305. data/test/fixtures/movies/second +0 -2
  306. data/test/fixtures/projects/action_controller +0 -2
  307. data/test/fixtures/projects/active_record +0 -2
  308. data/test/fixtures/topics/first +0 -9
  309. data/test/fixtures/topics/second +0 -8
  310. data/test/inflector_test.rb +0 -104
  311. data/test/thread_safety_test.rb +0 -33
@@ -0,0 +1,442 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/post'
3
+ require 'fixtures/comment'
4
+ require 'fixtures/author'
5
+ require 'fixtures/category'
6
+ require 'fixtures/company'
7
+ require 'fixtures/person'
8
+ require 'fixtures/reader'
9
+
10
+ class EagerAssociationTest < Test::Unit::TestCase
11
+ fixtures :posts, :comments, :authors, :categories, :categories_posts,
12
+ :companies, :accounts, :tags, :people, :readers
13
+
14
+ def test_loading_with_one_association
15
+ posts = Post.find(:all, :include => :comments)
16
+ post = posts.find { |p| p.id == 1 }
17
+ assert_equal 2, post.comments.size
18
+ assert post.comments.include?(comments(:greetings))
19
+
20
+ post = Post.find(:first, :include => :comments, :conditions => "posts.title = 'Welcome to the weblog'")
21
+ assert_equal 2, post.comments.size
22
+ assert post.comments.include?(comments(:greetings))
23
+ end
24
+
25
+ def test_loading_conditions_with_or
26
+ posts = authors(:david).posts.find(:all, :include => :comments, :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'")
27
+ assert_nil posts.detect { |p| p.author_id != authors(:david).id },
28
+ "expected to find only david's posts"
29
+ end
30
+
31
+ def test_with_ordering
32
+ list = Post.find(:all, :include => :comments, :order => "posts.id DESC")
33
+ [:eager_other, :sti_habtm, :sti_post_and_comments, :sti_comments,
34
+ :authorless, :thinking, :welcome
35
+ ].each_with_index do |post, index|
36
+ assert_equal posts(post), list[index]
37
+ end
38
+ end
39
+
40
+ def test_with_two_tables_in_from_without_getting_double_quoted
41
+ posts = Post.find(:all,
42
+ :select => "posts.*",
43
+ :from => "authors, posts",
44
+ :include => :comments,
45
+ :conditions => "posts.author_id = authors.id",
46
+ :order => "posts.id"
47
+ )
48
+
49
+ assert_equal 2, posts.first.comments.size
50
+ end
51
+
52
+ def test_loading_with_multiple_associations
53
+ posts = Post.find(:all, :include => [ :comments, :author, :categories ], :order => "posts.id")
54
+ assert_equal 2, posts.first.comments.size
55
+ assert_equal 2, posts.first.categories.size
56
+ assert posts.first.comments.include?(comments(:greetings))
57
+ end
58
+
59
+ def test_loading_from_an_association
60
+ posts = authors(:david).posts.find(:all, :include => :comments, :order => "posts.id")
61
+ assert_equal 2, posts.first.comments.size
62
+ end
63
+
64
+ def test_loading_with_no_associations
65
+ assert_nil Post.find(posts(:authorless).id, :include => :author).author
66
+ end
67
+
68
+ def test_eager_association_loading_with_belongs_to
69
+ comments = Comment.find(:all, :include => :post)
70
+ assert_equal 10, comments.length
71
+ titles = comments.map { |c| c.post.title }
72
+ assert titles.include?(posts(:welcome).title)
73
+ assert titles.include?(posts(:sti_post_and_comments).title)
74
+ end
75
+
76
+ def test_eager_association_loading_with_belongs_to_and_limit
77
+ comments = Comment.find(:all, :include => :post, :limit => 5, :order => 'comments.id')
78
+ assert_equal 5, comments.length
79
+ assert_equal [1,2,3,5,6], comments.collect { |c| c.id }
80
+ end
81
+
82
+ def test_eager_association_loading_with_belongs_to_and_limit_and_conditions
83
+ comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :order => 'comments.id')
84
+ assert_equal 3, comments.length
85
+ assert_equal [5,6,7], comments.collect { |c| c.id }
86
+ end
87
+
88
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset
89
+ comments = Comment.find(:all, :include => :post, :limit => 3, :offset => 2, :order => 'comments.id')
90
+ assert_equal 3, comments.length
91
+ assert_equal [3,5,6], comments.collect { |c| c.id }
92
+ end
93
+
94
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions
95
+ comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id')
96
+ assert_equal 3, comments.length
97
+ assert_equal [6,7,8], comments.collect { |c| c.id }
98
+ end
99
+
100
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array
101
+ comments = Comment.find(:all, :include => :post, :conditions => ['post_id = ?',4], :limit => 3, :offset => 1, :order => 'comments.id')
102
+ assert_equal 3, comments.length
103
+ assert_equal [6,7,8], comments.collect { |c| c.id }
104
+ end
105
+
106
+ def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations
107
+ posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :order => 'posts.id')
108
+ assert_equal 1, posts.length
109
+ assert_equal [1], posts.collect { |p| p.id }
110
+ end
111
+
112
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations
113
+ posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id')
114
+ assert_equal 1, posts.length
115
+ assert_equal [2], posts.collect { |p| p.id }
116
+ end
117
+
118
+ def test_eager_association_loading_with_explicit_join
119
+ posts = Post.find(:all, :include => :comments, :joins => "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", :limit => 1, :order => 'author_id')
120
+ assert_equal 1, posts.length
121
+ end
122
+
123
+ def test_eager_with_has_many_through
124
+ posts_with_comments = people(:michael).posts.find(:all, :include => :comments)
125
+ posts_with_author = people(:michael).posts.find(:all, :include => :author )
126
+ posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ])
127
+ assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum += post.comments.size }
128
+ assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
129
+ assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
130
+ end
131
+
132
+ def test_eager_with_has_many_through_an_sti_join_model
133
+ author = Author.find(:first, :include => :special_post_comments, :order => 'authors.id')
134
+ assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments }
135
+ end
136
+
137
+ def test_eager_with_has_many_through_an_sti_join_model_with_conditions_on_both
138
+ author = Author.find(:first, :include => :special_nonexistant_post_comments, :order => 'authors.id')
139
+ assert_equal [], author.special_nonexistant_post_comments
140
+ end
141
+
142
+ def test_eager_with_has_many_through_join_model_with_conditions
143
+ assert_equal Author.find(:first, :include => :hello_post_comments,
144
+ :order => 'authors.id').hello_post_comments.sort_by(&:id),
145
+ Author.find(:first, :order => 'authors.id').hello_post_comments.sort_by(&:id)
146
+ end
147
+
148
+ def test_eager_with_has_many_and_limit
149
+ posts = Post.find(:all, :order => 'posts.id asc', :include => [ :author, :comments ], :limit => 2)
150
+ assert_equal 2, posts.size
151
+ assert_equal 3, posts.inject(0) { |sum, post| sum += post.comments.size }
152
+ end
153
+
154
+ def test_eager_with_has_many_and_limit_and_conditions
155
+ if current_adapter?(:OpenBaseAdapter)
156
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "FETCHBLOB(posts.body) = 'hello'", :order => "posts.id")
157
+ else
158
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.body = 'hello'", :order => "posts.id")
159
+ end
160
+ assert_equal 2, posts.size
161
+ assert_equal [4,5], posts.collect { |p| p.id }
162
+ end
163
+
164
+ def test_eager_with_has_many_and_limit_and_conditions_array
165
+ if current_adapter?(:OpenBaseAdapter)
166
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "FETCHBLOB(posts.body) = ?", 'hello' ], :order => "posts.id")
167
+ else
168
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "posts.body = ?", 'hello' ], :order => "posts.id")
169
+ end
170
+ assert_equal 2, posts.size
171
+ assert_equal [4,5], posts.collect { |p| p.id }
172
+ end
173
+
174
+ def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
175
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
176
+ assert_equal 2, posts.size
177
+
178
+ count = Post.count(:include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
179
+ assert_equal count, posts.size
180
+ end
181
+
182
+ def test_eager_with_has_many_and_limit_ond_high_offset
183
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
184
+ assert_equal 0, posts.size
185
+ end
186
+
187
+ def test_count_eager_with_has_many_and_limit_ond_high_offset
188
+ posts = Post.count(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
189
+ assert_equal 0, posts
190
+ end
191
+
192
+ def test_eager_with_has_many_and_limit_with_no_results
193
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'")
194
+ assert_equal 0, posts.size
195
+ end
196
+
197
+ def test_eager_count_performed_on_a_has_many_association_with_multi_table_conditional
198
+ author = authors(:david)
199
+ author_posts_without_comments = author.posts.select { |post| post.comments.blank? }
200
+ assert_equal author_posts_without_comments.size, author.posts.count(:all, :include => :comments, :conditions => 'comments.id is null')
201
+ end
202
+
203
+ def test_eager_with_has_and_belongs_to_many_and_limit
204
+ posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3)
205
+ assert_equal 3, posts.size
206
+ assert_equal 2, posts[0].categories.size
207
+ assert_equal 1, posts[1].categories.size
208
+ assert_equal 0, posts[2].categories.size
209
+ assert posts[0].categories.include?(categories(:technology))
210
+ assert posts[1].categories.include?(categories(:general))
211
+ end
212
+
213
+ def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
214
+ posts = authors(:david).posts.find(:all,
215
+ :include => :comments,
216
+ :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
217
+ :limit => 2
218
+ )
219
+ assert_equal 2, posts.size
220
+
221
+ count = Post.count(
222
+ :include => [ :comments, :author ],
223
+ :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
224
+ :limit => 2
225
+ )
226
+ assert_equal count, posts.size
227
+ end
228
+
229
+ def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
230
+ posts = nil
231
+ Post.with_scope(:find => {
232
+ :include => :comments,
233
+ :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'"
234
+ }) do
235
+ posts = authors(:david).posts.find(:all, :limit => 2)
236
+ assert_equal 2, posts.size
237
+ end
238
+
239
+ Post.with_scope(:find => {
240
+ :include => [ :comments, :author ],
241
+ :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')"
242
+ }) do
243
+ count = Post.count(:limit => 2)
244
+ assert_equal count, posts.size
245
+ end
246
+ end
247
+
248
+ def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the_eagers
249
+ Post.with_scope(:find => { :conditions => "1=1" }) do
250
+ posts = authors(:david).posts.find(:all,
251
+ :include => :comments,
252
+ :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
253
+ :limit => 2
254
+ )
255
+ assert_equal 2, posts.size
256
+
257
+ count = Post.count(
258
+ :include => [ :comments, :author ],
259
+ :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
260
+ :limit => 2
261
+ )
262
+ assert_equal count, posts.size
263
+ end
264
+ end
265
+
266
+ def test_eager_with_scoped_order_using_association_limiting_without_explicit_scope
267
+ posts_with_explicit_order = Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :order => 'posts.id DESC', :limit => 2)
268
+ posts_with_scoped_order = Post.with_scope(:find => {:order => 'posts.id DESC'}) do
269
+ Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :limit => 2)
270
+ end
271
+ assert_equal posts_with_explicit_order, posts_with_scoped_order
272
+ end
273
+
274
+ def test_eager_association_loading_with_habtm
275
+ posts = Post.find(:all, :include => :categories, :order => "posts.id")
276
+ assert_equal 2, posts[0].categories.size
277
+ assert_equal 1, posts[1].categories.size
278
+ assert_equal 0, posts[2].categories.size
279
+ assert posts[0].categories.include?(categories(:technology))
280
+ assert posts[1].categories.include?(categories(:general))
281
+ end
282
+
283
+ def test_eager_with_inheritance
284
+ posts = SpecialPost.find(:all, :include => [ :comments ])
285
+ end
286
+
287
+ def test_eager_has_one_with_association_inheritance
288
+ post = Post.find(4, :include => [ :very_special_comment ])
289
+ assert_equal "VerySpecialComment", post.very_special_comment.class.to_s
290
+ end
291
+
292
+ def test_eager_has_many_with_association_inheritance
293
+ post = Post.find(4, :include => [ :special_comments ])
294
+ post.special_comments.each do |special_comment|
295
+ assert_equal "SpecialComment", special_comment.class.to_s
296
+ end
297
+ end
298
+
299
+ def test_eager_habtm_with_association_inheritance
300
+ post = Post.find(6, :include => [ :special_categories ])
301
+ assert_equal 1, post.special_categories.size
302
+ post.special_categories.each do |special_category|
303
+ assert_equal "SpecialCategory", special_category.class.to_s
304
+ end
305
+ end
306
+
307
+ def test_eager_with_has_one_dependent_does_not_destroy_dependent
308
+ assert_not_nil companies(:first_firm).account
309
+ f = Firm.find(:first, :include => :account,
310
+ :conditions => ["companies.name = ?", "37signals"])
311
+ assert_not_nil f.account
312
+ assert_equal companies(:first_firm, :reload).account, f.account
313
+ end
314
+
315
+ def test_eager_with_multi_table_conditional_properly_counts_the_records_when_using_size
316
+ author = authors(:david)
317
+ posts_with_no_comments = author.posts.select { |post| post.comments.blank? }
318
+ assert_equal posts_with_no_comments.size, author.posts_with_no_comments.size
319
+ assert_equal posts_with_no_comments, author.posts_with_no_comments
320
+ end
321
+
322
+ def test_eager_with_invalid_association_reference
323
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
324
+ post = Post.find(6, :include=> :monkeys )
325
+ }
326
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
327
+ post = Post.find(6, :include=>[ :monkeys ])
328
+ }
329
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
330
+ post = Post.find(6, :include=>[ 'monkeys' ])
331
+ }
332
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
333
+ post = Post.find(6, :include=>[ :monkeys, :elephants ])
334
+ }
335
+ end
336
+
337
+ def find_all_ordered(className, include=nil)
338
+ className.find(:all, :order=>"#{className.table_name}.#{className.primary_key}", :include=>include)
339
+ end
340
+
341
+ def test_limited_eager_with_order
342
+ assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title)', :limit => 2, :offset => 1)
343
+ assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC', :limit => 2, :offset => 1)
344
+ end
345
+
346
+ def test_limited_eager_with_multiple_order_columns
347
+ assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title), posts.id', :limit => 2, :offset => 1)
348
+ assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC, posts.id', :limit => 2, :offset => 1)
349
+ end
350
+
351
+ def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm
352
+ # Eager includes of has many and habtm associations aren't necessarily sorted in the same way
353
+ def assert_equal_after_sort(item1, item2, item3 = nil)
354
+ assert_equal(item1.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id})
355
+ assert_equal(item3.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) if item3
356
+ end
357
+ # Test regular association, association with conditions, association with
358
+ # STI, and association with conditions assured not to be true
359
+ post_types = [:posts, :other_posts, :special_posts]
360
+ # test both has_many and has_and_belongs_to_many
361
+ [Author, Category].each do |className|
362
+ d1 = find_all_ordered(className)
363
+ # test including all post types at once
364
+ d2 = find_all_ordered(className, post_types)
365
+ d1.each_index do |i|
366
+ assert_equal(d1[i], d2[i])
367
+ assert_equal_after_sort(d1[i].posts, d2[i].posts)
368
+ post_types[1..-1].each do |post_type|
369
+ # test including post_types together
370
+ d3 = find_all_ordered(className, [:posts, post_type])
371
+ assert_equal(d1[i], d3[i])
372
+ assert_equal_after_sort(d1[i].posts, d3[i].posts)
373
+ assert_equal_after_sort(d1[i].send(post_type), d2[i].send(post_type), d3[i].send(post_type))
374
+ end
375
+ end
376
+ end
377
+ end
378
+
379
+ def test_eager_with_multiple_associations_with_same_table_has_one
380
+ d1 = find_all_ordered(Firm)
381
+ d2 = find_all_ordered(Firm, :account)
382
+ d1.each_index do |i|
383
+ assert_equal(d1[i], d2[i])
384
+ assert_equal(d1[i].account, d2[i].account)
385
+ end
386
+ end
387
+
388
+ def test_eager_with_multiple_associations_with_same_table_belongs_to
389
+ firm_types = [:firm, :firm_with_basic_id, :firm_with_other_name, :firm_with_condition]
390
+ d1 = find_all_ordered(Client)
391
+ d2 = find_all_ordered(Client, firm_types)
392
+ d1.each_index do |i|
393
+ assert_equal(d1[i], d2[i])
394
+ firm_types.each { |type| assert_equal(d1[i].send(type), d2[i].send(type)) }
395
+ end
396
+ end
397
+ def test_eager_with_valid_association_as_string_not_symbol
398
+ assert_nothing_raised { Post.find(:all, :include => 'comments') }
399
+ end
400
+
401
+ def test_preconfigured_includes_with_belongs_to
402
+ author = posts(:welcome).author_with_posts
403
+ assert_equal 5, author.posts.size
404
+ end
405
+
406
+ def test_preconfigured_includes_with_has_one
407
+ comment = posts(:sti_comments).very_special_comment_with_post
408
+ assert_equal posts(:sti_comments), comment.post
409
+ end
410
+
411
+ def test_preconfigured_includes_with_has_many
412
+ posts = authors(:david).posts_with_comments
413
+ one = posts.detect { |p| p.id == 1 }
414
+ assert_equal 5, posts.size
415
+ assert_equal 2, one.comments.size
416
+ end
417
+
418
+ def test_preconfigured_includes_with_habtm
419
+ posts = authors(:david).posts_with_categories
420
+ one = posts.detect { |p| p.id == 1 }
421
+ assert_equal 5, posts.size
422
+ assert_equal 2, one.categories.size
423
+ end
424
+
425
+ def test_preconfigured_includes_with_has_many_and_habtm
426
+ posts = authors(:david).posts_with_comments_and_categories
427
+ one = posts.detect { |p| p.id == 1 }
428
+ assert_equal 5, posts.size
429
+ assert_equal 2, one.comments.size
430
+ assert_equal 2, one.categories.size
431
+ end
432
+
433
+ def test_count_with_include
434
+ if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
435
+ assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15")
436
+ elsif current_adapter?(:OpenBaseAdapter)
437
+ assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(FETCHBLOB(comments.body)) > 15")
438
+ else
439
+ assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(comments.body) > 15")
440
+ end
441
+ end
442
+ end
@@ -0,0 +1,47 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/post'
3
+ require 'fixtures/comment'
4
+ require 'fixtures/project'
5
+ require 'fixtures/developer'
6
+
7
+ class AssociationsExtensionsTest < Test::Unit::TestCase
8
+ fixtures :projects, :developers, :developers_projects, :comments, :posts
9
+
10
+ def test_extension_on_has_many
11
+ assert_equal comments(:more_greetings), posts(:welcome).comments.find_most_recent
12
+ end
13
+
14
+ def test_extension_on_habtm
15
+ assert_equal projects(:action_controller), developers(:david).projects.find_most_recent
16
+ end
17
+
18
+ def test_named_extension_on_habtm
19
+ assert_equal projects(:action_controller), developers(:david).projects_extended_by_name.find_most_recent
20
+ end
21
+
22
+ def test_named_two_extensions_on_habtm
23
+ assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_twice.find_most_recent
24
+ assert_equal projects(:active_record), developers(:david).projects_extended_by_name_twice.find_least_recent
25
+ end
26
+
27
+ def test_named_extension_and_block_on_habtm
28
+ assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_and_block.find_most_recent
29
+ assert_equal projects(:active_record), developers(:david).projects_extended_by_name_and_block.find_least_recent
30
+ end
31
+
32
+ def test_marshalling_extensions
33
+ david = developers(:david)
34
+ assert_equal projects(:action_controller), david.projects.find_most_recent
35
+
36
+ david = Marshal.load(Marshal.dump(david))
37
+ assert_equal projects(:action_controller), david.projects.find_most_recent
38
+ end
39
+
40
+ def test_marshalling_named_extensions
41
+ david = developers(:david)
42
+ assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
43
+
44
+ david = Marshal.load(Marshal.dump(david))
45
+ assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
46
+ end
47
+ end
@@ -0,0 +1,88 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/post'
3
+ require 'fixtures/comment'
4
+ require 'fixtures/author'
5
+ require 'fixtures/category'
6
+ require 'fixtures/categorization'
7
+
8
+ class InnerJoinAssociationTest < Test::Unit::TestCase
9
+ fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations
10
+
11
+ def test_construct_finder_sql_creates_inner_joins
12
+ sql = Author.send(:construct_finder_sql, :joins => :posts)
13
+ assert_match /INNER JOIN `?posts`? ON `?posts`?.author_id = authors.id/, sql
14
+ end
15
+
16
+ def test_construct_finder_sql_cascades_inner_joins
17
+ sql = Author.send(:construct_finder_sql, :joins => {:posts => :comments})
18
+ assert_match /INNER JOIN `?posts`? ON `?posts`?.author_id = authors.id/, sql
19
+ assert_match /INNER JOIN `?comments`? ON `?comments`?.post_id = posts.id/, sql
20
+ end
21
+
22
+ def test_construct_finder_sql_inner_joins_through_associations
23
+ sql = Author.send(:construct_finder_sql, :joins => :categorized_posts)
24
+ assert_match /INNER JOIN `?categorizations`?.*INNER JOIN `?posts`?/, sql
25
+ end
26
+
27
+ def test_construct_finder_sql_applies_association_conditions
28
+ sql = Author.send(:construct_finder_sql, :joins => :categories_like_general, :conditions => "TERMINATING_MARKER")
29
+ assert_match /INNER JOIN `?categories`? ON.*AND.*`?General`?.*TERMINATING_MARKER/, sql
30
+ end
31
+
32
+ def test_construct_finder_sql_unpacks_nested_joins
33
+ sql = Author.send(:construct_finder_sql, :joins => {:posts => [[:comments]]})
34
+ assert_no_match /inner join.*inner join.*inner join/i, sql, "only two join clauses should be present"
35
+ assert_match /INNER JOIN `?posts`? ON `?posts`?.author_id = authors.id/, sql
36
+ assert_match /INNER JOIN `?comments`? ON `?comments`?.post_id = `?posts`?.id/, sql
37
+ end
38
+
39
+ def test_construct_finder_sql_ignores_empty_joins_hash
40
+ sql = Author.send(:construct_finder_sql, :joins => {})
41
+ assert_no_match /JOIN/i, sql
42
+ end
43
+
44
+ def test_construct_finder_sql_ignores_empty_joins_array
45
+ sql = Author.send(:construct_finder_sql, :joins => [])
46
+ assert_no_match /JOIN/i, sql
47
+ end
48
+
49
+ def test_find_with_implicit_inner_joins_honors_readonly_without_select
50
+ authors = Author.find(:all, :joins => :posts)
51
+ assert !authors.empty?, "expected authors to be non-empty"
52
+ assert authors.all? {|a| a.readonly? }, "expected all authors to be readonly"
53
+ end
54
+
55
+ def test_find_with_implicit_inner_joins_honors_readonly_with_select
56
+ authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
57
+ assert !authors.empty?, "expected authors to be non-empty"
58
+ assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
59
+ end
60
+
61
+ def test_find_with_implicit_inner_joins_honors_readonly_false
62
+ authors = Author.find(:all, :joins => :posts, :readonly => false)
63
+ assert !authors.empty?, "expected authors to be non-empty"
64
+ assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
65
+ end
66
+
67
+ def test_find_with_implicit_inner_joins_does_not_set_associations
68
+ authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
69
+ assert !authors.empty?, "expected authors to be non-empty"
70
+ assert authors.all? {|a| !a.send(:instance_variables).include?("@posts")}, "expected no authors to have the @posts association loaded"
71
+ end
72
+
73
+ def test_count_honors_implicit_inner_joins
74
+ real_count = Author.find(:all).sum{|a| a.posts.count }
75
+ assert_equal real_count, Author.count(:joins => :posts), "plain inner join count should match the number of referenced posts records"
76
+ end
77
+
78
+ def test_calculate_honors_implicit_inner_joins
79
+ real_count = Author.find(:all).sum{|a| a.posts.count }
80
+ assert_equal real_count, Author.calculate(:count, 'authors.id', :joins => :posts), "plain inner join count should match the number of referenced posts records"
81
+ end
82
+
83
+ def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions
84
+ real_count = Author.find(:all).select {|a| a.posts.any? {|p| p.title =~ /^Welcome/} }.length
85
+ authors_with_welcoming_post_titles = Author.calculate(:count, 'authors.id', :joins => :posts, :distinct => true, :conditions => "posts.title like 'Welcome%'")
86
+ assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'"
87
+ end
88
+ end