activerecord_authorails 1.0.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 (270) hide show
  1. data/CHANGELOG +3043 -0
  2. data/README +360 -0
  3. data/RUNNING_UNIT_TESTS +64 -0
  4. data/Rakefile +226 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/associations.rb +87 -0
  7. data/examples/shared_setup.rb +15 -0
  8. data/examples/validation.rb +85 -0
  9. data/install.rb +30 -0
  10. data/lib/active_record.rb +85 -0
  11. data/lib/active_record/acts/list.rb +244 -0
  12. data/lib/active_record/acts/nested_set.rb +211 -0
  13. data/lib/active_record/acts/tree.rb +89 -0
  14. data/lib/active_record/aggregations.rb +191 -0
  15. data/lib/active_record/associations.rb +1637 -0
  16. data/lib/active_record/associations/association_collection.rb +190 -0
  17. data/lib/active_record/associations/association_proxy.rb +158 -0
  18. data/lib/active_record/associations/belongs_to_association.rb +56 -0
  19. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  20. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +169 -0
  21. data/lib/active_record/associations/has_many_association.rb +210 -0
  22. data/lib/active_record/associations/has_many_through_association.rb +247 -0
  23. data/lib/active_record/associations/has_one_association.rb +80 -0
  24. data/lib/active_record/attribute_methods.rb +75 -0
  25. data/lib/active_record/base.rb +2164 -0
  26. data/lib/active_record/calculations.rb +270 -0
  27. data/lib/active_record/callbacks.rb +367 -0
  28. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +279 -0
  29. data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +58 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +343 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +161 -0
  34. data/lib/active_record/connection_adapters/db2_adapter.rb +228 -0
  35. data/lib/active_record/connection_adapters/firebird_adapter.rb +728 -0
  36. data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +414 -0
  38. data/lib/active_record/connection_adapters/openbase_adapter.rb +350 -0
  39. data/lib/active_record/connection_adapters/oracle_adapter.rb +689 -0
  40. data/lib/active_record/connection_adapters/postgresql_adapter.rb +584 -0
  41. data/lib/active_record/connection_adapters/sqlite_adapter.rb +407 -0
  42. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +591 -0
  43. data/lib/active_record/connection_adapters/sybase_adapter.rb +662 -0
  44. data/lib/active_record/deprecated_associations.rb +104 -0
  45. data/lib/active_record/deprecated_finders.rb +44 -0
  46. data/lib/active_record/fixtures.rb +628 -0
  47. data/lib/active_record/locking/optimistic.rb +106 -0
  48. data/lib/active_record/locking/pessimistic.rb +77 -0
  49. data/lib/active_record/migration.rb +394 -0
  50. data/lib/active_record/observer.rb +178 -0
  51. data/lib/active_record/query_cache.rb +64 -0
  52. data/lib/active_record/reflection.rb +222 -0
  53. data/lib/active_record/schema.rb +58 -0
  54. data/lib/active_record/schema_dumper.rb +149 -0
  55. data/lib/active_record/timestamp.rb +51 -0
  56. data/lib/active_record/transactions.rb +136 -0
  57. data/lib/active_record/validations.rb +843 -0
  58. data/lib/active_record/vendor/db2.rb +362 -0
  59. data/lib/active_record/vendor/mysql.rb +1214 -0
  60. data/lib/active_record/vendor/simple.rb +693 -0
  61. data/lib/active_record/version.rb +9 -0
  62. data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
  63. data/lib/active_record/wrappings.rb +58 -0
  64. data/lib/active_record/xml_serialization.rb +308 -0
  65. data/test/aaa_create_tables_test.rb +59 -0
  66. data/test/abstract_unit.rb +77 -0
  67. data/test/active_schema_test_mysql.rb +31 -0
  68. data/test/adapter_test.rb +87 -0
  69. data/test/adapter_test_sqlserver.rb +81 -0
  70. data/test/aggregations_test.rb +95 -0
  71. data/test/all.sh +8 -0
  72. data/test/ar_schema_test.rb +33 -0
  73. data/test/association_inheritance_reload.rb +14 -0
  74. data/test/associations/callbacks_test.rb +126 -0
  75. data/test/associations/cascaded_eager_loading_test.rb +138 -0
  76. data/test/associations/eager_test.rb +393 -0
  77. data/test/associations/extension_test.rb +42 -0
  78. data/test/associations/join_model_test.rb +497 -0
  79. data/test/associations_test.rb +1809 -0
  80. data/test/attribute_methods_test.rb +49 -0
  81. data/test/base_test.rb +1586 -0
  82. data/test/binary_test.rb +37 -0
  83. data/test/calculations_test.rb +219 -0
  84. data/test/callbacks_test.rb +377 -0
  85. data/test/class_inheritable_attributes_test.rb +32 -0
  86. data/test/column_alias_test.rb +17 -0
  87. data/test/connection_test_firebird.rb +8 -0
  88. data/test/connections/native_db2/connection.rb +25 -0
  89. data/test/connections/native_firebird/connection.rb +26 -0
  90. data/test/connections/native_frontbase/connection.rb +27 -0
  91. data/test/connections/native_mysql/connection.rb +24 -0
  92. data/test/connections/native_openbase/connection.rb +21 -0
  93. data/test/connections/native_oracle/connection.rb +27 -0
  94. data/test/connections/native_postgresql/connection.rb +23 -0
  95. data/test/connections/native_sqlite/connection.rb +34 -0
  96. data/test/connections/native_sqlite3/connection.rb +34 -0
  97. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  98. data/test/connections/native_sqlserver/connection.rb +23 -0
  99. data/test/connections/native_sqlserver_odbc/connection.rb +25 -0
  100. data/test/connections/native_sybase/connection.rb +23 -0
  101. data/test/copy_table_sqlite.rb +64 -0
  102. data/test/datatype_test_postgresql.rb +52 -0
  103. data/test/default_test_firebird.rb +16 -0
  104. data/test/defaults_test.rb +60 -0
  105. data/test/deprecated_associations_test.rb +396 -0
  106. data/test/deprecated_finder_test.rb +151 -0
  107. data/test/empty_date_time_test.rb +25 -0
  108. data/test/finder_test.rb +504 -0
  109. data/test/fixtures/accounts.yml +28 -0
  110. data/test/fixtures/author.rb +99 -0
  111. data/test/fixtures/author_favorites.yml +4 -0
  112. data/test/fixtures/authors.yml +7 -0
  113. data/test/fixtures/auto_id.rb +4 -0
  114. data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
  115. data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
  116. data/test/fixtures/bad_fixtures/blank_line +3 -0
  117. data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
  118. data/test/fixtures/bad_fixtures/missing_value +1 -0
  119. data/test/fixtures/binary.rb +2 -0
  120. data/test/fixtures/categories.yml +14 -0
  121. data/test/fixtures/categories/special_categories.yml +9 -0
  122. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  123. data/test/fixtures/categories_ordered.yml +7 -0
  124. data/test/fixtures/categories_posts.yml +23 -0
  125. data/test/fixtures/categorization.rb +5 -0
  126. data/test/fixtures/categorizations.yml +17 -0
  127. data/test/fixtures/category.rb +20 -0
  128. data/test/fixtures/column_name.rb +3 -0
  129. data/test/fixtures/comment.rb +23 -0
  130. data/test/fixtures/comments.yml +59 -0
  131. data/test/fixtures/companies.yml +55 -0
  132. data/test/fixtures/company.rb +107 -0
  133. data/test/fixtures/company_in_module.rb +59 -0
  134. data/test/fixtures/computer.rb +3 -0
  135. data/test/fixtures/computers.yml +4 -0
  136. data/test/fixtures/course.rb +3 -0
  137. data/test/fixtures/courses.yml +7 -0
  138. data/test/fixtures/customer.rb +55 -0
  139. data/test/fixtures/customers.yml +17 -0
  140. data/test/fixtures/db_definitions/db2.drop.sql +32 -0
  141. data/test/fixtures/db_definitions/db2.sql +231 -0
  142. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  143. data/test/fixtures/db_definitions/db22.sql +5 -0
  144. data/test/fixtures/db_definitions/firebird.drop.sql +63 -0
  145. data/test/fixtures/db_definitions/firebird.sql +304 -0
  146. data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
  147. data/test/fixtures/db_definitions/firebird2.sql +6 -0
  148. data/test/fixtures/db_definitions/frontbase.drop.sql +32 -0
  149. data/test/fixtures/db_definitions/frontbase.sql +268 -0
  150. data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
  151. data/test/fixtures/db_definitions/frontbase2.sql +4 -0
  152. data/test/fixtures/db_definitions/mysql.drop.sql +32 -0
  153. data/test/fixtures/db_definitions/mysql.sql +234 -0
  154. data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
  155. data/test/fixtures/db_definitions/mysql2.sql +5 -0
  156. data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
  157. data/test/fixtures/db_definitions/openbase.sql +302 -0
  158. data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
  159. data/test/fixtures/db_definitions/openbase2.sql +7 -0
  160. data/test/fixtures/db_definitions/oracle.drop.sql +65 -0
  161. data/test/fixtures/db_definitions/oracle.sql +325 -0
  162. data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
  163. data/test/fixtures/db_definitions/oracle2.sql +6 -0
  164. data/test/fixtures/db_definitions/postgresql.drop.sql +37 -0
  165. data/test/fixtures/db_definitions/postgresql.sql +263 -0
  166. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  167. data/test/fixtures/db_definitions/postgresql2.sql +5 -0
  168. data/test/fixtures/db_definitions/schema.rb +60 -0
  169. data/test/fixtures/db_definitions/sqlite.drop.sql +32 -0
  170. data/test/fixtures/db_definitions/sqlite.sql +215 -0
  171. data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
  172. data/test/fixtures/db_definitions/sqlite2.sql +5 -0
  173. data/test/fixtures/db_definitions/sqlserver.drop.sql +34 -0
  174. data/test/fixtures/db_definitions/sqlserver.sql +243 -0
  175. data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
  176. data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
  177. data/test/fixtures/db_definitions/sybase.drop.sql +34 -0
  178. data/test/fixtures/db_definitions/sybase.sql +218 -0
  179. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  180. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  181. data/test/fixtures/default.rb +2 -0
  182. data/test/fixtures/developer.rb +52 -0
  183. data/test/fixtures/developers.yml +21 -0
  184. data/test/fixtures/developers_projects.yml +17 -0
  185. data/test/fixtures/developers_projects/david_action_controller +3 -0
  186. data/test/fixtures/developers_projects/david_active_record +3 -0
  187. data/test/fixtures/developers_projects/jamis_active_record +2 -0
  188. data/test/fixtures/edge.rb +5 -0
  189. data/test/fixtures/edges.yml +6 -0
  190. data/test/fixtures/entrant.rb +3 -0
  191. data/test/fixtures/entrants.yml +14 -0
  192. data/test/fixtures/fk_test_has_fk.yml +3 -0
  193. data/test/fixtures/fk_test_has_pk.yml +2 -0
  194. data/test/fixtures/flowers.jpg +0 -0
  195. data/test/fixtures/funny_jokes.yml +10 -0
  196. data/test/fixtures/joke.rb +6 -0
  197. data/test/fixtures/keyboard.rb +3 -0
  198. data/test/fixtures/legacy_thing.rb +3 -0
  199. data/test/fixtures/legacy_things.yml +3 -0
  200. data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
  201. data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
  202. data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
  203. data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
  204. data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
  205. data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
  206. data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
  207. data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
  208. data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
  209. data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
  210. data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
  211. data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
  212. data/test/fixtures/mixed_case_monkey.rb +3 -0
  213. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  214. data/test/fixtures/mixin.rb +63 -0
  215. data/test/fixtures/mixins.yml +127 -0
  216. data/test/fixtures/movie.rb +5 -0
  217. data/test/fixtures/movies.yml +7 -0
  218. data/test/fixtures/naked/csv/accounts.csv +1 -0
  219. data/test/fixtures/naked/yml/accounts.yml +1 -0
  220. data/test/fixtures/naked/yml/companies.yml +1 -0
  221. data/test/fixtures/naked/yml/courses.yml +1 -0
  222. data/test/fixtures/order.rb +4 -0
  223. data/test/fixtures/people.yml +3 -0
  224. data/test/fixtures/person.rb +4 -0
  225. data/test/fixtures/post.rb +58 -0
  226. data/test/fixtures/posts.yml +48 -0
  227. data/test/fixtures/project.rb +27 -0
  228. data/test/fixtures/projects.yml +7 -0
  229. data/test/fixtures/reader.rb +4 -0
  230. data/test/fixtures/readers.yml +4 -0
  231. data/test/fixtures/reply.rb +37 -0
  232. data/test/fixtures/subject.rb +4 -0
  233. data/test/fixtures/subscriber.rb +6 -0
  234. data/test/fixtures/subscribers/first +2 -0
  235. data/test/fixtures/subscribers/second +2 -0
  236. data/test/fixtures/tag.rb +7 -0
  237. data/test/fixtures/tagging.rb +6 -0
  238. data/test/fixtures/taggings.yml +18 -0
  239. data/test/fixtures/tags.yml +7 -0
  240. data/test/fixtures/task.rb +3 -0
  241. data/test/fixtures/tasks.yml +7 -0
  242. data/test/fixtures/topic.rb +25 -0
  243. data/test/fixtures/topics.yml +22 -0
  244. data/test/fixtures/vertex.rb +9 -0
  245. data/test/fixtures/vertices.yml +4 -0
  246. data/test/fixtures_test.rb +401 -0
  247. data/test/inheritance_test.rb +205 -0
  248. data/test/lifecycle_test.rb +137 -0
  249. data/test/locking_test.rb +190 -0
  250. data/test/method_scoping_test.rb +416 -0
  251. data/test/migration_test.rb +768 -0
  252. data/test/migration_test_firebird.rb +124 -0
  253. data/test/mixin_nested_set_test.rb +196 -0
  254. data/test/mixin_test.rb +550 -0
  255. data/test/modules_test.rb +34 -0
  256. data/test/multiple_db_test.rb +60 -0
  257. data/test/pk_test.rb +104 -0
  258. data/test/readonly_test.rb +107 -0
  259. data/test/reflection_test.rb +159 -0
  260. data/test/schema_authorization_test_postgresql.rb +75 -0
  261. data/test/schema_dumper_test.rb +96 -0
  262. data/test/schema_test_postgresql.rb +64 -0
  263. data/test/synonym_test_oracle.rb +17 -0
  264. data/test/table_name_test_sqlserver.rb +23 -0
  265. data/test/threaded_connections_test.rb +48 -0
  266. data/test/transactions_test.rb +230 -0
  267. data/test/unconnected_test.rb +32 -0
  268. data/test/validations_test.rb +1097 -0
  269. data/test/xml_serialization_test.rb +125 -0
  270. metadata +365 -0
