ibm_db 3.0.0-x86-mingw32 → 3.0.1-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -0
  3. data/MANIFEST +14 -14
  4. data/README +225 -225
  5. data/ext/Makefile.nt32 +181 -181
  6. data/ext/Makefile.nt32.191 +212 -212
  7. data/ext/OLD/extconf.rb +264 -0
  8. data/ext/{extconf_MacOS.rb → OLD/extconf_MacOS.rb} +269 -269
  9. data/ext/extconf.rb +291 -264
  10. data/ext/ibm_db.c +2 -2
  11. data/ext/ruby_ibm_db.h +241 -241
  12. data/ext/ruby_ibm_db_cli.h +500 -500
  13. data/init.rb +41 -41
  14. data/lib/IBM_DB.rb +27 -27
  15. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +4 -4
  16. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
  17. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  18. data/lib/mswin32/ibm_db.rb +115 -115
  19. data/test/active_record/connection_adapters/fake_adapter.rb +46 -0
  20. data/test/assets/example.log +1 -0
  21. data/test/assets/flowers.jpg +0 -0
  22. data/test/assets/test.txt +1 -0
  23. data/test/cases/adapter_test.rb +261 -207
  24. data/test/cases/aggregations_test.rb +158 -0
  25. data/test/cases/ar_schema_test.rb +161 -0
  26. data/test/cases/associations/association_scope_test.rb +21 -0
  27. data/test/cases/associations/belongs_to_associations_test.rb +1029 -711
  28. data/test/cases/associations/callbacks_test.rb +192 -0
  29. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -181
  30. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +26 -0
  31. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  32. data/test/cases/associations/eager_load_nested_include_test.rb +128 -0
  33. data/test/cases/associations/eager_singularization_test.rb +148 -0
  34. data/test/cases/associations/eager_test.rb +1411 -0
  35. data/test/cases/associations/extension_test.rb +82 -0
  36. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +932 -851
  37. data/test/cases/associations/has_many_associations_test.rb +2162 -0
  38. data/test/cases/associations/has_many_through_associations_test.rb +1204 -0
  39. data/test/cases/associations/has_one_associations_test.rb +610 -0
  40. data/test/cases/associations/has_one_through_associations_test.rb +380 -0
  41. data/test/cases/associations/inner_join_association_test.rb +139 -0
  42. data/test/cases/associations/inverse_associations_test.rb +693 -0
  43. data/test/cases/associations/join_model_test.rb +754 -743
  44. data/test/cases/associations/nested_through_associations_test.rb +579 -0
  45. data/test/cases/associations/required_test.rb +82 -0
  46. data/test/cases/associations_test.rb +380 -0
  47. data/test/cases/attribute_decorators_test.rb +125 -0
  48. data/test/cases/attribute_methods/read_test.rb +60 -0
  49. data/test/cases/attribute_methods/serialization_test.rb +29 -0
  50. data/test/cases/attribute_methods_test.rb +952 -822
  51. data/test/cases/attribute_set_test.rb +200 -0
  52. data/test/cases/attribute_test.rb +180 -0
  53. data/test/cases/attributes_test.rb +136 -0
  54. data/test/cases/autosave_association_test.rb +1595 -0
  55. data/test/cases/base_test.rb +1638 -2133
  56. data/test/cases/batches_test.rb +212 -0
  57. data/test/cases/binary_test.rb +52 -0
  58. data/test/cases/bind_parameter_test.rb +100 -0
  59. data/test/cases/calculations_test.rb +646 -482
  60. data/test/cases/callbacks_test.rb +543 -0
  61. data/test/cases/clone_test.rb +40 -0
  62. data/test/cases/coders/yaml_column_test.rb +63 -0
  63. data/test/cases/column_alias_test.rb +17 -0
  64. data/test/cases/column_definition_test.rb +123 -0
  65. data/test/cases/connection_adapters/adapter_leasing_test.rb +54 -0
  66. data/test/cases/connection_adapters/connection_handler_test.rb +53 -0
  67. data/test/cases/connection_adapters/connection_specification_test.rb +12 -0
  68. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +293 -0
  69. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +65 -0
  70. data/test/cases/connection_adapters/quoting_test.rb +13 -0
  71. data/test/cases/connection_adapters/schema_cache_test.rb +56 -0
  72. data/test/cases/connection_adapters/type_lookup_test.rb +110 -0
  73. data/test/cases/connection_management_test.rb +122 -0
  74. data/test/cases/connection_pool_test.rb +346 -0
  75. data/test/cases/connection_specification/resolver_test.rb +116 -0
  76. data/test/cases/core_test.rb +112 -0
  77. data/test/cases/counter_cache_test.rb +209 -0
  78. data/test/cases/custom_locking_test.rb +17 -0
  79. data/test/cases/database_statements_test.rb +19 -0
  80. data/test/cases/date_time_test.rb +61 -0
  81. data/test/cases/defaults_test.rb +223 -0
  82. data/test/cases/dirty_test.rb +775 -0
  83. data/test/cases/disconnected_test.rb +28 -0
  84. data/test/cases/dup_test.rb +157 -0
  85. data/test/cases/enum_test.rb +290 -0
  86. data/test/cases/explain_subscriber_test.rb +64 -0
  87. data/test/cases/explain_test.rb +76 -0
  88. data/test/cases/finder_respond_to_test.rb +60 -0
  89. data/test/cases/finder_test.rb +1166 -0
  90. data/test/cases/fixture_set/file_test.rb +138 -0
  91. data/test/cases/fixtures_test.rb +897 -0
  92. data/test/cases/forbidden_attributes_protection_test.rb +99 -0
  93. data/test/cases/habtm_destroy_order_test.rb +61 -0
  94. data/test/cases/helper.rb +210 -0
  95. data/test/cases/hot_compatibility_test.rb +54 -0
  96. data/test/cases/i18n_test.rb +45 -0
  97. data/test/cases/inheritance_test.rb +375 -0
  98. data/test/cases/integration_test.rb +139 -0
  99. data/test/cases/invalid_connection_test.rb +22 -0
  100. data/test/cases/invalid_date_test.rb +32 -0
  101. data/test/cases/invertible_migration_test.rb +295 -0
  102. data/test/cases/json_serialization_test.rb +302 -0
  103. data/test/cases/locking_test.rb +477 -0
  104. data/test/cases/log_subscriber_test.rb +136 -0
  105. data/test/cases/migration/change_schema_test - Copy.rb +448 -0
  106. data/test/cases/migration/change_schema_test.rb +472 -0
  107. data/test/cases/migration/change_table_test.rb +224 -0
  108. data/test/cases/migration/column_attributes_test.rb +192 -0
  109. data/test/cases/migration/column_positioning_test.rb +56 -0
  110. data/test/cases/migration/columns_test.rb +304 -0
  111. data/test/cases/migration/command_recorder_test.rb +305 -0
  112. data/test/cases/migration/create_join_table_test.rb +148 -0
  113. data/test/cases/migration/foreign_key_test - Changed.rb +325 -0
  114. data/test/cases/migration/foreign_key_test.rb +360 -0
  115. data/test/cases/migration/helper.rb +39 -0
  116. data/test/cases/migration/index_test.rb +216 -0
  117. data/test/cases/migration/logger_test.rb +36 -0
  118. data/test/cases/migration/pending_migrations_test.rb +53 -0
  119. data/test/cases/migration/references_foreign_key_test.rb +214 -0
  120. data/test/cases/migration/references_index_test.rb +101 -0
  121. data/test/cases/migration/references_statements_test.rb +116 -0
  122. data/test/cases/migration/rename_table_test.rb +93 -0
  123. data/test/cases/migration/table_and_index_test.rb +24 -0
  124. data/test/cases/migration_test.rb +959 -2408
  125. data/test/cases/migrator_test.rb +388 -0
  126. data/test/cases/mixin_test.rb +70 -0
  127. data/test/cases/modules_test.rb +173 -0
  128. data/test/cases/multiparameter_attributes_test.rb +350 -0
  129. data/test/cases/multiple_db_test.rb +115 -0
  130. data/test/cases/nested_attributes_test.rb +1057 -0
  131. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -0
  132. data/test/cases/persistence_test.rb +909 -642
  133. data/test/cases/pooled_connections_test.rb +81 -0
  134. data/test/cases/primary_keys_test.rb +237 -0
  135. data/test/cases/query_cache_test.rb +326 -257
  136. data/test/cases/quoting_test.rb +156 -0
  137. data/test/cases/readonly_test.rb +118 -0
  138. data/test/cases/reaper_test.rb +85 -0
  139. data/test/cases/reflection_test.rb +454 -0
  140. data/test/cases/relation/delegation_test.rb +68 -0
  141. data/test/cases/relation/merging_test.rb +161 -0
  142. data/test/cases/relation/mutation_test.rb +165 -0
  143. data/test/cases/relation/predicate_builder_test.rb +14 -0
  144. data/test/cases/relation/where_chain_test.rb +181 -0
  145. data/test/cases/relation/where_test.rb +300 -0
  146. data/test/cases/relation/where_test2.rb +36 -0
  147. data/test/cases/relation_test.rb +297 -0
  148. data/test/cases/relations_test.rb +1815 -1182
  149. data/test/cases/reload_models_test.rb +22 -0
  150. data/test/cases/result_test.rb +80 -0
  151. data/test/cases/sanitize_test.rb +83 -0
  152. data/test/cases/schema_dumper_test.rb +463 -256
  153. data/test/cases/scoping/default_scoping_test.rb +454 -0
  154. data/test/cases/scoping/named_scoping_test.rb +524 -0
  155. data/test/cases/scoping/relation_scoping_test.rb +357 -0
  156. data/test/cases/serialization_test.rb +104 -0
  157. data/test/cases/serialized_attribute_test.rb +277 -0
  158. data/test/cases/statement_cache_test.rb +98 -0
  159. data/test/cases/store_test.rb +194 -0
  160. data/test/cases/tasks/database_tasks_test.rb +396 -0
  161. data/test/cases/tasks/mysql_rake_test.rb +311 -0
  162. data/test/cases/tasks/postgresql_rake_test.rb +245 -0
  163. data/test/cases/tasks/sqlite_rake_test.rb +193 -0
  164. data/test/cases/test_case.rb +123 -0
  165. data/test/cases/timestamp_test.rb +468 -0
  166. data/test/cases/transaction_callbacks_test.rb +452 -300
  167. data/test/cases/transaction_isolation_test.rb +106 -0
  168. data/test/cases/transactions_test.rb +817 -0
  169. data/test/cases/type/decimal_test.rb +51 -0
  170. data/test/cases/type/integer_test.rb +121 -0
  171. data/test/cases/type/string_test.rb +36 -0
  172. data/test/cases/type/type_map_test.rb +177 -0
  173. data/test/cases/type/unsigned_integer_test.rb +18 -0
  174. data/test/cases/types_test.rb +141 -0
  175. data/test/cases/unconnected_test.rb +33 -0
  176. data/test/cases/validations/association_validation_test.rb +86 -0
  177. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -0
  178. data/test/cases/validations/i18n_validation_test.rb +90 -0
  179. data/test/cases/validations/length_validation_test.rb +47 -0
  180. data/test/cases/validations/presence_validation_test.rb +68 -0
  181. data/test/cases/validations/uniqueness_validation_test.rb +434 -299
  182. data/test/cases/validations_repair_helper.rb +23 -0
  183. data/test/cases/validations_test.rb +165 -0
  184. data/test/cases/view_test.rb +113 -0
  185. data/test/cases/xml_serialization_test.rb +457 -408
  186. data/test/cases/yaml_serialization_test.rb +86 -0
  187. data/test/config.rb +5 -0
  188. data/test/config.yml +154 -154
  189. data/test/connections/native_ibm_db/connection.rb +43 -43
  190. data/test/fixtures/accounts.yml +29 -0
  191. data/test/fixtures/admin/accounts.yml +2 -0
  192. data/test/fixtures/admin/randomly_named_a9.yml +7 -0
  193. data/test/fixtures/admin/randomly_named_b0.yml +7 -0
  194. data/test/fixtures/admin/users.yml +10 -0
  195. data/test/fixtures/all/admin +1 -0
  196. data/test/fixtures/all/developers.yml +0 -0
  197. data/test/fixtures/all/people.yml +0 -0
  198. data/test/fixtures/all/tasks.yml +0 -0
  199. data/test/fixtures/author_addresses.yml +18 -0
  200. data/test/fixtures/author_favorites.yml +4 -0
  201. data/test/fixtures/authors.yml +23 -0
  202. data/test/fixtures/binaries.yml +133 -0
  203. data/test/fixtures/books.yml +11 -0
  204. data/test/fixtures/bulbs.yml +5 -0
  205. data/test/fixtures/cars.yml +9 -0
  206. data/test/fixtures/categories.yml +19 -0
  207. data/test/fixtures/categories/special_categories.yml +9 -0
  208. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  209. data/test/fixtures/categories_ordered.yml +7 -0
  210. data/test/fixtures/categories_posts.yml +31 -0
  211. data/test/fixtures/categorizations.yml +23 -0
  212. data/test/fixtures/clubs.yml +8 -0
  213. data/test/fixtures/collections.yml +3 -0
  214. data/test/fixtures/colleges.yml +3 -0
  215. data/test/fixtures/comments.yml +65 -0
  216. data/test/fixtures/companies.yml +67 -0
  217. data/test/fixtures/computers.yml +10 -0
  218. data/test/fixtures/courses.yml +8 -0
  219. data/test/fixtures/customers.yml +26 -0
  220. data/test/fixtures/dashboards.yml +6 -0
  221. data/test/fixtures/developers.yml +22 -0
  222. data/test/fixtures/developers_projects.yml +17 -0
  223. data/test/fixtures/dog_lovers.yml +7 -0
  224. data/test/fixtures/dogs.yml +4 -0
  225. data/test/fixtures/doubloons.yml +3 -0
  226. data/test/fixtures/edges.yml +5 -0
  227. data/test/fixtures/entrants.yml +14 -0
  228. data/test/fixtures/essays.yml +6 -0
  229. data/test/fixtures/faces.yml +11 -0
  230. data/test/fixtures/fk_test_has_fk.yml +3 -0
  231. data/test/fixtures/fk_test_has_pk.yml +2 -0
  232. data/test/fixtures/friendships.yml +4 -0
  233. data/test/fixtures/funny_jokes.yml +10 -0
  234. data/test/fixtures/interests.yml +33 -0
  235. data/test/fixtures/items.yml +3 -0
  236. data/test/fixtures/jobs.yml +7 -0
  237. data/test/fixtures/legacy_things.yml +3 -0
  238. data/test/fixtures/mateys.yml +4 -0
  239. data/test/fixtures/member_details.yml +8 -0
  240. data/test/fixtures/member_types.yml +6 -0
  241. data/test/fixtures/members.yml +11 -0
  242. data/test/fixtures/memberships.yml +34 -0
  243. data/test/fixtures/men.yml +5 -0
  244. data/test/fixtures/minimalistics.yml +2 -0
  245. data/test/fixtures/minivans.yml +5 -0
  246. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  247. data/test/fixtures/mixins.yml +29 -0
  248. data/test/fixtures/movies.yml +7 -0
  249. data/test/fixtures/naked/csv/accounts.csv +1 -0
  250. data/test/fixtures/naked/yml/accounts.yml +1 -0
  251. data/test/fixtures/naked/yml/companies.yml +1 -0
  252. data/test/fixtures/naked/yml/courses.yml +1 -0
  253. data/test/fixtures/organizations.yml +5 -0
  254. data/test/fixtures/other_topics.yml +42 -0
  255. data/test/fixtures/owners.yml +9 -0
  256. data/test/fixtures/parrots.yml +27 -0
  257. data/test/fixtures/parrots_pirates.yml +7 -0
  258. data/test/fixtures/people.yml +24 -0
  259. data/test/fixtures/peoples_treasures.yml +3 -0
  260. data/test/fixtures/pets.yml +19 -0
  261. data/test/fixtures/pirates.yml +12 -0
  262. data/test/fixtures/posts.yml +80 -0
  263. data/test/fixtures/price_estimates.yml +7 -0
  264. data/test/fixtures/products.yml +4 -0
  265. data/test/fixtures/projects.yml +7 -0
  266. data/test/fixtures/randomly_named_a9.yml +7 -0
  267. data/test/fixtures/ratings.yml +14 -0
  268. data/test/fixtures/readers.yml +11 -0
  269. data/test/fixtures/references.yml +17 -0
  270. data/test/fixtures/reserved_words/distinct.yml +5 -0
  271. data/test/fixtures/reserved_words/distinct_select.yml +11 -0
  272. data/test/fixtures/reserved_words/group.yml +14 -0
  273. data/test/fixtures/reserved_words/select.yml +8 -0
  274. data/test/fixtures/reserved_words/values.yml +7 -0
  275. data/test/fixtures/ships.yml +6 -0
  276. data/test/fixtures/speedometers.yml +8 -0
  277. data/test/fixtures/sponsors.yml +12 -0
  278. data/test/fixtures/string_key_objects.yml +7 -0
  279. data/test/fixtures/subscribers.yml +11 -0
  280. data/test/fixtures/subscriptions.yml +12 -0
  281. data/test/fixtures/taggings.yml +78 -0
  282. data/test/fixtures/tags.yml +11 -0
  283. data/test/fixtures/tasks.yml +7 -0
  284. data/test/fixtures/teapots.yml +3 -0
  285. data/test/fixtures/to_be_linked/accounts.yml +2 -0
  286. data/test/fixtures/to_be_linked/users.yml +10 -0
  287. data/test/fixtures/topics.yml +49 -0
  288. data/test/fixtures/toys.yml +14 -0
  289. data/test/fixtures/traffic_lights.yml +10 -0
  290. data/test/fixtures/treasures.yml +10 -0
  291. data/test/fixtures/uuid_children.yml +3 -0
  292. data/test/fixtures/uuid_parents.yml +2 -0
  293. data/test/fixtures/variants.yml +4 -0
  294. data/test/fixtures/vegetables.yml +20 -0
  295. data/test/fixtures/vertices.yml +4 -0
  296. data/test/fixtures/warehouse_things.yml +3 -0
  297. data/test/fixtures/zines.yml +5 -0
  298. data/test/ibm_db_test.rb +24 -24
  299. data/test/migrations/10_urban/9_add_expressions.rb +11 -0
  300. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  301. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -0
  302. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  303. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  304. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  305. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  306. data/test/migrations/rename/1_we_need_things.rb +11 -0
  307. data/test/migrations/rename/2_rename_things.rb +9 -0
  308. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -0
  309. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -0
  310. data/test/migrations/to_copy2/1_create_articles.rb +7 -0
  311. data/test/migrations/to_copy2/2_create_comments.rb +7 -0
  312. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -0
  313. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -0
  314. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -0
  315. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -0
  316. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -0
  317. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -0
  318. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  319. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  320. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -0
  321. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -0
  322. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -0
  323. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -0
  324. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -0
  325. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -0
  326. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -0
  327. data/test/models/admin.rb +5 -0
  328. data/test/models/admin/account.rb +3 -0
  329. data/test/models/admin/randomly_named_c1.rb +3 -0
  330. data/test/models/admin/user.rb +40 -0
  331. data/test/models/aircraft.rb +4 -0
  332. data/test/models/arunit2_model.rb +3 -0
  333. data/test/models/author.rb +212 -0
  334. data/test/models/auto_id.rb +4 -0
  335. data/test/models/autoloadable/extra_firm.rb +2 -0
  336. data/test/models/binary.rb +2 -0
  337. data/test/models/bird.rb +12 -0
  338. data/test/models/book.rb +18 -0
  339. data/test/models/boolean.rb +2 -0
  340. data/test/models/bulb.rb +51 -0
  341. data/test/models/cake_designer.rb +3 -0
  342. data/test/models/car.rb +26 -0
  343. data/test/models/carrier.rb +2 -0
  344. data/test/models/categorization.rb +19 -0
  345. data/test/models/category.rb +35 -0
  346. data/test/models/chef.rb +3 -0
  347. data/test/models/citation.rb +3 -0
  348. data/test/models/club.rb +23 -0
  349. data/test/models/college.rb +10 -0
  350. data/test/models/column.rb +3 -0
  351. data/test/models/column_name.rb +3 -0
  352. data/test/models/comment.rb +64 -0
  353. data/test/models/company.rb +225 -0
  354. data/test/models/company_in_module.rb +98 -0
  355. data/test/models/computer.rb +3 -0
  356. data/test/models/contact.rb +41 -0
  357. data/test/models/contract.rb +20 -0
  358. data/test/models/country.rb +7 -0
  359. data/test/models/course.rb +6 -0
  360. data/test/models/customer.rb +77 -0
  361. data/test/models/customer_carrier.rb +14 -0
  362. data/test/models/dashboard.rb +3 -0
  363. data/test/models/default.rb +2 -0
  364. data/test/models/department.rb +4 -0
  365. data/test/models/developer.rb +252 -0
  366. data/test/models/dog.rb +5 -0
  367. data/test/models/dog_lover.rb +5 -0
  368. data/test/models/doubloon.rb +12 -0
  369. data/test/models/drink_designer.rb +3 -0
  370. data/test/models/edge.rb +5 -0
  371. data/test/models/electron.rb +5 -0
  372. data/test/models/engine.rb +4 -0
  373. data/test/models/entrant.rb +3 -0
  374. data/test/models/essay.rb +5 -0
  375. data/test/models/event.rb +3 -0
  376. data/test/models/eye.rb +37 -0
  377. data/test/models/face.rb +9 -0
  378. data/test/models/friendship.rb +6 -0
  379. data/test/models/guid.rb +2 -0
  380. data/test/models/hotel.rb +6 -0
  381. data/test/models/image.rb +3 -0
  382. data/test/models/interest.rb +5 -0
  383. data/test/models/invoice.rb +4 -0
  384. data/test/models/item.rb +7 -0
  385. data/test/models/job.rb +7 -0
  386. data/test/models/joke.rb +7 -0
  387. data/test/models/keyboard.rb +3 -0
  388. data/test/models/legacy_thing.rb +3 -0
  389. data/test/models/lesson.rb +11 -0
  390. data/test/models/line_item.rb +3 -0
  391. data/test/models/liquid.rb +4 -0
  392. data/test/models/man.rb +11 -0
  393. data/test/models/matey.rb +4 -0
  394. data/test/models/member.rb +41 -0
  395. data/test/models/member_detail.rb +7 -0
  396. data/test/models/member_type.rb +3 -0
  397. data/test/models/membership.rb +35 -0
  398. data/test/models/minimalistic.rb +2 -0
  399. data/test/models/minivan.rb +9 -0
  400. data/test/models/mixed_case_monkey.rb +3 -0
  401. data/test/models/molecule.rb +6 -0
  402. data/test/models/movie.rb +5 -0
  403. data/test/models/order.rb +4 -0
  404. data/test/models/organization.rb +14 -0
  405. data/test/models/owner.rb +34 -0
  406. data/test/models/parrot.rb +29 -0
  407. data/test/models/person.rb +143 -0
  408. data/test/models/personal_legacy_thing.rb +4 -0
  409. data/test/models/pet.rb +15 -0
  410. data/test/models/pirate.rb +92 -0
  411. data/test/models/possession.rb +3 -0
  412. data/test/models/post.rb +264 -0
  413. data/test/models/price_estimate.rb +4 -0
  414. data/test/models/professor.rb +5 -0
  415. data/test/models/project.rb +29 -0
  416. data/test/models/publisher.rb +2 -0
  417. data/test/models/publisher/article.rb +4 -0
  418. data/test/models/publisher/magazine.rb +3 -0
  419. data/test/models/randomly_named_c1.rb +3 -0
  420. data/test/models/rating.rb +4 -0
  421. data/test/models/reader.rb +23 -0
  422. data/test/models/record.rb +2 -0
  423. data/test/models/reference.rb +22 -0
  424. data/test/models/reply.rb +61 -0
  425. data/test/models/ship.rb +33 -0
  426. data/test/models/ship_part.rb +8 -0
  427. data/test/models/shop.rb +17 -0
  428. data/test/models/shop_account.rb +6 -0
  429. data/test/models/speedometer.rb +6 -0
  430. data/test/models/sponsor.rb +7 -0
  431. data/test/models/string_key_object.rb +3 -0
  432. data/test/models/student.rb +4 -0
  433. data/test/models/subject.rb +16 -0
  434. data/test/models/subscriber.rb +8 -0
  435. data/test/models/subscription.rb +4 -0
  436. data/test/models/tag.rb +7 -0
  437. data/test/models/tagging.rb +13 -0
  438. data/test/models/task.rb +5 -0
  439. data/test/models/topic.rb +124 -0
  440. data/test/models/toy.rb +6 -0
  441. data/test/models/traffic_light.rb +4 -0
  442. data/test/models/treasure.rb +14 -0
  443. data/test/models/treaty.rb +7 -0
  444. data/test/models/tyre.rb +11 -0
  445. data/test/models/uuid_child.rb +3 -0
  446. data/test/models/uuid_parent.rb +3 -0
  447. data/test/models/vegetables.rb +24 -0
  448. data/test/models/vehicle.rb +7 -0
  449. data/test/models/vertex.rb +9 -0
  450. data/test/models/warehouse_thing.rb +5 -5
  451. data/test/models/wheel.rb +3 -0
  452. data/test/models/without_table.rb +3 -0
  453. data/test/models/zine.rb +3 -0
  454. data/test/schema/mysql2_specific_schema.rb +58 -0
  455. data/test/schema/mysql_specific_schema.rb +70 -0
  456. data/test/schema/oracle_specific_schema.rb +43 -0
  457. data/test/schema/postgresql_specific_schema.rb +202 -0
  458. data/test/schema/schema.rb +938 -751
  459. data/test/schema/sqlite_specific_schema.rb +22 -0
  460. data/test/support/config.rb +43 -0
  461. data/test/support/connection.rb +22 -0
  462. data/test/support/connection_helper.rb +14 -0
  463. data/test/support/ddl_helper.rb +8 -0
  464. data/test/support/schema_dumping_helper.rb +20 -0
  465. metadata +444 -18
