ibm_db 5.6.1-arm64-darwin-24

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 (753) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +299 -0
  3. data/LICENSE +55 -0
  4. data/MANIFEST +14 -0
  5. data/ParameterizedQueries README +39 -0
  6. data/README +210 -0
  7. data/ext/Makefile +270 -0
  8. data/ext/Makefile.nt32 +181 -0
  9. data/ext/Makefile.nt32.191 +212 -0
  10. data/ext/extconf.rb +320 -0
  11. data/ext/gil_release_version.h +3 -0
  12. data/ext/ibm_db.bundle +0 -0
  13. data/ext/ibm_db.c +11865 -0
  14. data/ext/ibm_db.o +0 -0
  15. data/ext/mkmf.log +98 -0
  16. data/ext/ruby_ibm_db.h +241 -0
  17. data/ext/ruby_ibm_db_cli.c +867 -0
  18. data/ext/ruby_ibm_db_cli.h +508 -0
  19. data/ext/ruby_ibm_db_cli.o +0 -0
  20. data/ext/unicode_support_version.h +3 -0
  21. data/init.rb +42 -0
  22. data/lib/IBM_DB.rb +27 -0
  23. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +4407 -0
  24. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
  25. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -0
  26. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  27. data/lib/ibm_db.bundle +0 -0
  28. data/test/active_record/connection_adapters/fake_adapter.rb +52 -0
  29. data/test/activejob/destroy_association_async_test.rb +305 -0
  30. data/test/activejob/destroy_async_job_not_present_test.rb +31 -0
  31. data/test/activejob/helper.rb +15 -0
  32. data/test/assets/example.log +1 -0
  33. data/test/assets/flowers.jpg +0 -0
  34. data/test/assets/schema_dump_5_1.yml +345 -0
  35. data/test/assets/test.txt +1 -0
  36. data/test/cases/adapter_prevent_writes_test.rb +334 -0
  37. data/test/cases/adapter_test.rb +565 -0
  38. data/test/cases/adapters/mysql2/active_schema_test.rb +203 -0
  39. data/test/cases/adapters/mysql2/auto_increment_test.rb +34 -0
  40. data/test/cases/adapters/mysql2/bind_parameter_test.rb +52 -0
  41. data/test/cases/adapters/mysql2/boolean_test.rb +102 -0
  42. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +65 -0
  43. data/test/cases/adapters/mysql2/charset_collation_test.rb +57 -0
  44. data/test/cases/adapters/mysql2/connection_test.rb +208 -0
  45. data/test/cases/adapters/mysql2/count_deleted_rows_with_lock_test.rb +28 -0
  46. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +49 -0
  47. data/test/cases/adapters/mysql2/enum_test.rb +47 -0
  48. data/test/cases/adapters/mysql2/explain_test.rb +23 -0
  49. data/test/cases/adapters/mysql2/json_test.rb +24 -0
  50. data/test/cases/adapters/mysql2/mysql2_adapter_prevent_writes_test.rb +208 -0
  51. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +238 -0
  52. data/test/cases/adapters/mysql2/nested_deadlock_test.rb +75 -0
  53. data/test/cases/adapters/mysql2/optimizer_hints_test.rb +69 -0
  54. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  55. data/test/cases/adapters/mysql2/schema_migrations_test.rb +64 -0
  56. data/test/cases/adapters/mysql2/schema_test.rb +128 -0
  57. data/test/cases/adapters/mysql2/set_test.rb +32 -0
  58. data/test/cases/adapters/mysql2/sp_test.rb +38 -0
  59. data/test/cases/adapters/mysql2/sql_types_test.rb +16 -0
  60. data/test/cases/adapters/mysql2/table_options_test.rb +125 -0
  61. data/test/cases/adapters/mysql2/transaction_test.rb +151 -0
  62. data/test/cases/adapters/mysql2/unsigned_type_test.rb +68 -0
  63. data/test/cases/adapters/mysql2/virtual_column_test.rb +66 -0
  64. data/test/cases/adapters/postgresql/active_schema_test.rb +113 -0
  65. data/test/cases/adapters/postgresql/array_test.rb +394 -0
  66. data/test/cases/adapters/postgresql/bit_string_test.rb +84 -0
  67. data/test/cases/adapters/postgresql/bytea_test.rb +135 -0
  68. data/test/cases/adapters/postgresql/case_insensitive_test.rb +27 -0
  69. data/test/cases/adapters/postgresql/change_schema_test.rb +40 -0
  70. data/test/cases/adapters/postgresql/cidr_test.rb +27 -0
  71. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  72. data/test/cases/adapters/postgresql/collation_test.rb +55 -0
  73. data/test/cases/adapters/postgresql/composite_test.rb +134 -0
  74. data/test/cases/adapters/postgresql/connection_test.rb +245 -0
  75. data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +74 -0
  76. data/test/cases/adapters/postgresql/datatype_test.rb +89 -0
  77. data/test/cases/adapters/postgresql/date_test.rb +42 -0
  78. data/test/cases/adapters/postgresql/domain_test.rb +49 -0
  79. data/test/cases/adapters/postgresql/enum_test.rb +93 -0
  80. data/test/cases/adapters/postgresql/explain_test.rb +22 -0
  81. data/test/cases/adapters/postgresql/extension_migration_test.rb +64 -0
  82. data/test/cases/adapters/postgresql/foreign_table_test.rb +109 -0
  83. data/test/cases/adapters/postgresql/full_text_test.rb +46 -0
  84. data/test/cases/adapters/postgresql/geometric_test.rb +372 -0
  85. data/test/cases/adapters/postgresql/hstore_test.rb +390 -0
  86. data/test/cases/adapters/postgresql/infinity_test.rb +108 -0
  87. data/test/cases/adapters/postgresql/integer_test.rb +27 -0
  88. data/test/cases/adapters/postgresql/interval_test.rb +99 -0
  89. data/test/cases/adapters/postgresql/json_test.rb +52 -0
  90. data/test/cases/adapters/postgresql/ltree_test.rb +51 -0
  91. data/test/cases/adapters/postgresql/money_test.rb +127 -0
  92. data/test/cases/adapters/postgresql/network_test.rb +102 -0
  93. data/test/cases/adapters/postgresql/numbers_test.rb +51 -0
  94. data/test/cases/adapters/postgresql/optimizer_hints_test.rb +71 -0
  95. data/test/cases/adapters/postgresql/partitions_test.rb +22 -0
  96. data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +205 -0
  97. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +447 -0
  98. data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +27 -0
  99. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  100. data/test/cases/adapters/postgresql/quoting_test.rb +50 -0
  101. data/test/cases/adapters/postgresql/range_test.rb +457 -0
  102. data/test/cases/adapters/postgresql/referential_integrity_test.rb +112 -0
  103. data/test/cases/adapters/postgresql/rename_table_test.rb +35 -0
  104. data/test/cases/adapters/postgresql/schema_authorization_test.rb +110 -0
  105. data/test/cases/adapters/postgresql/schema_test.rb +713 -0
  106. data/test/cases/adapters/postgresql/serial_test.rb +156 -0
  107. data/test/cases/adapters/postgresql/statement_pool_test.rb +61 -0
  108. data/test/cases/adapters/postgresql/timestamp_test.rb +92 -0
  109. data/test/cases/adapters/postgresql/transaction_nested_test.rb +114 -0
  110. data/test/cases/adapters/postgresql/transaction_test.rb +189 -0
  111. data/test/cases/adapters/postgresql/type_lookup_test.rb +35 -0
  112. data/test/cases/adapters/postgresql/utils_test.rb +64 -0
  113. data/test/cases/adapters/postgresql/uuid_test.rb +411 -0
  114. data/test/cases/adapters/postgresql/xml_test.rb +50 -0
  115. data/test/cases/adapters/sqlite3/collation_test.rb +64 -0
  116. data/test/cases/adapters/sqlite3/copy_table_test.rb +101 -0
  117. data/test/cases/adapters/sqlite3/explain_test.rb +23 -0
  118. data/test/cases/adapters/sqlite3/json_test.rb +29 -0
  119. data/test/cases/adapters/sqlite3/quoting_test.rb +79 -0
  120. data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +186 -0
  121. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +628 -0
  122. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  123. data/test/cases/adapters/sqlite3/statement_pool_test.rb +21 -0
  124. data/test/cases/adapters/sqlite3/transaction_test.rb +123 -0
  125. data/test/cases/aggregations_test.rb +170 -0
  126. data/test/cases/annotate_test.rb +46 -0
  127. data/test/cases/ar_schema_test.rb +213 -0
  128. data/test/cases/arel/attributes/attribute_test.rb +1145 -0
  129. data/test/cases/arel/attributes/math_test.rb +83 -0
  130. data/test/cases/arel/attributes_test.rb +27 -0
  131. data/test/cases/arel/collectors/bind_test.rb +40 -0
  132. data/test/cases/arel/collectors/composite_test.rb +47 -0
  133. data/test/cases/arel/collectors/sql_string_test.rb +41 -0
  134. data/test/cases/arel/collectors/substitute_bind_collector_test.rb +48 -0
  135. data/test/cases/arel/crud_test.rb +65 -0
  136. data/test/cases/arel/delete_manager_test.rb +53 -0
  137. data/test/cases/arel/factory_methods_test.rb +46 -0
  138. data/test/cases/arel/helper.rb +45 -0
  139. data/test/cases/arel/insert_manager_test.rb +241 -0
  140. data/test/cases/arel/nodes/and_test.rb +30 -0
  141. data/test/cases/arel/nodes/as_test.rb +36 -0
  142. data/test/cases/arel/nodes/ascending_test.rb +46 -0
  143. data/test/cases/arel/nodes/bin_test.rb +35 -0
  144. data/test/cases/arel/nodes/binary_test.rb +29 -0
  145. data/test/cases/arel/nodes/bind_param_test.rb +22 -0
  146. data/test/cases/arel/nodes/case_test.rb +96 -0
  147. data/test/cases/arel/nodes/casted_test.rb +18 -0
  148. data/test/cases/arel/nodes/comment_test.rb +22 -0
  149. data/test/cases/arel/nodes/count_test.rb +35 -0
  150. data/test/cases/arel/nodes/delete_statement_test.rb +36 -0
  151. data/test/cases/arel/nodes/descending_test.rb +46 -0
  152. data/test/cases/arel/nodes/distinct_test.rb +21 -0
  153. data/test/cases/arel/nodes/equality_test.rb +62 -0
  154. data/test/cases/arel/nodes/extract_test.rb +43 -0
  155. data/test/cases/arel/nodes/false_test.rb +21 -0
  156. data/test/cases/arel/nodes/grouping_test.rb +26 -0
  157. data/test/cases/arel/nodes/infix_operation_test.rb +42 -0
  158. data/test/cases/arel/nodes/insert_statement_test.rb +44 -0
  159. data/test/cases/arel/nodes/named_function_test.rb +48 -0
  160. data/test/cases/arel/nodes/node_test.rb +22 -0
  161. data/test/cases/arel/nodes/not_test.rb +31 -0
  162. data/test/cases/arel/nodes/or_test.rb +36 -0
  163. data/test/cases/arel/nodes/over_test.rb +69 -0
  164. data/test/cases/arel/nodes/select_core_test.rb +79 -0
  165. data/test/cases/arel/nodes/select_statement_test.rb +51 -0
  166. data/test/cases/arel/nodes/sql_literal_test.rb +75 -0
  167. data/test/cases/arel/nodes/sum_test.rb +35 -0
  168. data/test/cases/arel/nodes/table_alias_test.rb +29 -0
  169. data/test/cases/arel/nodes/true_test.rb +21 -0
  170. data/test/cases/arel/nodes/unary_operation_test.rb +41 -0
  171. data/test/cases/arel/nodes/update_statement_test.rb +60 -0
  172. data/test/cases/arel/nodes/window_test.rb +81 -0
  173. data/test/cases/arel/nodes_test.rb +34 -0
  174. data/test/cases/arel/select_manager_test.rb +1238 -0
  175. data/test/cases/arel/support/fake_record.rb +135 -0
  176. data/test/cases/arel/table_test.rb +216 -0
  177. data/test/cases/arel/update_manager_test.rb +126 -0
  178. data/test/cases/arel/visitors/dispatch_contamination_test.rb +78 -0
  179. data/test/cases/arel/visitors/dot_test.rb +90 -0
  180. data/test/cases/arel/visitors/mysql_test.rb +157 -0
  181. data/test/cases/arel/visitors/postgres_test.rb +366 -0
  182. data/test/cases/arel/visitors/sqlite_test.rb +75 -0
  183. data/test/cases/arel/visitors/to_sql_test.rb +750 -0
  184. data/test/cases/associations/association_scope_test.rb +16 -0
  185. data/test/cases/associations/belongs_to_associations_test.rb +1493 -0
  186. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +43 -0
  187. data/test/cases/associations/callbacks_test.rb +208 -0
  188. data/test/cases/associations/cascaded_eager_loading_test.rb +245 -0
  189. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +156 -0
  190. data/test/cases/associations/eager_load_nested_include_test.rb +127 -0
  191. data/test/cases/associations/eager_singularization_test.rb +148 -0
  192. data/test/cases/associations/eager_test.rb +1658 -0
  193. data/test/cases/associations/extension_test.rb +93 -0
  194. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1025 -0
  195. data/test/cases/associations/has_many_associations_test.rb +3074 -0
  196. data/test/cases/associations/has_many_through_associations_test.rb +1580 -0
  197. data/test/cases/associations/has_one_associations_test.rb +872 -0
  198. data/test/cases/associations/has_one_through_associations_test.rb +429 -0
  199. data/test/cases/associations/inner_join_association_test.rb +215 -0
  200. data/test/cases/associations/inverse_associations_test.rb +941 -0
  201. data/test/cases/associations/join_model_test.rb +787 -0
  202. data/test/cases/associations/left_outer_join_association_test.rb +123 -0
  203. data/test/cases/associations/nested_through_associations_test.rb +636 -0
  204. data/test/cases/associations/required_test.rb +127 -0
  205. data/test/cases/associations_test.rb +516 -0
  206. data/test/cases/attribute_decorators_test.rb +126 -0
  207. data/test/cases/attribute_methods/read_test.rb +60 -0
  208. data/test/cases/attribute_methods_test.rb +1124 -0
  209. data/test/cases/attribute_set_test.rb +270 -0
  210. data/test/cases/attribute_test.rb +246 -0
  211. data/test/cases/attributes_test.rb +371 -0
  212. data/test/cases/autosave_association_test.rb +1953 -0
  213. data/test/cases/base_prevent_writes_test.rb +229 -0
  214. data/test/cases/base_test.rb +1770 -0
  215. data/test/cases/batches_test.rb +695 -0
  216. data/test/cases/binary_test.rb +39 -0
  217. data/test/cases/bind_parameter_test.rb +283 -0
  218. data/test/cases/boolean_test.rb +52 -0
  219. data/test/cases/cache_key_test.rb +131 -0
  220. data/test/cases/calculations_test.rb +1361 -0
  221. data/test/cases/callbacks_test.rb +503 -0
  222. data/test/cases/clone_test.rb +45 -0
  223. data/test/cases/coders/json_test.rb +17 -0
  224. data/test/cases/coders/yaml_column_test.rb +66 -0
  225. data/test/cases/collection_cache_key_test.rb +272 -0
  226. data/test/cases/column_alias_test.rb +19 -0
  227. data/test/cases/column_definition_test.rb +34 -0
  228. data/test/cases/comment_test.rb +204 -0
  229. data/test/cases/connection_adapters/adapter_leasing_test.rb +60 -0
  230. data/test/cases/connection_adapters/connection_handler_test.rb +467 -0
  231. data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +400 -0
  232. data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +103 -0
  233. data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +499 -0
  234. data/test/cases/connection_adapters/connection_specification_test.rb +12 -0
  235. data/test/cases/connection_adapters/connection_swapping_nested_test.rb +457 -0
  236. data/test/cases/connection_adapters/legacy_connection_handlers_multi_db_test.rb +486 -0
  237. data/test/cases/connection_adapters/legacy_connection_handlers_sharding_db_test.rb +586 -0
  238. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +436 -0
  239. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +81 -0
  240. data/test/cases/connection_adapters/quoting_test.rb +13 -0
  241. data/test/cases/connection_adapters/schema_cache_test.rb +294 -0
  242. data/test/cases/connection_adapters/type_lookup_test.rb +119 -0
  243. data/test/cases/connection_management_test.rb +114 -0
  244. data/test/cases/connection_pool_test.rb +754 -0
  245. data/test/cases/connection_specification/resolver_test.rb +131 -0
  246. data/test/cases/core_test.rb +136 -0
  247. data/test/cases/counter_cache_test.rb +368 -0
  248. data/test/cases/custom_locking_test.rb +19 -0
  249. data/test/cases/database_configurations/hash_config_test.rb +74 -0
  250. data/test/cases/database_configurations/resolver_test.rb +150 -0
  251. data/test/cases/database_configurations_test.rb +145 -0
  252. data/test/cases/database_selector_test.rb +296 -0
  253. data/test/cases/database_statements_test.rb +36 -0
  254. data/test/cases/date_test.rb +36 -0
  255. data/test/cases/date_time_precision_test.rb +129 -0
  256. data/test/cases/date_time_test.rb +76 -0
  257. data/test/cases/defaults_test.rb +254 -0
  258. data/test/cases/delegated_type_test.rb +57 -0
  259. data/test/cases/dirty_test.rb +959 -0
  260. data/test/cases/disconnected_test.rb +30 -0
  261. data/test/cases/dup_test.rb +184 -0
  262. data/test/cases/enum_test.rb +823 -0
  263. data/test/cases/errors_test.rb +16 -0
  264. data/test/cases/explain_subscriber_test.rb +66 -0
  265. data/test/cases/explain_test.rb +79 -0
  266. data/test/cases/filter_attributes_test.rb +153 -0
  267. data/test/cases/finder_respond_to_test.rb +60 -0
  268. data/test/cases/finder_test.rb +1676 -0
  269. data/test/cases/fixture_set/file_test.rb +152 -0
  270. data/test/cases/fixtures_test.rb +1645 -0
  271. data/test/cases/forbidden_attributes_protection_test.rb +130 -0
  272. data/test/cases/habtm_destroy_order_test.rb +61 -0
  273. data/test/cases/helper.rb +233 -0
  274. data/test/cases/hot_compatibility_test.rb +143 -0
  275. data/test/cases/i18n_test.rb +46 -0
  276. data/test/cases/inheritance_test.rb +671 -0
  277. data/test/cases/insert_all_test.rb +489 -0
  278. data/test/cases/instrumentation_test.rb +101 -0
  279. data/test/cases/integration_test.rb +243 -0
  280. data/test/cases/invalid_connection_test.rb +26 -0
  281. data/test/cases/invertible_migration_test.rb +527 -0
  282. data/test/cases/json_attribute_test.rb +35 -0
  283. data/test/cases/json_serialization_test.rb +310 -0
  284. data/test/cases/json_shared_test_cases.rb +290 -0
  285. data/test/cases/locking_test.rb +787 -0
  286. data/test/cases/log_subscriber_test.rb +267 -0
  287. data/test/cases/marshal_serialization_test.rb +39 -0
  288. data/test/cases/migration/change_schema_test.rb +504 -0
  289. data/test/cases/migration/change_table_test.rb +364 -0
  290. data/test/cases/migration/check_constraint_test.rb +162 -0
  291. data/test/cases/migration/column_attributes_test.rb +186 -0
  292. data/test/cases/migration/column_positioning_test.rb +68 -0
  293. data/test/cases/migration/columns_test.rb +326 -0
  294. data/test/cases/migration/command_recorder_test.rb +437 -0
  295. data/test/cases/migration/compatibility_test.rb +673 -0
  296. data/test/cases/migration/create_join_table_test.rb +167 -0
  297. data/test/cases/migration/foreign_key_test.rb +581 -0
  298. data/test/cases/migration/helper.rb +40 -0
  299. data/test/cases/migration/index_test.rb +267 -0
  300. data/test/cases/migration/logger_test.rb +39 -0
  301. data/test/cases/migration/pending_migrations_test.rb +106 -0
  302. data/test/cases/migration/references_foreign_key_test.rb +235 -0
  303. data/test/cases/migration/references_index_test.rb +120 -0
  304. data/test/cases/migration/references_statements_test.rb +137 -0
  305. data/test/cases/migration/rename_table_test.rb +116 -0
  306. data/test/cases/migration_test.rb +1525 -0
  307. data/test/cases/migrator_test.rb +527 -0
  308. data/test/cases/mixin_test.rb +64 -0
  309. data/test/cases/modules_test.rb +174 -0
  310. data/test/cases/multi_db_migrator_test.rb +223 -0
  311. data/test/cases/multiparameter_attributes_test.rb +399 -0
  312. data/test/cases/multiple_db_test.rb +116 -0
  313. data/test/cases/nested_attributes_test.rb +1119 -0
  314. data/test/cases/nested_attributes_with_callbacks_test.rb +146 -0
  315. data/test/cases/null_relation_test.rb +84 -0
  316. data/test/cases/numeric_data_test.rb +93 -0
  317. data/test/cases/persistence_test.rb +1093 -0
  318. data/test/cases/pooled_connections_test.rb +73 -0
  319. data/test/cases/prepared_statement_status_test.rb +48 -0
  320. data/test/cases/primary_keys_test.rb +482 -0
  321. data/test/cases/query_cache_test.rb +915 -0
  322. data/test/cases/quoting_test.rb +303 -0
  323. data/test/cases/readonly_test.rb +120 -0
  324. data/test/cases/reaper_test.rb +199 -0
  325. data/test/cases/reflection_test.rb +520 -0
  326. data/test/cases/relation/delegation_test.rb +76 -0
  327. data/test/cases/relation/delete_all_test.rb +117 -0
  328. data/test/cases/relation/merging_test.rb +434 -0
  329. data/test/cases/relation/mutation_test.rb +145 -0
  330. data/test/cases/relation/or_test.rb +192 -0
  331. data/test/cases/relation/predicate_builder_test.rb +31 -0
  332. data/test/cases/relation/record_fetch_warning_test.rb +42 -0
  333. data/test/cases/relation/select_test.rb +67 -0
  334. data/test/cases/relation/update_all_test.rb +317 -0
  335. data/test/cases/relation/where_chain_test.rb +141 -0
  336. data/test/cases/relation/where_clause_test.rb +257 -0
  337. data/test/cases/relation/where_test.rb +429 -0
  338. data/test/cases/relation_test.rb +482 -0
  339. data/test/cases/relations_test.rb +2251 -0
  340. data/test/cases/reload_models_test.rb +26 -0
  341. data/test/cases/reserved_word_test.rb +141 -0
  342. data/test/cases/result_test.rb +141 -0
  343. data/test/cases/sanitize_test.rb +192 -0
  344. data/test/cases/schema_dumper_test.rb +550 -0
  345. data/test/cases/schema_loading_test.rb +53 -0
  346. data/test/cases/scoping/default_scoping_test.rb +569 -0
  347. data/test/cases/scoping/named_scoping_test.rb +649 -0
  348. data/test/cases/scoping/relation_scoping_test.rb +522 -0
  349. data/test/cases/secure_token_test.rb +47 -0
  350. data/test/cases/serialization_test.rb +106 -0
  351. data/test/cases/serialized_attribute_test.rb +455 -0
  352. data/test/cases/signed_id_test.rb +168 -0
  353. data/test/cases/statement_cache_test.rb +153 -0
  354. data/test/cases/statement_invalid_test.rb +42 -0
  355. data/test/cases/store_test.rb +320 -0
  356. data/test/cases/strict_loading_test.rb +473 -0
  357. data/test/cases/suppressor_test.rb +77 -0
  358. data/test/cases/tasks/database_tasks_test.rb +1526 -0
  359. data/test/cases/tasks/mysql_rake_test.rb +417 -0
  360. data/test/cases/tasks/postgresql_rake_test.rb +534 -0
  361. data/test/cases/tasks/sqlite_rake_test.rb +267 -0
  362. data/test/cases/test_case.rb +142 -0
  363. data/test/cases/test_databases_test.rb +79 -0
  364. data/test/cases/test_fixtures_test.rb +96 -0
  365. data/test/cases/time_precision_test.rb +125 -0
  366. data/test/cases/timestamp_test.rb +504 -0
  367. data/test/cases/touch_later_test.rb +123 -0
  368. data/test/cases/transaction_callbacks_test.rb +772 -0
  369. data/test/cases/transaction_isolation_test.rb +106 -0
  370. data/test/cases/transactions_test.rb +1285 -0
  371. data/test/cases/type/adapter_specific_registry_test.rb +145 -0
  372. data/test/cases/type/date_time_test.rb +16 -0
  373. data/test/cases/type/integer_test.rb +29 -0
  374. data/test/cases/type/string_test.rb +24 -0
  375. data/test/cases/type/time_test.rb +28 -0
  376. data/test/cases/type/type_map_test.rb +178 -0
  377. data/test/cases/type/unsigned_integer_test.rb +19 -0
  378. data/test/cases/type_test.rb +41 -0
  379. data/test/cases/types_test.rb +26 -0
  380. data/test/cases/unconnected_test.rb +46 -0
  381. data/test/cases/unsafe_raw_sql_test.rb +274 -0
  382. data/test/cases/validations/absence_validation_test.rb +75 -0
  383. data/test/cases/validations/association_validation_test.rb +99 -0
  384. data/test/cases/validations/i18n_generate_message_validation_test.rb +102 -0
  385. data/test/cases/validations/i18n_validation_test.rb +87 -0
  386. data/test/cases/validations/length_validation_test.rb +80 -0
  387. data/test/cases/validations/numericality_validation_test.rb +181 -0
  388. data/test/cases/validations/presence_validation_test.rb +105 -0
  389. data/test/cases/validations/uniqueness_validation_test.rb +618 -0
  390. data/test/cases/validations_repair_helper.rb +21 -0
  391. data/test/cases/validations_test.rb +229 -0
  392. data/test/cases/view_test.rb +222 -0
  393. data/test/cases/yaml_serialization_test.rb +166 -0
  394. data/test/config.example.yml +97 -0
  395. data/test/config.rb +7 -0
  396. data/test/config.yml +220 -0
  397. data/test/connections/native_ibm_db/connection.rb +44 -0
  398. data/test/fixtures/accounts.yml +29 -0
  399. data/test/fixtures/admin/accounts.yml +2 -0
  400. data/test/fixtures/admin/randomly_named_a9.yml +7 -0
  401. data/test/fixtures/admin/randomly_named_b0.yml +7 -0
  402. data/test/fixtures/admin/users.yml +10 -0
  403. data/test/fixtures/all/admin +1 -0
  404. data/test/fixtures/all/developers.yml +0 -0
  405. data/test/fixtures/all/namespaced/accounts.yml +2 -0
  406. data/test/fixtures/all/people.yml +0 -0
  407. data/test/fixtures/all/tasks.yml +0 -0
  408. data/test/fixtures/author_addresses.yml +11 -0
  409. data/test/fixtures/author_favorites.yml +4 -0
  410. data/test/fixtures/authors.yml +17 -0
  411. data/test/fixtures/bad_posts.yml +9 -0
  412. data/test/fixtures/binaries.yml +137 -0
  413. data/test/fixtures/books.yml +38 -0
  414. data/test/fixtures/bulbs.yml +5 -0
  415. data/test/fixtures/cars.yml +9 -0
  416. data/test/fixtures/categories/special_categories.yml +9 -0
  417. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  418. data/test/fixtures/categories.yml +19 -0
  419. data/test/fixtures/categories_ordered.yml +7 -0
  420. data/test/fixtures/categories_posts.yml +34 -0
  421. data/test/fixtures/categorizations.yml +23 -0
  422. data/test/fixtures/citations.yml +5 -0
  423. data/test/fixtures/clubs.yml +8 -0
  424. data/test/fixtures/collections.yml +3 -0
  425. data/test/fixtures/colleges.yml +3 -0
  426. data/test/fixtures/comments.yml +72 -0
  427. data/test/fixtures/companies.yml +72 -0
  428. data/test/fixtures/computers.yml +12 -0
  429. data/test/fixtures/content.yml +3 -0
  430. data/test/fixtures/content_positions.yml +3 -0
  431. data/test/fixtures/courses.yml +8 -0
  432. data/test/fixtures/customers.yml +35 -0
  433. data/test/fixtures/dashboards.yml +6 -0
  434. data/test/fixtures/dead_parrots.yml +5 -0
  435. data/test/fixtures/developers.yml +22 -0
  436. data/test/fixtures/developers_projects.yml +17 -0
  437. data/test/fixtures/dog_lovers.yml +7 -0
  438. data/test/fixtures/dogs.yml +4 -0
  439. data/test/fixtures/doubloons.yml +3 -0
  440. data/test/fixtures/edges.yml +5 -0
  441. data/test/fixtures/entrants.yml +14 -0
  442. data/test/fixtures/essays.yml +16 -0
  443. data/test/fixtures/faces.yml +11 -0
  444. data/test/fixtures/fk_test_has_fk.yml +3 -0
  445. data/test/fixtures/fk_test_has_pk.yml +2 -0
  446. data/test/fixtures/friendships.yml +4 -0
  447. data/test/fixtures/funny_jokes.yml +10 -0
  448. data/test/fixtures/humans.yml +5 -0
  449. data/test/fixtures/interests.yml +33 -0
  450. data/test/fixtures/items.yml +3 -0
  451. data/test/fixtures/jobs.yml +7 -0
  452. data/test/fixtures/legacy_things.yml +3 -0
  453. data/test/fixtures/live_parrots.yml +4 -0
  454. data/test/fixtures/mateys.yml +4 -0
  455. data/test/fixtures/member_details.yml +8 -0
  456. data/test/fixtures/member_types.yml +6 -0
  457. data/test/fixtures/members.yml +11 -0
  458. data/test/fixtures/memberships.yml +41 -0
  459. data/test/fixtures/men.yml +5 -0
  460. data/test/fixtures/minimalistics.yml +5 -0
  461. data/test/fixtures/minivans.yml +5 -0
  462. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  463. data/test/fixtures/mixins.yml +29 -0
  464. data/test/fixtures/movies.yml +7 -0
  465. data/test/fixtures/naked/yml/accounts.yml +1 -0
  466. data/test/fixtures/naked/yml/companies.yml +1 -0
  467. data/test/fixtures/naked/yml/courses.yml +1 -0
  468. data/test/fixtures/naked/yml/courses_with_invalid_key.yml +3 -0
  469. data/test/fixtures/naked/yml/parrots.yml +3 -0
  470. data/test/fixtures/naked/yml/trees.yml +3 -0
  471. data/test/fixtures/nodes.yml +29 -0
  472. data/test/fixtures/organizations.yml +5 -0
  473. data/test/fixtures/other_books.yml +26 -0
  474. data/test/fixtures/other_comments.yml +6 -0
  475. data/test/fixtures/other_dogs.yml +2 -0
  476. data/test/fixtures/other_posts.yml +8 -0
  477. data/test/fixtures/other_topics.yml +42 -0
  478. data/test/fixtures/owners.yml +9 -0
  479. data/test/fixtures/parrots.yml +33 -0
  480. data/test/fixtures/parrots_pirates.yml +7 -0
  481. data/test/fixtures/people.yml +24 -0
  482. data/test/fixtures/peoples_treasures.yml +3 -0
  483. data/test/fixtures/pets.yml +19 -0
  484. data/test/fixtures/pirates.yml +15 -0
  485. data/test/fixtures/posts.yml +88 -0
  486. data/test/fixtures/price_estimates.yml +16 -0
  487. data/test/fixtures/products.yml +4 -0
  488. data/test/fixtures/projects.yml +7 -0
  489. data/test/fixtures/randomly_named_a9.yml +7 -0
  490. data/test/fixtures/ratings.yml +14 -0
  491. data/test/fixtures/readers.yml +17 -0
  492. data/test/fixtures/references.yml +17 -0
  493. data/test/fixtures/reserved_words/distinct.yml +5 -0
  494. data/test/fixtures/reserved_words/distinct_select.yml +11 -0
  495. data/test/fixtures/reserved_words/group.yml +14 -0
  496. data/test/fixtures/reserved_words/select.yml +8 -0
  497. data/test/fixtures/reserved_words/values.yml +7 -0
  498. data/test/fixtures/ships.yml +6 -0
  499. data/test/fixtures/speedometers.yml +8 -0
  500. data/test/fixtures/sponsors.yml +15 -0
  501. data/test/fixtures/strict_zines.yml +2 -0
  502. data/test/fixtures/string_key_objects.yml +7 -0
  503. data/test/fixtures/subscribers.yml +11 -0
  504. data/test/fixtures/subscriptions.yml +12 -0
  505. data/test/fixtures/taggings.yml +78 -0
  506. data/test/fixtures/tags.yml +11 -0
  507. data/test/fixtures/tasks.yml +7 -0
  508. data/test/fixtures/teapots.yml +3 -0
  509. data/test/fixtures/to_be_linked/accounts.yml +2 -0
  510. data/test/fixtures/to_be_linked/users.yml +10 -0
  511. data/test/fixtures/topics.yml +49 -0
  512. data/test/fixtures/toys.yml +14 -0
  513. data/test/fixtures/traffic_lights.yml +10 -0
  514. data/test/fixtures/treasures.yml +10 -0
  515. data/test/fixtures/trees.yml +3 -0
  516. data/test/fixtures/uuid_children.yml +3 -0
  517. data/test/fixtures/uuid_parents.yml +2 -0
  518. data/test/fixtures/variants.yml +4 -0
  519. data/test/fixtures/vegetables.yml +20 -0
  520. data/test/fixtures/vertices.yml +4 -0
  521. data/test/fixtures/warehouse-things.yml +3 -0
  522. data/test/fixtures/warehouse_things.yml +3 -0
  523. data/test/fixtures/zines.yml +5 -0
  524. data/test/ibm_db_test.rb +25 -0
  525. data/test/migrations/10_urban/9_add_expressions.rb +13 -0
  526. data/test/migrations/decimal/1_give_me_big_numbers.rb +17 -0
  527. data/test/migrations/magic/1_currencies_have_symbols.rb +13 -0
  528. data/test/migrations/missing/1000_people_have_middle_names.rb +11 -0
  529. data/test/migrations/missing/1_people_have_last_names.rb +11 -0
  530. data/test/migrations/missing/3_we_need_reminders.rb +14 -0
  531. data/test/migrations/missing/4_innocent_jointable.rb +14 -0
  532. data/test/migrations/rename/1_we_need_things.rb +13 -0
  533. data/test/migrations/rename/2_rename_things.rb +11 -0
  534. data/test/migrations/to_copy/1_people_have_hobbies.rb +11 -0
  535. data/test/migrations/to_copy/2_people_have_descriptions.rb +11 -0
  536. data/test/migrations/to_copy2/1_create_articles.rb +9 -0
  537. data/test/migrations/to_copy2/2_create_comments.rb +9 -0
  538. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +11 -0
  539. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +11 -0
  540. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +11 -0
  541. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +9 -0
  542. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +9 -0
  543. data/test/migrations/valid/1_valid_people_have_last_names.rb +11 -0
  544. data/test/migrations/valid/2_we_need_reminders.rb +14 -0
  545. data/test/migrations/valid/3_innocent_jointable.rb +14 -0
  546. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +11 -0
  547. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +14 -0
  548. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +14 -0
  549. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +11 -0
  550. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +14 -0
  551. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +14 -0
  552. data/test/migrations/version_check/20131219224947_migration_version_check.rb +10 -0
  553. data/test/models/account.rb +46 -0
  554. data/test/models/admin/account.rb +5 -0
  555. data/test/models/admin/randomly_named_c1.rb +9 -0
  556. data/test/models/admin/user.rb +48 -0
  557. data/test/models/admin.rb +7 -0
  558. data/test/models/aircraft.rb +7 -0
  559. data/test/models/arunit2_model.rb +5 -0
  560. data/test/models/author.rb +260 -0
  561. data/test/models/auto_id.rb +6 -0
  562. data/test/models/autoloadable/extra_firm.rb +4 -0
  563. data/test/models/binary.rb +4 -0
  564. data/test/models/binary_field.rb +6 -0
  565. data/test/models/bird.rb +24 -0
  566. data/test/models/book.rb +33 -0
  567. data/test/models/book_destroy_async.rb +24 -0
  568. data/test/models/boolean.rb +7 -0
  569. data/test/models/bulb.rb +61 -0
  570. data/test/models/cake_designer.rb +5 -0
  571. data/test/models/car.rb +36 -0
  572. data/test/models/carrier.rb +4 -0
  573. data/test/models/cart.rb +5 -0
  574. data/test/models/cat.rb +12 -0
  575. data/test/models/categorization.rb +21 -0
  576. data/test/models/category.rb +47 -0
  577. data/test/models/chef.rb +10 -0
  578. data/test/models/citation.rb +7 -0
  579. data/test/models/club.rb +28 -0
  580. data/test/models/college.rb +12 -0
  581. data/test/models/column.rb +5 -0
  582. data/test/models/column_name.rb +5 -0
  583. data/test/models/comment.rb +98 -0
  584. data/test/models/company.rb +226 -0
  585. data/test/models/company_in_module.rb +99 -0
  586. data/test/models/computer.rb +5 -0
  587. data/test/models/contact.rb +43 -0
  588. data/test/models/content.rb +42 -0
  589. data/test/models/contract.rb +38 -0
  590. data/test/models/country.rb +5 -0
  591. data/test/models/course.rb +8 -0
  592. data/test/models/customer.rb +85 -0
  593. data/test/models/customer_carrier.rb +16 -0
  594. data/test/models/dashboard.rb +5 -0
  595. data/test/models/default.rb +4 -0
  596. data/test/models/department.rb +6 -0
  597. data/test/models/destroy_async_parent.rb +15 -0
  598. data/test/models/destroy_async_parent_soft_delete.rb +20 -0
  599. data/test/models/developer.rb +341 -0
  600. data/test/models/dl_keyed_belongs_to.rb +13 -0
  601. data/test/models/dl_keyed_belongs_to_soft_delete.rb +19 -0
  602. data/test/models/dl_keyed_has_many.rb +5 -0
  603. data/test/models/dl_keyed_has_many_through.rb +5 -0
  604. data/test/models/dl_keyed_has_one.rb +5 -0
  605. data/test/models/dl_keyed_join.rb +10 -0
  606. data/test/models/dog.rb +7 -0
  607. data/test/models/dog_lover.rb +7 -0
  608. data/test/models/doubloon.rb +14 -0
  609. data/test/models/drink_designer.rb +20 -0
  610. data/test/models/edge.rb +7 -0
  611. data/test/models/electron.rb +7 -0
  612. data/test/models/engine.rb +5 -0
  613. data/test/models/entrant.rb +5 -0
  614. data/test/models/entry.rb +5 -0
  615. data/test/models/essay.rb +8 -0
  616. data/test/models/essay_destroy_async.rb +12 -0
  617. data/test/models/event.rb +5 -0
  618. data/test/models/eye.rb +39 -0
  619. data/test/models/face.rb +17 -0
  620. data/test/models/family.rb +6 -0
  621. data/test/models/family_tree.rb +6 -0
  622. data/test/models/friendship.rb +8 -0
  623. data/test/models/frog.rb +8 -0
  624. data/test/models/guid.rb +4 -0
  625. data/test/models/guitar.rb +6 -0
  626. data/test/models/hotel.rb +13 -0
  627. data/test/models/human.rb +39 -0
  628. data/test/models/image.rb +5 -0
  629. data/test/models/interest.rb +16 -0
  630. data/test/models/invoice.rb +6 -0
  631. data/test/models/item.rb +9 -0
  632. data/test/models/job.rb +9 -0
  633. data/test/models/joke.rb +9 -0
  634. data/test/models/keyboard.rb +5 -0
  635. data/test/models/legacy_thing.rb +5 -0
  636. data/test/models/lesson.rb +13 -0
  637. data/test/models/line_item.rb +5 -0
  638. data/test/models/liquid.rb +6 -0
  639. data/test/models/man.rb +11 -0
  640. data/test/models/matey.rb +6 -0
  641. data/test/models/measurement.rb +4 -0
  642. data/test/models/member.rb +45 -0
  643. data/test/models/member_detail.rb +11 -0
  644. data/test/models/member_type.rb +5 -0
  645. data/test/models/membership.rb +38 -0
  646. data/test/models/mentor.rb +5 -0
  647. data/test/models/message.rb +5 -0
  648. data/test/models/minimalistic.rb +4 -0
  649. data/test/models/minivan.rb +10 -0
  650. data/test/models/mixed_case_monkey.rb +5 -0
  651. data/test/models/mocktail_designer.rb +2 -0
  652. data/test/models/molecule.rb +8 -0
  653. data/test/models/mouse.rb +6 -0
  654. data/test/models/movie.rb +7 -0
  655. data/test/models/node.rb +7 -0
  656. data/test/models/non_primary_key.rb +4 -0
  657. data/test/models/notification.rb +5 -0
  658. data/test/models/numeric_data.rb +12 -0
  659. data/test/models/order.rb +6 -0
  660. data/test/models/organization.rb +16 -0
  661. data/test/models/other_dog.rb +7 -0
  662. data/test/models/owner.rb +39 -0
  663. data/test/models/parrot.rb +36 -0
  664. data/test/models/person.rb +147 -0
  665. data/test/models/personal_legacy_thing.rb +6 -0
  666. data/test/models/pet.rb +20 -0
  667. data/test/models/pet_treasure.rb +8 -0
  668. data/test/models/pirate.rb +116 -0
  669. data/test/models/possession.rb +5 -0
  670. data/test/models/post.rb +371 -0
  671. data/test/models/price_estimate.rb +14 -0
  672. data/test/models/professor.rb +7 -0
  673. data/test/models/project.rb +42 -0
  674. data/test/models/publisher/article.rb +6 -0
  675. data/test/models/publisher/magazine.rb +5 -0
  676. data/test/models/publisher.rb +4 -0
  677. data/test/models/randomly_named_c1.rb +5 -0
  678. data/test/models/rating.rb +8 -0
  679. data/test/models/reader.rb +25 -0
  680. data/test/models/recipe.rb +5 -0
  681. data/test/models/record.rb +4 -0
  682. data/test/models/reference.rb +25 -0
  683. data/test/models/reply.rb +79 -0
  684. data/test/models/room.rb +6 -0
  685. data/test/models/section.rb +6 -0
  686. data/test/models/seminar.rb +6 -0
  687. data/test/models/session.rb +6 -0
  688. data/test/models/ship.rb +42 -0
  689. data/test/models/ship_part.rb +10 -0
  690. data/test/models/shop.rb +19 -0
  691. data/test/models/shop_account.rb +8 -0
  692. data/test/models/speedometer.rb +8 -0
  693. data/test/models/sponsor.rb +10 -0
  694. data/test/models/squeak.rb +6 -0
  695. data/test/models/strict_zine.rb +7 -0
  696. data/test/models/string_key_object.rb +5 -0
  697. data/test/models/student.rb +6 -0
  698. data/test/models/subject.rb +16 -0
  699. data/test/models/subscriber.rb +10 -0
  700. data/test/models/subscription.rb +8 -0
  701. data/test/models/tag.rb +16 -0
  702. data/test/models/tagging.rb +20 -0
  703. data/test/models/task.rb +7 -0
  704. data/test/models/topic.rb +153 -0
  705. data/test/models/toy.rb +10 -0
  706. data/test/models/traffic_light.rb +6 -0
  707. data/test/models/treasure.rb +16 -0
  708. data/test/models/treaty.rb +5 -0
  709. data/test/models/tree.rb +5 -0
  710. data/test/models/tuning_peg.rb +6 -0
  711. data/test/models/tyre.rb +13 -0
  712. data/test/models/user.rb +22 -0
  713. data/test/models/uuid_child.rb +5 -0
  714. data/test/models/uuid_item.rb +8 -0
  715. data/test/models/uuid_parent.rb +5 -0
  716. data/test/models/vegetables.rb +33 -0
  717. data/test/models/vehicle.rb +7 -0
  718. data/test/models/vertex.rb +11 -0
  719. data/test/models/warehouse_thing.rb +7 -0
  720. data/test/models/wheel.rb +5 -0
  721. data/test/models/without_table.rb +5 -0
  722. data/test/models/zine.rb +5 -0
  723. data/test/schema/i5/ibm_db_specific_schema.rb +137 -0
  724. data/test/schema/ids/ibm_db_specific_schema.rb +140 -0
  725. data/test/schema/luw/ibm_db_specific_schema.rb +137 -0
  726. data/test/schema/mysql2_specific_schema.rb +82 -0
  727. data/test/schema/oracle_specific_schema.rb +38 -0
  728. data/test/schema/postgresql_specific_schema.rb +125 -0
  729. data/test/schema/schema.rb +1237 -0
  730. data/test/schema/schema.rb.original +1057 -0
  731. data/test/schema/sqlite_specific_schema.rb +11 -0
  732. data/test/schema/zOS/ibm_db_specific_schema.rb +208 -0
  733. data/test/support/config.rb +43 -0
  734. data/test/support/connection.rb +29 -0
  735. data/test/support/connection_helper.rb +16 -0
  736. data/test/support/ddl_helper.rb +10 -0
  737. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic.dump +0 -0
  738. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic_associations.dump +0 -0
  739. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic.dump +0 -0
  740. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic_associations.dump +0 -0
  741. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic.dump +0 -0
  742. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic_associations.dump +0 -0
  743. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic.dump +0 -0
  744. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic_associations.dump +0 -0
  745. data/test/support/marshal_compatibility_fixtures/legacy_6_0_record_mysql.dump +0 -0
  746. data/test/support/marshal_compatibility_fixtures/legacy_relation.dump +0 -0
  747. data/test/support/schema_dumping_helper.rb +22 -0
  748. data/test/support/stubs/strong_parameters.rb +40 -0
  749. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  750. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  751. data/test/support/yaml_compatibility_fixtures/rails_v1_mysql.yml +206 -0
  752. data/test/support/yaml_compatibility_fixtures/rails_v2.yml +55 -0
  753. metadata +876 -0
