activerecord_csi 2.3.5.p6

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 (333) hide show
  1. data/CHANGELOG +5858 -0
  2. data/README +351 -0
  3. data/RUNNING_UNIT_TESTS +36 -0
  4. data/Rakefile +270 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/performance.rb +162 -0
  7. data/install.rb +30 -0
  8. data/lib/active_record/aggregations.rb +261 -0
  9. data/lib/active_record/association_preload.rb +389 -0
  10. data/lib/active_record/associations/association_collection.rb +475 -0
  11. data/lib/active_record/associations/association_proxy.rb +278 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +76 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +122 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +266 -0
  17. data/lib/active_record/associations/has_one_association.rb +133 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +37 -0
  19. data/lib/active_record/associations.rb +2241 -0
  20. data/lib/active_record/attribute_methods.rb +388 -0
  21. data/lib/active_record/autosave_association.rb +364 -0
  22. data/lib/active_record/base.rb +3171 -0
  23. data/lib/active_record/batches.rb +81 -0
  24. data/lib/active_record/calculations.rb +311 -0
  25. data/lib/active_record/callbacks.rb +360 -0
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
  27. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
  34. data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
  35. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
  36. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  37. data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
  38. data/lib/active_record/dirty.rb +183 -0
  39. data/lib/active_record/dynamic_finder_match.rb +41 -0
  40. data/lib/active_record/dynamic_scope_match.rb +25 -0
  41. data/lib/active_record/fixtures.rb +996 -0
  42. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  43. data/lib/active_record/locale/en.yml +58 -0
  44. data/lib/active_record/locking/optimistic.rb +148 -0
  45. data/lib/active_record/locking/pessimistic.rb +55 -0
  46. data/lib/active_record/migration.rb +566 -0
  47. data/lib/active_record/named_scope.rb +192 -0
  48. data/lib/active_record/nested_attributes.rb +392 -0
  49. data/lib/active_record/observer.rb +197 -0
  50. data/lib/active_record/query_cache.rb +33 -0
  51. data/lib/active_record/reflection.rb +320 -0
  52. data/lib/active_record/schema.rb +51 -0
  53. data/lib/active_record/schema_dumper.rb +182 -0
  54. data/lib/active_record/serialization.rb +101 -0
  55. data/lib/active_record/serializers/json_serializer.rb +91 -0
  56. data/lib/active_record/serializers/xml_serializer.rb +357 -0
  57. data/lib/active_record/session_store.rb +326 -0
  58. data/lib/active_record/test_case.rb +66 -0
  59. data/lib/active_record/timestamp.rb +71 -0
  60. data/lib/active_record/transactions.rb +235 -0
  61. data/lib/active_record/validations.rb +1135 -0
  62. data/lib/active_record/version.rb +9 -0
  63. data/lib/active_record.rb +84 -0
  64. data/lib/activerecord.rb +2 -0
  65. data/test/assets/example.log +1 -0
  66. data/test/assets/flowers.jpg +0 -0
  67. data/test/cases/aaa_create_tables_test.rb +24 -0
  68. data/test/cases/active_schema_test_mysql.rb +100 -0
  69. data/test/cases/active_schema_test_postgresql.rb +24 -0
  70. data/test/cases/adapter_test.rb +145 -0
  71. data/test/cases/aggregations_test.rb +167 -0
  72. data/test/cases/ar_schema_test.rb +32 -0
  73. data/test/cases/associations/belongs_to_associations_test.rb +425 -0
  74. data/test/cases/associations/callbacks_test.rb +161 -0
  75. data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
  76. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  77. data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
  78. data/test/cases/associations/eager_singularization_test.rb +145 -0
  79. data/test/cases/associations/eager_test.rb +834 -0
  80. data/test/cases/associations/extension_test.rb +62 -0
  81. data/test/cases/associations/habtm_join_table_test.rb +56 -0
  82. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
  83. data/test/cases/associations/has_many_associations_test.rb +1134 -0
  84. data/test/cases/associations/has_many_through_associations_test.rb +346 -0
  85. data/test/cases/associations/has_one_associations_test.rb +330 -0
  86. data/test/cases/associations/has_one_through_associations_test.rb +209 -0
  87. data/test/cases/associations/inner_join_association_test.rb +93 -0
  88. data/test/cases/associations/join_model_test.rb +712 -0
  89. data/test/cases/associations_test.rb +262 -0
  90. data/test/cases/attribute_methods_test.rb +305 -0
  91. data/test/cases/autosave_association_test.rb +1142 -0
  92. data/test/cases/base_test.rb +2154 -0
  93. data/test/cases/batches_test.rb +61 -0
  94. data/test/cases/binary_test.rb +30 -0
  95. data/test/cases/calculations_test.rb +348 -0
  96. data/test/cases/callbacks_observers_test.rb +38 -0
  97. data/test/cases/callbacks_test.rb +438 -0
  98. data/test/cases/class_inheritable_attributes_test.rb +32 -0
  99. data/test/cases/column_alias_test.rb +17 -0
  100. data/test/cases/column_definition_test.rb +70 -0
  101. data/test/cases/connection_pool_test.rb +25 -0
  102. data/test/cases/connection_test_firebird.rb +8 -0
  103. data/test/cases/connection_test_mysql.rb +64 -0
  104. data/test/cases/copy_table_test_sqlite.rb +80 -0
  105. data/test/cases/database_statements_test.rb +12 -0
  106. data/test/cases/datatype_test_postgresql.rb +204 -0
  107. data/test/cases/date_time_test.rb +37 -0
  108. data/test/cases/default_test_firebird.rb +16 -0
  109. data/test/cases/defaults_test.rb +111 -0
  110. data/test/cases/deprecated_finder_test.rb +30 -0
  111. data/test/cases/dirty_test.rb +316 -0
  112. data/test/cases/finder_respond_to_test.rb +76 -0
  113. data/test/cases/finder_test.rb +1066 -0
  114. data/test/cases/fixtures_test.rb +656 -0
  115. data/test/cases/helper.rb +68 -0
  116. data/test/cases/i18n_test.rb +46 -0
  117. data/test/cases/inheritance_test.rb +262 -0
  118. data/test/cases/invalid_date_test.rb +24 -0
  119. data/test/cases/json_serialization_test.rb +205 -0
  120. data/test/cases/lifecycle_test.rb +193 -0
  121. data/test/cases/locking_test.rb +304 -0
  122. data/test/cases/method_scoping_test.rb +704 -0
  123. data/test/cases/migration_test.rb +1523 -0
  124. data/test/cases/migration_test_firebird.rb +124 -0
  125. data/test/cases/mixin_test.rb +96 -0
  126. data/test/cases/modules_test.rb +81 -0
  127. data/test/cases/multiple_db_test.rb +85 -0
  128. data/test/cases/named_scope_test.rb +361 -0
  129. data/test/cases/nested_attributes_test.rb +581 -0
  130. data/test/cases/pk_test.rb +119 -0
  131. data/test/cases/pooled_connections_test.rb +103 -0
  132. data/test/cases/query_cache_test.rb +123 -0
  133. data/test/cases/readonly_test.rb +107 -0
  134. data/test/cases/reflection_test.rb +194 -0
  135. data/test/cases/reload_models_test.rb +22 -0
  136. data/test/cases/repair_helper.rb +50 -0
  137. data/test/cases/reserved_word_test_mysql.rb +176 -0
  138. data/test/cases/sanitize_test.rb +25 -0
  139. data/test/cases/schema_authorization_test_postgresql.rb +75 -0
  140. data/test/cases/schema_dumper_test.rb +211 -0
  141. data/test/cases/schema_test_postgresql.rb +178 -0
  142. data/test/cases/serialization_test.rb +47 -0
  143. data/test/cases/synonym_test_oracle.rb +17 -0
  144. data/test/cases/timestamp_test.rb +75 -0
  145. data/test/cases/transactions_test.rb +522 -0
  146. data/test/cases/unconnected_test.rb +32 -0
  147. data/test/cases/validations_i18n_test.rb +955 -0
  148. data/test/cases/validations_test.rb +1640 -0
  149. data/test/cases/xml_serialization_test.rb +240 -0
  150. data/test/config.rb +5 -0
  151. data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
  152. data/test/connections/jdbc_jdbch2/connection.rb +18 -0
  153. data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
  154. data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
  155. data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
  156. data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
  157. data/test/connections/native_db2/connection.rb +25 -0
  158. data/test/connections/native_firebird/connection.rb +26 -0
  159. data/test/connections/native_frontbase/connection.rb +27 -0
  160. data/test/connections/native_mysql/connection.rb +25 -0
  161. data/test/connections/native_openbase/connection.rb +21 -0
  162. data/test/connections/native_oracle/connection.rb +27 -0
  163. data/test/connections/native_postgresql/connection.rb +25 -0
  164. data/test/connections/native_sqlite/connection.rb +25 -0
  165. data/test/connections/native_sqlite3/connection.rb +25 -0
  166. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  167. data/test/connections/native_sybase/connection.rb +23 -0
  168. data/test/fixtures/accounts.yml +29 -0
  169. data/test/fixtures/all/developers.yml +0 -0
  170. data/test/fixtures/all/people.csv +0 -0
  171. data/test/fixtures/all/tasks.yml +0 -0
  172. data/test/fixtures/author_addresses.yml +5 -0
  173. data/test/fixtures/author_favorites.yml +4 -0
  174. data/test/fixtures/authors.yml +9 -0
  175. data/test/fixtures/binaries.yml +132 -0
  176. data/test/fixtures/books.yml +7 -0
  177. data/test/fixtures/categories/special_categories.yml +9 -0
  178. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  179. data/test/fixtures/categories.yml +14 -0
  180. data/test/fixtures/categories_ordered.yml +7 -0
  181. data/test/fixtures/categories_posts.yml +23 -0
  182. data/test/fixtures/categorizations.yml +17 -0
  183. data/test/fixtures/clubs.yml +6 -0
  184. data/test/fixtures/comments.yml +59 -0
  185. data/test/fixtures/companies.yml +56 -0
  186. data/test/fixtures/computers.yml +4 -0
  187. data/test/fixtures/courses.yml +7 -0
  188. data/test/fixtures/customers.yml +26 -0
  189. data/test/fixtures/developers.yml +21 -0
  190. data/test/fixtures/developers_projects.yml +17 -0
  191. data/test/fixtures/edges.yml +6 -0
  192. data/test/fixtures/entrants.yml +14 -0
  193. data/test/fixtures/fixture_database.sqlite3 +0 -0
  194. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  195. data/test/fixtures/fk_test_has_fk.yml +3 -0
  196. data/test/fixtures/fk_test_has_pk.yml +2 -0
  197. data/test/fixtures/funny_jokes.yml +10 -0
  198. data/test/fixtures/items.yml +4 -0
  199. data/test/fixtures/jobs.yml +7 -0
  200. data/test/fixtures/legacy_things.yml +3 -0
  201. data/test/fixtures/mateys.yml +4 -0
  202. data/test/fixtures/member_types.yml +6 -0
  203. data/test/fixtures/members.yml +6 -0
  204. data/test/fixtures/memberships.yml +20 -0
  205. data/test/fixtures/minimalistics.yml +2 -0
  206. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  207. data/test/fixtures/mixins.yml +29 -0
  208. data/test/fixtures/movies.yml +7 -0
  209. data/test/fixtures/naked/csv/accounts.csv +1 -0
  210. data/test/fixtures/naked/yml/accounts.yml +1 -0
  211. data/test/fixtures/naked/yml/companies.yml +1 -0
  212. data/test/fixtures/naked/yml/courses.yml +1 -0
  213. data/test/fixtures/organizations.yml +5 -0
  214. data/test/fixtures/owners.yml +7 -0
  215. data/test/fixtures/parrots.yml +27 -0
  216. data/test/fixtures/parrots_pirates.yml +7 -0
  217. data/test/fixtures/people.yml +15 -0
  218. data/test/fixtures/pets.yml +14 -0
  219. data/test/fixtures/pirates.yml +9 -0
  220. data/test/fixtures/posts.yml +52 -0
  221. data/test/fixtures/price_estimates.yml +7 -0
  222. data/test/fixtures/projects.yml +7 -0
  223. data/test/fixtures/readers.yml +9 -0
  224. data/test/fixtures/references.yml +17 -0
  225. data/test/fixtures/reserved_words/distinct.yml +5 -0
  226. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  227. data/test/fixtures/reserved_words/group.yml +14 -0
  228. data/test/fixtures/reserved_words/select.yml +8 -0
  229. data/test/fixtures/reserved_words/values.yml +7 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/sponsors.yml +9 -0
  232. data/test/fixtures/subscribers.yml +7 -0
  233. data/test/fixtures/subscriptions.yml +12 -0
  234. data/test/fixtures/taggings.yml +28 -0
  235. data/test/fixtures/tags.yml +7 -0
  236. data/test/fixtures/tasks.yml +7 -0
  237. data/test/fixtures/topics.yml +42 -0
  238. data/test/fixtures/toys.yml +4 -0
  239. data/test/fixtures/treasures.yml +10 -0
  240. data/test/fixtures/vertices.yml +4 -0
  241. data/test/fixtures/warehouse-things.yml +3 -0
  242. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  243. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  244. data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
  245. data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
  246. data/test/migrations/duplicate/3_foo.rb +7 -0
  247. data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
  248. data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
  249. data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
  250. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
  251. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
  252. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
  253. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
  254. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
  255. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
  256. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  257. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  258. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  259. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  260. data/test/migrations/valid/1_people_have_last_names.rb +9 -0
  261. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  262. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  263. data/test/models/author.rb +146 -0
  264. data/test/models/auto_id.rb +4 -0
  265. data/test/models/binary.rb +2 -0
  266. data/test/models/bird.rb +3 -0
  267. data/test/models/book.rb +4 -0
  268. data/test/models/categorization.rb +5 -0
  269. data/test/models/category.rb +34 -0
  270. data/test/models/citation.rb +6 -0
  271. data/test/models/club.rb +13 -0
  272. data/test/models/column_name.rb +3 -0
  273. data/test/models/comment.rb +29 -0
  274. data/test/models/company.rb +171 -0
  275. data/test/models/company_in_module.rb +61 -0
  276. data/test/models/computer.rb +3 -0
  277. data/test/models/contact.rb +16 -0
  278. data/test/models/contract.rb +5 -0
  279. data/test/models/course.rb +3 -0
  280. data/test/models/customer.rb +73 -0
  281. data/test/models/default.rb +2 -0
  282. data/test/models/developer.rb +101 -0
  283. data/test/models/edge.rb +5 -0
  284. data/test/models/entrant.rb +3 -0
  285. data/test/models/essay.rb +3 -0
  286. data/test/models/event.rb +3 -0
  287. data/test/models/guid.rb +2 -0
  288. data/test/models/item.rb +7 -0
  289. data/test/models/job.rb +5 -0
  290. data/test/models/joke.rb +3 -0
  291. data/test/models/keyboard.rb +3 -0
  292. data/test/models/legacy_thing.rb +3 -0
  293. data/test/models/matey.rb +4 -0
  294. data/test/models/member.rb +12 -0
  295. data/test/models/member_detail.rb +5 -0
  296. data/test/models/member_type.rb +3 -0
  297. data/test/models/membership.rb +9 -0
  298. data/test/models/minimalistic.rb +2 -0
  299. data/test/models/mixed_case_monkey.rb +3 -0
  300. data/test/models/movie.rb +5 -0
  301. data/test/models/order.rb +4 -0
  302. data/test/models/organization.rb +6 -0
  303. data/test/models/owner.rb +5 -0
  304. data/test/models/parrot.rb +16 -0
  305. data/test/models/person.rb +16 -0
  306. data/test/models/pet.rb +5 -0
  307. data/test/models/pirate.rb +70 -0
  308. data/test/models/post.rb +100 -0
  309. data/test/models/price_estimate.rb +3 -0
  310. data/test/models/project.rb +30 -0
  311. data/test/models/reader.rb +4 -0
  312. data/test/models/reference.rb +4 -0
  313. data/test/models/reply.rb +46 -0
  314. data/test/models/ship.rb +10 -0
  315. data/test/models/ship_part.rb +5 -0
  316. data/test/models/sponsor.rb +4 -0
  317. data/test/models/subject.rb +4 -0
  318. data/test/models/subscriber.rb +8 -0
  319. data/test/models/subscription.rb +4 -0
  320. data/test/models/tag.rb +7 -0
  321. data/test/models/tagging.rb +10 -0
  322. data/test/models/task.rb +3 -0
  323. data/test/models/topic.rb +80 -0
  324. data/test/models/toy.rb +6 -0
  325. data/test/models/treasure.rb +8 -0
  326. data/test/models/vertex.rb +9 -0
  327. data/test/models/warehouse_thing.rb +5 -0
  328. data/test/schema/mysql_specific_schema.rb +24 -0
  329. data/test/schema/postgresql_specific_schema.rb +114 -0
  330. data/test/schema/schema.rb +493 -0
  331. data/test/schema/schema2.rb +6 -0
  332. data/test/schema/sqlite_specific_schema.rb +25 -0
  333. metadata +420 -0