@@ -1,1182 +1,1815 @@
1
- require "cases/helper"
2
- require 'models/tag'
3
- require 'models/tagging'
4
- require 'models/post'
5
- require 'models/topic'
6
- require 'models/comment'
7
- require 'models/reply'
8
- require 'models/author'
9
- require 'models/comment'
10
- require 'models/entrant'
11
- require 'models/developer'
12
- require 'models/company'
13
- require 'models/bird'
14
- require 'models/car'
15
- require 'models/engine'
16
- require 'models/tyre'
17
- require 'models/minivan'
18
-
19
-
20
- class RelationTest < ActiveRecord::TestCase
21
- fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments,
22
- :tags, :taggings, :cars, :minivans
23
-
24
- def test_do_not_double_quote_string_id
25
- van = Minivan.last
26
- assert van
27
- assert_equal van.id, Minivan.where(:minivan_id => van).to_a.first.minivan_id
28
- end
29
-
30
- def test_do_not_double_quote_string_id_with_array
31
- van = Minivan.last
32
- assert van
33
- assert_equal van, Minivan.where(:minivan_id => [van]).to_a.first
34
- end
35
-
36
- def test_bind_values
37
- relation = Post.scoped
38
- assert_equal [], relation.bind_values
39
-
40
- relation2 = relation.bind 'foo'
41
- assert_equal %w{ foo }, relation2.bind_values
42
- assert_equal [], relation.bind_values
43
- end
44
-
45
- def test_two_scopes_with_includes_should_not_drop_any_include
46
- car = Car.incl_engines.incl_tyres.first
47
- assert_no_queries { car.tyres.length }
48
- assert_no_queries { car.engines.length }
49
- end
50
-
51
- def test_dynamic_finder
52
- x = Post.where('author_id = ?', 1)
53
- assert x.klass.respond_to?(:find_by_id), '@klass should handle dynamic finders'
54
- end
55
-
56
- def test_multivalue_where
57
- posts = Post.where('author_id = ? AND id = ?', 1, 1)
58
- assert_equal 1, posts.to_a.size
59
- end
60
-
61
- def test_scoped
62
- topics = Topic.scoped
63
- assert_kind_of ActiveRecord::Relation, topics
64
- assert_equal 4, topics.size
65
- end
66
-
67
- def test_to_json
68
- assert_nothing_raised { Bird.scoped.to_json }
69
- assert_nothing_raised { Bird.scoped.all.to_json }
70
- end
71
-
72
- def test_to_yaml
73
- assert_nothing_raised { Bird.scoped.to_yaml }
74
- assert_nothing_raised { Bird.scoped.all.to_yaml }
75
- end
76
-
77
- def test_to_xml
78
- assert_nothing_raised { Bird.scoped.to_xml }
79
- assert_nothing_raised { Bird.scoped.all.to_xml }
80
- end
81
-
82
- def test_scoped_all
83
- topics = Topic.scoped.all
84
- assert_kind_of Array, topics
85
- assert_no_queries { assert_equal 4, topics.size }
86
- end
87
-
88
- def test_loaded_all
89
- topics = Topic.scoped
90
-
91
- assert_queries(1) do
92
- 2.times { assert_equal 4, topics.all.size }
93
- end
94
-
95
- assert topics.loaded?
96
- end
97
-
98
- def test_scoped_first
99
- topics = Topic.scoped.order('id ASC')
100
-
101
- assert_queries(1) do
102
- 2.times { assert_equal "The First Topic", topics.first.title }
103
- end
104
-
105
- assert ! topics.loaded?
106
- end
107
-
108
- def test_loaded_first
109
- topics = Topic.scoped.order('id ASC')
110
-
111
- assert_queries(1) do
112
- topics.all # force load
113
- 2.times { assert_equal "The First Topic", topics.first.title }
114
- end
115
-
116
- assert topics.loaded?
117
- end
118
-
119
- def test_reload
120
- topics = Topic.scoped
121
-
122
- assert_queries(1) do
123
- 2.times { topics.to_a }
124
- end
125
-
126
- assert topics.loaded?
127
-
128
- original_size = topics.to_a.size
129
- Topic.create! :title => 'fake'
130
-
131
- assert_queries(1) { topics.reload }
132
- assert_equal original_size + 1, topics.size
133
- assert topics.loaded?
134
- end
135
-
136
- def test_finding_with_conditions
137
- assert_equal ["David"], Author.where(:name => 'David').map(&:name)
138
- assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name)
139
- assert_equal ['Mary'], Author.where("name = ?", 'Mary').map(&:name)
140
- end
141
-
142
- def test_finding_with_order
143
- topics = Topic.order('id')
144
- assert_equal 4, topics.to_a.size
145
- assert_equal topics(:first).title, topics.first.title
146
- end
147
-
148
-
149
- def test_finding_with_arel_order
150
- topics = Topic.order(Topic.arel_table[:id].asc)
151
- assert_equal 4, topics.to_a.size
152
- assert_equal topics(:first).title, topics.first.title
153
- end
154
-
155
- def test_finding_last_with_arel_order
156
- topics = Topic.order(Topic.arel_table[:id].asc)
157
- assert_equal topics(:fourth).title, topics.last.title
158
- end
159
-
160
- def test_finding_with_order_concatenated
161
- topics = Topic.order('author_name').order('title')
162
- assert_equal 4, topics.to_a.size
163
- assert_equal topics(:fourth).title, topics.first.title
164
- end
165
-
166
- def test_finding_with_reorder
167
- topics = Topic.order('author_name').order('title').reorder('id').all
168
- topics_titles = topics.map{ |t| t.title }
169
- assert_equal ['The First Topic', 'The Second Topic of the day', 'The Third Topic of the day', 'The Fourth Topic of the day'], topics_titles
170
- end
171
-
172
- def test_finding_with_order_and_take
173
- entrants = Entrant.order("id ASC").limit(2).to_a
174
-
175
- assert_equal 2, entrants.size
176
- assert_equal entrants(:first).name, entrants.first.name
177
- end
178
-
179
- def test_finding_with_cross_table_order_and_limit
180
- tags = Tag.includes(:taggings).
181
- order("tags.name asc", "taggings.taggable_id asc", "REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").
182
- limit(1).to_a
183
- assert_equal 1, tags.length
184
- end
185
-
186
- def test_finding_with_complex_order_and_limit
187
- tags = Tag.includes(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").limit(1).to_a
188
- assert_equal 1, tags.length
189
- end
190
-
191
- def test_finding_with_complex_order
192
- tags = Tag.includes(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").to_a
193
- assert_equal 3, tags.length
194
- end
195
-
196
- def test_finding_with_order_limit_and_offset
197
- entrants = Entrant.order("id ASC").limit(2).offset(1)
198
-
199
- assert_equal 2, entrants.to_a.size
200
- assert_equal entrants(:second).name, entrants.first.name
201
-
202
- entrants = Entrant.order("id ASC").limit(2).offset(2)
203
- assert_equal 1, entrants.to_a.size
204
- assert_equal entrants(:third).name, entrants.first.name
205
- end
206
-
207
- def test_finding_with_group
208
- developers = Developer.group("salary").select("salary").to_a
209
- assert_equal 4, developers.size
210
- assert_equal 4, developers.map(&:salary).uniq.size
211
- end
212
-
213
- def test_select_with_block
214
- even_ids = Developer.scoped.select {|d| d.id % 2 == 0 }.map(&:id)
215
- assert_equal [2, 4, 6, 8, 10], even_ids.sort
216
- end
217
-
218
- def test_joins_with_nil_argument
219
- assert_nothing_raised { DependentFirm.joins(nil).first }
220
- end
221
-
222
- def test_finding_with_hash_conditions_on_joined_table
223
- firms = DependentFirm.joins(:account).where({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a
224
- assert_equal 1, firms.size
225
- assert_equal companies(:rails_core), firms.first
226
- end
227
-
228
- def test_find_all_with_join
229
- developers_on_project_one = Developer.joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').
230
- where('project_id=1').to_a
231
-
232
- assert_equal 3, developers_on_project_one.length
233
- developer_names = developers_on_project_one.map { |d| d.name }
234
- assert developer_names.include?('David')
235
- assert developer_names.include?('Jamis')
236
- end
237
-
238
- def test_find_on_hash_conditions
239
- assert_equal Topic.find(:all, :conditions => {:approved => false}), Topic.where({ :approved => false }).to_a
240
- end
241
-
242
- def test_joins_with_string_array
243
- person_with_reader_and_post = Post.joins([
244
- "INNER JOIN categorizations ON categorizations.post_id = posts.id",
245
- "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
246
- ]
247
- ).to_a
248
- assert_equal 1, person_with_reader_and_post.size
249
- end
250
-
251
- def test_scoped_responds_to_delegated_methods
252
- relation = Topic.scoped
253
-
254
- ["map", "uniq", "sort", "insert", "delete", "update"].each do |method|
255
- assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}"
256
- end
257
- end
258
-
259
- def test_respond_to_delegates_to_relation
260
- relation = Topic.scoped
261
- fake_arel = Struct.new(:responds) {
262
- def respond_to? method, access = false
263
- responds << [method, access]
264
- end
265
- }.new []
266
-
267
- relation.extend(Module.new { attr_accessor :arel })
268
- relation.arel = fake_arel
269
-
270
- relation.respond_to?(:matching_attributes)
271
- assert_equal [:matching_attributes, false], fake_arel.responds.first
272
-
273
- fake_arel.responds = []
274
- relation.respond_to?(:matching_attributes, true)
275
- assert_equal [:matching_attributes, true], fake_arel.responds.first
276
- end
277
-
278
- def test_respond_to_dynamic_finders
279
- relation = Topic.scoped
280
-
281
- ["find_by_title", "find_by_title_and_author_name", "find_or_create_by_title", "find_or_initialize_by_title_and_author_name"].each do |method|
282
- assert_respond_to relation, method, "Topic.scoped should respond to #{method.inspect}"
283
- end
284
- end
285
-
286
- def test_respond_to_class_methods_and_scopes
287
- assert DeveloperOrderedBySalary.scoped.respond_to?(:all_ordered_by_name)
288
- assert Topic.scoped.respond_to?(:by_lifo)
289
- end
290
-
291
- def test_find_with_readonly_option
292
- Developer.scoped.each { |d| assert !d.readonly? }
293
- Developer.scoped.readonly.each { |d| assert d.readonly? }
294
- end
295
-
296
- def test_eager_association_loading_of_stis_with_multiple_references
297
- authors = Author.eager_load(:posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } }).
298
- order('comments.body, very_special_comments_posts.body').where('posts.id = 4').to_a
299
-
300
- assert_equal [authors(:david)], authors
301
- assert_no_queries do
302
- authors.first.posts.first.special_comments.first.post.special_comments
303
- authors.first.posts.first.special_comments.first.post.very_special_comment
304
- end
305
- end
306
-
307
- def test_find_with_preloaded_associations
308
- assert_queries(2) do
309
- posts = Post.preload(:comments).order('posts.id')
310
- assert posts.first.comments.first
311
- end
312
-
313
- assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do
314
- posts = Post.preload(:comments).order('posts.id')
315
- assert posts.first.comments.first
316
- end
317
-
318
- assert_queries(2) do
319
- posts = Post.preload(:author).order('posts.id')
320
- assert posts.first.author
321
- end
322
-
323
- assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do
324
- posts = Post.preload(:author).order('posts.id')
325
- assert posts.first.author
326
- end
327
-
328
- assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 3) do
329
- posts = Post.preload(:author, :comments).order('posts.id')
330
- assert posts.first.author
331
- assert posts.first.comments.first
332
- end
333
- end
334
-
335
- def test_find_with_included_associations
336
- assert_queries(2) do
337
- posts = Post.includes(:comments).order('posts.id')
338
- assert posts.first.comments.first
339
- end
340
-
341
- assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 2) do
342
- posts = Post.scoped.includes(:comments).order('posts.id')
343
- assert posts.first.comments.first
344
- end
345
-
346
- assert_queries(2) do
347
- posts = Post.includes(:author).order('posts.id')
348
- assert posts.first.author
349
- end
350
-
351
- assert_queries(ActiveRecord::IdentityMap.enabled? ? 1 : 3) do
352
- posts = Post.includes(:author, :comments).order('posts.id')
353
- assert posts.first.author
354
- assert posts.first.comments.first
355
- end
356
- end
357
-
358
- def test_default_scope_with_conditions_string
359
- assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.scoped.map(&:id).sort
360
- assert_nil DeveloperCalledDavid.create!.name
361
- end
362
-
363
- def test_default_scope_with_conditions_hash
364
- assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.scoped.map(&:id).sort
365
- assert_equal 'Jamis', DeveloperCalledJamis.create!.name
366
- end
367
-
368
- def test_default_scoping_finder_methods
369
- developers = DeveloperCalledDavid.order('id').map(&:id).sort
370
- assert_equal Developer.find_all_by_name('David').map(&:id).sort, developers
371
- end
372
-
373
- def test_loading_with_one_association
374
- posts = Post.preload(:comments)
375
- post = posts.find { |p| p.id == 1 }
376
- assert_equal 2, post.comments.size
377
- assert post.comments.include?(comments(:greetings))
378
-
379
- post = Post.where("posts.title = 'Welcome to the weblog'").preload(:comments).first
380
- assert_equal 2, post.comments.size
381
- assert post.comments.include?(comments(:greetings))
382
-
383
- posts = Post.preload(:last_comment)
384
- post = posts.find { |p| p.id == 1 }
385
- assert_equal Post.find(1).last_comment, post.last_comment
386
- end
387
-
388
- def test_loading_with_one_association_with_non_preload
389
- posts = Post.eager_load(:last_comment).order('comments.id DESC')
390
- post = posts.find { |p| p.id == 1 }
391
- assert_equal Post.find(1).last_comment, post.last_comment
392
- end
393
-
394
- def test_dynamic_find_by_attributes_should_yield_found_object
395
- david = authors(:david)
396
- yielded_value = nil
397
- Author.find_by_name(david.name) do |author|
398
- yielded_value = author
399
- end
400
- assert_equal david, yielded_value
401
- end
402
-
403
- def test_dynamic_find_by_attributes
404
- david = authors(:david)
405
- author = Author.preload(:taggings).find_by_id(david.id)
406
- expected_taggings = taggings(:welcome_general, :thinking_general)
407
-
408
- assert_no_queries do
409
- assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
410
- end
411
-
412
- authors = Author.scoped
413
- assert_equal david, authors.find_by_id_and_name(david.id, david.name)
414
- assert_equal david, authors.find_by_id_and_name!(david.id, david.name)
415
- end
416
-
417
- def test_dynamic_find_by_attributes_bang
418
- author = Author.scoped.find_by_id!(authors(:david).id)
419
- assert_equal "David", author.name
420
-
421
- assert_raises(ActiveRecord::RecordNotFound) { Author.scoped.find_by_id_and_name!(20, 'invalid') }
422
- end
423
-
424
- def test_dynamic_find_all_by_attributes
425
- authors = Author.scoped
426
-
427
- davids = authors.find_all_by_name('David')
428
- assert_kind_of Array, davids
429
- assert_equal [authors(:david)], davids
430
- end
431
-
432
- def test_dynamic_find_or_initialize_by_attributes
433
- authors = Author.scoped
434
-
435
- lifo = authors.find_or_initialize_by_name('Lifo')
436
- assert_equal "Lifo", lifo.name
437
- assert !lifo.persisted?
438
-
439
- assert_equal authors(:david), authors.find_or_initialize_by_name(:name => 'David')
440
- end
441
-
442
- def test_dynamic_find_or_create_by_attributes
443
- authors = Author.scoped
444
-
445
- lifo = authors.find_or_create_by_name('Lifo')
446
- assert_equal "Lifo", lifo.name
447
- assert lifo.persisted?
448
-
449
- assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David')
450
- end
451
-
452
- def test_dynamic_find_or_create_by_attributes_bang
453
- authors = Author.scoped
454
-
455
- assert_raises(ActiveRecord::RecordInvalid) { authors.find_or_create_by_name!('') }
456
-
457
- lifo = authors.find_or_create_by_name!('Lifo')
458
- assert_equal "Lifo", lifo.name
459
- assert lifo.persisted?
460
-
461
- assert_equal authors(:david), authors.find_or_create_by_name!(:name => 'David')
462
- end
463
-
464
- def test_find_id
465
- authors = Author.scoped
466
-
467
- david = authors.find(authors(:david).id)
468
- assert_equal 'David', david.name
469
-
470
- assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('42') }
471
- end
472
-
473
- def test_find_ids
474
- authors = Author.order('id ASC')
475
-
476
- results = authors.find(authors(:david).id, authors(:mary).id)
477
- assert_kind_of Array, results
478
- assert_equal 2, results.size
479
- assert_equal 'David', results[0].name
480
- assert_equal 'Mary', results[1].name
481
- assert_equal results, authors.find([authors(:david).id, authors(:mary).id])
482
-
483
- assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, '42') }
484
- assert_raises(ActiveRecord::RecordNotFound) { authors.find(['42', 43]) }
485
- end
486
-
487
- def test_find_in_empty_array
488
- authors = Author.scoped.where(:id => [])
489
- assert_blank authors.all
490
- end
491
-
492
- def test_where_with_ar_object
493
- author = Author.first
494
- authors = Author.scoped.where(:id => author)
495
- assert_equal 1, authors.all.length
496
- end
497
-
498
- def test_find_with_list_of_ar
499
- author = Author.first
500
- authors = Author.find([author])
501
- assert_equal author, authors.first
502
- end
503
-
504
- class Mary < Author; end
505
-
506
- def test_find_by_classname
507
- Author.create!(:name => Mary.name)
508
- assert_equal 1, Author.where(:name => Mary).size
509
- end
510
-
511
- def test_find_by_id_with_list_of_ar
512
- author = Author.first
513
- authors = Author.find_by_id([author])
514
- assert_equal author, authors
515
- end
516
-
517
- def test_find_all_using_where_twice_should_or_the_relation
518
- david = authors(:david)
519
- relation = Author.unscoped
520
- relation = relation.where(:name => david.name)
521
- relation = relation.where(:name => 'Santiago')
522
- relation = relation.where(:id => david.id)
523
- assert_equal [], relation.all
524
- end
525
-
526
- def test_multi_where_ands_queries
527
- relation = Author.unscoped
528
- david = authors(:david)
529
- sql = relation.where(:name => david.name).where(:name => 'Santiago').to_sql
530
- assert_match('AND', sql)
531
- end
532
-
533
- def test_find_all_with_multiple_should_use_and
534
- david = authors(:david)
535
- relation = [
536
- { :name => david.name },
537
- { :name => 'Santiago' },
538
- { :name => 'tenderlove' },
539
- ].inject(Author.unscoped) do |memo, param|
540
- memo.where(param)
541
- end
542
- assert_equal [], relation.all
543
- end
544
-
545
- def test_find_all_using_where_with_relation
546
- david = authors(:david)
547
- # switching the lines below would succeed in current rails
548
- # assert_queries(2) {
549
- assert_queries(1) {
550
- relation = Author.where(:id => Author.where(:id => david.id))
551
- assert_equal [david], relation.all
552
- }
553
- end
554
-
555
- def test_find_all_using_where_with_relation_and_alternate_primary_key
556
- cool_first = minivans(:cool_first)
557
- # switching the lines below would succeed in current rails
558
- # assert_queries(2) {
559
- assert_queries(1) {
560
- relation = Minivan.where(:minivan_id => Minivan.where(:name => cool_first.name))
561
- assert_equal [cool_first], relation.all
562
- }
563
- end
564
-
565
- def test_find_all_using_where_with_relation_does_not_alter_select_values
566
- david = authors(:david)
567
-
568
- subquery = Author.where(:id => david.id)
569
-
570
- assert_queries(1) {
571
- relation = Author.where(:id => subquery)
572
- assert_equal [david], relation.all
573
- }
574
-
575
- assert_equal 0, subquery.select_values.size
576
- end
577
-
578
- def test_find_all_using_where_with_relation_with_joins
579
- david = authors(:david)
580
- assert_queries(1) {
581
- relation = Author.where(:id => Author.joins(:posts).where(:id => david.id))
582
- assert_equal [david], relation.all
583
- }
584
- end
585
-
586
-
587
- def test_find_all_using_where_with_relation_with_select_to_build_subquery
588
- david = authors(:david)
589
- assert_queries(1) {
590
- relation = Author.where(:name => Author.where(:id => david.id).select(:name))
591
- assert_equal [david], relation.all
592
- }
593
- end
594
-
595
- def test_exists
596
- davids = Author.where(:name => 'David')
597
- assert davids.exists?
598
- assert davids.exists?(authors(:david).id)
599
- assert ! davids.exists?(authors(:mary).id)
600
- assert ! davids.exists?("42")
601
- assert ! davids.exists?(42)
602
-
603
- fake = Author.where(:name => 'fake author')
604
- assert ! fake.exists?
605
- assert ! fake.exists?(authors(:david).id)
606
- end
607
-
608
- def test_last
609
- authors = Author.scoped
610
- assert_equal authors(:bob), authors.last
611
- end
612
-
613
- def test_destroy_all
614
- davids = Author.where(:name => 'David')
615
-
616
- # Force load
617
- assert_equal [authors(:david)], davids.to_a
618
- assert davids.loaded?
619
-
620
- assert_difference('Author.count', -1) { davids.destroy_all }
621
-
622
- assert_equal [], davids.to_a
623
- assert davids.loaded?
624
- end
625
-
626
- def test_delete_all
627
- davids = Author.where(:name => 'David')
628
-
629
- assert_difference('Author.count', -1) { davids.delete_all }
630
- assert ! davids.loaded?
631
- end
632
-
633
- def test_delete_all_loaded
634
- davids = Author.where(:name => 'David')
635
-
636
- # Force load
637
- assert_equal [authors(:david)], davids.to_a
638
- assert davids.loaded?
639
-
640
- assert_difference('Author.count', -1) { davids.delete_all }
641
-
642
- assert_equal [], davids.to_a
643
- assert davids.loaded?
644
- end
645
-
646
- def test_select_argument_error
647
- assert_raises(ArgumentError) { Developer.select }
648
- end
649
-
650
- def test_relation_merging
651
- devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order('id ASC').where("id < 3"))
652
- assert_equal [developers(:david), developers(:jamis)], devs.to_a
653
-
654
- dev_with_count = Developer.limit(1).merge(Developer.order('id DESC')).merge(Developer.select('developers.*'))
655
- assert_equal [developers(:poor_jamis)], dev_with_count.to_a
656
- end
657
-
658
- def test_relation_merging_with_eager_load
659
- relations = []
660
- relations << Post.order('comments.id DESC').merge(Post.eager_load(:last_comment)).merge(Post.scoped)
661
- relations << Post.eager_load(:last_comment).merge(Post.order('comments.id DESC')).merge(Post.scoped)
662
-
663
- relations.each do |posts|
664
- post = posts.find { |p| p.id == 1 }
665
- assert_equal Post.find(1).last_comment, post.last_comment
666
- end
667
- end
668
-
669
- def test_relation_merging_with_locks
670
- devs = Developer.lock.where("salary >= 80000").order("id DESC").merge(Developer.limit(2))
671
- assert_present devs.locked
672
- end
673
-
674
- def test_relation_merging_with_preload
675
- ActiveRecord::IdentityMap.without do
676
- [Post.scoped.merge(Post.preload(:author)), Post.preload(:author).merge(Post.scoped)].each do |posts|
677
- assert_queries(2) { assert posts.order(:id).first.author }
678
- end
679
- end
680
- end
681
-
682
- def test_relation_merging_with_joins
683
- comments = Comment.joins(:post).where(:body => 'Thank you for the welcome').merge(Post.where(:body => 'Such a lovely day'))
684
- assert_equal 1, comments.count
685
- end
686
-
687
- def test_count
688
- posts = Post.scoped
689
-
690
- assert_equal 11, posts.count
691
- assert_equal 11, posts.count(:all)
692
- assert_equal 11, posts.count(:id)
693
-
694
- assert_equal 1, posts.where('comments_count > 1').count
695
- assert_equal 9, posts.where(:comments_count => 0).count
696
- end
697
-
698
- def test_count_with_distinct
699
- posts = Post.scoped
700
-
701
- assert_equal 3, posts.count(:comments_count, :distinct => true)
702
- assert_equal 11, posts.count(:comments_count, :distinct => false)
703
-
704
- assert_equal 3, posts.select(:comments_count).count(:distinct => true)
705
- assert_equal 11, posts.select(:comments_count).count(:distinct => false)
706
- end
707
-
708
- def test_count_explicit_columns
709
- Post.update_all(:comments_count => nil)
710
- posts = Post.scoped
711
-
712
- assert_equal [0], posts.select('comments_count').where('id is not null').group('id').order('id').count.values.uniq
713
- assert_equal 0, posts.where('id is not null').select('comments_count').count
714
-
715
- assert_equal 11, posts.select('comments_count').count('id')
716
- assert_equal 0, posts.select('comments_count').count
717
- assert_equal 0, posts.count(:comments_count)
718
- assert_equal 0, posts.count('comments_count')
719
- end
720
-
721
- def test_multiple_selects
722
- post = Post.scoped.select('comments_count').select('title').order("id ASC").first
723
- assert_equal "Welcome to the weblog", post.title
724
- assert_equal 2, post.comments_count
725
- end
726
-
727
- def test_size
728
- posts = Post.scoped
729
-
730
- assert_queries(1) { assert_equal 11, posts.size }
731
- assert ! posts.loaded?
732
-
733
- best_posts = posts.where(:comments_count => 0)
734
- best_posts.to_a # force load
735
- assert_no_queries { assert_equal 9, best_posts.size }
736
- end
737
-
738
- def test_size_with_limit
739
- posts = Post.limit(10)
740
-
741
- assert_queries(1) { assert_equal 10, posts.size }
742
- assert ! posts.loaded?
743
-
744
- best_posts = posts.where(:comments_count => 0)
745
- best_posts.to_a # force load
746
- assert_no_queries { assert_equal 9, best_posts.size }
747
- end
748
-
749
- def test_size_with_zero_limit
750
- posts = Post.limit(0)
751
-
752
- assert_no_queries { assert_equal 0, posts.size }
753
- assert ! posts.loaded?
754
-
755
- posts.to_a # force load
756
- assert_no_queries { assert_equal 0, posts.size }
757
- end
758
-
759
- def test_empty_with_zero_limit
760
- posts = Post.limit(0)
761
-
762
- assert_no_queries { assert_equal true, posts.empty? }
763
- assert ! posts.loaded?
764
- end
765
-
766
- def test_count_complex_chained_relations
767
- posts = Post.select('comments_count').where('id is not null').group("author_id").where("comments_count > 0")
768
-
769
- expected = { 1 => 2 }
770
- assert_equal expected, posts.count
771
- end
772
-
773
- def test_empty
774
- posts = Post.scoped
775
-
776
- assert_queries(1) { assert_equal false, posts.empty? }
777
- assert ! posts.loaded?
778
-
779
- no_posts = posts.where(:title => "")
780
- assert_queries(1) { assert_equal true, no_posts.empty? }
781
- assert ! no_posts.loaded?
782
-
783
- best_posts = posts.where(:comments_count => 0)
784
- best_posts.to_a # force load
785
- assert_no_queries { assert_equal false, best_posts.empty? }
786
- end
787
-
788
- def test_empty_complex_chained_relations
789
- posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0")
790
-
791
- assert_queries(1) { assert_equal false, posts.empty? }
792
- assert ! posts.loaded?
793
-
794
- no_posts = posts.where(:title => "")
795
- assert_queries(1) { assert_equal true, no_posts.empty? }
796
- assert ! no_posts.loaded?
797
- end
798
-
799
- def test_any
800
- posts = Post.scoped
801
-
802
- # This test was failing when run on its own (as opposed to running the entire suite).
803
- # The second line in the assert_queries block was causing visit_Arel_Attributes_Attribute
804
- # in Arel::Visitors::ToSql to trigger a SHOW TABLES query. Running that line here causes
805
- # the SHOW TABLES result to be cached so we don't have to do it again in the block.
806
- #
807
- # This is obviously a rubbish fix but it's the best I can come up with for now...
808
- posts.where(:id => nil).any?
809
-
810
- assert_queries(3) do
811
- assert posts.any? # Uses COUNT()
812
- assert ! posts.where(:id => nil).any?
813
-
814
- assert posts.any? {|p| p.id > 0 }
815
- assert ! posts.any? {|p| p.id <= 0 }
816
- end
817
-
818
- assert posts.loaded?
819
- end
820
-
821
- def test_many
822
- posts = Post.scoped
823
-
824
- assert_queries(2) do
825
- assert posts.many? # Uses COUNT()
826
- assert posts.many? {|p| p.id > 0 }
827
- assert ! posts.many? {|p| p.id < 2 }
828
- end
829
-
830
- assert posts.loaded?
831
- end
832
-
833
- def test_many_with_limits
834
- posts = Post.scoped
835
-
836
- assert posts.many?
837
- assert ! posts.limit(1).many?
838
- end
839
-
840
- def test_build
841
- posts = Post.scoped
842
-
843
- post = posts.new
844
- assert_kind_of Post, post
845
- end
846
-
847
- def test_scoped_build
848
- posts = Post.where(:title => 'You told a lie')
849
-
850
- post = posts.new
851
- assert_kind_of Post, post
852
- assert_equal 'You told a lie', post.title
853
- end
854
-
855
- def test_create
856
- birds = Bird.scoped
857
-
858
- sparrow = birds.create
859
- assert_kind_of Bird, sparrow
860
- assert !sparrow.persisted?
861
-
862
- hen = birds.where(:name => 'hen').create
863
- assert hen.persisted?
864
- assert_equal 'hen', hen.name
865
- end
866
-
867
- def test_create_bang
868
- birds = Bird.scoped
869
-
870
- assert_raises(ActiveRecord::RecordInvalid) { birds.create! }
871
-
872
- hen = birds.where(:name => 'hen').create!
873
- assert_kind_of Bird, hen
874
- assert hen.persisted?
875
- assert_equal 'hen', hen.name
876
- end
877
-
878
- def test_first_or_create
879
- parrot = Bird.where(:color => 'green').first_or_create(:name => 'parrot')
880
- assert_kind_of Bird, parrot
881
- assert parrot.persisted?
882
- assert_equal 'parrot', parrot.name
883
- assert_equal 'green', parrot.color
884
-
885
- same_parrot = Bird.where(:color => 'green').first_or_create(:name => 'parakeet')
886
- assert_kind_of Bird, same_parrot
887
- assert same_parrot.persisted?
888
- assert_equal parrot, same_parrot
889
- end
890
-
891
- def test_first_or_create_with_no_parameters
892
- parrot = Bird.where(:color => 'green').first_or_create
893
- assert_kind_of Bird, parrot
894
- assert !parrot.persisted?
895
- assert_equal 'green', parrot.color
896
- end
897
-
898
- def test_first_or_create_with_block
899
- parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parrot' }
900
- assert_kind_of Bird, parrot
901
- assert parrot.persisted?
902
- assert_equal 'green', parrot.color
903
- assert_equal 'parrot', parrot.name
904
-
905
- same_parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parakeet' }
906
- assert_equal parrot, same_parrot
907
- end
908
-
909
- def test_first_or_create_with_array
910
- several_green_birds = Bird.where(:color => 'green').first_or_create([{:name => 'parrot'}, {:name => 'parakeet'}])
911
- assert_kind_of Array, several_green_birds
912
- several_green_birds.each { |bird| assert bird.persisted? }
913
-
914
- same_parrot = Bird.where(:color => 'green').first_or_create([{:name => 'hummingbird'}, {:name => 'macaw'}])
915
- assert_kind_of Bird, same_parrot
916
- assert_equal several_green_birds.first, same_parrot
917
- end
918
-
919
- def test_first_or_create_bang_with_valid_options
920
- parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parrot')
921
- assert_kind_of Bird, parrot
922
- assert parrot.persisted?
923
- assert_equal 'parrot', parrot.name
924
- assert_equal 'green', parrot.color
925
-
926
- same_parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parakeet')
927
- assert_kind_of Bird, same_parrot
928
- assert same_parrot.persisted?
929
- assert_equal parrot, same_parrot
930
- end
931
-
932
- def test_first_or_create_bang_with_invalid_options
933
- assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!(:pirate_id => 1) }
934
- end
935
-
936
- def test_first_or_create_bang_with_no_parameters
937
- assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create! }
938
- end
939
-
940
- def test_first_or_create_bang_with_valid_block
941
- parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parrot' }
942
- assert_kind_of Bird, parrot
943
- assert parrot.persisted?
944
- assert_equal 'green', parrot.color
945
- assert_equal 'parrot', parrot.name
946
-
947
- same_parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parakeet' }
948
- assert_equal parrot, same_parrot
949
- end
950
-
951
- def test_first_or_create_bang_with_invalid_block
952
- assert_raise(ActiveRecord::RecordInvalid) do
953
- Bird.where(:color => 'green').first_or_create! { |bird| bird.pirate_id = 1 }
954
- end
955
- end
956
-
957
- def test_first_or_create_with_valid_array
958
- several_green_birds = Bird.where(:color => 'green').first_or_create!([{:name => 'parrot'}, {:name => 'parakeet'}])
959
- assert_kind_of Array, several_green_birds
960
- several_green_birds.each { |bird| assert bird.persisted? }
961
-
962
- same_parrot = Bird.where(:color => 'green').first_or_create!([{:name => 'hummingbird'}, {:name => 'macaw'}])
963
- assert_kind_of Bird, same_parrot
964
- assert_equal several_green_birds.first, same_parrot
965
- end
966
-
967
- def test_first_or_create_with_invalid_array
968
- assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!([ {:name => 'parrot'}, {:pirate_id => 1} ]) }
969
- end
970
-
971
- def test_first_or_initialize
972
- parrot = Bird.where(:color => 'green').first_or_initialize(:name => 'parrot')
973
- assert_kind_of Bird, parrot
974
- assert !parrot.persisted?
975
- assert parrot.valid?
976
- assert parrot.new_record?
977
- assert_equal 'parrot', parrot.name
978
- assert_equal 'green', parrot.color
979
- end
980
-
981
- def test_first_or_initialize_with_no_parameters
982
- parrot = Bird.where(:color => 'green').first_or_initialize
983
- assert_kind_of Bird, parrot
984
- assert !parrot.persisted?
985
- assert !parrot.valid?
986
- assert parrot.new_record?
987
- assert_equal 'green', parrot.color
988
- end
989
-
990
- def test_first_or_initialize_with_block
991
- parrot = Bird.where(:color => 'green').first_or_initialize { |bird| bird.name = 'parrot' }
992
- assert_kind_of Bird, parrot
993
- assert !parrot.persisted?
994
- assert parrot.valid?
995
- assert parrot.new_record?
996
- assert_equal 'green', parrot.color
997
- assert_equal 'parrot', parrot.name
998
- end
999
-
1000
- def test_explicit_create_scope
1001
- hens = Bird.where(:name => 'hen')
1002
- assert_equal 'hen', hens.new.name
1003
-
1004
- hens = hens.create_with(:name => 'cock')
1005
- assert_equal 'cock', hens.new.name
1006
- end
1007
-
1008
- def test_except
1009
- relation = Post.where(:author_id => 1).order('id ASC').limit(1)
1010
- assert_equal [posts(:welcome)], relation.all
1011
-
1012
- author_posts = relation.except(:order, :limit)
1013
- assert_equal Post.where(:author_id => 1).all, author_posts.all
1014
-
1015
- all_posts = relation.except(:where, :order, :limit)
1016
- assert_equal Post.all, all_posts.all
1017
- end
1018
-
1019
- def test_extensions_with_except
1020
- assert_equal 2, Topic.named_extension.order(:author_name).except(:order).two
1021
- end
1022
-
1023
- def test_only
1024
- relation = Post.where(:author_id => 1).order('id ASC').limit(1)
1025
- assert_equal [posts(:welcome)], relation.all
1026
-
1027
- author_posts = relation.only(:where)
1028
- assert_equal Post.where(:author_id => 1).all, author_posts.all
1029
-
1030
- all_posts = relation.only(:limit)
1031
- assert_equal Post.limit(1).all.first, all_posts.first
1032
- end
1033
-
1034
- def test_extensions_with_only
1035
- assert_equal 2, Topic.named_extension.order(:author_name).only(:order).two
1036
- end
1037
-
1038
- def test_anonymous_extension
1039
- relation = Post.where(:author_id => 1).order('id ASC').extending do
1040
- def author
1041
- 'lifo'
1042
- end
1043
- end
1044
-
1045
- assert_equal "lifo", relation.author
1046
- assert_equal "lifo", relation.limit(1).author
1047
- end
1048
-
1049
- def test_named_extension
1050
- relation = Post.where(:author_id => 1).order('id ASC').extending(Post::NamedExtension)
1051
- assert_equal "lifo", relation.author
1052
- assert_equal "lifo", relation.limit(1).author
1053
- end
1054
-
1055
- def test_order_by_relation_attribute
1056
- assert_equal Post.order(Post.arel_table[:title]).all, Post.order("title").all
1057
- end
1058
-
1059
- def test_order_with_find_with_order
1060
- assert_equal 'zyke', CoolCar.order('name desc').find(:first, :order => 'id').name
1061
- assert_equal 'zyke', FastCar.order('name desc').find(:first, :order => 'id').name
1062
- end
1063
-
1064
- def test_default_scope_order_with_scope_order
1065
- assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name
1066
- assert_equal 'zyke', CoolCar.order_using_old_style.limit(1).first.name
1067
- assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name
1068
- assert_equal 'zyke', FastCar.order_using_old_style.limit(1).first.name
1069
- end
1070
-
1071
- def test_order_using_scoping
1072
- car1 = CoolCar.order('id DESC').scoping do
1073
- CoolCar.find(:first, :order => 'id asc')
1074
- end
1075
- assert_equal 'zyke', car1.name
1076
-
1077
- car2 = FastCar.order('id DESC').scoping do
1078
- FastCar.find(:first, :order => 'id asc')
1079
- end
1080
- assert_equal 'zyke', car2.name
1081
- end
1082
-
1083
- def test_unscoped_block_style
1084
- assert_equal 'honda', CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name}
1085
- assert_equal 'honda', CoolCar.unscoped { CoolCar.order_using_old_style.limit(1).first.name}
1086
-
1087
- assert_equal 'honda', FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name}
1088
- assert_equal 'honda', FastCar.unscoped { FastCar.order_using_old_style.limit(1).first.name}
1089
- end
1090
-
1091
- def test_intersection_with_array
1092
- relation = Author.where(:name => "David")
1093
- rails_author = relation.first
1094
-
1095
- assert_equal [rails_author], [rails_author] & relation
1096
- assert_equal [rails_author], relation & [rails_author]
1097
- end
1098
-
1099
- def test_removing_limit_with_options
1100
- assert_not_equal 1, Post.limit(1).all(:limit => nil).count
1101
- end
1102
-
1103
- def test_primary_key
1104
- assert_equal "id", Post.scoped.primary_key
1105
- end
1106
-
1107
- def test_eager_loading_with_conditions_on_joins
1108
- scope = Post.includes(:comments)
1109
-
1110
- # This references the comments table, and so it should cause the comments to be eager
1111
- # loaded via a JOIN, rather than by subsequent queries.
1112
- scope = scope.joins(
1113
- Post.arel_table.create_join(
1114
- Post.arel_table,
1115
- Post.arel_table.create_on(Comment.arel_table[:id].eq(3))
1116
- )
1117
- )
1118
-
1119
- assert scope.eager_loading?
1120
- end
1121
-
1122
- def test_ordering_with_extra_spaces
1123
- assert_equal authors(:david), Author.order('id DESC , name DESC').last
1124
- end
1125
-
1126
- def test_update_all_with_joins
1127
- comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id)
1128
- count = comments.count
1129
-
1130
- assert_equal count, comments.update_all(:post_id => posts(:thinking).id)
1131
- assert_equal posts(:thinking), comments(:greetings).post
1132
- end
1133
-
1134
- def test_update_all_with_joins_and_limit
1135
- comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).limit(1)
1136
- assert_equal 1, comments.update_all(:post_id => posts(:thinking).id)
1137
- end
1138
-
1139
- def test_update_all_with_joins_and_limit_and_order
1140
- comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('comments.id').limit(1)
1141
- assert_equal 1, comments.update_all(:post_id => posts(:thinking).id)
1142
- assert_equal posts(:thinking), comments(:greetings).post
1143
- assert_equal posts(:welcome), comments(:more_greetings).post
1144
- end
1145
-
1146
- unless current_adapter?(:IBM_DBAdapter)
1147
- #IBM_DB does not support offset on subselect of the update statement
1148
- def test_update_all_with_joins_and_offset
1149
- all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id)
1150
- count = all_comments.count
1151
- comments = all_comments.offset(1)
1152
-
1153
- assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id)
1154
- end
1155
-
1156
- def test_update_all_with_joins_and_offset_and_order
1157
- all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('posts.id', 'comments.id')
1158
- count = all_comments.count
1159
- comments = all_comments.offset(1)
1160
-
1161
- assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id)
1162
- assert_equal posts(:thinking), comments(:more_greetings).post
1163
- assert_equal posts(:welcome), comments(:greetings).post
1164
- end
1165
- end
1166
-
1167
- def test_uniq
1168
- tag1 = Tag.create(:name => 'Foo')
1169
- tag2 = Tag.create(:name => 'Foo')
1170
-
1171
- query = Tag.select(:name).where(:id => [tag1.id, tag2.id])
1172
-
1173
- assert_equal ['Foo', 'Foo'], query.map(&:name)
1174
- assert_sql(/DISTINCT/) do
1175
- assert_equal ['Foo'], query.uniq.map(&:name)
1176
- end
1177
- assert_sql(/DISTINCT/) do
1178
- assert_equal ['Foo'], query.uniq(true).map(&:name)
1179
- end
1180
- assert_equal ['Foo', 'Foo'], query.uniq(true).uniq(false).map(&:name)
1181
- end
1182
- end
1
+ require "cases/helper"
2
+ require 'models/tag'
3
+ require 'models/tagging'
4
+ require 'models/post'
5
+ require 'models/topic'
6
+ require 'models/comment'
7
+ require 'models/author'
8
+ require 'models/entrant'
9
+ require 'models/developer'
10
+ require 'models/computer'
11
+ require 'models/reply'
12
+ require 'models/company'
13
+ require 'models/bird'
14
+ require 'models/car'
15
+ require 'models/engine'
16
+ require 'models/tyre'
17
+ require 'models/minivan'
18
+ require 'models/aircraft'
19
+ require "models/possession"
20
+ require "models/reader"
21
+
22
+ class RelationTest < ActiveRecord::TestCase
23
+ fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments,
24
+ :tags, :taggings, :cars, :minivans, :author_addresses
25
+
26
+ def test_do_not_double_quote_string_id
27
+ van = Minivan.last
28
+ assert van
29
+ assert_equal van.id, Minivan.where(:minivan_id => van).to_a.first.minivan_id
30
+ end
31
+
32
+ def test_do_not_double_quote_string_id_with_array
33
+ van = Minivan.last
34
+ assert van
35
+ assert_equal van, Minivan.where(:minivan_id => [van]).to_a.first
36
+ end
37
+
38
+ def test_bind_values
39
+ relation = Post.all
40
+ assert_equal [], relation.bind_values
41
+
42
+ relation2 = relation.bind 'foo'
43
+ assert_equal %w{ foo }, relation2.bind_values
44
+ assert_equal [], relation.bind_values
45
+ end
46
+
47
+ def test_two_scopes_with_includes_should_not_drop_any_include
48
+ # heat habtm cache
49
+ car = Car.incl_engines.incl_tyres.first
50
+ car.tyres.length
51
+ car.engines.length
52
+
53
+ car = Car.incl_engines.incl_tyres.first
54
+ assert_no_queries { car.tyres.length }
55
+ assert_no_queries { car.engines.length }
56
+ end
57
+
58
+ def test_dynamic_finder
59
+ x = Post.where('author_id = ?', 1)
60
+ assert x.klass.respond_to?(:find_by_id), '@klass should handle dynamic finders'
61
+ end
62
+
63
+ def test_multivalue_where
64
+ posts = Post.where('author_id = ? AND id = ?', 1, 1)
65
+ assert_equal 1, posts.to_a.size
66
+ end
67
+
68
+ def test_scoped
69
+ topics = Topic.all
70
+ assert_kind_of ActiveRecord::Relation, topics
71
+ assert_equal 5, topics.size
72
+ end
73
+
74
+ def test_to_json
75
+ assert_nothing_raised { Bird.all.to_json }
76
+ assert_nothing_raised { Bird.all.to_a.to_json }
77
+ end
78
+
79
+ def test_to_yaml
80
+ assert_nothing_raised { Bird.all.to_yaml }
81
+ assert_nothing_raised { Bird.all.to_a.to_yaml }
82
+ end
83
+
84
+ def test_to_xml
85
+ assert_nothing_raised { Bird.all.to_xml }
86
+ assert_nothing_raised { Bird.all.to_a.to_xml }
87
+ end
88
+
89
+ def test_scoped_all
90
+ topics = Topic.all.to_a
91
+ assert_kind_of Array, topics
92
+ assert_no_queries { assert_equal 5, topics.size }
93
+ end
94
+
95
+ def test_loaded_all
96
+ topics = Topic.all
97
+
98
+ assert_queries(1) do
99
+ 2.times { assert_equal 5, topics.to_a.size }
100
+ end
101
+
102
+ assert topics.loaded?
103
+ end
104
+
105
+ def test_scoped_first
106
+ topics = Topic.all.order('id ASC')
107
+
108
+ assert_queries(1) do
109
+ 2.times { assert_equal "The First Topic", topics.first.title }
110
+ end
111
+
112
+ assert ! topics.loaded?
113
+ end
114
+
115
+ def test_loaded_first
116
+ topics = Topic.all.order('id ASC')
117
+
118
+ assert_queries(1) do
119
+ topics.to_a # force load
120
+ 2.times { assert_equal "The First Topic", topics.first.title }
121
+ end
122
+
123
+ assert topics.loaded?
124
+ end
125
+
126
+ def test_reload
127
+ topics = Topic.all
128
+
129
+ assert_queries(1) do
130
+ 2.times { topics.to_a }
131
+ end
132
+
133
+ assert topics.loaded?
134
+
135
+ original_size = topics.to_a.size
136
+ Topic.create! :title => 'fake'
137
+
138
+ assert_queries(1) { topics.reload }
139
+ assert_equal original_size + 1, topics.size
140
+ assert topics.loaded?
141
+ end
142
+
143
+ def test_finding_with_subquery
144
+ relation = Topic.where(:approved => true)
145
+ assert_equal relation.to_a, Topic.select('*').from(relation).to_a
146
+ assert_equal relation.to_a, Topic.select('subquery.*').from(relation).to_a
147
+ assert_equal relation.to_a, Topic.select('a.*').from(relation, :a).to_a
148
+ end
149
+
150
+ def test_finding_with_subquery_with_binds
151
+ relation = Post.first.comments
152
+ assert_equal relation.to_a, Comment.select('*').from(relation).to_a
153
+ assert_equal relation.to_a, Comment.select('subquery.*').from(relation).to_a
154
+ assert_equal relation.to_a, Comment.select('a.*').from(relation, :a).to_a
155
+ end
156
+
157
+ def test_finding_with_subquery_without_select_does_not_change_the_select
158
+ relation = Topic.where(approved: true)
159
+ assert_raises(ActiveRecord::StatementInvalid) do
160
+ Topic.from(relation).to_a
161
+ end
162
+ end
163
+
164
+ def test_select_with_subquery_in_from_does_not_use_original_table_name
165
+ relation = Comment.group(:type).select('COUNT(post_id) AS post_count, type')
166
+ subquery = Comment.from(relation).select('type','post_count')
167
+ assert_equal(relation.map(&:post_count).sort,subquery.map(&:post_count).sort)
168
+ end
169
+
170
+ def test_group_with_subquery_in_from_does_not_use_original_table_name
171
+ relation = Comment.group(:type).select('COUNT(post_id) AS post_count,type')
172
+ subquery = Comment.from(relation).group('type').average("post_count")
173
+ assert_equal(relation.map(&:post_count).sort,subquery.values.sort)
174
+ end
175
+
176
+ def test_finding_with_conditions
177
+ assert_equal ["David"], Author.where(:name => 'David').map(&:name)
178
+ assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name)
179
+ assert_equal ['Mary'], Author.where("name = ?", 'Mary').map(&:name)
180
+ end
181
+
182
+ def test_finding_with_order
183
+ topics = Topic.order('id')
184
+ assert_equal 5, topics.to_a.size
185
+ assert_equal topics(:first).title, topics.first.title
186
+ end
187
+
188
+ def test_finding_with_arel_order
189
+ topics = Topic.order(Topic.arel_table[:id].asc)
190
+ assert_equal 5, topics.to_a.size
191
+ assert_equal topics(:first).title, topics.first.title
192
+ end
193
+
194
+ def test_finding_with_assoc_order
195
+ topics = Topic.order(:id => :desc)
196
+ assert_equal 5, topics.to_a.size
197
+ assert_equal topics(:fifth).title, topics.first.title
198
+ end
199
+
200
+ def test_finding_with_reverted_assoc_order
201
+ topics = Topic.order(:id => :asc).reverse_order
202
+ assert_equal 5, topics.to_a.size
203
+ assert_equal topics(:fifth).title, topics.first.title
204
+ end
205
+
206
+ def test_order_with_hash_and_symbol_generates_the_same_sql
207
+ assert_equal Topic.order(:id).to_sql, Topic.order(:id => :asc).to_sql
208
+ end
209
+
210
+ def test_finding_with_desc_order_with_string
211
+ topics = Topic.order(id: "desc")
212
+ assert_equal 5, topics.to_a.size
213
+ assert_equal [topics(:fifth), topics(:fourth), topics(:third), topics(:second), topics(:first)], topics.to_a
214
+ end
215
+
216
+ def test_finding_with_asc_order_with_string
217
+ topics = Topic.order(id: 'asc')
218
+ assert_equal 5, topics.to_a.size
219
+ assert_equal [topics(:first), topics(:second), topics(:third), topics(:fourth), topics(:fifth)], topics.to_a
220
+ end
221
+
222
+ def test_support_upper_and_lower_case_directions
223
+ assert_includes Topic.order(id: "ASC").to_sql, "ASC"
224
+ assert_includes Topic.order(id: "asc").to_sql, "ASC"
225
+ assert_includes Topic.order(id: :ASC).to_sql, "ASC"
226
+ assert_includes Topic.order(id: :asc).to_sql, "ASC"
227
+
228
+ assert_includes Topic.order(id: "DESC").to_sql, "DESC"
229
+ assert_includes Topic.order(id: "desc").to_sql, "DESC"
230
+ assert_includes Topic.order(id: :DESC).to_sql, "DESC"
231
+ assert_includes Topic.order(id: :desc).to_sql,"DESC"
232
+ end
233
+
234
+ def test_raising_exception_on_invalid_hash_params
235
+ e = assert_raise(ArgumentError) { Topic.order(:name, "id DESC", id: :asfsdf) }
236
+ assert_equal 'Direction "asfsdf" is invalid. Valid directions are: [:asc, :desc, :ASC, :DESC, "asc", "desc", "ASC", "DESC"]', e.message
237
+ end
238
+
239
+ def test_finding_last_with_arel_order
240
+ topics = Topic.order(Topic.arel_table[:id].asc)
241
+ assert_equal topics(:fifth).title, topics.last.title
242
+ end
243
+
244
+ def test_finding_with_order_concatenated
245
+ topics = Topic.order('author_name').order('title')
246
+ assert_equal 5, topics.to_a.size
247
+ assert_equal topics(:fourth).title, topics.first.title
248
+ end
249
+
250
+ def test_finding_with_order_by_aliased_attributes
251
+ topics = Topic.order(:heading)
252
+ assert_equal 5, topics.to_a.size
253
+ assert_equal topics(:fifth).title, topics.first.title
254
+ end
255
+
256
+ def test_finding_with_assoc_order_by_aliased_attributes
257
+ topics = Topic.order(heading: :desc)
258
+ assert_equal 5, topics.to_a.size
259
+ assert_equal topics(:third).title, topics.first.title
260
+ end
261
+
262
+ def test_finding_with_reorder
263
+ topics = Topic.order('author_name').order('title').reorder('id').to_a
264
+ topics_titles = topics.map{ |t| t.title }
265
+ assert_equal ['The First Topic', 'The Second Topic of the day', 'The Third Topic of the day', 'The Fourth Topic of the day', 'The Fifth Topic of the day'], topics_titles
266
+ end
267
+
268
+ def test_finding_with_reorder_by_aliased_attributes
269
+ topics = Topic.order('author_name').reorder(:heading)
270
+ assert_equal 5, topics.to_a.size
271
+ assert_equal topics(:fifth).title, topics.first.title
272
+ end
273
+
274
+ def test_finding_with_assoc_reorder_by_aliased_attributes
275
+ topics = Topic.order('author_name').reorder(heading: :desc)
276
+ assert_equal 5, topics.to_a.size
277
+ assert_equal topics(:third).title, topics.first.title
278
+ end
279
+
280
+ def test_finding_with_order_and_take
281
+ entrants = Entrant.order("id ASC").limit(2).to_a
282
+
283
+ assert_equal 2, entrants.size
284
+ assert_equal entrants(:first).name, entrants.first.name
285
+ end
286
+
287
+ def test_finding_with_cross_table_order_and_limit
288
+ tags = Tag.includes(:taggings).
289
+ order("tags.name asc", "taggings.taggable_id asc", "REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").
290
+ limit(1).to_a
291
+ assert_equal 1, tags.length
292
+ end
293
+
294
+ def test_finding_with_complex_order_and_limit
295
+ tags = Tag.includes(:taggings).references(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").limit(1).to_a
296
+ assert_equal 1, tags.length
297
+ end
298
+
299
+ def test_finding_with_complex_order
300
+ tags = Tag.includes(:taggings).references(:taggings).order("REPLACE('abc', taggings.taggable_type, taggings.taggable_type)").to_a
301
+ assert_equal 3, tags.length
302
+ end
303
+
304
+ def test_finding_with_order_limit_and_offset
305
+ entrants = Entrant.order("id ASC").limit(2).offset(1)
306
+
307
+ assert_equal 2, entrants.to_a.size
308
+ assert_equal entrants(:second).name, entrants.first.name
309
+
310
+ entrants = Entrant.order("id ASC").limit(2).offset(2)
311
+ assert_equal 1, entrants.to_a.size
312
+ assert_equal entrants(:third).name, entrants.first.name
313
+ end
314
+
315
+ def test_finding_with_group
316
+ developers = Developer.group("salary").select("salary").to_a
317
+ assert_equal 4, developers.size
318
+ assert_equal 4, developers.map(&:salary).uniq.size
319
+ end
320
+
321
+ def test_select_with_block
322
+ even_ids = Developer.all.select {|d| d.id % 2 == 0 }.map(&:id)
323
+ assert_equal [2, 4, 6, 8, 10], even_ids.sort
324
+ end
325
+
326
+ def test_none
327
+ assert_no_queries(ignore_none: false) do
328
+ assert_equal [], Developer.none
329
+ assert_equal [], Developer.all.none
330
+ end
331
+ end
332
+
333
+ def test_none_chainable
334
+ assert_no_queries(ignore_none: false) do
335
+ assert_equal [], Developer.none.where(:name => 'David')
336
+ end
337
+ end
338
+
339
+ def test_none_chainable_to_existing_scope_extension_method
340
+ assert_no_queries(ignore_none: false) do
341
+ assert_equal 1, Topic.anonymous_extension.none.one
342
+ end
343
+ end
344
+
345
+ def test_none_chained_to_methods_firing_queries_straight_to_db
346
+ assert_no_queries(ignore_none: false) do
347
+ assert_equal [], Developer.none.pluck(:id, :name)
348
+ assert_equal 0, Developer.none.delete_all
349
+ assert_equal 0, Developer.none.update_all(:name => 'David')
350
+ assert_equal 0, Developer.none.delete(1)
351
+ assert_equal false, Developer.none.exists?(1)
352
+ end
353
+ end
354
+
355
+ def test_null_relation_content_size_methods
356
+ assert_no_queries(ignore_none: false) do
357
+ assert_equal 0, Developer.none.size
358
+ assert_equal 0, Developer.none.count
359
+ assert_equal true, Developer.none.empty?
360
+ assert_equal false, Developer.none.any?
361
+ assert_equal false, Developer.none.many?
362
+ end
363
+ end
364
+
365
+ def test_null_relation_calculations_methods
366
+ assert_no_queries(ignore_none: false) do
367
+ assert_equal 0, Developer.none.count
368
+ assert_equal 0, Developer.none.calculate(:count, nil, {})
369
+ assert_equal nil, Developer.none.calculate(:average, 'salary')
370
+ end
371
+ end
372
+
373
+ def test_null_relation_metadata_methods
374
+ assert_equal "", Developer.none.to_sql
375
+ assert_equal({}, Developer.none.where_values_hash)
376
+ end
377
+
378
+ def test_null_relation_where_values_hash
379
+ assert_equal({ 'salary' => 100_000 }, Developer.none.where(salary: 100_000).where_values_hash)
380
+ end
381
+
382
+ def test_null_relation_sum
383
+ ac = Aircraft.new
384
+ assert_equal Hash.new, ac.engines.group(:id).sum(:id)
385
+ assert_equal 0, ac.engines.count
386
+ ac.save
387
+ assert_equal Hash.new, ac.engines.group(:id).sum(:id)
388
+ assert_equal 0, ac.engines.count
389
+ end
390
+
391
+ def test_null_relation_count
392
+ ac = Aircraft.new
393
+ assert_equal Hash.new, ac.engines.group(:id).count
394
+ assert_equal 0, ac.engines.count
395
+ ac.save
396
+ assert_equal Hash.new, ac.engines.group(:id).count
397
+ assert_equal 0, ac.engines.count
398
+ end
399
+
400
+ def test_null_relation_size
401
+ ac = Aircraft.new
402
+ assert_equal Hash.new, ac.engines.group(:id).size
403
+ assert_equal 0, ac.engines.size
404
+ ac.save
405
+ assert_equal Hash.new, ac.engines.group(:id).size
406
+ assert_equal 0, ac.engines.size
407
+ end
408
+
409
+ def test_null_relation_average
410
+ ac = Aircraft.new
411
+ assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
412
+ assert_equal nil, ac.engines.average(:id)
413
+ ac.save
414
+ assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
415
+ assert_equal nil, ac.engines.average(:id)
416
+ end
417
+
418
+ def test_null_relation_minimum
419
+ ac = Aircraft.new
420
+ assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
421
+ assert_equal nil, ac.engines.minimum(:id)
422
+ ac.save
423
+ assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
424
+ assert_equal nil, ac.engines.minimum(:id)
425
+ end
426
+
427
+ def test_null_relation_maximum
428
+ ac = Aircraft.new
429
+ assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
430
+ assert_equal nil, ac.engines.maximum(:id)
431
+ ac.save
432
+ assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
433
+ assert_equal nil, ac.engines.maximum(:id)
434
+ end
435
+
436
+ def test_null_relation_in_where_condition
437
+ assert_operator Comment.count, :>, 0 # precondition, make sure there are comments.
438
+ assert_equal 0, Comment.where(post_id: Post.none).to_a.size
439
+ end
440
+
441
+ def test_joins_with_nil_argument
442
+ assert_nothing_raised { DependentFirm.joins(nil).first }
443
+ end
444
+
445
+ def test_finding_with_hash_conditions_on_joined_table
446
+ firms = DependentFirm.joins(:account).where({:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}).to_a
447
+ assert_equal 1, firms.size
448
+ assert_equal companies(:rails_core), firms.first
449
+ end
450
+
451
+ def test_find_all_with_join
452
+ developers_on_project_one = Developer.joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').
453
+ where('project_id=1').to_a
454
+
455
+ assert_equal 3, developers_on_project_one.length
456
+ developer_names = developers_on_project_one.map { |d| d.name }
457
+ assert developer_names.include?('David')
458
+ assert developer_names.include?('Jamis')
459
+ end
460
+
461
+ def test_find_on_hash_conditions
462
+ assert_equal Topic.all.merge!(:where => {:approved => false}).to_a, Topic.where({ :approved => false }).to_a
463
+ end
464
+
465
+ def test_joins_with_string_array
466
+ person_with_reader_and_post = Post.joins([
467
+ "INNER JOIN categorizations ON categorizations.post_id = posts.id",
468
+ "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
469
+ ]
470
+ ).to_a
471
+ assert_equal 1, person_with_reader_and_post.size
472
+ end
473
+
474
+ def test_no_arguments_to_query_methods_raise_errors
475
+ assert_raises(ArgumentError) { Topic.references() }
476
+ assert_raises(ArgumentError) { Topic.includes() }
477
+ assert_raises(ArgumentError) { Topic.preload() }
478
+ assert_raises(ArgumentError) { Topic.group() }
479
+ assert_raises(ArgumentError) { Topic.reorder() }
480
+ end
481
+
482
+ def test_blank_like_arguments_to_query_methods_dont_raise_errors
483
+ assert_nothing_raised { Topic.references([]) }
484
+ assert_nothing_raised { Topic.includes([]) }
485
+ assert_nothing_raised { Topic.preload([]) }
486
+ assert_nothing_raised { Topic.group([]) }
487
+ assert_nothing_raised { Topic.reorder([]) }
488
+ end
489
+
490
+ def test_scoped_responds_to_delegated_methods
491
+ relation = Topic.all
492
+
493
+ ["map", "uniq", "sort", "insert", "delete", "update"].each do |method|
494
+ assert_respond_to relation, method, "Topic.all should respond to #{method.inspect}"
495
+ end
496
+ end
497
+
498
+ def test_respond_to_delegates_to_relation
499
+ relation = Topic.all
500
+ fake_arel = Struct.new(:responds) {
501
+ def respond_to? method, access = false
502
+ responds << [method, access]
503
+ end
504
+ }.new []
505
+
506
+ relation.extend(Module.new { attr_accessor :arel })
507
+ relation.arel = fake_arel
508
+
509
+ relation.respond_to?(:matching_attributes)
510
+ assert_equal [:matching_attributes, false], fake_arel.responds.first
511
+
512
+ fake_arel.responds = []
513
+ relation.respond_to?(:matching_attributes, true)
514
+ assert_equal [:matching_attributes, true], fake_arel.responds.first
515
+ end
516
+
517
+ def test_respond_to_dynamic_finders
518
+ relation = Topic.all
519
+
520
+ ["find_by_title", "find_by_title_and_author_name"].each do |method|
521
+ assert_respond_to relation, method, "Topic.all should respond to #{method.inspect}"
522
+ end
523
+ end
524
+
525
+ def test_respond_to_class_methods_and_scopes
526
+ assert Topic.all.respond_to?(:by_lifo)
527
+ end
528
+
529
+ def test_find_with_readonly_option
530
+ Developer.all.each { |d| assert !d.readonly? }
531
+ Developer.all.readonly.each { |d| assert d.readonly? }
532
+ end
533
+
534
+ def test_eager_association_loading_of_stis_with_multiple_references
535
+ authors = Author.eager_load(:posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } }).
536
+ order('comments.body, very_special_comments_posts.body').where('posts.id = 4').to_a
537
+
538
+ assert_equal [authors(:david)], authors
539
+ assert_no_queries do
540
+ authors.first.posts.first.special_comments.first.post.special_comments
541
+ authors.first.posts.first.special_comments.first.post.very_special_comment
542
+ end
543
+ end
544
+
545
+ def test_find_with_preloaded_associations
546
+ assert_queries(2) do
547
+ posts = Post.preload(:comments).order('posts.id')
548
+ assert posts.first.comments.first
549
+ end
550
+
551
+ assert_queries(2) do
552
+ posts = Post.preload(:comments).order('posts.id')
553
+ assert posts.first.comments.first
554
+ end
555
+
556
+ assert_queries(2) do
557
+ posts = Post.preload(:author).order('posts.id')
558
+ assert posts.first.author
559
+ end
560
+
561
+ assert_queries(2) do
562
+ posts = Post.preload(:author).order('posts.id')
563
+ assert posts.first.author
564
+ end
565
+
566
+ assert_queries(3) do
567
+ posts = Post.preload(:author, :comments).order('posts.id')
568
+ assert posts.first.author
569
+ assert posts.first.comments.first
570
+ end
571
+ end
572
+
573
+ def test_preload_applies_to_all_chained_preloaded_scopes
574
+ assert_queries(3) do
575
+ post = Post.with_comments.with_tags.first
576
+ assert post
577
+ end
578
+ end
579
+
580
+ def test_find_with_included_associations
581
+ assert_queries(2) do
582
+ posts = Post.includes(:comments).order('posts.id')
583
+ assert posts.first.comments.first
584
+ end
585
+
586
+ assert_queries(2) do
587
+ posts = Post.all.includes(:comments).order('posts.id')
588
+ assert posts.first.comments.first
589
+ end
590
+
591
+ assert_queries(2) do
592
+ posts = Post.includes(:author).order('posts.id')
593
+ assert posts.first.author
594
+ end
595
+
596
+ assert_queries(3) do
597
+ posts = Post.includes(:author, :comments).order('posts.id')
598
+ assert posts.first.author
599
+ assert posts.first.comments.first
600
+ end
601
+ end
602
+
603
+ def test_default_scope_with_conditions_string
604
+ assert_equal Developer.where(name: 'David').map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort
605
+ assert_nil DeveloperCalledDavid.create!.name
606
+ end
607
+
608
+ def test_default_scope_with_conditions_hash
609
+ assert_equal Developer.where(name: 'Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort
610
+ assert_equal 'Jamis', DeveloperCalledJamis.create!.name
611
+ end
612
+
613
+ def test_default_scoping_finder_methods
614
+ developers = DeveloperCalledDavid.order('id').map(&:id).sort
615
+ assert_equal Developer.where(name: 'David').map(&:id).sort, developers
616
+ end
617
+
618
+ def test_includes_with_select
619
+ query = Post.select('comments_count AS ranking').order('ranking').includes(:comments)
620
+ .where(comments: { id: 1 })
621
+
622
+ assert_equal ['comments_count AS ranking'], query.select_values
623
+ assert_equal 1, query.to_a.size
624
+ end
625
+
626
+ def test_preloading_with_associations_and_merges
627
+ post = Post.create! title: 'Uhuu', body: 'body'
628
+ reader = Reader.create! post_id: post.id, person_id: 1
629
+ comment = Comment.create! post_id: post.id, body: 'body'
630
+
631
+ assert !comment.respond_to?(:readers)
632
+
633
+ post_rel = Post.preload(:readers).joins(:readers).where(title: 'Uhuu')
634
+ result_comment = Comment.joins(:post).merge(post_rel).to_a.first
635
+ assert_equal comment, result_comment
636
+
637
+ assert_no_queries do
638
+ assert_equal post, result_comment.post
639
+ assert_equal [reader], result_comment.post.readers.to_a
640
+ end
641
+
642
+ post_rel = Post.includes(:readers).where(title: 'Uhuu')
643
+ result_comment = Comment.joins(:post).merge(post_rel).first
644
+ assert_equal comment, result_comment
645
+
646
+ assert_no_queries do
647
+ assert_equal post, result_comment.post
648
+ assert_equal [reader], result_comment.post.readers.to_a
649
+ end
650
+ end
651
+
652
+ def test_preloading_with_associations_default_scopes_and_merges
653
+ post = Post.create! title: 'Uhuu', body: 'body'
654
+ reader = Reader.create! post_id: post.id, person_id: 1
655
+
656
+ post_rel = PostWithPreloadDefaultScope.preload(:readers).joins(:readers).where(title: 'Uhuu')
657
+ result_post = PostWithPreloadDefaultScope.all.merge(post_rel).to_a.first
658
+
659
+ assert_no_queries do
660
+ assert_equal [reader], result_post.readers.to_a
661
+ end
662
+
663
+ post_rel = PostWithIncludesDefaultScope.includes(:readers).where(title: 'Uhuu')
664
+ result_post = PostWithIncludesDefaultScope.all.merge(post_rel).to_a.first
665
+
666
+ assert_no_queries do
667
+ assert_equal [reader], result_post.readers.to_a
668
+ end
669
+ end
670
+
671
+ def test_loading_with_one_association
672
+ posts = Post.preload(:comments)
673
+ post = posts.find { |p| p.id == 1 }
674
+ assert_equal 2, post.comments.size
675
+ assert post.comments.include?(comments(:greetings))
676
+
677
+ post = Post.where("posts.title = 'Welcome to the weblog'").preload(:comments).first
678
+ assert_equal 2, post.comments.size
679
+ assert post.comments.include?(comments(:greetings))
680
+
681
+ posts = Post.preload(:last_comment)
682
+ post = posts.find { |p| p.id == 1 }
683
+ assert_equal Post.find(1).last_comment, post.last_comment
684
+ end
685
+
686
+ def test_to_sql_on_eager_join
687
+ expected = assert_sql {
688
+ Post.eager_load(:last_comment).order('comments.id DESC').to_a
689
+ }.first
690
+ actual = Post.eager_load(:last_comment).order('comments.id DESC').to_sql
691
+ assert_equal expected, actual
692
+ end
693
+
694
+ def test_to_sql_on_scoped_proxy
695
+ auth = Author.first
696
+ Post.where("1=1").written_by(auth)
697
+ assert_not auth.posts.to_sql.include?("1=1")
698
+ end
699
+
700
+ def test_loading_with_one_association_with_non_preload
701
+ posts = Post.eager_load(:last_comment).order('comments.id DESC')
702
+ post = posts.find { |p| p.id == 1 }
703
+ assert_equal Post.find(1).last_comment, post.last_comment
704
+ end
705
+
706
+ def test_dynamic_find_by_attributes
707
+ david = authors(:david)
708
+ author = Author.preload(:taggings).find_by_id(david.id)
709
+ expected_taggings = taggings(:welcome_general, :thinking_general)
710
+
711
+ assert_no_queries do
712
+ assert_equal expected_taggings, author.taggings.distinct.sort_by { |t| t.id }
713
+ assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
714
+ end
715
+
716
+ authors = Author.all
717
+ assert_equal david, authors.find_by_id_and_name(david.id, david.name)
718
+ assert_equal david, authors.find_by_id_and_name!(david.id, david.name)
719
+ end
720
+
721
+ def test_dynamic_find_by_attributes_bang
722
+ author = Author.all.find_by_id!(authors(:david).id)
723
+ assert_equal "David", author.name
724
+
725
+ assert_raises(ActiveRecord::RecordNotFound) { Author.all.find_by_id_and_name!(20, 'invalid') }
726
+ end
727
+
728
+ def test_find_id
729
+ authors = Author.all
730
+
731
+ david = authors.find(authors(:david).id)
732
+ assert_equal 'David', david.name
733
+
734
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find('42') }
735
+ end
736
+
737
+ def test_find_ids
738
+ authors = Author.order('id ASC')
739
+
740
+ results = authors.find(authors(:david).id, authors(:mary).id)
741
+ assert_kind_of Array, results
742
+ assert_equal 2, results.size
743
+ assert_equal 'David', results[0].name
744
+ assert_equal 'Mary', results[1].name
745
+ assert_equal results, authors.find([authors(:david).id, authors(:mary).id])
746
+
747
+ assert_raises(ActiveRecord::RecordNotFound) { authors.where(:name => 'lifo').find(authors(:david).id, '42') }
748
+ assert_raises(ActiveRecord::RecordNotFound) { authors.find(['42', 43]) }
749
+ end
750
+
751
+ def test_find_in_empty_array
752
+ authors = Author.all.where(:id => [])
753
+ assert authors.to_a.blank?
754
+ end
755
+
756
+ def test_where_with_ar_object
757
+ author = Author.first
758
+ authors = Author.all.where(:id => author)
759
+ assert_equal 1, authors.to_a.length
760
+ end
761
+
762
+ def test_find_with_list_of_ar
763
+ author = Author.first
764
+ authors = Author.find([author.id])
765
+ assert_equal author, authors.first
766
+ end
767
+
768
+ class Mary < Author; end
769
+
770
+ def test_find_by_classname
771
+ Author.create!(:name => Mary.name)
772
+ assert_equal 1, Author.where(:name => Mary).size
773
+ end
774
+
775
+ def test_find_by_id_with_list_of_ar
776
+ author = Author.first
777
+ authors = Author.find_by_id([author])
778
+ assert_equal author, authors
779
+ end
780
+
781
+ def test_find_all_using_where_twice_should_or_the_relation
782
+ david = authors(:david)
783
+ relation = Author.unscoped
784
+ relation = relation.where(:name => david.name)
785
+ relation = relation.where(:name => 'Santiago')
786
+ relation = relation.where(:id => david.id)
787
+ assert_equal [], relation.to_a
788
+ end
789
+
790
+ def test_multi_where_ands_queries
791
+ relation = Author.unscoped
792
+ david = authors(:david)
793
+ sql = relation.where(:name => david.name).where(:name => 'Santiago').to_sql
794
+ assert_match('AND', sql)
795
+ end
796
+
797
+ def test_find_all_with_multiple_should_use_and
798
+ david = authors(:david)
799
+ relation = [
800
+ { :name => david.name },
801
+ { :name => 'Santiago' },
802
+ { :name => 'tenderlove' },
803
+ ].inject(Author.unscoped) do |memo, param|
804
+ memo.where(param)
805
+ end
806
+ assert_equal [], relation.to_a
807
+ end
808
+
809
+ def test_typecasting_where_with_array
810
+ ids = Author.pluck(:id)
811
+ slugs = ids.map { |id| "#{id}-as-a-slug" }
812
+
813
+ assert_equal Author.all.to_a, Author.where(id: slugs).to_a
814
+ end
815
+
816
+ def test_find_all_using_where_with_relation
817
+ david = authors(:david)
818
+ # switching the lines below would succeed in current rails
819
+ # assert_queries(2) {
820
+ assert_queries(1) {
821
+ relation = Author.where(:id => Author.where(:id => david.id))
822
+ assert_equal [david], relation.to_a
823
+ }
824
+
825
+ assert_queries(1) {
826
+ relation = Author.where('id in (?)', Author.where(id: david).select(:id))
827
+ assert_equal [david], relation.to_a
828
+ }
829
+
830
+ assert_queries(1) do
831
+ relation = Author.where('id in (:author_ids)', author_ids: Author.where(id: david).select(:id))
832
+ assert_equal [david], relation.to_a
833
+ end
834
+ end
835
+
836
+ def test_find_all_using_where_with_relation_with_bound_values
837
+ david = authors(:david)
838
+ davids_posts = david.posts.order(:id).to_a
839
+
840
+ assert_queries(1) do
841
+ relation = Post.where(id: david.posts.select(:id))
842
+ assert_equal davids_posts, relation.order(:id).to_a
843
+ end
844
+
845
+ assert_queries(1) do
846
+ relation = Post.where('id in (?)', david.posts.select(:id))
847
+ assert_equal davids_posts, relation.order(:id).to_a, 'should process Relation as bind variables'
848
+ end
849
+
850
+ assert_queries(1) do
851
+ relation = Post.where('id in (:post_ids)', post_ids: david.posts.select(:id))
852
+ assert_equal davids_posts, relation.order(:id).to_a, 'should process Relation as named bind variables'
853
+ end
854
+ end
855
+
856
+ def test_find_all_using_where_with_relation_and_alternate_primary_key
857
+ cool_first = minivans(:cool_first)
858
+ # switching the lines below would succeed in current rails
859
+ # assert_queries(2) {
860
+ assert_queries(1) {
861
+ relation = Minivan.where(:minivan_id => Minivan.where(:name => cool_first.name))
862
+ assert_equal [cool_first], relation.to_a
863
+ }
864
+ end
865
+
866
+ def test_find_all_using_where_with_relation_does_not_alter_select_values
867
+ david = authors(:david)
868
+
869
+ subquery = Author.where(:id => david.id)
870
+
871
+ assert_queries(1) {
872
+ relation = Author.where(:id => subquery)
873
+ assert_equal [david], relation.to_a
874
+ }
875
+
876
+ assert_equal 0, subquery.select_values.size
877
+ end
878
+
879
+ def test_find_all_using_where_with_relation_with_joins
880
+ david = authors(:david)
881
+ assert_queries(1) {
882
+ relation = Author.where(:id => Author.joins(:posts).where(:id => david.id))
883
+ assert_equal [david], relation.to_a
884
+ }
885
+ end
886
+
887
+
888
+ def test_find_all_using_where_with_relation_with_select_to_build_subquery
889
+ david = authors(:david)
890
+ assert_queries(1) {
891
+ relation = Author.where(:name => Author.where(:id => david.id).select(:name))
892
+ assert_equal [david], relation.to_a
893
+ }
894
+ end
895
+
896
+ def test_exists
897
+ davids = Author.where(:name => 'David')
898
+ assert davids.exists?
899
+ assert davids.exists?(authors(:david).id)
900
+ assert ! davids.exists?(authors(:mary).id)
901
+ assert ! davids.exists?("42")
902
+ assert ! davids.exists?(42)
903
+ assert ! davids.exists?(davids.new.id)
904
+
905
+ fake = Author.where(:name => 'fake author')
906
+ assert ! fake.exists?
907
+ assert ! fake.exists?(authors(:david).id)
908
+ end
909
+
910
+ def test_exists_uses_existing_scope
911
+ post = authors(:david).posts.first
912
+ authors = Author.includes(:posts).where(name: "David", posts: { id: post.id })
913
+ assert authors.exists?(authors(:david).id)
914
+ end
915
+
916
+ def test_last
917
+ authors = Author.all
918
+ assert_equal authors(:bob), authors.last
919
+ end
920
+
921
+ def test_destroy_all
922
+ davids = Author.where(:name => 'David')
923
+
924
+ # Force load
925
+ assert_equal [authors(:david)], davids.to_a
926
+ assert davids.loaded?
927
+
928
+ assert_difference('Author.count', -1) { davids.destroy_all }
929
+
930
+ assert_equal [], davids.to_a
931
+ assert davids.loaded?
932
+ end
933
+
934
+ def test_delete_all
935
+ davids = Author.where(:name => 'David')
936
+
937
+ assert_difference('Author.count', -1) { davids.delete_all }
938
+ assert ! davids.loaded?
939
+ end
940
+
941
+ def test_delete_all_loaded
942
+ davids = Author.where(:name => 'David')
943
+
944
+ # Force load
945
+ assert_equal [authors(:david)], davids.to_a
946
+ assert davids.loaded?
947
+
948
+ assert_difference('Author.count', -1) { davids.delete_all }
949
+
950
+ assert_equal [], davids.to_a
951
+ assert davids.loaded?
952
+ end
953
+
954
+ def test_delete_all_with_unpermitted_relation_raises_error
955
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.limit(10).delete_all }
956
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.uniq.delete_all }
957
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.group(:name).delete_all }
958
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.having('SUM(id) < 3').delete_all }
959
+ assert_raises(ActiveRecord::ActiveRecordError) { Author.offset(10).delete_all }
960
+ end
961
+
962
+ def test_select_with_aggregates
963
+ posts = Post.select(:title, :body)
964
+
965
+ assert_equal 11, posts.count(:all)
966
+ assert_equal 11, posts.size
967
+ assert posts.any?
968
+ assert posts.many?
969
+ assert_not posts.empty?
970
+ end
971
+
972
+ def test_select_takes_a_variable_list_of_args
973
+ david = developers(:david)
974
+
975
+ developer = Developer.where(id: david.id).select(:name, :salary).first
976
+ assert_equal david.name, developer.name
977
+ assert_equal david.salary, developer.salary
978
+ end
979
+
980
+ def test_select_takes_an_aliased_attribute
981
+ first = topics(:first)
982
+
983
+ topic = Topic.where(id: first.id).select(:heading).first
984
+ assert_equal first.heading, topic.heading
985
+ end
986
+
987
+ def test_select_argument_error
988
+ assert_raises(ArgumentError) { Developer.select }
989
+ end
990
+
991
+ def test_count
992
+ posts = Post.all
993
+
994
+ assert_equal 11, posts.count
995
+ assert_equal 11, posts.count(:all)
996
+ assert_equal 11, posts.count(:id)
997
+
998
+ assert_equal 1, posts.where('comments_count > 1').count
999
+ assert_equal 9, posts.where(:comments_count => 0).count
1000
+ end
1001
+
1002
+ def test_count_on_association_relation
1003
+ author = Author.last
1004
+ another_author = Author.first
1005
+ posts = Post.where(author_id: author.id)
1006
+
1007
+ assert_equal author.posts.where(author_id: author.id).size, posts.count
1008
+
1009
+ assert_equal 0, author.posts.where(author_id: another_author.id).size
1010
+ assert author.posts.where(author_id: another_author.id).empty?
1011
+ end
1012
+
1013
+ def test_count_with_distinct
1014
+ posts = Post.all
1015
+
1016
+ assert_equal 3, posts.distinct(true).count(:comments_count)
1017
+ assert_equal 11, posts.distinct(false).count(:comments_count)
1018
+
1019
+ assert_equal 3, posts.distinct(true).select(:comments_count).count
1020
+ assert_equal 11, posts.distinct(false).select(:comments_count).count
1021
+ end
1022
+
1023
+ def test_update_all_with_scope
1024
+ tag = Tag.first
1025
+ Post.tagged_with(tag.id).update_all title: "rofl"
1026
+ list = Post.tagged_with(tag.id).all.to_a
1027
+ assert_operator list.length, :>, 0
1028
+ list.each { |post| assert_equal 'rofl', post.title }
1029
+ end
1030
+
1031
+ def test_count_explicit_columns
1032
+ Post.update_all(:comments_count => nil)
1033
+ posts = Post.all
1034
+
1035
+ assert_equal [0], posts.select('comments_count').where('id is not null').group('id').order('id').count.values.uniq
1036
+ assert_equal 0, posts.where('id is not null').select('comments_count').count
1037
+
1038
+ assert_equal 11, posts.select('comments_count').count('id')
1039
+ assert_equal 0, posts.select('comments_count').count
1040
+ assert_equal 0, posts.count(:comments_count)
1041
+ assert_equal 0, posts.count('comments_count')
1042
+ end
1043
+
1044
+ def test_multiple_selects
1045
+ post = Post.all.select('comments_count').select('title').order("id ASC").first
1046
+ assert_equal "Welcome to the weblog", post.title
1047
+ assert_equal 2, post.comments_count
1048
+ end
1049
+
1050
+ def test_size
1051
+ posts = Post.all
1052
+
1053
+ assert_queries(1) { assert_equal 11, posts.size }
1054
+ assert ! posts.loaded?
1055
+
1056
+ best_posts = posts.where(:comments_count => 0)
1057
+ best_posts.to_a # force load
1058
+ assert_no_queries { assert_equal 9, best_posts.size }
1059
+ end
1060
+
1061
+ def test_size_with_limit
1062
+ posts = Post.limit(10)
1063
+
1064
+ assert_queries(1) { assert_equal 10, posts.size }
1065
+ assert ! posts.loaded?
1066
+
1067
+ best_posts = posts.where(:comments_count => 0)
1068
+ best_posts.to_a # force load
1069
+ assert_no_queries { assert_equal 9, best_posts.size }
1070
+ end
1071
+
1072
+ def test_size_with_zero_limit
1073
+ posts = Post.limit(0)
1074
+
1075
+ assert_no_queries { assert_equal 0, posts.size }
1076
+ assert ! posts.loaded?
1077
+
1078
+ posts.to_a # force load
1079
+ assert_no_queries { assert_equal 0, posts.size }
1080
+ end
1081
+
1082
+ def test_empty_with_zero_limit
1083
+ posts = Post.limit(0)
1084
+
1085
+ assert_no_queries { assert_equal true, posts.empty? }
1086
+ assert ! posts.loaded?
1087
+ end
1088
+
1089
+ def test_count_complex_chained_relations
1090
+ posts = Post.select('comments_count').where('id is not null').group("author_id").where("comments_count > 0")
1091
+
1092
+ expected = { 1 => 2 }
1093
+ assert_equal expected, posts.count
1094
+ end
1095
+
1096
+ def test_empty
1097
+ posts = Post.all
1098
+
1099
+ assert_queries(1) { assert_equal false, posts.empty? }
1100
+ assert ! posts.loaded?
1101
+
1102
+ no_posts = posts.where(:title => "")
1103
+ assert_queries(1) { assert_equal true, no_posts.empty? }
1104
+ assert ! no_posts.loaded?
1105
+
1106
+ best_posts = posts.where(:comments_count => 0)
1107
+ best_posts.to_a # force load
1108
+ assert_no_queries { assert_equal false, best_posts.empty? }
1109
+ end
1110
+
1111
+ def test_empty_complex_chained_relations
1112
+ posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0")
1113
+
1114
+ assert_queries(1) { assert_equal false, posts.empty? }
1115
+ assert ! posts.loaded?
1116
+
1117
+ no_posts = posts.where(:title => "")
1118
+ assert_queries(1) { assert_equal true, no_posts.empty? }
1119
+ assert ! no_posts.loaded?
1120
+ end
1121
+
1122
+ def test_any
1123
+ posts = Post.all
1124
+
1125
+ # This test was failing when run on its own (as opposed to running the entire suite).
1126
+ # The second line in the assert_queries block was causing visit_Arel_Attributes_Attribute
1127
+ # in Arel::Visitors::ToSql to trigger a SHOW TABLES query. Running that line here causes
1128
+ # the SHOW TABLES result to be cached so we don't have to do it again in the block.
1129
+ #
1130
+ # This is obviously a rubbish fix but it's the best I can come up with for now...
1131
+ posts.where(:id => nil).any?
1132
+
1133
+ assert_queries(3) do
1134
+ assert posts.any? # Uses COUNT()
1135
+ assert ! posts.where(:id => nil).any?
1136
+
1137
+ assert posts.any? {|p| p.id > 0 }
1138
+ assert ! posts.any? {|p| p.id <= 0 }
1139
+ end
1140
+
1141
+ assert posts.loaded?
1142
+ end
1143
+
1144
+ def test_many
1145
+ posts = Post.all
1146
+
1147
+ assert_queries(2) do
1148
+ assert posts.many? # Uses COUNT()
1149
+ assert posts.many? {|p| p.id > 0 }
1150
+ assert ! posts.many? {|p| p.id < 2 }
1151
+ end
1152
+
1153
+ assert posts.loaded?
1154
+ end
1155
+
1156
+ def test_many_with_limits
1157
+ posts = Post.all
1158
+
1159
+ assert posts.many?
1160
+ assert ! posts.limit(1).many?
1161
+ end
1162
+
1163
+ def test_build
1164
+ posts = Post.all
1165
+
1166
+ post = posts.new
1167
+ assert_kind_of Post, post
1168
+ end
1169
+
1170
+ def test_scoped_build
1171
+ posts = Post.where(:title => 'You told a lie')
1172
+
1173
+ post = posts.new
1174
+ assert_kind_of Post, post
1175
+ assert_equal 'You told a lie', post.title
1176
+ end
1177
+
1178
+ def test_create
1179
+ birds = Bird.all
1180
+
1181
+ sparrow = birds.create
1182
+ assert_kind_of Bird, sparrow
1183
+ assert !sparrow.persisted?
1184
+
1185
+ hen = birds.where(:name => 'hen').create
1186
+ assert hen.persisted?
1187
+ assert_equal 'hen', hen.name
1188
+ end
1189
+
1190
+ def test_create_bang
1191
+ birds = Bird.all
1192
+
1193
+ assert_raises(ActiveRecord::RecordInvalid) { birds.create! }
1194
+
1195
+ hen = birds.where(:name => 'hen').create!
1196
+ assert_kind_of Bird, hen
1197
+ assert hen.persisted?
1198
+ assert_equal 'hen', hen.name
1199
+ end
1200
+
1201
+ def test_first_or_create
1202
+ parrot = Bird.where(:color => 'green').first_or_create(:name => 'parrot')
1203
+ assert_kind_of Bird, parrot
1204
+ assert parrot.persisted?
1205
+ assert_equal 'parrot', parrot.name
1206
+ assert_equal 'green', parrot.color
1207
+
1208
+ same_parrot = Bird.where(:color => 'green').first_or_create(:name => 'parakeet')
1209
+ assert_kind_of Bird, same_parrot
1210
+ assert same_parrot.persisted?
1211
+ assert_equal parrot, same_parrot
1212
+ end
1213
+
1214
+ def test_first_or_create_with_no_parameters
1215
+ parrot = Bird.where(:color => 'green').first_or_create
1216
+ assert_kind_of Bird, parrot
1217
+ assert !parrot.persisted?
1218
+ assert_equal 'green', parrot.color
1219
+ end
1220
+
1221
+ def test_first_or_create_with_block
1222
+ parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parrot' }
1223
+ assert_kind_of Bird, parrot
1224
+ assert parrot.persisted?
1225
+ assert_equal 'green', parrot.color
1226
+ assert_equal 'parrot', parrot.name
1227
+
1228
+ same_parrot = Bird.where(:color => 'green').first_or_create { |bird| bird.name = 'parakeet' }
1229
+ assert_equal parrot, same_parrot
1230
+ end
1231
+
1232
+ def test_first_or_create_with_array
1233
+ several_green_birds = Bird.where(:color => 'green').first_or_create([{:name => 'parrot'}, {:name => 'parakeet'}])
1234
+ assert_kind_of Array, several_green_birds
1235
+ several_green_birds.each { |bird| assert bird.persisted? }
1236
+
1237
+ same_parrot = Bird.where(:color => 'green').first_or_create([{:name => 'hummingbird'}, {:name => 'macaw'}])
1238
+ assert_kind_of Bird, same_parrot
1239
+ assert_equal several_green_birds.first, same_parrot
1240
+ end
1241
+
1242
+ def test_first_or_create_bang_with_valid_options
1243
+ parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parrot')
1244
+ assert_kind_of Bird, parrot
1245
+ assert parrot.persisted?
1246
+ assert_equal 'parrot', parrot.name
1247
+ assert_equal 'green', parrot.color
1248
+
1249
+ same_parrot = Bird.where(:color => 'green').first_or_create!(:name => 'parakeet')
1250
+ assert_kind_of Bird, same_parrot
1251
+ assert same_parrot.persisted?
1252
+ assert_equal parrot, same_parrot
1253
+ end
1254
+
1255
+ def test_first_or_create_bang_with_invalid_options
1256
+ assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!(:pirate_id => 1) }
1257
+ end
1258
+
1259
+ def test_first_or_create_bang_with_no_parameters
1260
+ assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create! }
1261
+ end
1262
+
1263
+ def test_first_or_create_bang_with_valid_block
1264
+ parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parrot' }
1265
+ assert_kind_of Bird, parrot
1266
+ assert parrot.persisted?
1267
+ assert_equal 'green', parrot.color
1268
+ assert_equal 'parrot', parrot.name
1269
+
1270
+ same_parrot = Bird.where(:color => 'green').first_or_create! { |bird| bird.name = 'parakeet' }
1271
+ assert_equal parrot, same_parrot
1272
+ end
1273
+
1274
+ def test_first_or_create_bang_with_invalid_block
1275
+ assert_raise(ActiveRecord::RecordInvalid) do
1276
+ Bird.where(:color => 'green').first_or_create! { |bird| bird.pirate_id = 1 }
1277
+ end
1278
+ end
1279
+
1280
+ def test_first_or_create_with_valid_array
1281
+ several_green_birds = Bird.where(:color => 'green').first_or_create!([{:name => 'parrot'}, {:name => 'parakeet'}])
1282
+ assert_kind_of Array, several_green_birds
1283
+ several_green_birds.each { |bird| assert bird.persisted? }
1284
+
1285
+ same_parrot = Bird.where(:color => 'green').first_or_create!([{:name => 'hummingbird'}, {:name => 'macaw'}])
1286
+ assert_kind_of Bird, same_parrot
1287
+ assert_equal several_green_birds.first, same_parrot
1288
+ end
1289
+
1290
+ def test_first_or_create_with_invalid_array
1291
+ assert_raises(ActiveRecord::RecordInvalid) { Bird.where(:color => 'green').first_or_create!([ {:name => 'parrot'}, {:pirate_id => 1} ]) }
1292
+ end
1293
+
1294
+ def test_first_or_initialize
1295
+ parrot = Bird.where(:color => 'green').first_or_initialize(:name => 'parrot')
1296
+ assert_kind_of Bird, parrot
1297
+ assert !parrot.persisted?
1298
+ assert parrot.valid?
1299
+ assert parrot.new_record?
1300
+ assert_equal 'parrot', parrot.name
1301
+ assert_equal 'green', parrot.color
1302
+ end
1303
+
1304
+ def test_first_or_initialize_with_no_parameters
1305
+ parrot = Bird.where(:color => 'green').first_or_initialize
1306
+ assert_kind_of Bird, parrot
1307
+ assert !parrot.persisted?
1308
+ assert !parrot.valid?
1309
+ assert parrot.new_record?
1310
+ assert_equal 'green', parrot.color
1311
+ end
1312
+
1313
+ def test_first_or_initialize_with_block
1314
+ parrot = Bird.where(:color => 'green').first_or_initialize { |bird| bird.name = 'parrot' }
1315
+ assert_kind_of Bird, parrot
1316
+ assert !parrot.persisted?
1317
+ assert parrot.valid?
1318
+ assert parrot.new_record?
1319
+ assert_equal 'green', parrot.color
1320
+ assert_equal 'parrot', parrot.name
1321
+ end
1322
+
1323
+ def test_find_or_create_by
1324
+ assert_nil Bird.find_by(name: 'bob')
1325
+
1326
+ bird = Bird.find_or_create_by(name: 'bob')
1327
+ assert bird.persisted?
1328
+
1329
+ assert_equal bird, Bird.find_or_create_by(name: 'bob')
1330
+ end
1331
+
1332
+ def test_find_or_create_by_with_create_with
1333
+ assert_nil Bird.find_by(name: 'bob')
1334
+
1335
+ bird = Bird.create_with(color: 'green').find_or_create_by(name: 'bob')
1336
+ assert bird.persisted?
1337
+ assert_equal 'green', bird.color
1338
+
1339
+ assert_equal bird, Bird.create_with(color: 'blue').find_or_create_by(name: 'bob')
1340
+ end
1341
+
1342
+ def test_find_or_create_by!
1343
+ assert_raises(ActiveRecord::RecordInvalid) { Bird.find_or_create_by!(color: 'green') }
1344
+ end
1345
+
1346
+ def test_find_or_initialize_by
1347
+ assert_nil Bird.find_by(name: 'bob')
1348
+
1349
+ bird = Bird.find_or_initialize_by(name: 'bob')
1350
+ assert bird.new_record?
1351
+ bird.save!
1352
+
1353
+ assert_equal bird, Bird.find_or_initialize_by(name: 'bob')
1354
+ end
1355
+
1356
+ def test_explicit_create_scope
1357
+ hens = Bird.where(:name => 'hen')
1358
+ assert_equal 'hen', hens.new.name
1359
+
1360
+ hens = hens.create_with(:name => 'cock')
1361
+ assert_equal 'cock', hens.new.name
1362
+ end
1363
+
1364
+ def test_except
1365
+ relation = Post.where(:author_id => 1).order('id ASC').limit(1)
1366
+ assert_equal [posts(:welcome)], relation.to_a
1367
+
1368
+ author_posts = relation.except(:order, :limit)
1369
+ assert_equal Post.where(:author_id => 1).to_a, author_posts.to_a
1370
+
1371
+ all_posts = relation.except(:where, :order, :limit)
1372
+ assert_equal Post.all, all_posts
1373
+ end
1374
+
1375
+ def test_only
1376
+ relation = Post.where(:author_id => 1).order('id ASC').limit(1)
1377
+ assert_equal [posts(:welcome)], relation.to_a
1378
+
1379
+ author_posts = relation.only(:where)
1380
+ assert_equal Post.where(:author_id => 1).to_a, author_posts.to_a
1381
+
1382
+ all_posts = relation.only(:limit)
1383
+ assert_equal Post.limit(1).to_a.first, all_posts.first
1384
+ end
1385
+
1386
+ def test_anonymous_extension
1387
+ relation = Post.where(:author_id => 1).order('id ASC').extending do
1388
+ def author
1389
+ 'lifo'
1390
+ end
1391
+ end
1392
+
1393
+ assert_equal "lifo", relation.author
1394
+ assert_equal "lifo", relation.limit(1).author
1395
+ end
1396
+
1397
+ def test_named_extension
1398
+ relation = Post.where(:author_id => 1).order('id ASC').extending(Post::NamedExtension)
1399
+ assert_equal "lifo", relation.author
1400
+ assert_equal "lifo", relation.limit(1).author
1401
+ end
1402
+
1403
+ def test_order_by_relation_attribute
1404
+ assert_equal Post.order(Post.arel_table[:title]).to_a, Post.order("title").to_a
1405
+ end
1406
+
1407
+ def test_default_scope_order_with_scope_order
1408
+ assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name
1409
+ assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name
1410
+ end
1411
+
1412
+ def test_order_using_scoping
1413
+ car1 = CoolCar.order('id DESC').scoping do
1414
+ CoolCar.all.merge!(order: 'id asc').first
1415
+ end
1416
+ assert_equal 'zyke', car1.name
1417
+
1418
+ car2 = FastCar.order('id DESC').scoping do
1419
+ FastCar.all.merge!(order: 'id asc').first
1420
+ end
1421
+ assert_equal 'zyke', car2.name
1422
+ end
1423
+
1424
+ def test_unscoped_block_style
1425
+ assert_equal 'honda', CoolCar.unscoped { CoolCar.order_using_new_style.limit(1).first.name}
1426
+ assert_equal 'honda', FastCar.unscoped { FastCar.order_using_new_style.limit(1).first.name}
1427
+ end
1428
+
1429
+ def test_intersection_with_array
1430
+ relation = Author.where(:name => "David")
1431
+ rails_author = relation.first
1432
+
1433
+ assert_equal [rails_author], [rails_author] & relation
1434
+ assert_equal [rails_author], relation & [rails_author]
1435
+ end
1436
+
1437
+ def test_primary_key
1438
+ assert_equal "id", Post.all.primary_key
1439
+ end
1440
+
1441
+ def test_disable_implicit_join_references_is_deprecated
1442
+ assert_deprecated do
1443
+ ActiveRecord::Base.disable_implicit_join_references = true
1444
+ end
1445
+ end
1446
+
1447
+ def test_ordering_with_extra_spaces
1448
+ assert_equal authors(:david), Author.order('id DESC , name DESC').last
1449
+ end
1450
+
1451
+ def test_update_all_with_blank_argument
1452
+ assert_raises(ArgumentError) { Comment.update_all({}) }
1453
+ end
1454
+
1455
+ def test_update_all_with_joins
1456
+ comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id)
1457
+ count = comments.count
1458
+
1459
+ assert_equal count, comments.update_all(:post_id => posts(:thinking).id)
1460
+ assert_equal posts(:thinking), comments(:greetings).post
1461
+ end
1462
+
1463
+ def test_update_all_with_joins_and_limit
1464
+ comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).limit(1)
1465
+ assert_equal 1, comments.update_all(:post_id => posts(:thinking).id)
1466
+ end
1467
+
1468
+ def test_update_all_with_joins_and_limit_and_order
1469
+ comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('comments.id').limit(1)
1470
+ assert_equal 1, comments.update_all(:post_id => posts(:thinking).id)
1471
+ assert_equal posts(:thinking), comments(:greetings).post
1472
+ assert_equal posts(:welcome), comments(:more_greetings).post
1473
+ end
1474
+
1475
+ unless current_adapter?(:IBM_DBAdapter)
1476
+ #IBM_DB does not support offset on subselect of the update statement
1477
+ def test_update_all_with_joins_and_offset
1478
+ all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id)
1479
+ count = all_comments.count
1480
+ comments = all_comments.offset(1)
1481
+
1482
+ assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id)
1483
+ end
1484
+
1485
+ def test_update_all_with_joins_and_offset_and_order
1486
+ all_comments = Comment.joins(:post).where('posts.id' => posts(:welcome).id).order('posts.id', 'comments.id')
1487
+ count = all_comments.count
1488
+ comments = all_comments.offset(1)
1489
+
1490
+ assert_equal count - 1, comments.update_all(:post_id => posts(:thinking).id)
1491
+ assert_equal posts(:thinking), comments(:more_greetings).post
1492
+ assert_equal posts(:welcome), comments(:greetings).post
1493
+ end
1494
+ end
1495
+
1496
+ def test_distinct
1497
+ tag1 = Tag.create(:name => 'Foo')
1498
+ tag2 = Tag.create(:name => 'Foo')
1499
+
1500
+ query = Tag.select(:name).where(:id => [tag1.id, tag2.id])
1501
+
1502
+ assert_equal ['Foo', 'Foo'], query.map(&:name)
1503
+ assert_sql(/DISTINCT/) do
1504
+ assert_equal ['Foo'], query.distinct.map(&:name)
1505
+ assert_equal ['Foo'], query.uniq.map(&:name)
1506
+ end
1507
+ assert_sql(/DISTINCT/) do
1508
+ assert_equal ['Foo'], query.distinct(true).map(&:name)
1509
+ assert_equal ['Foo'], query.uniq(true).map(&:name)
1510
+ end
1511
+ assert_equal ['Foo', 'Foo'], query.distinct(true).distinct(false).map(&:name)
1512
+ assert_equal ['Foo', 'Foo'], query.uniq(true).uniq(false).map(&:name)
1513
+ end
1514
+
1515
+ def test_doesnt_add_having_values_if_options_are_blank
1516
+ scope = Post.having('')
1517
+ assert_equal [], scope.having_values
1518
+
1519
+ scope = Post.having([])
1520
+ assert_equal [], scope.having_values
1521
+ end
1522
+
1523
+ def test_grouping_by_column_with_reserved_name
1524
+ assert_equal [], Possession.select(:where).group(:where).to_a
1525
+ end
1526
+
1527
+ def test_references_triggers_eager_loading
1528
+ scope = Post.includes(:comments)
1529
+ assert !scope.eager_loading?
1530
+ assert scope.references(:comments).eager_loading?
1531
+ end
1532
+
1533
+ def test_references_doesnt_trigger_eager_loading_if_reference_not_included
1534
+ scope = Post.references(:comments)
1535
+ assert !scope.eager_loading?
1536
+ end
1537
+
1538
+ def test_automatically_added_where_references
1539
+ scope = Post.where(:comments => { :body => "Bla" })
1540
+ assert_equal ['comments'], scope.references_values
1541
+
1542
+ scope = Post.where('comments.body' => 'Bla')
1543
+ assert_equal ['comments'], scope.references_values
1544
+ end
1545
+
1546
+ def test_automatically_added_where_not_references
1547
+ scope = Post.where.not(comments: { body: "Bla" })
1548
+ assert_equal ['comments'], scope.references_values
1549
+
1550
+ scope = Post.where.not('comments.body' => 'Bla')
1551
+ assert_equal ['comments'], scope.references_values
1552
+ end
1553
+
1554
+ def test_automatically_added_having_references
1555
+ scope = Post.having(:comments => { :body => "Bla" })
1556
+ assert_equal ['comments'], scope.references_values
1557
+
1558
+ scope = Post.having('comments.body' => 'Bla')
1559
+ assert_equal ['comments'], scope.references_values
1560
+ end
1561
+
1562
+ def test_automatically_added_order_references
1563
+ scope = Post.order('comments.body')
1564
+ assert_equal ['comments'], scope.references_values
1565
+
1566
+ scope = Post.order('comments.body', 'yaks.body')
1567
+ assert_equal ['comments', 'yaks'], scope.references_values
1568
+
1569
+ # Don't infer yaks, let's not go down that road again...
1570
+ scope = Post.order('comments.body, yaks.body')
1571
+ assert_equal ['comments'], scope.references_values
1572
+
1573
+ scope = Post.order('comments.body asc')
1574
+ assert_equal ['comments'], scope.references_values
1575
+
1576
+ scope = Post.order('foo(comments.body)')
1577
+ assert_equal [], scope.references_values
1578
+ end
1579
+
1580
+ def test_automatically_added_reorder_references
1581
+ scope = Post.reorder('comments.body')
1582
+ assert_equal %w(comments), scope.references_values
1583
+
1584
+ scope = Post.reorder('comments.body', 'yaks.body')
1585
+ assert_equal %w(comments yaks), scope.references_values
1586
+
1587
+ # Don't infer yaks, let's not go down that road again...
1588
+ scope = Post.reorder('comments.body, yaks.body')
1589
+ assert_equal %w(comments), scope.references_values
1590
+
1591
+ scope = Post.reorder('comments.body asc')
1592
+ assert_equal %w(comments), scope.references_values
1593
+
1594
+ scope = Post.reorder('foo(comments.body)')
1595
+ assert_equal [], scope.references_values
1596
+ end
1597
+
1598
+ def test_order_with_reorder_nil_removes_the_order
1599
+ relation = Post.order(:title).reorder(nil)
1600
+
1601
+ assert_nil relation.order_values.first
1602
+ end
1603
+
1604
+ def test_reverse_order_with_reorder_nil_removes_the_order
1605
+ relation = Post.order(:title).reverse_order.reorder(nil)
1606
+
1607
+ assert_nil relation.order_values.first
1608
+ end
1609
+
1610
+ def test_presence
1611
+ topics = Topic.all
1612
+
1613
+ # the first query is triggered because there are no topics yet.
1614
+ assert_queries(1) { assert topics.present? }
1615
+
1616
+ # checking if there are topics is used before you actually display them,
1617
+ # thus it shouldn't invoke an extra count query.
1618
+ assert_no_queries { assert topics.present? }
1619
+ assert_no_queries { assert !topics.blank? }
1620
+
1621
+ # shows count of topics and loops after loading the query should not trigger extra queries either.
1622
+ assert_no_queries { topics.size }
1623
+ assert_no_queries { topics.length }
1624
+ assert_no_queries { topics.each }
1625
+
1626
+ # count always trigger the COUNT query.
1627
+ assert_queries(1) { topics.count }
1628
+
1629
+ assert topics.loaded?
1630
+ end
1631
+
1632
+ test "find_by with hash conditions returns the first matching record" do
1633
+ assert_equal posts(:eager_other), Post.order(:id).find_by(author_id: 2)
1634
+ end
1635
+
1636
+ test "find_by with non-hash conditions returns the first matching record" do
1637
+ assert_equal posts(:eager_other), Post.order(:id).find_by("author_id = 2")
1638
+ end
1639
+
1640
+ test "find_by with multi-arg conditions returns the first matching record" do
1641
+ assert_equal posts(:eager_other), Post.order(:id).find_by('author_id = ?', 2)
1642
+ end
1643
+
1644
+ test "find_by returns nil if the record is missing" do
1645
+ assert_equal nil, Post.all.find_by("1 = 0")
1646
+ end
1647
+
1648
+ test "find_by doesn't have implicit ordering" do
1649
+ assert_sql(/^((?!ORDER).)*$/) { Post.all.find_by(author_id: 2) }
1650
+ end
1651
+
1652
+ test "find_by! with hash conditions returns the first matching record" do
1653
+ assert_equal posts(:eager_other), Post.order(:id).find_by!(author_id: 2)
1654
+ end
1655
+
1656
+ test "find_by! with non-hash conditions returns the first matching record" do
1657
+ assert_equal posts(:eager_other), Post.order(:id).find_by!("author_id = 2")
1658
+ end
1659
+
1660
+ test "find_by! with multi-arg conditions returns the first matching record" do
1661
+ assert_equal posts(:eager_other), Post.order(:id).find_by!('author_id = ?', 2)
1662
+ end
1663
+
1664
+ test "find_by! doesn't have implicit ordering" do
1665
+ assert_sql(/^((?!ORDER).)*$/) { Post.all.find_by!(author_id: 2) }
1666
+ end
1667
+
1668
+ test "find_by! raises RecordNotFound if the record is missing" do
1669
+ assert_raises(ActiveRecord::RecordNotFound) do
1670
+ Post.all.find_by!("1 = 0")
1671
+ end
1672
+ end
1673
+
1674
+ test "loaded relations cannot be mutated by multi value methods" do
1675
+ relation = Post.all
1676
+ relation.to_a
1677
+
1678
+ assert_raises(ActiveRecord::ImmutableRelation) do
1679
+ relation.where! 'foo'
1680
+ end
1681
+ end
1682
+
1683
+ test "loaded relations cannot be mutated by single value methods" do
1684
+ relation = Post.all
1685
+ relation.to_a
1686
+
1687
+ assert_raises(ActiveRecord::ImmutableRelation) do
1688
+ relation.limit! 5
1689
+ end
1690
+ end
1691
+
1692
+ test "loaded relations cannot be mutated by merge!" do
1693
+ relation = Post.all
1694
+ relation.to_a
1695
+
1696
+ assert_raises(ActiveRecord::ImmutableRelation) do
1697
+ relation.merge! where: 'foo'
1698
+ end
1699
+ end
1700
+
1701
+ test "loaded relations cannot be mutated by extending!" do
1702
+ relation = Post.all
1703
+ relation.to_a
1704
+
1705
+ assert_raises(ActiveRecord::ImmutableRelation) do
1706
+ relation.extending! Module.new
1707
+ end
1708
+ end
1709
+
1710
+ test "relations show the records in #inspect" do
1711
+ relation = Post.limit(2)
1712
+ assert_equal "#<ActiveRecord::Relation [#{Post.limit(2).map(&:inspect).join(', ')}]>", relation.inspect
1713
+ end
1714
+
1715
+ test "relations limit the records in #inspect at 10" do
1716
+ relation = Post.limit(11)
1717
+ assert_equal "#<ActiveRecord::Relation [#{Post.limit(10).map(&:inspect).join(', ')}, ...]>", relation.inspect
1718
+ end
1719
+
1720
+ test "already-loaded relations don't perform a new query in #inspect" do
1721
+ relation = Post.limit(2)
1722
+ relation.to_a
1723
+
1724
+ expected = "#<ActiveRecord::Relation [#{Post.limit(2).map(&:inspect).join(', ')}]>"
1725
+
1726
+ assert_no_queries do
1727
+ assert_equal expected, relation.inspect
1728
+ end
1729
+ end
1730
+
1731
+ test 'using a custom table affects the wheres' do
1732
+ table_alias = Post.arel_table.alias('omg_posts')
1733
+
1734
+ relation = ActiveRecord::Relation.new Post, table_alias
1735
+ relation.where!(:foo => "bar")
1736
+
1737
+ node = relation.arel.constraints.first.grep(Arel::Attributes::Attribute).first
1738
+ assert_equal table_alias, node.relation
1739
+ end
1740
+
1741
+ test '#load' do
1742
+ relation = Post.all
1743
+ assert_queries(1) do
1744
+ assert_equal relation, relation.load
1745
+ end
1746
+ assert_no_queries { relation.to_a }
1747
+ end
1748
+
1749
+ test 'group with select and includes' do
1750
+ authors_count = Post.select('author_id, COUNT(author_id) AS num_posts').
1751
+ group('author_id').order('author_id').includes(:author).to_a
1752
+
1753
+ assert_no_queries do
1754
+ result = authors_count.map do |post|
1755
+ [post.num_posts, post.author.try(:name)]
1756
+ end
1757
+
1758
+ expected = [[1, nil], [5, "David"], [3, "Mary"], [2, "Bob"]]
1759
+ assert_equal expected, result
1760
+ end
1761
+ end
1762
+
1763
+ test "joins with select" do
1764
+ posts = Post.joins(:author).select("id", "authors.author_address_id").order("posts.id").limit(3)
1765
+ assert_equal [1, 2, 4], posts.map(&:id)
1766
+ assert_equal [1, 1, 1], posts.map(&:author_address_id)
1767
+ end
1768
+
1769
+ test "delegations do not leak to other classes" do
1770
+ Topic.all.by_lifo
1771
+ assert Topic.all.class.method_defined?(:by_lifo)
1772
+ assert !Post.all.respond_to?(:by_lifo)
1773
+ end
1774
+
1775
+ def test_unscope_removes_binds
1776
+ left = Post.where(id: Arel::Nodes::BindParam.new)
1777
+ column = Post.columns_hash['id']
1778
+ left.bind_values += [[column, 20]]
1779
+
1780
+ relation = left.unscope(where: :id)
1781
+ assert_equal [], relation.bind_values
1782
+ end
1783
+
1784
+ def test_merging_removes_rhs_bind_parameters
1785
+ left = Post.where(id: 20)
1786
+ right = Post.where(id: [1,2,3,4])
1787
+
1788
+ merged = left.merge(right)
1789
+ assert_equal [], merged.bind_values
1790
+ end
1791
+
1792
+ def test_merging_keeps_lhs_bind_parameters
1793
+ column = Post.columns_hash['id']
1794
+ binds = [[column, 20]]
1795
+
1796
+ right = Post.where(id: 20)
1797
+ left = Post.where(id: 10)
1798
+
1799
+ merged = left.merge(right)
1800
+ assert_equal binds, merged.bind_values
1801
+ end
1802
+
1803
+ def test_merging_reorders_bind_params
1804
+ post = Post.first
1805
+ right = Post.where(id: post.id)
1806
+ left = Post.where(title: post.title)
1807
+
1808
+ merged = left.merge(right)
1809
+ assert_equal post, merged.first
1810
+ end
1811
+
1812
+ def test_relation_join_method
1813
+ assert_equal 'Thank you for the welcome,Thank you again for the welcome', Post.first.comments.join(",")
1814
+ end
1815
+ end