@@ -0,0 +1,138 @@
1
+ require 'abstract_unit'
2
+ require 'active_record/acts/list'
3
+ require 'fixtures/post'
4
+ require 'fixtures/comment'
5
+ require 'fixtures/author'
6
+ require 'fixtures/category'
7
+ require 'fixtures/categorization'
8
+ require 'fixtures/mixin'
9
+ require 'fixtures/company'
10
+ require 'fixtures/topic'
11
+ require 'fixtures/reply'
12
+
13
+ class CascadedEagerLoadingTest < Test::Unit::TestCase
14
+ fixtures :authors, :mixins, :companies, :posts, :topics
15
+
16
+ def test_eager_association_loading_with_cascaded_two_levels
17
+ authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id")
18
+ assert_equal 2, authors.size
19
+ assert_equal 5, authors[0].posts.size
20
+ assert_equal 1, authors[1].posts.size
21
+ assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
22
+ end
23
+
24
+ def test_eager_association_loading_with_cascaded_two_levels_and_one_level
25
+ authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id")
26
+ assert_equal 2, authors.size
27
+ assert_equal 5, authors[0].posts.size
28
+ assert_equal 1, authors[1].posts.size
29
+ assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
30
+ assert_equal 1, authors[0].categorizations.size
31
+ assert_equal 2, authors[1].categorizations.size
32
+ end
33
+
34
+ def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations
35
+ authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id")
36
+ assert_equal 2, authors.size
37
+ assert_equal 5, authors[0].posts.size
38
+ assert_equal 1, authors[1].posts.size
39
+ assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
40
+ end
41
+
42
+ def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference
43
+ authors = Author.find(:all, :include=>{:posts=>[:comments, :author]}, :order=>"authors.id")
44
+ assert_equal 2, authors.size
45
+ assert_equal 5, authors[0].posts.size
46
+ assert_equal authors(:david).name, authors[0].name
47
+ assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq
48
+ end
49
+
50
+ def test_eager_association_loading_with_cascaded_two_levels_with_condition
51
+ authors = Author.find(:all, :include=>{:posts=>:comments}, :conditions=>"authors.id=1", :order=>"authors.id")
52
+ assert_equal 1, authors.size
53
+ assert_equal 5, authors[0].posts.size
54
+ end
55
+
56
+ def test_eager_association_loading_with_acts_as_tree
57
+ roots = TreeMixin.find(:all, :include=>"children", :conditions=>"mixins.parent_id IS NULL", :order=>"mixins.id")
58
+ assert_equal [mixins(:tree_1), mixins(:tree2_1), mixins(:tree3_1)], roots
59
+ assert_no_queries do
60
+ assert_equal 2, roots[0].children.size
61
+ assert_equal 0, roots[1].children.size
62
+ assert_equal 0, roots[2].children.size
63
+ end
64
+ end
65
+
66
+ def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong
67
+ firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id")
68
+ assert_equal 2, firms.size
69
+ assert_equal firms.first.account, firms.first.account.firm.account
70
+ assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account }
71
+ assert_equal companies(:first_firm).account.firm.account, assert_no_queries { firms.first.account.firm.account }
72
+ end
73
+
74
+ def test_eager_association_loading_with_has_many_sti
75
+ topics = Topic.find(:all, :include => :replies, :order => 'topics.id')
76
+ assert_equal [topics(:first), topics(:second)], topics
77
+ assert_no_queries do
78
+ assert_equal 1, topics[0].replies.size
79
+ assert_equal 0, topics[1].replies.size
80
+ end
81
+ end
82
+
83
+ def test_eager_association_loading_with_belongs_to_sti
84
+ replies = Reply.find(:all, :include => :topic, :order => 'topics.id')
85
+ assert_equal [topics(:second)], replies
86
+ assert_equal topics(:first), assert_no_queries { replies.first.topic }
87
+ end
88
+
89
+ def test_eager_association_loading_with_multiple_stis_and_order
90
+ author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => 'authors.name, comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4')
91
+ assert_equal authors(:david), author
92
+ assert_no_queries do
93
+ author.posts.first.special_comments
94
+ author.posts.first.very_special_comment
95
+ end
96
+ end
97
+
98
+ def test_eager_association_loading_of_stis_with_multiple_references
99
+ authors = Author.find(:all, :include => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4')
100
+ assert_equal [authors(:david)], authors
101
+ assert_no_queries do
102
+ authors.first.posts.first.special_comments.first.post.special_comments
103
+ authors.first.posts.first.special_comments.first.post.very_special_comment
104
+ end
105
+ end
106
+
107
+ def test_eager_association_loading_with_recursive_cascading_three_levels_has_many
108
+ root_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:children=>{:children=>:children}}, :order => 'mixins.id')
109
+ assert_equal mixins(:recursively_cascaded_tree_4), assert_no_queries { root_node.children.first.children.first.children.first }
110
+ end
111
+
112
+ def test_eager_association_loading_with_recursive_cascading_three_levels_has_one
113
+ root_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:first_child=>{:first_child=>:first_child}}, :order => 'mixins.id')
114
+ assert_equal mixins(:recursively_cascaded_tree_4), assert_no_queries { root_node.first_child.first_child.first_child }
115
+ end
116
+
117
+ def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to
118
+ leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:parent=>{:parent=>:parent}}, :order => 'mixins.id DESC')
119
+ assert_equal mixins(:recursively_cascaded_tree_1), assert_no_queries { leaf_node.parent.parent.parent }
120
+ end
121
+ end
122
+
123
+
124
+ require 'fixtures/vertex'
125
+ require 'fixtures/edge'
126
+ class CascadedEagerLoadingTest < Test::Unit::TestCase
127
+ fixtures :edges, :vertices
128
+
129
+ def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through
130
+ source = Vertex.find(:first, :include=>{:sinks=>{:sinks=>{:sinks=>:sinks}}}, :order => 'vertices.id')
131
+ assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first }
132
+ end
133
+
134
+ def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many
135
+ sink = Vertex.find(:first, :include=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC')
136
+ assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first }
137
+ end
138
+ end
@@ -0,0 +1,393 @@
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_loading_with_multiple_associations
41
+ posts = Post.find(:all, :include => [ :comments, :author, :categories ], :order => "posts.id")
42
+ assert_equal 2, posts.first.comments.size
43
+ assert_equal 2, posts.first.categories.size
44
+ assert posts.first.comments.include?(comments(:greetings))
45
+ end
46
+
47
+ def test_loading_from_an_association
48
+ posts = authors(:david).posts.find(:all, :include => :comments, :order => "posts.id")
49
+ assert_equal 2, posts.first.comments.size
50
+ end
51
+
52
+ def test_loading_with_no_associations
53
+ assert_nil Post.find(posts(:authorless).id, :include => :author).author
54
+ end
55
+
56
+ def test_eager_association_loading_with_belongs_to
57
+ comments = Comment.find(:all, :include => :post)
58
+ assert_equal 10, comments.length
59
+ titles = comments.map { |c| c.post.title }
60
+ assert titles.include?(posts(:welcome).title)
61
+ assert titles.include?(posts(:sti_post_and_comments).title)
62
+ end
63
+
64
+ def test_eager_association_loading_with_belongs_to_and_limit
65
+ comments = Comment.find(:all, :include => :post, :limit => 5, :order => 'comments.id')
66
+ assert_equal 5, comments.length
67
+ assert_equal [1,2,3,5,6], comments.collect { |c| c.id }
68
+ end
69
+
70
+ def test_eager_association_loading_with_belongs_to_and_limit_and_conditions
71
+ comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :order => 'comments.id')
72
+ assert_equal 3, comments.length
73
+ assert_equal [5,6,7], comments.collect { |c| c.id }
74
+ end
75
+
76
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset
77
+ comments = Comment.find(:all, :include => :post, :limit => 3, :offset => 2, :order => 'comments.id')
78
+ assert_equal 3, comments.length
79
+ assert_equal [3,5,6], comments.collect { |c| c.id }
80
+ end
81
+
82
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions
83
+ comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id')
84
+ assert_equal 3, comments.length
85
+ assert_equal [6,7,8], comments.collect { |c| c.id }
86
+ end
87
+
88
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array
89
+ comments = Comment.find(:all, :include => :post, :conditions => ['post_id = ?',4], :limit => 3, :offset => 1, :order => 'comments.id')
90
+ assert_equal 3, comments.length
91
+ assert_equal [6,7,8], comments.collect { |c| c.id }
92
+ end
93
+
94
+ def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations
95
+ posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :order => 'posts.id')
96
+ assert_equal 1, posts.length
97
+ assert_equal [1], posts.collect { |p| p.id }
98
+ end
99
+
100
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations
101
+ posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id')
102
+ assert_equal 1, posts.length
103
+ assert_equal [2], posts.collect { |p| p.id }
104
+ end
105
+
106
+ def test_eager_with_has_many_through
107
+ posts_with_comments = people(:michael).posts.find(:all, :include => :comments)
108
+ posts_with_author = people(:michael).posts.find(:all, :include => :author )
109
+ posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ])
110
+ assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum += post.comments.size }
111
+ assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
112
+ assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
113
+ end
114
+
115
+ def test_eager_with_has_many_through_an_sti_join_model
116
+ author = Author.find(:first, :include => :special_post_comments, :order => 'authors.id')
117
+ assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments }
118
+ end
119
+
120
+ def test_eager_with_has_many_through_an_sti_join_model_with_conditions_on_both
121
+ author = Author.find(:first, :include => :special_nonexistant_post_comments, :order => 'authors.id')
122
+ assert_equal [], author.special_nonexistant_post_comments
123
+ end
124
+
125
+ def test_eager_with_has_many_through_join_model_with_conditions
126
+ assert_equal Author.find(:first, :include => :hello_post_comments,
127
+ :order => 'authors.id').hello_post_comments.sort_by(&:id),
128
+ Author.find(:first, :order => 'authors.id').hello_post_comments.sort_by(&:id)
129
+ end
130
+
131
+ def test_eager_with_has_many_and_limit
132
+ posts = Post.find(:all, :order => 'posts.id asc', :include => [ :author, :comments ], :limit => 2)
133
+ assert_equal 2, posts.size
134
+ assert_equal 3, posts.inject(0) { |sum, post| sum += post.comments.size }
135
+ end
136
+
137
+ def test_eager_with_has_many_and_limit_and_conditions
138
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.body = 'hello'", :order => "posts.id")
139
+ assert_equal 2, posts.size
140
+ assert_equal [4,5], posts.collect { |p| p.id }
141
+ end
142
+
143
+ def test_eager_with_has_many_and_limit_and_conditions_array
144
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "posts.body = ?", 'hello' ], :order => "posts.id")
145
+ assert_equal 2, posts.size
146
+ assert_equal [4,5], posts.collect { |p| p.id }
147
+ end
148
+
149
+ def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
150
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
151
+ assert_equal 2, posts.size
152
+
153
+ count = Post.count(:include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
154
+ assert_equal count, posts.size
155
+ end
156
+
157
+ def test_eager_with_has_many_and_limit_ond_high_offset
158
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
159
+ assert_equal 0, posts.size
160
+ end
161
+
162
+ def test_count_eager_with_has_many_and_limit_ond_high_offset
163
+ posts = Post.count(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
164
+ assert_equal 0, posts
165
+ end
166
+
167
+ def test_eager_with_has_many_and_limit_with_no_results
168
+ posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'")
169
+ assert_equal 0, posts.size
170
+ end
171
+
172
+ def test_eager_with_has_and_belongs_to_many_and_limit
173
+ posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3)
174
+ assert_equal 3, posts.size
175
+ assert_equal 2, posts[0].categories.size
176
+ assert_equal 1, posts[1].categories.size
177
+ assert_equal 0, posts[2].categories.size
178
+ assert posts[0].categories.include?(categories(:technology))
179
+ assert posts[1].categories.include?(categories(:general))
180
+ end
181
+
182
+ def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
183
+ posts = authors(:david).posts.find(:all,
184
+ :include => :comments,
185
+ :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
186
+ :limit => 2
187
+ )
188
+ assert_equal 2, posts.size
189
+
190
+ count = Post.count(
191
+ :include => [ :comments, :author ],
192
+ :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
193
+ :limit => 2
194
+ )
195
+ assert_equal count, posts.size
196
+ end
197
+
198
+ def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
199
+ posts = nil
200
+ Post.with_scope(:find => {
201
+ :include => :comments,
202
+ :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'"
203
+ }) do
204
+ posts = authors(:david).posts.find(:all, :limit => 2)
205
+ assert_equal 2, posts.size
206
+ end
207
+
208
+ Post.with_scope(:find => {
209
+ :include => [ :comments, :author ],
210
+ :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')"
211
+ }) do
212
+ count = Post.count(:limit => 2)
213
+ assert_equal count, posts.size
214
+ end
215
+ end
216
+
217
+ def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the_eagers
218
+ Post.with_scope(:find => { :conditions => "1=1" }) do
219
+ posts = authors(:david).posts.find(:all,
220
+ :include => :comments,
221
+ :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
222
+ :limit => 2
223
+ )
224
+ assert_equal 2, posts.size
225
+
226
+ count = Post.count(
227
+ :include => [ :comments, :author ],
228
+ :conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
229
+ :limit => 2
230
+ )
231
+ assert_equal count, posts.size
232
+ end
233
+ end
234
+ def test_eager_association_loading_with_habtm
235
+ posts = Post.find(:all, :include => :categories, :order => "posts.id")
236
+ assert_equal 2, posts[0].categories.size
237
+ assert_equal 1, posts[1].categories.size
238
+ assert_equal 0, posts[2].categories.size
239
+ assert posts[0].categories.include?(categories(:technology))
240
+ assert posts[1].categories.include?(categories(:general))
241
+ end
242
+
243
+ def test_eager_with_inheritance
244
+ posts = SpecialPost.find(:all, :include => [ :comments ])
245
+ end
246
+
247
+ def test_eager_has_one_with_association_inheritance
248
+ post = Post.find(4, :include => [ :very_special_comment ])
249
+ assert_equal "VerySpecialComment", post.very_special_comment.class.to_s
250
+ end
251
+
252
+ def test_eager_has_many_with_association_inheritance
253
+ post = Post.find(4, :include => [ :special_comments ])
254
+ post.special_comments.each do |special_comment|
255
+ assert_equal "SpecialComment", special_comment.class.to_s
256
+ end
257
+ end
258
+
259
+ def test_eager_habtm_with_association_inheritance
260
+ post = Post.find(6, :include => [ :special_categories ])
261
+ assert_equal 1, post.special_categories.size
262
+ post.special_categories.each do |special_category|
263
+ assert_equal "SpecialCategory", special_category.class.to_s
264
+ end
265
+ end
266
+
267
+ def test_eager_with_has_one_dependent_does_not_destroy_dependent
268
+ assert_not_nil companies(:first_firm).account
269
+ f = Firm.find(:first, :include => :account,
270
+ :conditions => ["companies.name = ?", "37signals"])
271
+ assert_not_nil f.account
272
+ assert_equal companies(:first_firm, :reload).account, f.account
273
+ end
274
+
275
+ def test_eager_with_invalid_association_reference
276
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
277
+ post = Post.find(6, :include=> :monkeys )
278
+ }
279
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
280
+ post = Post.find(6, :include=>[ :monkeys ])
281
+ }
282
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
283
+ post = Post.find(6, :include=>[ 'monkeys' ])
284
+ }
285
+ assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
286
+ post = Post.find(6, :include=>[ :monkeys, :elephants ])
287
+ }
288
+ end
289
+
290
+ def find_all_ordered(className, include=nil)
291
+ className.find(:all, :order=>"#{className.table_name}.#{className.primary_key}", :include=>include)
292
+ end
293
+
294
+ def test_limited_eager_with_order
295
+ assert_equal [posts(:thinking), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title)', :limit => 2, :offset => 1)
296
+ assert_equal [posts(:sti_post_and_comments), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC', :limit => 2, :offset => 1)
297
+ end
298
+
299
+ def test_limited_eager_with_multiple_order_columns
300
+ assert_equal [posts(:thinking), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title), posts.id', :limit => 2, :offset => 1)
301
+ assert_equal [posts(:sti_post_and_comments), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC, posts.id', :limit => 2, :offset => 1)
302
+ end
303
+
304
+ def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm
305
+ # Eager includes of has many and habtm associations aren't necessarily sorted in the same way
306
+ def assert_equal_after_sort(item1, item2, item3 = nil)
307
+ assert_equal(item1.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id})
308
+ assert_equal(item3.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) if item3
309
+ end
310
+ # Test regular association, association with conditions, association with
311
+ # STI, and association with conditions assured not to be true
312
+ post_types = [:posts, :other_posts, :special_posts]
313
+ # test both has_many and has_and_belongs_to_many
314
+ [Author, Category].each do |className|
315
+ d1 = find_all_ordered(className)
316
+ # test including all post types at once
317
+ d2 = find_all_ordered(className, post_types)
318
+ d1.each_index do |i|
319
+ assert_equal(d1[i], d2[i])
320
+ assert_equal_after_sort(d1[i].posts, d2[i].posts)
321
+ post_types[1..-1].each do |post_type|
322
+ # test including post_types together
323
+ d3 = find_all_ordered(className, [:posts, post_type])
324
+ assert_equal(d1[i], d3[i])
325
+ assert_equal_after_sort(d1[i].posts, d3[i].posts)
326
+ assert_equal_after_sort(d1[i].send(post_type), d2[i].send(post_type), d3[i].send(post_type))
327
+ end
328
+ end
329
+ end
330
+ end
331
+
332
+ def test_eager_with_multiple_associations_with_same_table_has_one
333
+ d1 = find_all_ordered(Firm)
334
+ d2 = find_all_ordered(Firm, :account)
335
+ d1.each_index do |i|
336
+ assert_equal(d1[i], d2[i])
337
+ assert_equal(d1[i].account, d2[i].account)
338
+ end
339
+ end
340
+
341
+ def test_eager_with_multiple_associations_with_same_table_belongs_to
342
+ firm_types = [:firm, :firm_with_basic_id, :firm_with_other_name, :firm_with_condition]
343
+ d1 = find_all_ordered(Client)
344
+ d2 = find_all_ordered(Client, firm_types)
345
+ d1.each_index do |i|
346
+ assert_equal(d1[i], d2[i])
347
+ firm_types.each { |type| assert_equal(d1[i].send(type), d2[i].send(type)) }
348
+ end
349
+ end
350
+ def test_eager_with_valid_association_as_string_not_symbol
351
+ assert_nothing_raised { Post.find(:all, :include => 'comments') }
352
+ end
353
+
354
+ def test_preconfigured_includes_with_belongs_to
355
+ author = posts(:welcome).author_with_posts
356
+ assert_equal 5, author.posts.size
357
+ end
358
+
359
+ def test_preconfigured_includes_with_has_one
360
+ comment = posts(:sti_comments).very_special_comment_with_post
361
+ assert_equal posts(:sti_comments), comment.post
362
+ end
363
+
364
+ def test_preconfigured_includes_with_has_many
365
+ posts = authors(:david).posts_with_comments
366
+ one = posts.detect { |p| p.id == 1 }
367
+ assert_equal 5, posts.size
368
+ assert_equal 2, one.comments.size
369
+ end
370
+
371
+ def test_preconfigured_includes_with_habtm
372
+ posts = authors(:david).posts_with_categories
373
+ one = posts.detect { |p| p.id == 1 }
374
+ assert_equal 5, posts.size
375
+ assert_equal 2, one.categories.size
376
+ end
377
+
378
+ def test_preconfigured_includes_with_has_many_and_habtm
379
+ posts = authors(:david).posts_with_comments_and_categories
380
+ one = posts.detect { |p| p.id == 1 }
381
+ assert_equal 5, posts.size
382
+ assert_equal 2, one.comments.size
383
+ assert_equal 2, one.categories.size
384
+ end
385
+
386
+ def test_count_with_include
387
+ if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
388
+ assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15")
389
+ else
390
+ assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(comments.body) > 15")
391
+ end
392
+ end
393
+ end