@@ -0,0 +1,1658 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper"
4
+ require "models/post"
5
+ require "models/tagging"
6
+ require "models/tag"
7
+ require "models/rating"
8
+ require "models/comment"
9
+ require "models/author"
10
+ require "models/essay"
11
+ require "models/category"
12
+ require "models/company"
13
+ require "models/person"
14
+ require "models/reader"
15
+ require "models/owner"
16
+ require "models/pet"
17
+ require "models/reference"
18
+ require "models/job"
19
+ require "models/subscriber"
20
+ require "models/subscription"
21
+ require "models/book"
22
+ require "models/citation"
23
+ require "models/developer"
24
+ require "models/computer"
25
+ require "models/project"
26
+ require "models/member"
27
+ require "models/membership"
28
+ require "models/club"
29
+ require "models/categorization"
30
+ require "models/sponsor"
31
+ require "models/mentor"
32
+ require "models/contract"
33
+
34
+ class EagerLoadingTooManyIdsTest < ActiveRecord::TestCase
35
+ fixtures :citations
36
+
37
+ def test_preloading_too_many_ids
38
+ assert_equal Citation.count, Citation.preload(:reference_of).to_a.size
39
+ end
40
+
41
+ def test_eager_loading_too_many_ids
42
+ assert_equal Citation.count, Citation.eager_load(:citations).offset(0).size
43
+ end
44
+ end
45
+
46
+ class EagerAssociationTest < ActiveRecord::TestCase
47
+ fixtures :posts, :comments, :authors, :essays, :author_addresses, :categories, :categories_posts,
48
+ :companies, :accounts, :tags, :taggings, :ratings, :people, :readers, :categorizations,
49
+ :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books,
50
+ :developers, :projects, :developers_projects, :members, :memberships, :clubs, :sponsors
51
+
52
+ def test_eager_with_has_one_through_join_model_with_conditions_on_the_through
53
+ member = Member.all.merge!(includes: :favourite_club).find(members(:some_other_guy).id)
54
+ assert_nil member.favourite_club
55
+ end
56
+
57
+ def test_should_work_inverse_of_with_eager_load
58
+ author = authors(:david)
59
+ assert_same author, author.posts.first.author
60
+ assert_same author, author.posts.eager_load(:comments).first.author
61
+ end
62
+
63
+ def test_loading_with_one_association
64
+ posts = Post.all.merge!(includes: :comments).to_a
65
+ post = posts.find { |p| p.id == 1 }
66
+ assert_equal 2, post.comments.size
67
+ assert_includes post.comments, comments(:greetings)
68
+
69
+ post = Post.all.merge!(includes: :comments, where: "posts.title = 'Welcome to the weblog'").first
70
+ assert_equal 2, post.comments.size
71
+ assert_includes post.comments, comments(:greetings)
72
+
73
+ posts = Post.all.merge!(includes: :last_comment).to_a
74
+ post = posts.find { |p| p.id == 1 }
75
+ assert_equal Post.find(1).last_comment, post.last_comment
76
+ end
77
+
78
+ def test_loading_with_one_association_with_non_preload
79
+ posts = Post.all.merge!(includes: :last_comment, order: "comments.id DESC").to_a
80
+ post = posts.find { |p| p.id == 1 }
81
+ assert_equal Post.find(1).last_comment, post.last_comment
82
+ end
83
+
84
+ def test_loading_conditions_with_or
85
+ posts = authors(:david).posts.references(:comments).merge(
86
+ includes: :comments,
87
+ where: "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'"
88
+ ).to_a
89
+ assert_nil posts.detect { |p| p.author_id != authors(:david).id },
90
+ "expected to find only david's posts"
91
+ end
92
+
93
+ def test_loading_polymorphic_association_with_mixed_table_conditions
94
+ rating = Rating.first
95
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_without_tag
96
+
97
+ rating = Rating.preload(:taggings_without_tag).first
98
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_without_tag
99
+
100
+ rating = Rating.eager_load(:taggings_without_tag).first
101
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_without_tag
102
+ end
103
+
104
+ def test_loading_association_with_string_joins
105
+ rating = Rating.first
106
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_with_no_tag
107
+
108
+ rating = Rating.preload(:taggings_with_no_tag).first
109
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_with_no_tag
110
+
111
+ rating = Rating.eager_load(:taggings_with_no_tag).first
112
+ assert_equal [taggings(:normal_comment_rating)], rating.taggings_with_no_tag
113
+ end
114
+
115
+ def test_loading_with_scope_including_joins
116
+ member = Member.first
117
+ assert_equal members(:groucho), member
118
+ assert_equal clubs(:boring_club), member.general_club
119
+
120
+ member = Member.preload(:general_club).first
121
+ assert_equal members(:groucho), member
122
+ assert_equal clubs(:boring_club), member.general_club
123
+
124
+ member = Member.eager_load(:general_club).first
125
+ assert_equal members(:groucho), member
126
+ assert_equal clubs(:boring_club), member.general_club
127
+ end
128
+
129
+ def test_loading_association_with_same_table_joins
130
+ super_memberships = [memberships(:super_membership_of_boring_club)]
131
+
132
+ member = Member.joins(:favourite_memberships).first
133
+ assert_equal members(:groucho), member
134
+ assert_equal super_memberships, member.super_memberships
135
+
136
+ member = Member.joins(:favourite_memberships).preload(:super_memberships).first
137
+ assert_equal members(:groucho), member
138
+ assert_equal super_memberships, member.super_memberships
139
+
140
+ member = Member.joins(:favourite_memberships).eager_load(:super_memberships).first
141
+ assert_equal members(:groucho), member
142
+ assert_equal super_memberships, member.super_memberships
143
+ end
144
+
145
+ def test_loading_association_with_intersection_joins
146
+ member = Member.joins(:current_membership).first
147
+ assert_equal members(:groucho), member
148
+ assert_equal clubs(:boring_club), member.club
149
+ assert_equal memberships(:membership_of_boring_club), member.current_membership
150
+
151
+ member = Member.joins(:current_membership).preload(:club, :current_membership).first
152
+ assert_equal members(:groucho), member
153
+ assert_equal clubs(:boring_club), member.club
154
+ assert_equal memberships(:membership_of_boring_club), member.current_membership
155
+
156
+ member = Member.joins(:current_membership).eager_load(:club, :current_membership).first
157
+ assert_equal members(:groucho), member
158
+ assert_equal clubs(:boring_club), member.club
159
+ assert_equal memberships(:membership_of_boring_club), member.current_membership
160
+ end
161
+
162
+ def test_loading_associations_dont_leak_instance_state
163
+ assertions = ->(firm) {
164
+ assert_equal companies(:first_firm), firm
165
+
166
+ assert_predicate firm.association(:readonly_account), :loaded?
167
+ assert_predicate firm.association(:accounts), :loaded?
168
+
169
+ assert_equal accounts(:signals37), firm.readonly_account
170
+ assert_equal [accounts(:signals37)], firm.accounts
171
+
172
+ assert_predicate firm.readonly_account, :readonly?
173
+ assert firm.accounts.none?(&:readonly?)
174
+ }
175
+
176
+ assertions.call(Firm.preload(:readonly_account, :accounts).first)
177
+ assertions.call(Firm.eager_load(:readonly_account, :accounts).first)
178
+ end
179
+
180
+ def test_with_ordering
181
+ list = Post.all.merge!(includes: :comments, order: "posts.id DESC").to_a
182
+ [:other_by_mary, :other_by_bob, :misc_by_mary, :misc_by_bob, :eager_other,
183
+ :sti_habtm, :sti_post_and_comments, :sti_comments, :authorless, :thinking, :welcome
184
+ ].each_with_index do |post, index|
185
+ assert_equal posts(post), list[index]
186
+ end
187
+ end
188
+
189
+ def test_has_many_through_with_order
190
+ authors = Author.includes(:favorite_authors).to_a
191
+ assert authors.count > 0
192
+ assert_no_queries { authors.map(&:favorite_authors) }
193
+ end
194
+
195
+ def test_eager_loaded_has_one_association_with_references_does_not_run_additional_queries
196
+ Post.update_all(author_id: nil)
197
+ authors = Author.includes(:post).references(:post).to_a
198
+ assert authors.count > 0
199
+ assert_no_queries { authors.map(&:post) }
200
+ end
201
+
202
+ def test_type_cast_in_where_references_association_name
203
+ parent = comments(:greetings)
204
+ child = parent.children.create!(label: "child", body: "hi", post_id: parent.post_id)
205
+
206
+ comment = Comment.includes(:children).where("children.label": "child").last
207
+
208
+ assert_equal parent, comment
209
+ assert_equal [child], comment.children
210
+ end
211
+
212
+ def test_attribute_alias_in_where_references_association_name
213
+ firm = Firm.includes(:clients).where("clients.new_name": "Summit").last
214
+ assert_equal companies(:first_firm), firm
215
+ assert_equal [companies(:first_client)], firm.clients
216
+ end
217
+
218
+ def test_calculate_with_string_in_from_and_eager_loading
219
+ assert_equal 10, Post.from("authors, posts").eager_load(:comments).where("posts.author_id = authors.id").count
220
+ end
221
+
222
+ def test_with_two_tables_in_from_without_getting_double_quoted
223
+ posts = Post.select("posts.*").from("authors, posts").eager_load(:comments).where("posts.author_id = authors.id").order("posts.id").to_a
224
+ assert_equal 2, posts.first.comments.size
225
+ end
226
+
227
+ def test_loading_with_multiple_associations
228
+ posts = Post.all.merge!(includes: [ :comments, :author, :categories ], order: "posts.id").to_a
229
+ assert_equal 2, posts.first.comments.size
230
+ assert_equal 2, posts.first.categories.size
231
+ assert_includes posts.first.comments, comments(:greetings)
232
+ end
233
+
234
+ def test_duplicate_middle_objects
235
+ comments = Comment.all.merge!(where: "post_id = 1", includes: [post: :author]).to_a
236
+ assert_no_queries do
237
+ comments.each { |comment| comment.post.author.name }
238
+ end
239
+ end
240
+
241
+ def test_including_duplicate_objects_from_belongs_to
242
+ popular_post = Post.create!(title: "foo", body: "I like cars!")
243
+ comment = popular_post.comments.create!(body: "lol")
244
+ popular_post.readers.create!(person: people(:michael))
245
+ popular_post.readers.create!(person: people(:david))
246
+
247
+ readers = Reader.all.merge!(where: ["post_id = ?", popular_post.id],
248
+ includes: { post: :comments }).to_a
249
+ readers.each do |reader|
250
+ assert_equal [comment], reader.post.comments
251
+ end
252
+ end
253
+
254
+ def test_including_duplicate_objects_from_has_many
255
+ car_post = Post.create!(title: "foo", body: "I like cars!")
256
+ car_post.categories << categories(:general)
257
+ car_post.categories << categories(:technology)
258
+
259
+ comment = car_post.comments.create!(body: "hmm")
260
+ categories = Category.all.merge!(where: { "posts.id" => car_post.id },
261
+ includes: { posts: :comments }).to_a
262
+ categories.each do |category|
263
+ assert_equal [comment], category.posts[0].comments
264
+ end
265
+ end
266
+
267
+ def test_associations_loaded_for_all_records
268
+ post = Post.create!(title: "foo", body: "I like cars!")
269
+ SpecialComment.create!(body: "Come on!", post: post)
270
+ first_category = Category.create! name: "First!", posts: [post]
271
+ second_category = Category.create! name: "Second!", posts: [post]
272
+
273
+ categories = Category.where(id: [first_category.id, second_category.id]).includes(posts: :special_comments)
274
+ assert_equal categories.map { |category| category.posts.first.special_comments.loaded? }, [true, true]
275
+ end
276
+
277
+ def test_finding_with_includes_on_has_many_association_with_same_include_includes_only_once
278
+ author_id = authors(:david).id
279
+ author = assert_queries(3) { Author.all.merge!(includes: { posts_with_comments: :comments }).find(author_id) } # find the author, then find the posts, then find the comments
280
+ author.posts_with_comments.each do |post_with_comments|
281
+ assert_equal post_with_comments.comments.length, post_with_comments.comments.count
282
+ assert_nil post_with_comments.comments.to_a.uniq!
283
+ end
284
+ end
285
+
286
+ def test_finding_with_includes_on_has_one_association_with_same_include_includes_only_once
287
+ author = authors(:david)
288
+ post = author.post_about_thinking_with_last_comment
289
+ last_comment = post.last_comment
290
+ author = assert_queries(3) { Author.all.merge!(includes: { post_about_thinking_with_last_comment: :last_comment }).find(author.id) } # find the author, then find the posts, then find the comments
291
+ assert_no_queries do
292
+ assert_equal post, author.post_about_thinking_with_last_comment
293
+ assert_equal last_comment, author.post_about_thinking_with_last_comment.last_comment
294
+ end
295
+ end
296
+
297
+ def test_finding_with_includes_on_belongs_to_association_with_same_include_includes_only_once
298
+ post = posts(:welcome)
299
+ author = post.author
300
+ author_address = author.author_address
301
+ post = assert_queries(3) { Post.all.merge!(includes: { author_with_address: :author_address }).find(post.id) } # find the post, then find the author, then find the address
302
+ assert_no_queries do
303
+ assert_equal author, post.author_with_address
304
+ assert_equal author_address, post.author_with_address.author_address
305
+ end
306
+ end
307
+
308
+ def test_finding_with_includes_on_null_belongs_to_association_with_same_include_includes_only_once
309
+ post = posts(:welcome)
310
+ post.update!(author: nil)
311
+ post = assert_queries(1) { Post.all.merge!(includes: { author_with_address: :author_address }).find(post.id) }
312
+ # find the post, then find the author which is null so no query for the author or address
313
+ assert_no_queries do
314
+ assert_nil post.author_with_address
315
+ end
316
+ end
317
+
318
+ def test_finding_with_includes_on_null_belongs_to_polymorphic_association
319
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
320
+ sponsor.update!(sponsorable: nil)
321
+ sponsor = assert_queries(1) { Sponsor.all.merge!(includes: :sponsorable).find(sponsor.id) }
322
+ assert_no_queries do
323
+ assert_nil sponsor.sponsorable
324
+ end
325
+ end
326
+
327
+ def test_finding_with_includes_on_empty_polymorphic_type_column
328
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
329
+ sponsor.update!(sponsorable_type: "", sponsorable_id: nil) # sponsorable_type column might be declared NOT NULL
330
+ sponsor = assert_queries(1) do
331
+ assert_nothing_raised { Sponsor.all.merge!(includes: :sponsorable).find(sponsor.id) }
332
+ end
333
+ assert_no_queries do
334
+ assert_nil sponsor.sponsorable
335
+ end
336
+ end
337
+
338
+ def test_loading_from_an_association
339
+ posts = authors(:david).posts.merge(includes: :comments, order: "posts.id").to_a
340
+ assert_equal 2, posts.first.comments.size
341
+ end
342
+
343
+ def test_loading_from_an_association_that_has_a_hash_of_conditions
344
+ assert_not_empty Author.all.merge!(includes: :hello_posts_with_hash_conditions).find(authors(:david).id).hello_posts
345
+ end
346
+
347
+ def test_loading_with_no_associations
348
+ assert_nil Post.all.merge!(includes: :author).find(posts(:authorless).id).author
349
+ end
350
+
351
+ # Regression test for 21c75e5
352
+ def test_nested_loading_does_not_raise_exception_when_association_does_not_exist
353
+ assert_nothing_raised do
354
+ Post.all.merge!(includes: { author: :author_addresss }).find(posts(:authorless).id)
355
+ end
356
+ end
357
+
358
+ def test_three_level_nested_preloading_does_not_raise_exception_when_association_does_not_exist
359
+ post_id = Comment.where(author_id: nil).where.not(post_id: nil).first.post_id
360
+
361
+ assert_nothing_raised do
362
+ Post.preload(comments: [{ author: :essays }]).find(post_id)
363
+ end
364
+ end
365
+
366
+ def test_nested_loading_through_has_one_association
367
+ aa = AuthorAddress.all.merge!(includes: { author: :posts }).find(author_addresses(:david_address).id)
368
+ assert_equal aa.author.posts.count, aa.author.posts.length
369
+ end
370
+
371
+ def test_nested_loading_through_has_one_association_with_order
372
+ aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "author_addresses.id").find(author_addresses(:david_address).id)
373
+ assert_equal aa.author.posts.count, aa.author.posts.length
374
+ end
375
+
376
+ def test_nested_loading_through_has_one_association_with_order_on_association
377
+ aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "authors.id").find(author_addresses(:david_address).id)
378
+ assert_equal aa.author.posts.count, aa.author.posts.length
379
+ end
380
+
381
+ def test_nested_loading_through_has_one_association_with_order_on_nested_association
382
+ aa = AuthorAddress.all.merge!(includes: { author: :posts }, order: "posts.id").find(author_addresses(:david_address).id)
383
+ assert_equal aa.author.posts.count, aa.author.posts.length
384
+ end
385
+
386
+ def test_nested_loading_through_has_one_association_with_conditions
387
+ aa = AuthorAddress.references(:author_addresses).merge(
388
+ includes: { author: :posts },
389
+ where: "author_addresses.id > 0"
390
+ ).find author_addresses(:david_address).id
391
+ assert_equal aa.author.posts.count, aa.author.posts.length
392
+ end
393
+
394
+ def test_nested_loading_through_has_one_association_with_conditions_on_association
395
+ aa = AuthorAddress.references(:authors).merge(
396
+ includes: { author: :posts },
397
+ where: "authors.id > 0"
398
+ ).find author_addresses(:david_address).id
399
+ assert_equal aa.author.posts.count, aa.author.posts.length
400
+ end
401
+
402
+ def test_nested_loading_through_has_one_association_with_conditions_on_nested_association
403
+ aa = AuthorAddress.references(:posts).merge(
404
+ includes: { author: :posts },
405
+ where: "posts.id > 0"
406
+ ).find author_addresses(:david_address).id
407
+ assert_equal aa.author.posts.count, aa.author.posts.length
408
+ end
409
+
410
+ def test_eager_association_loading_with_belongs_to_and_foreign_keys
411
+ pets = Pet.all.merge!(includes: :owner).to_a
412
+ assert_equal 4, pets.length
413
+ end
414
+
415
+ def test_eager_association_loading_with_belongs_to
416
+ comments = Comment.all.merge!(includes: :post).to_a
417
+ assert_equal 12, comments.length
418
+ titles = comments.map { |c| c.post.title }
419
+ assert_includes titles, posts(:welcome).title
420
+ assert_includes titles, posts(:sti_post_and_comments).title
421
+ end
422
+
423
+ def test_eager_association_loading_with_belongs_to_and_limit
424
+ comments = Comment.all.merge!(includes: :post, limit: 5, order: "comments.id").to_a
425
+ assert_equal 5, comments.length
426
+ assert_equal [1, 2, 3, 5, 6], comments.collect(&:id)
427
+ end
428
+
429
+ def test_eager_association_loading_with_belongs_to_and_limit_and_conditions
430
+ comments = Comment.all.merge!(includes: :post, where: "post_id = 4", limit: 3, order: "comments.id").to_a
431
+ assert_equal 3, comments.length
432
+ assert_equal [5, 6, 7], comments.collect(&:id)
433
+ end
434
+
435
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset
436
+ comments = Comment.all.merge!(includes: :post, limit: 3, offset: 2, order: "comments.id").to_a
437
+ assert_equal 3, comments.length
438
+ assert_equal [3, 5, 6], comments.collect(&:id)
439
+ end
440
+
441
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions
442
+ comments = Comment.all.merge!(includes: :post, where: "post_id = 4", limit: 3, offset: 1, order: "comments.id").to_a
443
+ assert_equal 3, comments.length
444
+ assert_equal [6, 7, 8], comments.collect(&:id)
445
+ end
446
+
447
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array
448
+ comments = Comment.all.merge!(includes: :post, where: ["post_id = ?", 4], limit: 3, offset: 1, order: "comments.id").to_a
449
+ assert_equal 3, comments.length
450
+ assert_equal [6, 7, 8], comments.collect(&:id)
451
+ end
452
+
453
+ def test_eager_association_loading_with_belongs_to_and_conditions_string_with_unquoted_table_name
454
+ assert_nothing_raised do
455
+ Comment.includes(:post).references(:posts).where("posts.id = ?", 4)
456
+ end
457
+ end
458
+
459
+ def test_eager_association_loading_with_belongs_to_and_conditions_hash
460
+ comments = []
461
+ assert_nothing_raised do
462
+ comments = Comment.all.merge!(includes: :post, where: { posts: { id: 4 } }, limit: 3, order: "comments.id").to_a
463
+ end
464
+ assert_equal 3, comments.length
465
+ assert_equal [5, 6, 7], comments.collect(&:id)
466
+ assert_no_queries do
467
+ comments.first.post
468
+ end
469
+ end
470
+
471
+ def test_eager_association_loading_with_belongs_to_and_conditions_string_with_quoted_table_name
472
+ quoted_posts_id = Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id")
473
+ assert_nothing_raised do
474
+ Comment.includes(:post).references(:posts).where("#{quoted_posts_id} = ?", 4)
475
+ end
476
+ end
477
+
478
+ def test_eager_association_loading_with_belongs_to_and_order_string_with_unquoted_table_name
479
+ assert_nothing_raised do
480
+ Comment.all.merge!(includes: :post, order: "posts.id").to_a
481
+ end
482
+ end
483
+
484
+ def test_eager_association_loading_with_belongs_to_and_order_string_with_quoted_table_name
485
+ quoted_posts_id = Comment.connection.quote_table_name("posts") + "." + Comment.connection.quote_column_name("id")
486
+ assert_nothing_raised do
487
+ Comment.includes(:post).references(:posts).order(quoted_posts_id)
488
+ end
489
+ end
490
+
491
+ def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations
492
+ posts = Post.all.merge!(includes: [:author, :very_special_comment], limit: 1, order: "posts.id").to_a
493
+ assert_equal 1, posts.length
494
+ assert_equal [1], posts.collect(&:id)
495
+ end
496
+
497
+ def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations
498
+ posts = Post.all.merge!(includes: [:author, :very_special_comment], limit: 1, offset: 1, order: "posts.id").to_a
499
+ assert_equal 1, posts.length
500
+ assert_equal [2], posts.collect(&:id)
501
+ end
502
+
503
+ def test_eager_association_loading_with_belongs_to_inferred_foreign_key_from_association_name
504
+ author_favorite = AuthorFavorite.all.merge!(includes: :favorite_author).first
505
+ assert_equal authors(:mary), assert_no_queries { author_favorite.favorite_author }
506
+ end
507
+
508
+ def test_eager_load_belongs_to_quotes_table_and_column_names
509
+ job = Job.includes(:ideal_reference).find jobs(:unicyclist).id
510
+ references(:michael_unicyclist)
511
+ assert_no_queries { assert_equal references(:michael_unicyclist), job.ideal_reference }
512
+ end
513
+
514
+ def test_eager_load_has_one_quotes_table_and_column_names
515
+ michael = Person.all.merge!(includes: :favourite_reference).find(people(:michael).id)
516
+ references(:michael_unicyclist)
517
+ assert_no_queries { assert_equal references(:michael_unicyclist), michael.favourite_reference }
518
+ end
519
+
520
+ def test_eager_load_has_many_quotes_table_and_column_names
521
+ michael = Person.all.merge!(includes: :references).find(people(:michael).id)
522
+ references(:michael_magician, :michael_unicyclist)
523
+ assert_no_queries { assert_equal references(:michael_magician, :michael_unicyclist), michael.references.sort_by(&:id) }
524
+ end
525
+
526
+ def test_eager_load_has_many_through_quotes_table_and_column_names
527
+ michael = Person.all.merge!(includes: :jobs).find(people(:michael).id)
528
+ jobs(:magician, :unicyclist)
529
+ assert_no_queries { assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) }
530
+ end
531
+
532
+ def test_eager_load_has_many_with_string_keys
533
+ subscriptions = subscriptions(:webster_awdr, :webster_rfr)
534
+ subscriber = Subscriber.all.merge!(includes: :subscriptions).find(subscribers(:second).id)
535
+ assert_equal subscriptions, subscriber.subscriptions.sort_by(&:id)
536
+ end
537
+
538
+ def test_string_id_column_joins
539
+ s = Subscriber.create! do |c|
540
+ c.id = "PL"
541
+ end
542
+
543
+ b = Book.create!
544
+
545
+ Subscription.create!(subscriber_id: "PL", book_id: b.id)
546
+ s.reload
547
+ s.book_ids = s.book_ids
548
+ end
549
+
550
+ def test_eager_load_has_many_through_with_string_keys
551
+ books = books(:awdr, :rfr)
552
+ subscriber = Subscriber.all.merge!(includes: :books).find(subscribers(:second).id)
553
+ assert_equal books, subscriber.books.sort_by(&:id)
554
+ end
555
+
556
+ def test_eager_load_belongs_to_with_string_keys
557
+ subscriber = subscribers(:second)
558
+ subscription = Subscription.all.merge!(includes: :subscriber).find(subscriptions(:webster_awdr).id)
559
+ assert_equal subscriber, subscription.subscriber
560
+ end
561
+
562
+ def test_eager_association_loading_with_explicit_join
563
+ posts = Post.all.merge!(includes: :comments, joins: "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", limit: 1, order: "author_id").to_a
564
+ assert_equal 1, posts.length
565
+ end
566
+
567
+ def test_eager_with_has_many_through
568
+ posts_with_comments = people(:michael).posts.merge(includes: :comments, order: "posts.id").to_a
569
+ posts_with_author = people(:michael).posts.merge(includes: :author, order: "posts.id").to_a
570
+ posts_with_comments_and_author = people(:michael).posts.merge(includes: [ :comments, :author ], order: "posts.id").to_a
571
+ assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum + post.comments.size }
572
+ assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
573
+ assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
574
+ end
575
+
576
+ def test_eager_with_has_many_through_a_belongs_to_association
577
+ author = authors(:mary)
578
+ Post.create!(author: author, title: "TITLE", body: "BODY")
579
+ author.author_favorites.create(favorite_author_id: 1)
580
+ author.author_favorites.create(favorite_author_id: 2)
581
+ posts_with_author_favorites = author.posts.merge(includes: :author_favorites).to_a
582
+ assert_no_queries { posts_with_author_favorites.first.author_favorites.first.author_id }
583
+ end
584
+
585
+ def test_eager_with_has_many_through_an_sti_join_model
586
+ author = Author.all.merge!(includes: :special_post_comments, order: "authors.id").first
587
+ assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments }
588
+ end
589
+
590
+ def test_preloading_with_has_one_through_an_sti_with_after_initialize
591
+ author_a = Author.create!(name: "A")
592
+ author_b = Author.create!(name: "B")
593
+ post_a = StiPost.create!(author: author_a, title: "TITLE", body: "BODY")
594
+ post_b = SpecialPost.create!(author: author_b, title: "TITLE", body: "BODY")
595
+ comment_a = SpecialComment.create!(post: post_a, body: "TEST")
596
+ comment_b = SpecialComment.create!(post: post_b, body: "TEST")
597
+ reset_callbacks(StiPost, :initialize) do
598
+ StiPost.after_initialize { author }
599
+ SpecialComment.where(id: [comment_a.id, comment_b.id]).includes(:author).each do |comment|
600
+ assert comment.author
601
+ end
602
+ end
603
+ end
604
+
605
+ def test_preloading_has_many_through_with_implicit_source
606
+ authors = Author.includes(:very_special_comments).to_a.sort_by(&:id)
607
+ assert_no_queries do
608
+ special_comment_authors = authors.map { |author| [author.name, author.very_special_comments.size] }
609
+ assert_equal [["David", 1], ["Mary", 0], ["Bob", 0]], special_comment_authors
610
+ end
611
+ end
612
+
613
+ def test_eager_with_has_many_through_an_sti_join_model_with_conditions_on_both
614
+ author = Author.all.merge!(includes: :special_nonexistent_post_comments, order: "authors.id").first
615
+ assert_equal [], author.special_nonexistent_post_comments
616
+ end
617
+
618
+ def test_eager_with_has_many_through_join_model_with_conditions
619
+ assert_equal Author.all.merge!(includes: :hello_post_comments,
620
+ order: "authors.id").first.hello_post_comments.sort_by(&:id),
621
+ Author.all.merge!(order: "authors.id").first.hello_post_comments.sort_by(&:id)
622
+ end
623
+
624
+ def test_eager_with_has_many_through_join_model_with_conditions_on_top_level
625
+ assert_equal comments(:more_greetings), Author.all.merge!(includes: :comments_with_order_and_conditions).find(authors(:david).id).comments_with_order_and_conditions.first
626
+ end
627
+
628
+ def test_eager_with_has_many_through_join_model_with_include
629
+ author_comments = Author.all.merge!(includes: :comments_with_include).find(authors(:david).id).comments_with_include.to_a
630
+ assert_no_queries do
631
+ author_comments.first.post.title
632
+ end
633
+ end
634
+
635
+ def test_eager_with_has_many_through_with_conditions_join_model_with_include
636
+ post_tags = Post.find(posts(:welcome).id).misc_tags
637
+ eager_post_tags = Post.all.merge!(includes: :misc_tags).find(1).misc_tags
638
+ assert_equal post_tags, eager_post_tags
639
+ end
640
+
641
+ def test_eager_with_has_many_through_join_model_ignores_default_includes
642
+ assert_nothing_raised do
643
+ authors(:david).comments_on_posts_with_default_include.to_a
644
+ end
645
+ end
646
+
647
+ def test_eager_with_has_many_and_limit
648
+ posts = Post.all.merge!(order: "posts.id asc", includes: [ :author, :comments ], limit: 2).to_a
649
+ assert_equal 2, posts.size
650
+ assert_equal 3, posts.inject(0) { |sum, post| sum + post.comments.size }
651
+ end
652
+
653
+ def test_eager_with_has_many_and_limit_and_conditions
654
+ posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: "posts.body = 'hello'", order: "posts.id").to_a
655
+ assert_equal 2, posts.size
656
+ assert_equal [4, 5], posts.collect(&:id)
657
+ end
658
+
659
+ def test_eager_with_has_many_and_limit_and_conditions_array
660
+ posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: [ "posts.body = ?", "hello" ], order: "posts.id").to_a
661
+ assert_equal 2, posts.size
662
+ assert_equal [4, 5], posts.collect(&:id)
663
+ end
664
+
665
+ def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
666
+ posts = Post.includes(:author, :comments).limit(2).references("author").where("authors.name = ?", "David")
667
+ assert_equal 2, posts.size
668
+
669
+ count = Post.includes(:author, :comments).limit(2).references("author").where("authors.name = ?", "David").count
670
+ assert_equal posts.size, count
671
+ end
672
+
673
+ def test_eager_with_has_many_and_limit_and_high_offset
674
+ posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, offset: 10, where: { "authors.name" => "David" }).to_a
675
+ assert_equal 0, posts.size
676
+ end
677
+
678
+ def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_array_conditions
679
+ assert_queries(1) do
680
+ posts = Post.references(:authors, :comments).
681
+ merge(includes: [ :author, :comments ], limit: 2, offset: 10,
682
+ where: [ "authors.name = ? and comments.body = ?", "David", "go crazy" ]).to_a
683
+ assert_equal 0, posts.size
684
+ end
685
+ end
686
+
687
+ def test_eager_with_has_many_and_limit_and_high_offset_and_multiple_hash_conditions
688
+ assert_queries(1) do
689
+ posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, offset: 10,
690
+ where: { "authors.name" => "David", "comments.body" => "go crazy" }).to_a
691
+ assert_equal 0, posts.size
692
+ end
693
+ end
694
+
695
+ def test_count_eager_with_has_many_and_limit_and_high_offset
696
+ posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, offset: 10, where: { "authors.name" => "David" }).count(:all)
697
+ assert_equal 0, posts
698
+ end
699
+
700
+ def test_eager_with_has_many_and_limit_with_no_results
701
+ posts = Post.all.merge!(includes: [ :author, :comments ], limit: 2, where: "posts.title = 'magic forest'").to_a
702
+ assert_equal 0, posts.size
703
+ end
704
+
705
+ def test_eager_count_performed_on_a_has_many_association_with_multi_table_conditional
706
+ author = authors(:david)
707
+ author_posts_without_comments = author.posts.select { |post| post.comments.blank? }
708
+ assert_equal author_posts_without_comments.size, author.posts.includes(:comments).where("comments.id is null").references(:comments).count
709
+ end
710
+
711
+ def test_eager_count_performed_on_a_has_many_through_association_with_multi_table_conditional
712
+ person = people(:michael)
713
+ person_posts_without_comments = person.posts.select { |post| post.comments.blank? }
714
+ assert_equal person_posts_without_comments.size, person.posts_with_no_comments.count
715
+ end
716
+
717
+ def test_eager_with_has_and_belongs_to_many_and_limit
718
+ posts = Post.all.merge!(includes: :categories, order: "posts.id", limit: 3).to_a
719
+ assert_equal 3, posts.size
720
+ assert_equal 2, posts[0].categories.size
721
+ assert_equal 1, posts[1].categories.size
722
+ assert_equal 0, posts[2].categories.size
723
+ assert_includes posts[0].categories, categories(:technology)
724
+ assert_includes posts[1].categories, categories(:general)
725
+ end
726
+
727
+ # Since the preloader for habtm gets raw row hashes from the database and then
728
+ # instantiates them, this test ensures that it only instantiates one actual
729
+ # object per record from the database.
730
+ def test_has_and_belongs_to_many_should_not_instantiate_same_records_multiple_times
731
+ welcome = posts(:welcome)
732
+ categories = Category.includes(:posts)
733
+
734
+ general = categories.find { |c| c == categories(:general) }
735
+ technology = categories.find { |c| c == categories(:technology) }
736
+
737
+ post1 = general.posts.to_a.find { |p| p == welcome }
738
+ post2 = technology.posts.to_a.find { |p| p == welcome }
739
+
740
+ assert_same post1, post2
741
+ end
742
+
743
+ def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
744
+ posts =
745
+ authors(:david).posts
746
+ .includes(:comments)
747
+ .where("comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'")
748
+ .references(:comments)
749
+ .limit(2)
750
+ .to_a
751
+ assert_equal 2, posts.size
752
+
753
+ count =
754
+ Post.includes(:comments, :author)
755
+ .where("authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')")
756
+ .references(:authors, :comments)
757
+ .limit(2)
758
+ .count
759
+ assert_equal count, posts.size
760
+ end
761
+
762
+ def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
763
+ posts = nil
764
+ Post.includes(:comments)
765
+ .where("comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'")
766
+ .references(:comments)
767
+ .scoping do
768
+ posts = authors(:david).posts.limit(2).to_a
769
+ assert_equal 2, posts.size
770
+ end
771
+
772
+ Post.includes(:comments, :author)
773
+ .where("authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')")
774
+ .references(:authors, :comments)
775
+ .scoping do
776
+ count = Post.limit(2).count
777
+ assert_equal count, posts.size
778
+ end
779
+ end
780
+
781
+ def test_eager_association_loading_with_habtm
782
+ posts = Post.all.merge!(includes: :categories, order: "posts.id").to_a
783
+ assert_equal 2, posts[0].categories.size
784
+ assert_equal 1, posts[1].categories.size
785
+ assert_equal 0, posts[2].categories.size
786
+ assert_includes posts[0].categories, categories(:technology)
787
+ assert_includes posts[1].categories, categories(:general)
788
+ end
789
+
790
+ def test_eager_with_inheritance
791
+ SpecialPost.all.merge!(includes: [ :comments ]).to_a
792
+ end
793
+
794
+ def test_eager_has_one_with_association_inheritance
795
+ post = Post.all.merge!(includes: [ :very_special_comment ]).find(4)
796
+ assert_equal "VerySpecialComment", post.very_special_comment.class.to_s
797
+ end
798
+
799
+ def test_eager_has_many_with_association_inheritance
800
+ post = Post.all.merge!(includes: [ :special_comments ]).find(4)
801
+ post.special_comments.each do |special_comment|
802
+ assert special_comment.is_a?(SpecialComment)
803
+ end
804
+ end
805
+
806
+ def test_eager_habtm_with_association_inheritance
807
+ post = Post.all.merge!(includes: [ :special_categories ]).find(6)
808
+ assert_equal 1, post.special_categories.size
809
+ post.special_categories.each do |special_category|
810
+ assert_equal "SpecialCategory", special_category.class.to_s
811
+ end
812
+ end
813
+
814
+ def test_eager_with_has_one_dependent_does_not_destroy_dependent
815
+ assert_not_nil companies(:first_firm).account
816
+ f = Firm.all.merge!(includes: :account,
817
+ where: ["companies.name = ?", "37signals"]).first
818
+ assert_not_nil f.account
819
+ assert_equal companies(:first_firm, :reload).account, f.account
820
+ end
821
+
822
+ def test_eager_with_multi_table_conditional_properly_counts_the_records_when_using_size
823
+ author = authors(:david)
824
+ posts_with_no_comments = author.posts.select { |post| post.comments.blank? }
825
+ assert_equal posts_with_no_comments.size, author.posts_with_no_comments.size
826
+ assert_equal posts_with_no_comments, author.posts_with_no_comments
827
+ end
828
+
829
+ def test_eager_with_invalid_association_reference
830
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
831
+ Post.all.merge!(includes: :monkeys).find(6)
832
+ }
833
+ assert_match(/Association named 'monkeys' was not found on Post; perhaps you misspelled it\?/, e.message)
834
+
835
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
836
+ Post.all.merge!(includes: [ :monkeys ]).find(6)
837
+ }
838
+ assert_match(/Association named 'monkeys' was not found on Post; perhaps you misspelled it\?/, e.message)
839
+
840
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
841
+ Post.all.merge!(includes: [ "monkeys" ]).find(6)
842
+ }
843
+ assert_match(/Association named 'monkeys' was not found on Post; perhaps you misspelled it\?/, e.message)
844
+
845
+ e = assert_raise(ActiveRecord::AssociationNotFoundError) {
846
+ Post.all.merge!(includes: [ :monkeys, :elephants ]).find(6)
847
+ }
848
+ assert_match(/Association named 'monkeys' was not found on Post; perhaps you misspelled it\?/, e.message)
849
+ end
850
+
851
+ if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
852
+ test "exceptions have suggestions for fix" do
853
+ error = assert_raise(ActiveRecord::AssociationNotFoundError) {
854
+ Post.all.merge!(includes: :monkeys).find(6)
855
+ }
856
+ assert_match "Did you mean?", error.message
857
+ end
858
+ end
859
+
860
+ def test_eager_has_many_through_with_order
861
+ tag = OrderedTag.create(name: "Foo")
862
+ post1 = Post.create!(title: "Beaches", body: "I like beaches!")
863
+ post2 = Post.create!(title: "Pools", body: "I like pools!")
864
+
865
+ Tagging.create!(taggable_type: "Post", taggable_id: post1.id, tag: tag)
866
+ Tagging.create!(taggable_type: "Post", taggable_id: post2.id, tag: tag)
867
+
868
+ tag_with_includes = OrderedTag.includes(:tagged_posts).find(tag.id)
869
+ assert_equal tag_with_includes.ordered_taggings.map(&:taggable).map(&:title), tag_with_includes.tagged_posts.map(&:title)
870
+ end
871
+
872
+ def test_eager_has_many_through_multiple_with_order
873
+ tag1 = OrderedTag.create!(name: "Bar")
874
+ tag2 = OrderedTag.create!(name: "Foo")
875
+
876
+ post1 = Post.create!(title: "Beaches", body: "I like beaches!")
877
+ post2 = Post.create!(title: "Pools", body: "I like pools!")
878
+
879
+ Tagging.create!(taggable: post1, tag: tag1)
880
+ Tagging.create!(taggable: post2, tag: tag1)
881
+ Tagging.create!(taggable: post2, tag: tag2)
882
+ Tagging.create!(taggable: post1, tag: tag2)
883
+
884
+ tags_with_includes = OrderedTag.where(id: [tag1, tag2].map(&:id)).includes(:tagged_posts).order(:id).to_a
885
+ tag1_with_includes = tags_with_includes.first
886
+ tag2_with_includes = tags_with_includes.last
887
+
888
+ assert_equal([post2, post1].map(&:title), tag1_with_includes.tagged_posts.map(&:title))
889
+ assert_equal([post1, post2].map(&:title), tag2_with_includes.tagged_posts.map(&:title))
890
+ end
891
+
892
+ def test_eager_with_default_scope
893
+ developer = EagerDeveloperWithDefaultScope.where(name: "David").first
894
+ projects = Project.order(:id).to_a
895
+ assert_no_queries do
896
+ assert_equal(projects, developer.projects)
897
+ end
898
+ end
899
+
900
+ def test_eager_with_default_scope_as_class_method
901
+ developer = EagerDeveloperWithClassMethodDefaultScope.where(name: "David").first
902
+ projects = Project.order(:id).to_a
903
+ assert_no_queries do
904
+ assert_equal(projects, developer.projects)
905
+ end
906
+ end
907
+
908
+ def test_eager_with_default_scope_as_class_method_using_find_method
909
+ david = developers(:david)
910
+ developer = EagerDeveloperWithClassMethodDefaultScope.find(david.id)
911
+ projects = Project.order(:id).to_a
912
+ assert_no_queries do
913
+ assert_equal(projects, developer.projects)
914
+ end
915
+ end
916
+
917
+ def test_eager_with_default_scope_as_class_method_using_find_by_method
918
+ developer = EagerDeveloperWithClassMethodDefaultScope.find_by(name: "David")
919
+ projects = Project.order(:id).to_a
920
+ assert_no_queries do
921
+ assert_equal(projects, developer.projects)
922
+ end
923
+ end
924
+
925
+ def test_eager_with_default_scope_as_lambda
926
+ developer = EagerDeveloperWithLambdaDefaultScope.where(name: "David").first
927
+ projects = Project.order(:id).to_a
928
+ assert_no_queries do
929
+ assert_equal(projects, developer.projects)
930
+ end
931
+ end
932
+
933
+ def test_eager_with_default_scope_as_block
934
+ # warm up the habtm cache
935
+ EagerDeveloperWithBlockDefaultScope.where(name: "David").first.projects
936
+ developer = EagerDeveloperWithBlockDefaultScope.where(name: "David").first
937
+ projects = Project.order(:id).to_a
938
+ assert_no_queries do
939
+ assert_equal(projects, developer.projects)
940
+ end
941
+ end
942
+
943
+ def test_eager_with_default_scope_as_callable
944
+ developer = EagerDeveloperWithCallableDefaultScope.where(name: "David").first
945
+ projects = Project.order(:id).to_a
946
+ assert_no_queries do
947
+ assert_equal(projects, developer.projects)
948
+ end
949
+ end
950
+
951
+ def test_limited_eager_with_order
952
+ assert_equal(
953
+ posts(:thinking, :sti_comments),
954
+ Post.all.merge!(
955
+ includes: [:author, :comments], where: { "authors.name" => "David" },
956
+ order: "UPPER(posts.title)", limit: 2, offset: 1
957
+ ).to_a
958
+ )
959
+ assert_equal(
960
+ posts(:sti_post_and_comments, :sti_comments),
961
+ Post.all.merge!(
962
+ includes: [:author, :comments], where: { "authors.name" => "David" },
963
+ order: "UPPER(posts.title) DESC", limit: 2, offset: 1
964
+ ).to_a
965
+ )
966
+ end
967
+
968
+ def test_limited_eager_with_multiple_order_columns
969
+ assert_equal(
970
+ posts(:thinking, :sti_comments),
971
+ Post.all.merge!(
972
+ includes: [:author, :comments], where: { "authors.name" => "David" },
973
+ order: ["UPPER(posts.title)", "posts.id"], limit: 2, offset: 1
974
+ ).to_a
975
+ )
976
+ assert_equal(
977
+ posts(:sti_post_and_comments, :sti_comments),
978
+ Post.all.merge!(
979
+ includes: [:author, :comments], where: { "authors.name" => "David" },
980
+ order: ["UPPER(posts.title) DESC", "posts.id"], limit: 2, offset: 1
981
+ ).to_a
982
+ )
983
+ end
984
+
985
+ def test_limited_eager_with_numeric_in_association
986
+ assert_equal(
987
+ people(:david, :susan),
988
+ Person.references(:number1_fans_people).merge(
989
+ includes: [:readers, :primary_contact, :number1_fan],
990
+ where: "number1_fans_people.first_name like 'M%'",
991
+ order: "people.id", limit: 2, offset: 0
992
+ ).to_a
993
+ )
994
+ end
995
+
996
+ def test_polymorphic_type_condition
997
+ post = Post.all.merge!(includes: :taggings).find(posts(:thinking).id)
998
+ assert_includes post.taggings, taggings(:thinking_general)
999
+ post = SpecialPost.all.merge!(includes: :taggings).find(posts(:thinking).id)
1000
+ assert_includes post.taggings, taggings(:thinking_general)
1001
+ end
1002
+
1003
+ def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm
1004
+ # Eager includes of has many and habtm associations aren't necessarily sorted in the same way
1005
+ def assert_equal_after_sort(item1, item2, item3 = nil)
1006
+ assert_equal(item1.sort { |a, b| a.id <=> b.id }, item2.sort { |a, b| a.id <=> b.id })
1007
+ assert_equal(item3.sort { |a, b| a.id <=> b.id }, item2.sort { |a, b| a.id <=> b.id }) if item3
1008
+ end
1009
+ # Test regular association, association with conditions, association with
1010
+ # STI, and association with conditions assured not to be true
1011
+ post_types = [:posts, :other_posts, :special_posts]
1012
+ # test both has_many and has_and_belongs_to_many
1013
+ [Author, Category].each do |className|
1014
+ d1 = find_all_ordered(className)
1015
+ # test including all post types at once
1016
+ d2 = find_all_ordered(className, post_types)
1017
+ d1.each_index do |i|
1018
+ assert_equal(d1[i], d2[i])
1019
+ assert_equal_after_sort(d1[i].posts, d2[i].posts)
1020
+ post_types[1..-1].each do |post_type|
1021
+ # test including post_types together
1022
+ d3 = find_all_ordered(className, [:posts, post_type])
1023
+ assert_equal(d1[i], d3[i])
1024
+ assert_equal_after_sort(d1[i].posts, d3[i].posts)
1025
+ assert_equal_after_sort(d1[i].public_send(post_type), d2[i].public_send(post_type), d3[i].public_send(post_type))
1026
+ end
1027
+ end
1028
+ end
1029
+ end
1030
+
1031
+ def test_eager_with_multiple_associations_with_same_table_has_one
1032
+ d1 = find_all_ordered(Firm)
1033
+ d2 = find_all_ordered(Firm, :account)
1034
+ d1.each_index do |i|
1035
+ assert_equal(d1[i], d2[i])
1036
+ if d1[i].account.nil?
1037
+ assert_nil(d2[i].account)
1038
+ else
1039
+ assert_equal(d1[i].account, d2[i].account)
1040
+ end
1041
+ end
1042
+ end
1043
+
1044
+ def test_eager_with_multiple_associations_with_same_table_belongs_to
1045
+ firm_types = [:firm, :firm_with_basic_id, :firm_with_other_name, :firm_with_condition]
1046
+ d1 = find_all_ordered(Client)
1047
+ d2 = find_all_ordered(Client, firm_types)
1048
+ d1.each_index do |i|
1049
+ assert_equal(d1[i], d2[i])
1050
+ firm_types.each do |type|
1051
+ if (expected = d1[i].public_send(type)).nil?
1052
+ assert_nil(d2[i].public_send(type))
1053
+ else
1054
+ assert_equal(expected, d2[i].public_send(type))
1055
+ end
1056
+ end
1057
+ end
1058
+ end
1059
+ def test_eager_with_valid_association_as_string_not_symbol
1060
+ assert_nothing_raised { Post.all.merge!(includes: "comments").to_a }
1061
+ end
1062
+
1063
+ def test_eager_with_floating_point_numbers
1064
+ assert_queries(2) do
1065
+ # Before changes, the floating point numbers will be interpreted as table names and will cause this to run in one query
1066
+ Comment.all.merge!(where: "123.456 = 123.456", includes: :post).to_a
1067
+ end
1068
+ end
1069
+
1070
+ def test_preconfigured_includes_with_belongs_to
1071
+ author = posts(:welcome).author_with_posts
1072
+ assert_no_queries { assert_equal 5, author.posts.size }
1073
+ end
1074
+
1075
+ def test_preconfigured_includes_with_has_one
1076
+ comment = posts(:sti_comments).very_special_comment_with_post
1077
+ assert_no_queries { assert_equal posts(:sti_comments), comment.post }
1078
+ end
1079
+
1080
+ def test_eager_association_with_scope_with_joins
1081
+ assert_nothing_raised do
1082
+ Post.includes(:very_special_comment_with_post_with_joins).to_a
1083
+ end
1084
+ end
1085
+
1086
+ def test_preconfigured_includes_with_has_many
1087
+ posts = authors(:david).posts_with_comments
1088
+ one = posts.detect { |p| p.id == 1 }
1089
+ assert_no_queries do
1090
+ assert_equal 5, posts.size
1091
+ assert_equal 2, one.comments.size
1092
+ end
1093
+ end
1094
+
1095
+ def test_preconfigured_includes_with_habtm
1096
+ posts = authors(:david).posts_with_categories
1097
+ one = posts.detect { |p| p.id == 1 }
1098
+ assert_no_queries do
1099
+ assert_equal 5, posts.size
1100
+ assert_equal 2, one.categories.size
1101
+ end
1102
+ end
1103
+
1104
+ def test_preconfigured_includes_with_has_many_and_habtm
1105
+ posts = authors(:david).posts_with_comments_and_categories
1106
+ one = posts.detect { |p| p.id == 1 }
1107
+ assert_no_queries do
1108
+ assert_equal 5, posts.size
1109
+ assert_equal 2, one.comments.size
1110
+ assert_equal 2, one.categories.size
1111
+ end
1112
+ end
1113
+
1114
+ def test_count_with_include
1115
+ assert_equal 3, authors(:david).posts_with_comments.where("length(comments.body) > 15").references(:comments).count
1116
+ end
1117
+
1118
+ def test_association_loading_notification
1119
+ notifications = messages_for("instantiation.active_record") do
1120
+ Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a.size
1121
+ end
1122
+
1123
+ message = notifications.first
1124
+ payload = message.last
1125
+ count = Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a.size
1126
+
1127
+ # eagerloaded row count should be greater than just developer count
1128
+ assert_operator payload[:record_count], :>, count
1129
+ assert_equal Developer.name, payload[:class_name]
1130
+ end
1131
+
1132
+ def test_base_messages
1133
+ notifications = messages_for("instantiation.active_record") do
1134
+ Developer.all.to_a
1135
+ end
1136
+ message = notifications.first
1137
+ payload = message.last
1138
+
1139
+ assert_equal Developer.all.to_a.count, payload[:record_count]
1140
+ assert_equal Developer.name, payload[:class_name]
1141
+ end
1142
+
1143
+ def messages_for(name)
1144
+ notifications = []
1145
+ ActiveSupport::Notifications.subscribe(name) do |*args|
1146
+ notifications << args
1147
+ end
1148
+ yield
1149
+ notifications
1150
+ ensure
1151
+ ActiveSupport::Notifications.unsubscribe(name)
1152
+ end
1153
+
1154
+ def test_load_with_sti_sharing_association
1155
+ assert_queries(2) do # should not do 1 query per subclass
1156
+ Comment.includes(:post).to_a
1157
+ end
1158
+ end
1159
+
1160
+ def test_conditions_on_join_table_with_include_and_limit
1161
+ assert_equal 3, Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a.size
1162
+ end
1163
+
1164
+ def test_dont_create_temporary_active_record_instances
1165
+ Developer.instance_count = 0
1166
+ developers = Developer.all.merge!(includes: "projects", where: { "developers_projects.access_level" => 1 }, limit: 5).to_a
1167
+ assert_equal developers.count, Developer.instance_count
1168
+ end
1169
+
1170
+ def test_order_on_join_table_with_include_and_limit
1171
+ assert_equal 5, Developer.all.merge!(includes: "projects", order: "developers_projects.joined_on DESC", limit: 5).to_a.size
1172
+ end
1173
+
1174
+ def test_eager_loading_with_order_on_joined_table_preloads
1175
+ posts = assert_queries(2) do
1176
+ Post.all.merge!(joins: :comments, includes: :author, order: "comments.id DESC").to_a
1177
+ end
1178
+ assert_equal posts(:eager_other), posts[2]
1179
+ assert_equal authors(:mary), assert_no_queries { posts[2].author }
1180
+ end
1181
+
1182
+ def test_eager_loading_with_conditions_on_joined_table_preloads
1183
+ posts = assert_queries(2) do
1184
+ Post.all.merge!(select: "distinct posts.*", includes: :author, joins: [:comments], where: "comments.body like 'Thank you%'", order: "posts.id").to_a
1185
+ end
1186
+ assert_equal [posts(:welcome)], posts
1187
+ assert_equal authors(:david), assert_no_queries { posts[0].author }
1188
+
1189
+ posts = assert_queries(2) do
1190
+ Post.all.merge!(includes: :author, joins: { taggings: :tag }, where: "tags.name = 'General'", order: "posts.id").to_a
1191
+ end
1192
+ assert_equal posts(:welcome, :thinking), posts
1193
+
1194
+ posts = assert_queries(2) do
1195
+ Post.all.merge!(includes: :author, joins: { taggings: { tag: :taggings } }, where: "taggings_tags.super_tag_id=2", order: "posts.id").to_a
1196
+ end
1197
+ assert_equal posts(:welcome, :thinking), posts
1198
+ end
1199
+
1200
+ def test_preload_has_many_with_association_condition_and_default_scope
1201
+ post = Post.create!(title: "Beaches", body: "I like beaches!")
1202
+ Reader.create! person: people(:david), post: post
1203
+ LazyReader.create! person: people(:susan), post: post
1204
+
1205
+ assert_equal 1, post.lazy_readers.to_a.size
1206
+ assert_equal 2, post.lazy_readers_skimmers_or_not.to_a.size
1207
+
1208
+ post_with_readers = Post.includes(:lazy_readers_skimmers_or_not).find(post.id)
1209
+ assert_equal 2, post_with_readers.lazy_readers_skimmers_or_not.to_a.size
1210
+ end
1211
+
1212
+ def test_eager_loading_with_conditions_on_string_joined_table_preloads
1213
+ posts = assert_queries(2) do
1214
+ Post.all.merge!(select: "distinct posts.*", includes: :author, joins: "INNER JOIN comments on comments.post_id = posts.id", where: "comments.body like 'Thank you%'", order: "posts.id").to_a
1215
+ end
1216
+ assert_equal [posts(:welcome)], posts
1217
+ assert_equal authors(:david), assert_no_queries { posts[0].author }
1218
+
1219
+ posts = assert_queries(2) do
1220
+ Post.all.merge!(select: "distinct posts.*", includes: :author, joins: ["INNER JOIN comments on comments.post_id = posts.id"], where: "comments.body like 'Thank you%'", order: "posts.id").to_a
1221
+ end
1222
+ assert_equal [posts(:welcome)], posts
1223
+ assert_equal authors(:david), assert_no_queries { posts[0].author }
1224
+ end
1225
+
1226
+ def test_eager_loading_with_select_on_joined_table_preloads
1227
+ posts = assert_queries(2) do
1228
+ Post.all.merge!(select: "posts.*, authors.name as author_name", includes: :comments, joins: :author, order: "posts.id").to_a
1229
+ end
1230
+ assert_equal "David", posts[0].author_name
1231
+ assert_equal posts(:welcome).comments.sort_by(&:id), assert_no_queries { posts[0].comments.sort_by(&:id) }
1232
+ end
1233
+
1234
+ def test_eager_loading_with_conditions_on_join_model_preloads
1235
+ authors = assert_queries(2) do
1236
+ Author.all.merge!(includes: :author_address, joins: :comments, where: "posts.title like 'Welcome%'").to_a
1237
+ end
1238
+ assert_equal authors(:david), authors[0]
1239
+ assert_equal author_addresses(:david_address), authors[0].author_address
1240
+ end
1241
+
1242
+ def test_preload_belongs_to_uses_exclusive_scope
1243
+ people = Person.males.includes(:primary_contact).to_a
1244
+ assert_equal 2, people.length
1245
+ people.each do |person|
1246
+ assert_no_queries { assert_not_nil person.primary_contact }
1247
+ assert_equal Person.find(person.id).primary_contact, person.primary_contact
1248
+ end
1249
+ end
1250
+
1251
+ def test_preload_has_many_uses_exclusive_scope
1252
+ people = Person.males.includes(:agents).to_a
1253
+ assert_equal 2, people.length
1254
+ people.each do |person|
1255
+ assert_equal Person.find(person.id).agents.sort_by(&:id), person.agents.sort_by(&:id)
1256
+ end
1257
+ end
1258
+
1259
+ def test_preload_has_many_using_primary_key
1260
+ expected = Firm.first.clients_using_primary_key.sort_by(&:id)
1261
+ firm = Firm.includes(:clients_using_primary_key).first
1262
+ assert_no_queries do
1263
+ assert_equal expected, firm.clients_using_primary_key.sort_by(&:id)
1264
+ end
1265
+ end
1266
+
1267
+ def test_include_has_many_using_primary_key
1268
+ expected = Firm.find(1).clients_using_primary_key.sort_by(&:name)
1269
+ firm = Firm.all.merge!(includes: :clients_using_primary_key, order: "clients_using_primary_keys_companies.name").find(1)
1270
+ assert_no_queries do
1271
+ assert_equal expected, firm.clients_using_primary_key
1272
+ end
1273
+ end
1274
+
1275
+ def test_preload_has_one_using_primary_key
1276
+ expected = accounts(:signals37)
1277
+ firm = Firm.all.merge!(includes: :account_using_primary_key, order: "companies.id").first
1278
+ assert_no_queries do
1279
+ assert_equal expected, firm.account_using_primary_key
1280
+ end
1281
+ end
1282
+
1283
+ def test_include_has_one_using_primary_key
1284
+ expected = accounts(:signals37)
1285
+ firm = Firm.all.merge!(includes: :account_using_primary_key, order: "accounts.id").to_a.detect { |f| f.id == 1 }
1286
+ assert_no_queries do
1287
+ assert_equal expected, firm.account_using_primary_key
1288
+ end
1289
+ end
1290
+
1291
+ def test_preloading_empty_belongs_to
1292
+ c = Client.create!(name: "Foo", client_of: Company.maximum(:id) + 1)
1293
+
1294
+ client = assert_queries(2) { Client.preload(:firm).find(c.id) }
1295
+ assert_no_queries { assert_nil client.firm }
1296
+ assert_equal c.client_of, client.client_of
1297
+ end
1298
+
1299
+ def test_preloading_empty_belongs_to_polymorphic
1300
+ t = Tagging.create!(taggable_type: "Post", taggable_id: Post.maximum(:id) + 1, tag: tags(:general))
1301
+
1302
+ tagging = assert_queries(2) { Tagging.preload(:taggable).find(t.id) }
1303
+ assert_no_queries { assert_nil tagging.taggable }
1304
+ assert_equal t.taggable_id, tagging.taggable_id
1305
+ end
1306
+
1307
+ def test_preloading_through_empty_belongs_to
1308
+ c = Client.create!(name: "Foo", client_of: Company.maximum(:id) + 1)
1309
+
1310
+ client = assert_queries(2) { Client.preload(:accounts).find(c.id) }
1311
+ assert_no_queries { assert client.accounts.empty? }
1312
+ end
1313
+
1314
+ def test_preloading_has_many_through_with_distinct
1315
+ mary = Author.includes(:unique_categorized_posts).where(id: authors(:mary).id).first
1316
+ assert_equal 1, mary.unique_categorized_posts.length
1317
+ assert_equal 1, mary.unique_categorized_post_ids.length
1318
+ end
1319
+
1320
+ def test_preloading_has_one_using_reorder
1321
+ klass = Class.new(ActiveRecord::Base) do
1322
+ def self.name; "TempAuthor"; end
1323
+ self.table_name = "authors"
1324
+ has_one :post, class_name: "PostWithDefaultScope", foreign_key: :author_id
1325
+ has_one :reorderd_post, -> { reorder(title: :desc) }, class_name: "PostWithDefaultScope", foreign_key: :author_id
1326
+ end
1327
+
1328
+ author = klass.first
1329
+ # PRECONDITION: make sure ordering results in different results
1330
+ assert_not_equal author.post, author.reorderd_post
1331
+
1332
+ preloaded_reorderd_post = klass.preload(:reorderd_post).first.reorderd_post
1333
+
1334
+ assert_equal author.reorderd_post, preloaded_reorderd_post
1335
+ assert_equal Post.order(title: :desc).first.title, preloaded_reorderd_post.title
1336
+ end
1337
+
1338
+ def test_preloading_polymorphic_with_custom_foreign_type
1339
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
1340
+ groucho = members(:groucho)
1341
+
1342
+ sponsor = assert_queries(2) {
1343
+ Sponsor.includes(:thing).where(id: sponsor.id).first
1344
+ }
1345
+ assert_no_queries { assert_equal groucho, sponsor.thing }
1346
+ end
1347
+
1348
+ def test_joins_with_includes_should_preload_via_joins
1349
+ post = assert_queries(1) { Post.includes(:comments).joins(:comments).order("posts.id desc").to_a.first }
1350
+
1351
+ assert_no_queries do
1352
+ assert_not_equal 0, post.comments.to_a.count
1353
+ end
1354
+ end
1355
+
1356
+ def test_join_eager_with_empty_order_should_generate_valid_sql
1357
+ assert_nothing_raised do
1358
+ Post.includes(:comments).order("").where(comments: { body: "Thank you for the welcome" }).first
1359
+ end
1360
+ end
1361
+
1362
+ def test_deep_including_through_habtm
1363
+ # warm up habtm cache
1364
+ posts = Post.all.merge!(includes: { categories: :categorizations }, order: "posts.id").to_a
1365
+ posts[0].categories[0].categorizations.length
1366
+
1367
+ posts = Post.all.merge!(includes: { categories: :categorizations }, order: "posts.id").to_a
1368
+ assert_no_queries { assert_equal 2, posts[0].categories[0].categorizations.length }
1369
+ assert_no_queries { assert_equal 1, posts[0].categories[1].categorizations.length }
1370
+ assert_no_queries { assert_equal 2, posts[1].categories[0].categorizations.length }
1371
+ end
1372
+
1373
+ def test_eager_load_multiple_associations_with_references
1374
+ mentor = Mentor.create!(name: "Barış Can DAYLIK")
1375
+ developer = Developer.create!(name: "Mehmet Emin İNAÇ", mentor: mentor)
1376
+ Contract.create!(developer: developer)
1377
+ project = Project.create!(name: "VNGRS", mentor: mentor)
1378
+ project.developers << developer
1379
+ projects = Project.references(:mentors).includes(mentor: { developers: :contracts }, developers: :contracts)
1380
+ assert_equal projects.last.mentor.developers.first.contracts, projects.last.developers.last.contracts
1381
+ end
1382
+
1383
+ def test_preloading_has_many_through_with_custom_scope
1384
+ project = Project.includes(:developers_named_david_with_hash_conditions).find(projects(:active_record).id)
1385
+ assert_equal [developers(:david)], project.developers_named_david_with_hash_conditions
1386
+ end
1387
+
1388
+ test "scoping with a circular preload" do
1389
+ assert_equal Comment.find(1), Comment.preload(post: :comments).scoping { Comment.find(1) }
1390
+ end
1391
+
1392
+ test "circular preload does not modify unscoped" do
1393
+ expected = FirstPost.unscoped.find(2)
1394
+ FirstPost.preload(comments: :first_post).find(1)
1395
+ assert_equal expected, FirstPost.unscoped.find(2)
1396
+ end
1397
+
1398
+ test "belongs_to association ignores the scoping" do
1399
+ post = Comment.find(1).post
1400
+
1401
+ Post.where("1=0").scoping do
1402
+ assert_equal post, Comment.find(1).post
1403
+ assert_equal post, Comment.preload(:post).find(1).post
1404
+ assert_equal post, Comment.eager_load(:post).find(1).post
1405
+ end
1406
+ end
1407
+
1408
+ test "has_many association ignores the scoping" do
1409
+ comments = Post.find(1).comments.to_a
1410
+
1411
+ Comment.where("1=0").scoping do
1412
+ assert_equal comments, Post.find(1).comments
1413
+ assert_equal comments, Post.preload(:comments).find(1).comments
1414
+ assert_equal comments, Post.eager_load(:comments).find(1).comments
1415
+ end
1416
+ end
1417
+
1418
+ test "deep preload" do
1419
+ post = Post.preload(author: :posts, comments: :post).first
1420
+
1421
+ assert_predicate post.author.association(:posts), :loaded?
1422
+ assert_predicate post.comments.first.association(:post), :loaded?
1423
+ end
1424
+
1425
+ test "preloading does not cache has many association subset when preloaded with a through association" do
1426
+ author = Author.includes(:comments_with_order_and_conditions, :posts).first
1427
+ assert_no_queries { assert_equal 2, author.comments_with_order_and_conditions.size }
1428
+ assert_no_queries { assert_equal 5, author.posts.size, "should not cache a subset of the association" }
1429
+ end
1430
+
1431
+ test "preloading a through association twice does not reset it" do
1432
+ members = Member.includes(current_membership: :club).includes(:club).to_a
1433
+ assert_no_queries {
1434
+ assert_equal 3, members.map(&:current_membership).map(&:club).size
1435
+ }
1436
+ end
1437
+
1438
+ test "works in combination with order(:symbol) and reorder(:symbol)" do
1439
+ author = Author.includes(:posts).references(:posts).order(:name).find_by("posts.title IS NOT NULL")
1440
+ assert_equal authors(:bob), author
1441
+
1442
+ author = Author.includes(:posts).references(:posts).reorder(:name).find_by("posts.title IS NOT NULL")
1443
+ assert_equal authors(:bob), author
1444
+ end
1445
+
1446
+ test "preloading with a polymorphic association and using the existential predicate but also using a select" do
1447
+ assert_equal authors(:david), authors(:david).essays.includes(:writer).first.writer
1448
+
1449
+ assert_nothing_raised do
1450
+ authors(:david).essays.includes(:writer).select(:name).any?
1451
+ end
1452
+ end
1453
+
1454
+ test "preloading the same association twice works" do
1455
+ Member.create!
1456
+ members = Member.preload(:current_membership).includes(current_membership: :club).all.to_a
1457
+ assert_no_queries {
1458
+ members_with_membership = members.select(&:current_membership)
1459
+ assert_equal 3, members_with_membership.map(&:current_membership).map(&:club).size
1460
+ }
1461
+ end
1462
+
1463
+ test "preloading with a polymorphic association and using the existential predicate" do
1464
+ assert_equal authors(:david), authors(:david).essays.includes(:writer).first.writer
1465
+
1466
+ assert_nothing_raised do
1467
+ authors(:david).essays.includes(:writer).any?
1468
+ authors(:david).essays.includes(:writer).exists?
1469
+ authors(:david).essays.includes(:owner).where("name IS NOT NULL").exists?
1470
+ end
1471
+ end
1472
+
1473
+ test "preloading associations with string joins and order references" do
1474
+ author = assert_queries(2) {
1475
+ Author.includes(:posts).joins("LEFT JOIN posts ON posts.author_id = authors.id").order("posts.title DESC").first
1476
+ }
1477
+ assert_no_queries {
1478
+ assert_equal 5, author.posts.size
1479
+ }
1480
+ end
1481
+
1482
+ test "including associations with where.not adds implicit references" do
1483
+ author = assert_queries(2) {
1484
+ Author.includes(:posts).where.not(posts: { title: "Welcome to the weblog" }).last
1485
+ }
1486
+
1487
+ assert_no_queries {
1488
+ assert_equal 2, author.posts.size
1489
+ }
1490
+ end
1491
+
1492
+ test "including association based on sql condition and no database column" do
1493
+ assert_equal pets(:parrot), Owner.including_last_pet.first.last_pet
1494
+ end
1495
+
1496
+ test "preloading and eager loading of instance dependent associations is not supported" do
1497
+ message = "association scope 'posts_with_signature' is"
1498
+ error = assert_raises(ArgumentError) do
1499
+ Author.includes(:posts_with_signature).to_a
1500
+ end
1501
+ assert_match message, error.message
1502
+
1503
+ error = assert_raises(ArgumentError) do
1504
+ Author.preload(:posts_with_signature).to_a
1505
+ end
1506
+ assert_match message, error.message
1507
+
1508
+ error = assert_raises(ArgumentError) do
1509
+ Author.eager_load(:posts_with_signature).to_a
1510
+ end
1511
+ assert_match message, error.message
1512
+ end
1513
+
1514
+ test "preloading and eager loading of optional instance dependent associations is not supported" do
1515
+ message = "association scope 'posts_mentioning_author' is"
1516
+ error = assert_raises(ArgumentError) do
1517
+ Author.includes(:posts_mentioning_author).to_a
1518
+ end
1519
+ assert_match message, error.message
1520
+
1521
+ error = assert_raises(ArgumentError) do
1522
+ Author.preload(:posts_mentioning_author).to_a
1523
+ end
1524
+ assert_match message, error.message
1525
+
1526
+ error = assert_raises(ArgumentError) do
1527
+ Author.eager_load(:posts_mentioning_author).to_a
1528
+ end
1529
+ assert_match message, error.message
1530
+ end
1531
+
1532
+ test "preload with invalid argument" do
1533
+ exception = assert_raises(ArgumentError) do
1534
+ Author.preload(10).to_a
1535
+ end
1536
+ assert_equal("10 was not recognized for preload", exception.message)
1537
+ end
1538
+
1539
+ test "associations with extensions are not instance dependent" do
1540
+ assert_nothing_raised do
1541
+ Author.includes(:posts_with_extension).to_a
1542
+ end
1543
+ end
1544
+
1545
+ test "including associations with extensions and an instance dependent scope is not supported" do
1546
+ e = assert_raises(ArgumentError) do
1547
+ Author.includes(:posts_with_extension_and_instance).to_a
1548
+ end
1549
+ assert_match(/Preloading instance dependent scopes is not supported/, e.message)
1550
+ end
1551
+
1552
+ test "preloading readonly association" do
1553
+ # has-one
1554
+ firm = Firm.where(id: "1").preload(:readonly_account).first!
1555
+ assert_predicate firm.readonly_account, :readonly?
1556
+
1557
+ # has_and_belongs_to_many
1558
+ project = Project.where(id: "2").preload(:readonly_developers).first!
1559
+ assert_predicate project.readonly_developers.first, :readonly?
1560
+
1561
+ # has-many :through
1562
+ david = Author.where(id: "1").preload(:readonly_comments).first!
1563
+ assert_predicate david.readonly_comments.first, :readonly?
1564
+ end
1565
+
1566
+ test "eager-loading non-readonly association" do
1567
+ # has_one
1568
+ firm = Firm.where(id: "1").eager_load(:account).first!
1569
+ assert_not_predicate firm.account, :readonly?
1570
+
1571
+ # has_and_belongs_to_many
1572
+ project = Project.where(id: "2").eager_load(:developers).first!
1573
+ assert_not_predicate project.developers.first, :readonly?
1574
+
1575
+ # has_many :through
1576
+ david = Author.where(id: "1").eager_load(:comments).first!
1577
+ assert_not_predicate david.comments.first, :readonly?
1578
+
1579
+ # belongs_to
1580
+ post = Post.where(id: "1").eager_load(:author).first!
1581
+ assert_not_predicate post.author, :readonly?
1582
+ end
1583
+
1584
+ test "eager-loading readonly association" do
1585
+ # has-one
1586
+ firm = Firm.where(id: "1").eager_load(:readonly_account).first!
1587
+ assert_predicate firm.readonly_account, :readonly?
1588
+
1589
+ # has_and_belongs_to_many
1590
+ project = Project.where(id: "2").eager_load(:readonly_developers).first!
1591
+ assert_predicate project.readonly_developers.first, :readonly?
1592
+
1593
+ # has-many :through
1594
+ david = Author.where(id: "1").eager_load(:readonly_comments).first!
1595
+ assert_predicate david.readonly_comments.first, :readonly?
1596
+
1597
+ # belongs_to
1598
+ post = Post.where(id: "1").eager_load(:readonly_author).first!
1599
+ assert_predicate post.readonly_author, :readonly?
1600
+ end
1601
+
1602
+ test "preloading a polymorphic association with references to the associated table" do
1603
+ post = Post.includes(:tags).references(:tags).where("tags.name = ?", "General").first
1604
+ assert_equal posts(:welcome), post
1605
+ end
1606
+
1607
+ test "eager-loading a polymorphic association with references to the associated table" do
1608
+ post = Post.eager_load(:tags).where("tags.name = ?", "General").first
1609
+ assert_equal posts(:welcome), post
1610
+ end
1611
+
1612
+ test "eager-loading with a polymorphic association won't work consistently" do
1613
+ assert_raise(ActiveRecord::EagerLoadPolymorphicError) { authors(:david).essays.eager_load(:writer).to_a }
1614
+ assert_raise(ActiveRecord::EagerLoadPolymorphicError) { authors(:david).essays.eager_load(:writer).count }
1615
+ assert_raise(ActiveRecord::EagerLoadPolymorphicError) { authors(:david).essays.eager_load(:writer).exists? }
1616
+ end
1617
+
1618
+ # CollectionProxy#reader is expensive, so the preloader avoids calling it.
1619
+ test "preloading has_many_through association avoids calling association.reader" do
1620
+ assert_not_called_on_instance_of(ActiveRecord::Associations::HasManyAssociation, :reader) do
1621
+ Author.preload(:readonly_comments).first!
1622
+ end
1623
+ end
1624
+
1625
+ test "preloading through a polymorphic association doesn't require the association to exist" do
1626
+ sponsors = []
1627
+ assert_queries 5 do
1628
+ sponsors = Sponsor.where(sponsorable_id: 1).preload(sponsorable: [:post, :membership]).to_a
1629
+ end
1630
+ # check the preload worked
1631
+ assert_queries 0 do
1632
+ sponsors.map(&:sponsorable).map { |s| s.respond_to?(:posts) ? s.post.author : s.membership }
1633
+ end
1634
+ end
1635
+
1636
+ test "preloading a regular association through a polymorphic association doesn't require the association to exist on all types" do
1637
+ sponsors = []
1638
+ assert_queries 6 do
1639
+ sponsors = Sponsor.where(sponsorable_id: 1).preload(sponsorable: [{ post: :first_comment }, :membership]).to_a
1640
+ end
1641
+ # check the preload worked
1642
+ assert_queries 0 do
1643
+ sponsors.map(&:sponsorable).map { |s| s.respond_to?(:posts) ? s.post.author : s.membership }
1644
+ end
1645
+ end
1646
+
1647
+ test "preloading a regular association with a typo through a polymorphic association still raises" do
1648
+ # this test contains an intentional typo of first -> fist
1649
+ assert_raises(ActiveRecord::AssociationNotFoundError) do
1650
+ Sponsor.where(sponsorable_id: 1).preload(sponsorable: [{ post: :fist_comment }, :membership]).to_a
1651
+ end
1652
+ end
1653
+
1654
+ private
1655
+ def find_all_ordered(klass, include = nil)
1656
+ klass.order("#{klass.table_name}.#{klass.primary_key}").includes(include).to_a
1657
+ end
1658
+ end