@@ -0,0 +1,61 @@
1
+ require 'cases/helper'
2
+ require 'models/post'
3
+
4
+ class EachTest < ActiveRecord::TestCase
5
+ fixtures :posts
6
+
7
+ def setup
8
+ @posts = Post.all(:order => "id asc")
9
+ @total = Post.count
10
+ end
11
+
12
+ def test_each_should_excecute_one_query_per_batch
13
+ assert_queries(Post.count + 1) do
14
+ Post.find_each(:batch_size => 1) do |post|
15
+ assert_kind_of Post, post
16
+ end
17
+ end
18
+ end
19
+
20
+ def test_each_should_raise_if_the_order_is_set
21
+ assert_raise(RuntimeError) do
22
+ Post.find_each(:order => "title") { |post| post }
23
+ end
24
+ end
25
+
26
+ def test_each_should_raise_if_the_limit_is_set
27
+ assert_raise(RuntimeError) do
28
+ Post.find_each(:limit => 1) { |post| post }
29
+ end
30
+ end
31
+
32
+ def test_find_in_batches_should_return_batches
33
+ assert_queries(Post.count + 1) do
34
+ Post.find_in_batches(:batch_size => 1) do |batch|
35
+ assert_kind_of Array, batch
36
+ assert_kind_of Post, batch.first
37
+ end
38
+ end
39
+ end
40
+
41
+ def test_find_in_batches_should_start_from_the_start_option
42
+ assert_queries(Post.count) do
43
+ Post.find_in_batches(:batch_size => 1, :start => 2) do |batch|
44
+ assert_kind_of Array, batch
45
+ assert_kind_of Post, batch.first
46
+ end
47
+ end
48
+ end
49
+
50
+ def test_find_in_batches_shouldnt_excute_query_unless_needed
51
+ post_count = Post.count
52
+
53
+ assert_queries(2) do
54
+ Post.find_in_batches(:batch_size => post_count) {|batch| assert_kind_of Array, batch }
55
+ end
56
+
57
+ assert_queries(1) do
58
+ Post.find_in_batches(:batch_size => post_count + 1) {|batch| assert_kind_of Array, batch }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,30 @@
1
+ require "cases/helper"
2
+
3
+ # Without using prepared statements, it makes no sense to test
4
+ # BLOB data with DB2 or Firebird, because the length of a statement
5
+ # is limited to 32KB.
6
+ unless current_adapter?(:SybaseAdapter, :DB2Adapter, :FirebirdAdapter)
7
+ require 'models/binary'
8
+
9
+ class BinaryTest < ActiveRecord::TestCase
10
+ FIXTURES = %w(flowers.jpg example.log)
11
+
12
+ def test_load_save
13
+ Binary.delete_all
14
+
15
+ FIXTURES.each do |filename|
16
+ data = File.read(ASSETS_ROOT + "/#{filename}")
17
+ data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding)
18
+ data.freeze
19
+
20
+ bin = Binary.new(:data => data)
21
+ assert_equal data, bin.data, 'Newly assigned data differs from original'
22
+
23
+ bin.save!
24
+ assert_equal data, bin.data, 'Data differs from original after save'
25
+
26
+ assert_equal data, bin.reload.data, 'Reloaded data differs from original'
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,348 @@
1
+ require "cases/helper"
2
+ require 'models/company'
3
+ require 'models/topic'
4
+ require 'models/edge'
5
+ require 'models/owner'
6
+ require 'models/pet'
7
+ require 'models/toy'
8
+ require 'models/club'
9
+ require 'models/organization'
10
+
11
+ Company.has_many :accounts
12
+
13
+ class NumericData < ActiveRecord::Base
14
+ self.table_name = 'numeric_data'
15
+ end
16
+
17
+ class CalculationsTest < ActiveRecord::TestCase
18
+ fixtures :companies, :accounts, :topics, :owners, :pets, :toys
19
+
20
+ def test_should_sum_field
21
+ assert_equal 318, Account.sum(:credit_limit)
22
+ end
23
+
24
+ def test_should_average_field
25
+ value = Account.average(:credit_limit)
26
+ assert_kind_of BigDecimal, value
27
+ assert_equal BigDecimal.new('53.0'), value
28
+ end
29
+
30
+ def test_should_return_nil_as_average
31
+ assert_nil NumericData.average(:bank_balance)
32
+ end
33
+
34
+ def test_type_cast_calculated_value_should_convert_db_averages_of_fixnum_class_to_decimal
35
+ assert_equal 0, NumericData.send(:type_cast_calculated_value, 0, nil, 'avg')
36
+ assert_equal 53.0, NumericData.send(:type_cast_calculated_value, 53, nil, 'avg')
37
+ end
38
+
39
+ def test_should_get_maximum_of_field
40
+ assert_equal 60, Account.maximum(:credit_limit)
41
+ end
42
+
43
+ def test_should_get_maximum_of_field_with_include
44
+ assert_equal 50, Account.maximum(:credit_limit, :include => :firm, :conditions => "companies.name != 'Summit'")
45
+ end
46
+
47
+ def test_should_get_maximum_of_field_with_scoped_include
48
+ Account.with_scope :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do
49
+ assert_equal 50, Account.maximum(:credit_limit)
50
+ end
51
+ end
52
+
53
+ def test_should_get_minimum_of_field
54
+ assert_equal 50, Account.minimum(:credit_limit)
55
+ end
56
+
57
+ def test_should_group_by_field
58
+ c = Account.sum(:credit_limit, :group => :firm_id)
59
+ [1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
60
+ end
61
+
62
+ def test_should_group_by_summed_field
63
+ c = Account.sum(:credit_limit, :group => :firm_id)
64
+ assert_equal 50, c[1]
65
+ assert_equal 105, c[6]
66
+ assert_equal 60, c[2]
67
+ end
68
+
69
+ def test_should_order_by_grouped_field
70
+ c = Account.sum(:credit_limit, :group => :firm_id, :order => "firm_id")
71
+ assert_equal [1, 2, 6, 9], c.keys.compact
72
+ end
73
+
74
+ def test_should_order_by_calculation
75
+ c = Account.sum(:credit_limit, :group => :firm_id, :order => "sum_credit_limit desc, firm_id")
76
+ assert_equal [105, 60, 53, 50, 50], c.keys.collect { |k| c[k] }
77
+ assert_equal [6, 2, 9, 1], c.keys.compact
78
+ end
79
+
80
+ def test_should_limit_calculation
81
+ c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
82
+ :group => :firm_id, :order => "firm_id", :limit => 2)
83
+ assert_equal [1, 2], c.keys.compact
84
+ end
85
+
86
+ def test_should_limit_calculation_with_offset
87
+ c = Account.sum(:credit_limit, :conditions => "firm_id IS NOT NULL",
88
+ :group => :firm_id, :order => "firm_id", :limit => 2, :offset => 1)
89
+ assert_equal [2, 6], c.keys.compact
90
+ end
91
+
92
+ def test_should_group_by_summed_field_having_condition
93
+ c = Account.sum(:credit_limit, :group => :firm_id,
94
+ :having => 'sum(credit_limit) > 50')
95
+ assert_nil c[1]
96
+ assert_equal 105, c[6]
97
+ assert_equal 60, c[2]
98
+ end
99
+
100
+ def test_should_group_by_summed_field_having_sanitized_condition
101
+ c = Account.sum(:credit_limit, :group => :firm_id,
102
+ :having => ['sum(credit_limit) > ?', 50])
103
+ assert_nil c[1]
104
+ assert_equal 105, c[6]
105
+ assert_equal 60, c[2]
106
+ end
107
+
108
+ def test_should_group_by_summed_association
109
+ c = Account.sum(:credit_limit, :group => :firm)
110
+ assert_equal 50, c[companies(:first_firm)]
111
+ assert_equal 105, c[companies(:rails_core)]
112
+ assert_equal 60, c[companies(:first_client)]
113
+ end
114
+
115
+ def test_should_sum_field_with_conditions
116
+ assert_equal 105, Account.sum(:credit_limit, :conditions => 'firm_id = 6')
117
+ end
118
+
119
+ def test_should_return_zero_if_sum_conditions_return_nothing
120
+ assert_equal 0, Account.sum(:credit_limit, :conditions => '1 = 2')
121
+ assert_equal 0, companies(:rails_core).companies.sum(:id, :conditions => '1 = 2')
122
+ end
123
+
124
+ def test_sum_should_return_valid_values_for_decimals
125
+ NumericData.create(:bank_balance => 19.83)
126
+ assert_equal 19.83, NumericData.sum(:bank_balance)
127
+ end
128
+
129
+ def test_should_group_by_summed_field_with_conditions
130
+ c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
131
+ :group => :firm_id)
132
+ assert_nil c[1]
133
+ assert_equal 105, c[6]
134
+ assert_equal 60, c[2]
135
+ end
136
+
137
+ def test_should_group_by_summed_field_with_conditions_and_having
138
+ c = Account.sum(:credit_limit, :conditions => 'firm_id > 1',
139
+ :group => :firm_id,
140
+ :having => 'sum(credit_limit) > 60')
141
+ assert_nil c[1]
142
+ assert_equal 105, c[6]
143
+ assert_nil c[2]
144
+ end
145
+
146
+ def test_should_group_by_fields_with_table_alias
147
+ c = Account.sum(:credit_limit, :group => 'accounts.firm_id')
148
+ assert_equal 50, c[1]
149
+ assert_equal 105, c[6]
150
+ assert_equal 60, c[2]
151
+ end
152
+
153
+ def test_should_calculate_with_invalid_field
154
+ assert_equal 6, Account.calculate(:count, '*')
155
+ assert_equal 6, Account.calculate(:count, :all)
156
+ end
157
+
158
+ def test_should_calculate_grouped_with_invalid_field
159
+ c = Account.count(:all, :group => 'accounts.firm_id')
160
+ assert_equal 1, c[1]
161
+ assert_equal 2, c[6]
162
+ assert_equal 1, c[2]
163
+ end
164
+
165
+ def test_should_calculate_grouped_association_with_invalid_field
166
+ c = Account.count(:all, :group => :firm)
167
+ assert_equal 1, c[companies(:first_firm)]
168
+ assert_equal 2, c[companies(:rails_core)]
169
+ assert_equal 1, c[companies(:first_client)]
170
+ end
171
+
172
+ def test_should_group_by_association_with_non_numeric_foreign_key
173
+ ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
174
+
175
+ firm = mock()
176
+ firm.expects(:id).returns("ABC")
177
+ firm.expects(:class).returns(Firm)
178
+ Company.expects(:find).with(["ABC"]).returns([firm])
179
+
180
+ column = mock()
181
+ column.expects(:name).at_least_once.returns(:firm_id)
182
+ column.expects(:type_cast).with("ABC").returns("ABC")
183
+ Account.expects(:columns).at_least_once.returns([column])
184
+
185
+ c = Account.count(:all, :group => :firm)
186
+ first_key = c.keys.first
187
+ assert_equal Firm, first_key.class
188
+ assert_equal 1, c[first_key]
189
+ end
190
+
191
+ def test_should_calculate_grouped_association_with_foreign_key_option
192
+ Account.belongs_to :another_firm, :class_name => 'Firm', :foreign_key => 'firm_id'
193
+ c = Account.count(:all, :group => :another_firm)
194
+ assert_equal 1, c[companies(:first_firm)]
195
+ assert_equal 2, c[companies(:rails_core)]
196
+ assert_equal 1, c[companies(:first_client)]
197
+ end
198
+
199
+ def test_should_not_modify_options_when_using_includes
200
+ options = {:conditions => 'companies.id > 1', :include => :firm}
201
+ options_copy = options.dup
202
+
203
+ Account.count(:all, options)
204
+ assert_equal options_copy, options
205
+ end
206
+
207
+ def test_should_calculate_grouped_by_function
208
+ c = Company.count(:all, :group => "UPPER(#{QUOTED_TYPE})")
209
+ assert_equal 2, c[nil]
210
+ assert_equal 1, c['DEPENDENTFIRM']
211
+ assert_equal 3, c['CLIENT']
212
+ assert_equal 2, c['FIRM']
213
+ end
214
+
215
+ def test_should_calculate_grouped_by_function_with_table_alias
216
+ c = Company.count(:all, :group => "UPPER(companies.#{QUOTED_TYPE})")
217
+ assert_equal 2, c[nil]
218
+ assert_equal 1, c['DEPENDENTFIRM']
219
+ assert_equal 3, c['CLIENT']
220
+ assert_equal 2, c['FIRM']
221
+ end
222
+
223
+ def test_should_not_overshadow_enumerable_sum
224
+ assert_equal 6, [1, 2, 3].sum(&:abs)
225
+ end
226
+
227
+ def test_should_sum_scoped_field
228
+ assert_equal 15, companies(:rails_core).companies.sum(:id)
229
+ end
230
+
231
+ def test_should_sum_scoped_field_with_from
232
+ assert_equal Club.count, Organization.clubs.count
233
+ end
234
+
235
+ def test_should_sum_scoped_field_with_conditions
236
+ assert_equal 8, companies(:rails_core).companies.sum(:id, :conditions => 'id > 7')
237
+ end
238
+
239
+ def test_should_group_by_scoped_field
240
+ c = companies(:rails_core).companies.sum(:id, :group => :name)
241
+ assert_equal 7, c['Leetsoft']
242
+ assert_equal 8, c['Jadedpixel']
243
+ end
244
+
245
+ def test_should_group_by_summed_field_with_conditions_and_having
246
+ c = companies(:rails_core).companies.sum(:id, :group => :name,
247
+ :having => 'sum(id) > 7')
248
+ assert_nil c['Leetsoft']
249
+ assert_equal 8, c['Jadedpixel']
250
+ end
251
+
252
+ def test_should_reject_invalid_options
253
+ assert_nothing_raised do
254
+ [:count, :sum].each do |func|
255
+ # empty options are valid
256
+ Company.send(:validate_calculation_options, func)
257
+ # these options are valid for all calculations
258
+ [:select, :conditions, :joins, :order, :group, :having, :distinct].each do |opt|
259
+ Company.send(:validate_calculation_options, func, opt => true)
260
+ end
261
+ end
262
+
263
+ # :include is only valid on :count
264
+ Company.send(:validate_calculation_options, :count, :include => true)
265
+ end
266
+
267
+ assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :sum, :foo => :bar) }
268
+ assert_raise(ArgumentError) { Company.send(:validate_calculation_options, :count, :foo => :bar) }
269
+ end
270
+
271
+ def test_should_count_selected_field_with_include
272
+ assert_equal 6, Account.count(:distinct => true, :include => :firm)
273
+ assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
274
+ end
275
+
276
+ def test_should_count_manual_select_with_include
277
+ assert_equal 6, Account.count(:select => "DISTINCT accounts.id", :include => :firm)
278
+ end
279
+
280
+ def test_count_with_column_parameter
281
+ assert_equal 5, Account.count(:firm_id)
282
+ end
283
+
284
+ def test_count_with_column_and_options_parameter
285
+ assert_equal 2, Account.count(:firm_id, :conditions => "credit_limit = 50")
286
+ end
287
+
288
+ def test_count_with_no_parameters_isnt_deprecated
289
+ assert_not_deprecated { Account.count }
290
+ end
291
+
292
+ def test_count_with_too_many_parameters_raises
293
+ assert_raise(ArgumentError) { Account.count(1, 2, 3) }
294
+ end
295
+
296
+ def test_count_with_scoped_has_many_through_association
297
+ assert_equal 1, owners(:blackbeard).toys.with_name('Bone').count
298
+ end
299
+
300
+ def test_should_sum_expression
301
+ assert_equal '636', Account.sum("2 * credit_limit")
302
+ end
303
+
304
+ def test_count_with_from_option
305
+ assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
306
+ assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
307
+ Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
308
+ assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
309
+ Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
310
+ end
311
+
312
+ def test_sum_with_from_option
313
+ assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
314
+ assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
315
+ Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
316
+ end
317
+
318
+ def test_average_with_from_option
319
+ assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
320
+ assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
321
+ Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
322
+ end
323
+
324
+ def test_minimum_with_from_option
325
+ assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
326
+ assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
327
+ Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
328
+ end
329
+
330
+ def test_maximum_with_from_option
331
+ assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
332
+ assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
333
+ Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
334
+ end
335
+
336
+ def test_from_option_with_specified_index
337
+ if Edge.connection.adapter_name == 'MySQL'
338
+ assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
339
+ assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
340
+ Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
341
+ end
342
+ end
343
+
344
+ def test_from_option_with_table_different_than_class
345
+ assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
346
+ end
347
+
348
+ end
@@ -0,0 +1,38 @@
1
+ require "cases/helper"
2
+
3
+ class Comment < ActiveRecord::Base
4
+ attr_accessor :callers
5
+
6
+ before_validation :record_callers
7
+
8
+ def after_validation
9
+ record_callers
10
+ end
11
+
12
+ def record_callers
13
+ callers << self.class if callers
14
+ end
15
+ end
16
+
17
+ class CommentObserver < ActiveRecord::Observer
18
+ attr_accessor :callers
19
+
20
+ def after_validation(model)
21
+ callers << self.class if callers
22
+ end
23
+ end
24
+
25
+ class CallbacksObserversTest < ActiveRecord::TestCase
26
+ def test_model_callbacks_fire_before_observers_are_notified
27
+ callers = []
28
+
29
+ comment = Comment.new
30
+ comment.callers = callers
31
+
32
+ CommentObserver.instance.callers = callers
33
+
34
+ comment.valid?
35
+
36
+ assert_equal [Comment, Comment, CommentObserver], callers, "model callbacks did not fire before observers were notified"
37
+ end
38
+ end