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,147 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/post'
3
+ require 'fixtures/comment'
4
+ require 'fixtures/author'
5
+ require 'fixtures/category'
6
+ require 'fixtures/project'
7
+ require 'fixtures/developer'
8
+
9
+ class AssociationCallbacksTest < Test::Unit::TestCase
10
+ fixtures :posts, :authors, :projects, :developers
11
+
12
+ def setup
13
+ @david = authors(:david)
14
+ @thinking = posts(:thinking)
15
+ @authorless = posts(:authorless)
16
+ assert @david.post_log.empty?
17
+ end
18
+
19
+ def test_adding_macro_callbacks
20
+ @david.posts_with_callbacks << @thinking
21
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}"], @david.post_log
22
+ @david.posts_with_callbacks << @thinking
23
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}", "before_adding#{@thinking.id}",
24
+ "after_adding#{@thinking.id}"], @david.post_log
25
+ end
26
+
27
+ def test_adding_with_proc_callbacks
28
+ @david.posts_with_proc_callbacks << @thinking
29
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}"], @david.post_log
30
+ @david.posts_with_proc_callbacks << @thinking
31
+ assert_equal ["before_adding#{@thinking.id}", "after_adding#{@thinking.id}", "before_adding#{@thinking.id}",
32
+ "after_adding#{@thinking.id}"], @david.post_log
33
+ end
34
+
35
+ def test_removing_with_macro_callbacks
36
+ first_post, second_post = @david.posts_with_callbacks[0, 2]
37
+ @david.posts_with_callbacks.delete(first_post)
38
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}"], @david.post_log
39
+ @david.posts_with_callbacks.delete(second_post)
40
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}", "before_removing#{second_post.id}",
41
+ "after_removing#{second_post.id}"], @david.post_log
42
+ end
43
+
44
+ def test_removing_with_proc_callbacks
45
+ first_post, second_post = @david.posts_with_callbacks[0, 2]
46
+ @david.posts_with_proc_callbacks.delete(first_post)
47
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}"], @david.post_log
48
+ @david.posts_with_proc_callbacks.delete(second_post)
49
+ assert_equal ["before_removing#{first_post.id}", "after_removing#{first_post.id}", "before_removing#{second_post.id}",
50
+ "after_removing#{second_post.id}"], @david.post_log
51
+ end
52
+
53
+ def test_multiple_callbacks
54
+ @david.posts_with_multiple_callbacks << @thinking
55
+ assert_equal ["before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}", "after_adding#{@thinking.id}",
56
+ "after_adding_proc#{@thinking.id}"], @david.post_log
57
+ @david.posts_with_multiple_callbacks << @thinking
58
+ assert_equal ["before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}", "after_adding#{@thinking.id}",
59
+ "after_adding_proc#{@thinking.id}", "before_adding#{@thinking.id}", "before_adding_proc#{@thinking.id}",
60
+ "after_adding#{@thinking.id}", "after_adding_proc#{@thinking.id}"], @david.post_log
61
+ end
62
+
63
+ def test_has_many_callbacks_with_create
64
+ morten = Author.create :name => "Morten"
65
+ post = morten.posts_with_proc_callbacks.create! :title => "Hello", :body => "How are you doing?"
66
+ assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log
67
+ end
68
+
69
+ def test_has_many_callbacks_with_create!
70
+ morten = Author.create! :name => "Morten"
71
+ post = morten.posts_with_proc_callbacks.create :title => "Hello", :body => "How are you doing?"
72
+ assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log
73
+ end
74
+
75
+ def test_has_many_callbacks_for_save_on_parent
76
+ jack = Author.new :name => "Jack"
77
+ post = jack.posts_with_callbacks.build :title => "Call me back!", :body => "Before you wake up and after you sleep"
78
+
79
+ callback_log = ["before_adding<new>", "after_adding#{jack.posts_with_callbacks.first.id}"]
80
+ assert_equal callback_log, jack.post_log
81
+ assert jack.save
82
+ assert_equal 1, jack.posts_with_callbacks.count
83
+ assert_equal callback_log, jack.post_log
84
+ end
85
+
86
+ def test_has_and_belongs_to_many_add_callback
87
+ david = developers(:david)
88
+ ar = projects(:active_record)
89
+ assert ar.developers_log.empty?
90
+ ar.developers_with_callbacks << david
91
+ assert_equal ["before_adding#{david.id}", "after_adding#{david.id}"], ar.developers_log
92
+ ar.developers_with_callbacks << david
93
+ assert_equal ["before_adding#{david.id}", "after_adding#{david.id}", "before_adding#{david.id}",
94
+ "after_adding#{david.id}"], ar.developers_log
95
+ end
96
+
97
+ def test_has_and_belongs_to_many_remove_callback
98
+ david = developers(:david)
99
+ jamis = developers(:jamis)
100
+ activerecord = projects(:active_record)
101
+ assert activerecord.developers_log.empty?
102
+ activerecord.developers_with_callbacks.delete(david)
103
+ assert_equal ["before_removing#{david.id}", "after_removing#{david.id}"], activerecord.developers_log
104
+
105
+ activerecord.developers_with_callbacks.delete(jamis)
106
+ assert_equal ["before_removing#{david.id}", "after_removing#{david.id}", "before_removing#{jamis.id}",
107
+ "after_removing#{jamis.id}"], activerecord.developers_log
108
+ end
109
+
110
+ def test_has_and_belongs_to_many_remove_callback_on_clear
111
+ activerecord = projects(:active_record)
112
+ assert activerecord.developers_log.empty?
113
+ if activerecord.developers_with_callbacks.size == 0
114
+ activerecord.developers << developers(:david)
115
+ activerecord.developers << developers(:jamis)
116
+ activerecord.reload
117
+ assert activerecord.developers_with_callbacks.size == 2
118
+ end
119
+ log_array = activerecord.developers_with_callbacks.collect {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.flatten.sort
120
+ assert activerecord.developers_with_callbacks.clear
121
+ assert_equal log_array, activerecord.developers_log.sort
122
+ end
123
+
124
+ def test_has_many_and_belongs_to_many_callbacks_for_save_on_parent
125
+ project = Project.new :name => "Callbacks"
126
+ project.developers_with_callbacks.build :name => "Jack", :salary => 95000
127
+
128
+ callback_log = ["before_adding<new>", "after_adding<new>"]
129
+ assert_equal callback_log, project.developers_log
130
+ assert project.save
131
+ assert_equal 1, project.developers_with_callbacks.count
132
+ assert_equal callback_log, project.developers_log
133
+ end
134
+
135
+ def test_dont_add_if_before_callback_raises_exception
136
+ assert !@david.unchangable_posts.include?(@authorless)
137
+ begin
138
+ @david.unchangable_posts << @authorless
139
+ rescue Exception => e
140
+ end
141
+ assert @david.post_log.empty?
142
+ assert !@david.unchangable_posts.include?(@authorless)
143
+ @david.reload
144
+ assert !@david.unchangable_posts.include?(@authorless)
145
+ end
146
+ end
147
+
@@ -0,0 +1,110 @@
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
+ require 'fixtures/company'
8
+ require 'fixtures/topic'
9
+ require 'fixtures/reply'
10
+
11
+ class CascadedEagerLoadingTest < Test::Unit::TestCase
12
+ fixtures :authors, :mixins, :companies, :posts, :topics
13
+
14
+ def test_eager_association_loading_with_cascaded_two_levels
15
+ authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id")
16
+ assert_equal 2, authors.size
17
+ assert_equal 5, authors[0].posts.size
18
+ assert_equal 1, authors[1].posts.size
19
+ assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
20
+ end
21
+
22
+ def test_eager_association_loading_with_cascaded_two_levels_and_one_level
23
+ authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id")
24
+ assert_equal 2, authors.size
25
+ assert_equal 5, authors[0].posts.size
26
+ assert_equal 1, authors[1].posts.size
27
+ assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
28
+ assert_equal 1, authors[0].categorizations.size
29
+ assert_equal 2, authors[1].categorizations.size
30
+ end
31
+
32
+ def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations
33
+ authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id")
34
+ assert_equal 2, authors.size
35
+ assert_equal 5, authors[0].posts.size
36
+ assert_equal 1, authors[1].posts.size
37
+ assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
38
+ end
39
+
40
+ def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference
41
+ authors = Author.find(:all, :include=>{:posts=>[:comments, :author]}, :order=>"authors.id")
42
+ assert_equal 2, authors.size
43
+ assert_equal 5, authors[0].posts.size
44
+ assert_equal authors(:david).name, authors[0].name
45
+ assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq
46
+ end
47
+
48
+ def test_eager_association_loading_with_cascaded_two_levels_with_condition
49
+ authors = Author.find(:all, :include=>{:posts=>:comments}, :conditions=>"authors.id=1", :order=>"authors.id")
50
+ assert_equal 1, authors.size
51
+ assert_equal 5, authors[0].posts.size
52
+ end
53
+
54
+ def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong
55
+ firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id")
56
+ assert_equal 2, firms.size
57
+ assert_equal firms.first.account, firms.first.account.firm.account
58
+ assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account }
59
+ assert_equal companies(:first_firm).account.firm.account, assert_no_queries { firms.first.account.firm.account }
60
+ end
61
+
62
+ def test_eager_association_loading_with_has_many_sti
63
+ topics = Topic.find(:all, :include => :replies, :order => 'topics.id')
64
+ assert_equal topics(:first, :second), topics
65
+ assert_no_queries do
66
+ assert_equal 1, topics[0].replies.size
67
+ assert_equal 0, topics[1].replies.size
68
+ end
69
+ end
70
+
71
+ def test_eager_association_loading_with_belongs_to_sti
72
+ replies = Reply.find(:all, :include => :topic, :order => 'topics.id')
73
+ assert_equal [topics(:second)], replies
74
+ assert_equal topics(:first), assert_no_queries { replies.first.topic }
75
+ end
76
+
77
+ def test_eager_association_loading_with_multiple_stis_and_order
78
+ 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')
79
+ assert_equal authors(:david), author
80
+ assert_no_queries do
81
+ author.posts.first.special_comments
82
+ author.posts.first.very_special_comment
83
+ end
84
+ end
85
+
86
+ def test_eager_association_loading_of_stis_with_multiple_references
87
+ 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')
88
+ assert_equal [authors(:david)], authors
89
+ assert_no_queries do
90
+ authors.first.posts.first.special_comments.first.post.special_comments
91
+ authors.first.posts.first.special_comments.first.post.very_special_comment
92
+ end
93
+ end
94
+ end
95
+
96
+ require 'fixtures/vertex'
97
+ require 'fixtures/edge'
98
+ class CascadedEagerLoadingTest < Test::Unit::TestCase
99
+ fixtures :edges, :vertices
100
+
101
+ def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through
102
+ source = Vertex.find(:first, :include=>{:sinks=>{:sinks=>{:sinks=>:sinks}}}, :order => 'vertices.id')
103
+ assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first }
104
+ end
105
+
106
+ def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many
107
+ sink = Vertex.find(:first, :include=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC')
108
+ assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first }
109
+ end
110
+ end
@@ -0,0 +1,145 @@
1
+ require 'abstract_unit'
2
+
3
+ class Virus < ActiveRecord::Base
4
+ belongs_to :octopus
5
+ end
6
+ class Octopus < ActiveRecord::Base
7
+ has_one :virus
8
+ end
9
+ class Pass < ActiveRecord::Base
10
+ belongs_to :bus
11
+ end
12
+ class Bus < ActiveRecord::Base
13
+ has_many :passes
14
+ end
15
+ class Mess < ActiveRecord::Base
16
+ has_and_belongs_to_many :crises
17
+ end
18
+ class Crisis < ActiveRecord::Base
19
+ has_and_belongs_to_many :messes
20
+ has_many :analyses, :dependent => :destroy
21
+ has_many :successes, :through => :analyses
22
+ has_many :dresses, :dependent => :destroy
23
+ has_many :compresses, :through => :dresses
24
+ end
25
+ class Analysis < ActiveRecord::Base
26
+ belongs_to :crisis
27
+ belongs_to :success
28
+ end
29
+ class Success < ActiveRecord::Base
30
+ has_many :analyses, :dependent => :destroy
31
+ has_many :crises, :through => :analyses
32
+ end
33
+ class Dress < ActiveRecord::Base
34
+ belongs_to :crisis
35
+ has_many :compresses
36
+ end
37
+ class Compress < ActiveRecord::Base
38
+ belongs_to :dress
39
+ end
40
+
41
+
42
+ class EagerSingularizationTest < Test::Unit::TestCase
43
+
44
+ def setup
45
+ if ActiveRecord::Base.connection.supports_migrations?
46
+ ActiveRecord::Base.connection.create_table :viri do |t|
47
+ t.column :octopus_id, :integer
48
+ t.column :species, :string
49
+ end
50
+ ActiveRecord::Base.connection.create_table :octopi do |t|
51
+ t.column :species, :string
52
+ end
53
+ ActiveRecord::Base.connection.create_table :passes do |t|
54
+ t.column :bus_id, :integer
55
+ t.column :rides, :integer
56
+ end
57
+ ActiveRecord::Base.connection.create_table :buses do |t|
58
+ t.column :name, :string
59
+ end
60
+ ActiveRecord::Base.connection.create_table :crises_messes, :id => false do |t|
61
+ t.column :crisis_id, :integer
62
+ t.column :mess_id, :integer
63
+ end
64
+ ActiveRecord::Base.connection.create_table :messes do |t|
65
+ t.column :name, :string
66
+ end
67
+ ActiveRecord::Base.connection.create_table :crises do |t|
68
+ t.column :name, :string
69
+ end
70
+ ActiveRecord::Base.connection.create_table :successes do |t|
71
+ t.column :name, :string
72
+ end
73
+ ActiveRecord::Base.connection.create_table :analyses do |t|
74
+ t.column :crisis_id, :integer
75
+ t.column :success_id, :integer
76
+ end
77
+ ActiveRecord::Base.connection.create_table :dresses do |t|
78
+ t.column :crisis_id, :integer
79
+ end
80
+ ActiveRecord::Base.connection.create_table :compresses do |t|
81
+ t.column :dress_id, :integer
82
+ end
83
+ @have_tables = true
84
+ else
85
+ @have_tables = false
86
+ end
87
+ end
88
+
89
+ def teardown
90
+ ActiveRecord::Base.connection.drop_table :viri
91
+ ActiveRecord::Base.connection.drop_table :octopi
92
+ ActiveRecord::Base.connection.drop_table :passes
93
+ ActiveRecord::Base.connection.drop_table :buses
94
+ ActiveRecord::Base.connection.drop_table :crises_messes
95
+ ActiveRecord::Base.connection.drop_table :messes
96
+ ActiveRecord::Base.connection.drop_table :crises
97
+ ActiveRecord::Base.connection.drop_table :successes
98
+ ActiveRecord::Base.connection.drop_table :analyses
99
+ ActiveRecord::Base.connection.drop_table :dresses
100
+ ActiveRecord::Base.connection.drop_table :compresses
101
+ end
102
+
103
+ def test_eager_no_extra_singularization_belongs_to
104
+ return unless @have_tables
105
+ assert_nothing_raised do
106
+ Virus.find(:all, :include => :octopus)
107
+ end
108
+ end
109
+
110
+ def test_eager_no_extra_singularization_has_one
111
+ return unless @have_tables
112
+ assert_nothing_raised do
113
+ Octopus.find(:all, :include => :virus)
114
+ end
115
+ end
116
+
117
+ def test_eager_no_extra_singularization_has_many
118
+ return unless @have_tables
119
+ assert_nothing_raised do
120
+ Bus.find(:all, :include => :passes)
121
+ end
122
+ end
123
+
124
+ def test_eager_no_extra_singularization_has_and_belongs_to_many
125
+ return unless @have_tables
126
+ assert_nothing_raised do
127
+ Crisis.find(:all, :include => :messes)
128
+ Mess.find(:all, :include => :crises)
129
+ end
130
+ end
131
+
132
+ def test_eager_no_extra_singularization_has_many_through_belongs_to
133
+ return unless @have_tables
134
+ assert_nothing_raised do
135
+ Crisis.find(:all, :include => :successes)
136
+ end
137
+ end
138
+
139
+ def test_eager_no_extra_singularization_has_many_through_has_many
140
+ return unless @have_tables
141
+ assert_nothing_raised do
142
+ Crisis.find(:all, :include => :compresses)
143
+ end
144
+ end
145
+ end