ibm_db 5.6.1 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (592) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Makefile +13 -9
  3. data/ext/extconf.rb +176 -110
  4. data/ext/ibm_db.c +60 -0
  5. data/ext/ibm_db.o +0 -0
  6. data/ext/ibm_db.so +0 -0
  7. data/ext/mkmf.log +6 -6
  8. data/ext/ruby_ibm_db_cli.c +14 -10
  9. data/ext/ruby_ibm_db_cli.h +4 -0
  10. data/ext/ruby_ibm_db_cli.o +0 -0
  11. data/lib/IBM_DB.rb +2 -2
  12. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1254 -277
  13. data/test/active_record/connection_adapters/fake_legacy_adapter.rb +17 -0
  14. data/test/active_record/connection_adapters/fake_misleading_legacy_adapter.rb +8 -0
  15. data/test/activejob/destroy_association_async_job_test.rb +62 -0
  16. data/test/activejob/destroy_association_async_test.rb +147 -11
  17. data/test/activejob/job_runtime_test.rb +41 -0
  18. data/test/activejob/unloadable_base_job.rb +3 -0
  19. data/test/cases/active_record_schema_test.rb +196 -0
  20. data/test/cases/active_record_test.rb +21 -0
  21. data/test/cases/adapter_prevent_writes_test.rb +26 -202
  22. data/test/cases/adapter_test.rb +592 -82
  23. data/test/cases/adapters/abstract_mysql_adapter/active_schema_test.rb +210 -0
  24. data/test/cases/adapters/abstract_mysql_adapter/adapter_prevent_writes_test.rb +111 -0
  25. data/test/cases/adapters/abstract_mysql_adapter/auto_increment_test.rb +48 -0
  26. data/test/cases/adapters/abstract_mysql_adapter/bind_parameter_test.rb +91 -0
  27. data/test/cases/adapters/abstract_mysql_adapter/case_sensitivity_test.rb +65 -0
  28. data/test/cases/adapters/abstract_mysql_adapter/charset_collation_test.rb +85 -0
  29. data/test/cases/adapters/abstract_mysql_adapter/connection_test.rb +267 -0
  30. data/test/cases/adapters/abstract_mysql_adapter/count_deleted_rows_with_lock_test.rb +29 -0
  31. data/test/cases/adapters/abstract_mysql_adapter/json_test.rb +24 -0
  32. data/test/cases/adapters/abstract_mysql_adapter/mysql_boolean_test.rb +102 -0
  33. data/test/cases/adapters/abstract_mysql_adapter/mysql_enum_test.rb +47 -0
  34. data/test/cases/adapters/abstract_mysql_adapter/mysql_explain_test.rb +71 -0
  35. data/test/cases/adapters/abstract_mysql_adapter/nested_deadlock_test.rb +191 -0
  36. data/test/cases/adapters/abstract_mysql_adapter/optimizer_hints_test.rb +69 -0
  37. data/test/cases/adapters/abstract_mysql_adapter/quoting_test.rb +49 -0
  38. data/test/cases/adapters/abstract_mysql_adapter/schema_migrations_test.rb +68 -0
  39. data/test/cases/adapters/abstract_mysql_adapter/schema_test.rb +130 -0
  40. data/test/cases/adapters/abstract_mysql_adapter/set_test.rb +32 -0
  41. data/test/cases/adapters/abstract_mysql_adapter/sp_test.rb +39 -0
  42. data/test/cases/adapters/abstract_mysql_adapter/sql_types_test.rb +16 -0
  43. data/test/cases/adapters/abstract_mysql_adapter/table_options_test.rb +125 -0
  44. data/test/cases/adapters/abstract_mysql_adapter/transaction_test.rb +204 -0
  45. data/test/cases/adapters/abstract_mysql_adapter/unsigned_type_test.rb +77 -0
  46. data/test/cases/adapters/abstract_mysql_adapter/virtual_column_test.rb +69 -0
  47. data/test/cases/adapters/abstract_mysql_adapter/warnings_test.rb +109 -0
  48. data/test/cases/adapters/mysql2/check_constraint_quoting_test.rb +35 -0
  49. data/test/cases/adapters/mysql2/dbconsole_test.rb +87 -0
  50. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +136 -10
  51. data/test/cases/adapters/mysql2/mysql2_rake_test.rb +433 -0
  52. data/test/cases/adapters/postgresql/active_schema_test.rb +8 -4
  53. data/test/cases/adapters/postgresql/array_test.rb +6 -6
  54. data/test/cases/adapters/postgresql/bind_parameter_test.rb +52 -0
  55. data/test/cases/adapters/postgresql/bit_string_test.rb +2 -2
  56. data/test/cases/adapters/postgresql/bytea_test.rb +3 -3
  57. data/test/cases/adapters/postgresql/case_insensitive_test.rb +1 -1
  58. data/test/cases/adapters/postgresql/change_schema_test.rb +32 -1
  59. data/test/cases/adapters/postgresql/cidr_test.rb +17 -0
  60. data/test/cases/adapters/postgresql/citext_test.rb +7 -1
  61. data/test/cases/adapters/postgresql/collation_test.rb +1 -1
  62. data/test/cases/adapters/postgresql/composite_test.rb +1 -1
  63. data/test/cases/adapters/postgresql/connection_test.rb +43 -36
  64. data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +3 -2
  65. data/test/cases/adapters/postgresql/datatype_test.rb +9 -4
  66. data/test/cases/adapters/postgresql/date_test.rb +2 -2
  67. data/test/cases/adapters/postgresql/dbconsole_test.rb +109 -0
  68. data/test/cases/adapters/postgresql/deferred_constraints_test.rb +55 -0
  69. data/test/cases/adapters/postgresql/domain_test.rb +1 -1
  70. data/test/cases/adapters/postgresql/enum_test.rb +208 -8
  71. data/test/cases/adapters/postgresql/explain_test.rb +25 -6
  72. data/test/cases/adapters/postgresql/extension_migration_test.rb +51 -9
  73. data/test/cases/adapters/postgresql/foreign_table_test.rb +3 -3
  74. data/test/cases/adapters/postgresql/full_text_test.rb +1 -1
  75. data/test/cases/adapters/postgresql/geometric_test.rb +13 -6
  76. data/test/cases/adapters/postgresql/hstore_test.rb +22 -32
  77. data/test/cases/adapters/postgresql/infinity_test.rb +13 -2
  78. data/test/cases/adapters/postgresql/integer_test.rb +1 -1
  79. data/test/cases/adapters/postgresql/interval_test.rb +9 -17
  80. data/test/cases/adapters/postgresql/invertible_migration_test.rb +139 -0
  81. data/test/cases/adapters/postgresql/json_test.rb +5 -0
  82. data/test/cases/adapters/postgresql/ltree_test.rb +1 -1
  83. data/test/cases/adapters/postgresql/money_test.rb +17 -9
  84. data/test/cases/adapters/postgresql/network_test.rb +13 -1
  85. data/test/cases/adapters/postgresql/numbers_test.rb +18 -2
  86. data/test/cases/adapters/postgresql/optimizer_hints_test.rb +9 -9
  87. data/test/cases/adapters/postgresql/partitions_test.rb +5 -2
  88. data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +7 -110
  89. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +403 -20
  90. data/test/cases/adapters/postgresql/postgresql_rake_test.rb +637 -0
  91. data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +1 -1
  92. data/test/cases/adapters/postgresql/quoting_test.rb +60 -1
  93. data/test/cases/adapters/postgresql/range_test.rb +185 -21
  94. data/test/cases/adapters/postgresql/referential_integrity_test.rb +29 -5
  95. data/test/cases/adapters/postgresql/rename_table_test.rb +35 -8
  96. data/test/cases/adapters/postgresql/schema_authorization_test.rb +2 -2
  97. data/test/cases/adapters/postgresql/schema_test.rb +270 -20
  98. data/test/cases/adapters/postgresql/serial_test.rb +5 -5
  99. data/test/cases/adapters/postgresql/statement_pool_test.rb +6 -2
  100. data/test/cases/adapters/postgresql/timestamp_test.rb +122 -5
  101. data/test/cases/adapters/postgresql/transaction_nested_test.rb +130 -6
  102. data/test/cases/adapters/postgresql/transaction_test.rb +37 -11
  103. data/test/cases/adapters/postgresql/type_lookup_test.rb +1 -1
  104. data/test/cases/adapters/postgresql/uuid_test.rb +77 -9
  105. data/test/cases/adapters/postgresql/virtual_column_test.rb +114 -0
  106. data/test/cases/adapters/postgresql/xml_test.rb +1 -1
  107. data/test/cases/adapters/sqlite3/bind_parameter_test.rb +52 -0
  108. data/test/cases/adapters/sqlite3/collation_test.rb +1 -1
  109. data/test/cases/adapters/sqlite3/copy_table_test.rb +28 -7
  110. data/test/cases/adapters/sqlite3/dbconsole_test.rb +81 -0
  111. data/test/cases/adapters/sqlite3/explain_test.rb +3 -3
  112. data/test/cases/adapters/sqlite3/quoting_test.rb +34 -3
  113. data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +9 -102
  114. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +727 -72
  115. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +6 -3
  116. data/test/cases/adapters/sqlite3/sqlite_rake_test.rb +264 -0
  117. data/test/cases/adapters/sqlite3/statement_pool_test.rb +1 -1
  118. data/test/cases/adapters/sqlite3/transaction_test.rb +6 -3
  119. data/test/cases/adapters/sqlite3/virtual_column_test.rb +138 -0
  120. data/test/cases/adapters/sqlite3/virtual_table_test.rb +51 -0
  121. data/test/cases/adapters/trilogy/dbconsole_test.rb +76 -0
  122. data/test/cases/adapters/trilogy/trilogy_adapter_test.rb +473 -0
  123. data/test/cases/adapters/trilogy/trilogy_rake_test.rb +433 -0
  124. data/test/cases/aggregations_test.rb +16 -0
  125. data/test/cases/annotate_test.rb +14 -12
  126. data/test/cases/arel/attributes/attribute_test.rb +86 -47
  127. data/test/cases/arel/collectors/bind_test.rb +1 -1
  128. data/test/cases/arel/collectors/composite_test.rb +11 -1
  129. data/test/cases/arel/collectors/sql_string_test.rb +1 -1
  130. data/test/cases/arel/collectors/substitute_bind_collector_test.rb +1 -1
  131. data/test/cases/arel/delete_manager_test.rb +0 -6
  132. data/test/cases/arel/factory_methods_test.rb +45 -0
  133. data/test/cases/arel/insert_manager_test.rb +1 -7
  134. data/test/cases/arel/nodes/as_test.rb +12 -0
  135. data/test/cases/arel/nodes/ascending_test.rb +1 -1
  136. data/test/cases/arel/nodes/bin_test.rb +1 -1
  137. data/test/cases/arel/nodes/bound_sql_literal_test.rb +31 -0
  138. data/test/cases/arel/nodes/cte_test.rb +46 -0
  139. data/test/cases/arel/nodes/descending_test.rb +1 -1
  140. data/test/cases/arel/nodes/equality_test.rb +3 -3
  141. data/test/cases/arel/nodes/filter_test.rb +37 -0
  142. data/test/cases/arel/nodes/fragments_test.rb +38 -0
  143. data/test/cases/arel/nodes/homogeneous_in_test.rb +52 -0
  144. data/test/cases/arel/nodes/infix_operation_test.rb +1 -1
  145. data/test/cases/arel/nodes/node_test.rb +1 -1
  146. data/test/cases/arel/nodes/or_test.rb +2 -2
  147. data/test/cases/arel/nodes/sql_literal_test.rb +18 -1
  148. data/test/cases/arel/nodes/table_alias_test.rb +12 -0
  149. data/test/cases/arel/nodes/unary_operation_test.rb +1 -1
  150. data/test/cases/arel/nodes/update_statement_test.rb +4 -0
  151. data/test/cases/arel/nodes_test.rb +3 -2
  152. data/test/cases/arel/select_manager_test.rb +12 -12
  153. data/test/cases/arel/support/fake_record.rb +22 -17
  154. data/test/cases/arel/table_test.rb +15 -25
  155. data/test/cases/arel/update_manager_test.rb +51 -6
  156. data/test/cases/arel/visitors/dispatch_contamination_test.rb +1 -1
  157. data/test/cases/arel/visitors/dot_test.rb +177 -2
  158. data/test/cases/arel/visitors/mysql_test.rb +49 -1
  159. data/test/cases/arel/visitors/postgres_test.rb +1 -31
  160. data/test/cases/arel/visitors/sqlite_test.rb +1 -1
  161. data/test/cases/arel/visitors/to_sql_test.rb +330 -20
  162. data/test/cases/assertions/query_assertions_test.rb +136 -0
  163. data/test/cases/associations/belongs_to_associations_test.rb +502 -41
  164. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +1 -1
  165. data/test/cases/associations/cascaded_eager_loading_test.rb +26 -15
  166. data/test/cases/associations/eager_load_nested_include_test.rb +1 -1
  167. data/test/cases/associations/eager_singularization_test.rb +1 -1
  168. data/test/cases/associations/eager_test.rb +255 -93
  169. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +25 -53
  170. data/test/cases/associations/has_many_associations_test.rb +282 -72
  171. data/test/cases/associations/has_many_through_associations_test.rb +172 -45
  172. data/test/cases/associations/has_many_through_disable_joins_associations_test.rb +197 -0
  173. data/test/cases/associations/has_one_associations_test.rb +160 -29
  174. data/test/cases/associations/has_one_through_associations_test.rb +64 -15
  175. data/test/cases/associations/has_one_through_disable_joins_associations_test.rb +82 -0
  176. data/test/cases/associations/inner_join_association_test.rb +36 -6
  177. data/test/cases/associations/inverse_associations_test.rb +177 -40
  178. data/test/cases/associations/join_model_test.rb +17 -12
  179. data/test/cases/associations/left_outer_join_association_test.rb +14 -3
  180. data/test/cases/associations/nested_error_test.rb +116 -0
  181. data/test/cases/associations/nested_through_associations_test.rb +54 -19
  182. data/test/cases/associations/required_test.rb +1 -1
  183. data/test/cases/associations_test.rb +1278 -21
  184. data/test/cases/asynchronous_queries_test.rb +310 -0
  185. data/test/cases/attribute_methods/read_test.rb +6 -0
  186. data/test/cases/attribute_methods/time_zone_converter_test.rb +21 -0
  187. data/test/cases/attribute_methods_test.rb +565 -46
  188. data/test/cases/attributes_test.rb +42 -1
  189. data/test/cases/autosave_association_test.rb +645 -92
  190. data/test/cases/base_prevent_writes_test.rb +28 -159
  191. data/test/cases/base_test.rb +434 -209
  192. data/test/cases/batches_test.rb +441 -57
  193. data/test/cases/binary_test.rb +31 -0
  194. data/test/cases/bind_parameter_test.rb +107 -16
  195. data/test/cases/cache_key_test.rb +7 -7
  196. data/test/cases/calculations_test.rb +541 -110
  197. data/test/cases/callbacks_test.rb +0 -1
  198. data/test/cases/clone_test.rb +5 -4
  199. data/test/cases/coders/yaml_column_test.rb +97 -2
  200. data/test/cases/collection_cache_key_test.rb +24 -16
  201. data/test/cases/column_alias_test.rb +2 -8
  202. data/test/cases/column_definition_test.rb +12 -3
  203. data/test/cases/comment_test.rb +23 -26
  204. data/test/cases/connection_adapters/adapter_leasing_test.rb +9 -9
  205. data/test/cases/connection_adapters/connection_handler_test.rb +145 -99
  206. data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +79 -55
  207. data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +17 -20
  208. data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +146 -55
  209. data/test/cases/connection_adapters/connection_swapping_nested_test.rb +136 -23
  210. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +96 -27
  211. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +5 -5
  212. data/test/cases/connection_adapters/registration_test.rb +98 -0
  213. data/test/cases/connection_adapters/schema_cache_test.rb +288 -135
  214. data/test/cases/connection_adapters/standalone_connection_test.rb +38 -0
  215. data/test/cases/connection_adapters/statement_pool_test.rb +29 -0
  216. data/test/cases/connection_adapters/type_lookup_test.rb +12 -24
  217. data/test/cases/connection_handling_test.rb +210 -0
  218. data/test/cases/connection_management_test.rb +44 -7
  219. data/test/cases/connection_pool_test.rb +466 -99
  220. data/test/cases/core_test.rb +167 -9
  221. data/test/cases/counter_cache_test.rb +129 -2
  222. data/test/cases/custom_locking_test.rb +3 -3
  223. data/test/cases/database_configurations/hash_config_test.rb +149 -13
  224. data/test/cases/database_configurations/resolver_test.rb +14 -10
  225. data/test/cases/database_configurations/url_config_test.rb +53 -0
  226. data/test/cases/database_configurations_test.rb +86 -43
  227. data/test/cases/database_selector_test.rb +30 -8
  228. data/test/cases/database_statements_test.rb +10 -14
  229. data/test/cases/date_time_precision_test.rb +141 -11
  230. data/test/cases/date_time_test.rb +19 -1
  231. data/test/cases/defaults_test.rb +107 -41
  232. data/test/cases/delegated_type_test.rb +69 -9
  233. data/test/cases/dirty_test.rb +82 -25
  234. data/test/cases/disconnected_test.rb +10 -9
  235. data/test/cases/dup_test.rb +26 -6
  236. data/test/cases/encryption/cipher/aes256_gcm_test.rb +50 -0
  237. data/test/cases/encryption/cipher_test.rb +65 -0
  238. data/test/cases/encryption/concurrency_test.rb +27 -0
  239. data/test/cases/encryption/config_test.rb +21 -0
  240. data/test/cases/encryption/configurable_test.rb +93 -0
  241. data/test/cases/encryption/contexts_test.rb +105 -0
  242. data/test/cases/encryption/derived_secret_key_provider_test.rb +31 -0
  243. data/test/cases/encryption/deterministic_key_provider_test.rb +11 -0
  244. data/test/cases/encryption/encryptable_record_api_test.rb +175 -0
  245. data/test/cases/encryption/encryptable_record_message_pack_serialized_test.rb +42 -0
  246. data/test/cases/encryption/encryptable_record_test.rb +470 -0
  247. data/test/cases/encryption/encrypted_fixtures_test.rb +22 -0
  248. data/test/cases/encryption/encrypting_only_encryptor_test.rb +20 -0
  249. data/test/cases/encryption/encryption_schemes_test.rb +240 -0
  250. data/test/cases/encryption/encryptor_test.rb +113 -0
  251. data/test/cases/encryption/envelope_encryption_key_provider_test.rb +49 -0
  252. data/test/cases/encryption/extended_deterministic_queries_test.rb +81 -0
  253. data/test/cases/encryption/helper.rb +152 -0
  254. data/test/cases/encryption/key_generator_test.rb +55 -0
  255. data/test/cases/encryption/key_provider_test.rb +57 -0
  256. data/test/cases/encryption/key_test.rb +17 -0
  257. data/test/cases/encryption/message_pack_message_serializer_test.rb +70 -0
  258. data/test/cases/encryption/message_serializer_test.rb +82 -0
  259. data/test/cases/encryption/message_test.rb +43 -0
  260. data/test/cases/encryption/null_encryptor_test.rb +21 -0
  261. data/test/cases/encryption/properties_test.rb +69 -0
  262. data/test/cases/encryption/read_only_null_encryptor_test.rb +19 -0
  263. data/test/cases/encryption/scheme_test.rb +58 -0
  264. data/test/cases/encryption/unencrypted_attributes_test.rb +27 -0
  265. data/test/cases/encryption/uniqueness_validations_test.rb +65 -0
  266. data/test/cases/enum_test.rb +374 -72
  267. data/test/cases/errors_test.rb +7 -4
  268. data/test/cases/excluding_test.rb +116 -0
  269. data/test/cases/explain_subscriber_test.rb +6 -1
  270. data/test/cases/explain_test.rb +119 -10
  271. data/test/cases/filter_attributes_test.rb +7 -14
  272. data/test/cases/finder_respond_to_test.rb +3 -3
  273. data/test/cases/finder_test.rb +357 -72
  274. data/test/cases/fixture_set/file_test.rb +9 -0
  275. data/test/cases/fixtures_test.rb +426 -190
  276. data/test/cases/helper.rb +66 -192
  277. data/test/cases/hot_compatibility_test.rb +10 -10
  278. data/test/cases/inheritance_test.rb +51 -61
  279. data/test/cases/inherited_test.rb +40 -0
  280. data/test/cases/insert_all_test.rb +419 -9
  281. data/test/cases/instrumentation_test.rb +202 -30
  282. data/test/cases/integration_test.rb +25 -7
  283. data/test/cases/invalid_connection_test.rb +5 -5
  284. data/test/cases/invertible_migration_test.rb +108 -24
  285. data/test/cases/json_attribute_test.rb +1 -0
  286. data/test/cases/json_serialization_test.rb +5 -5
  287. data/test/cases/json_shared_test_cases.rb +5 -9
  288. data/test/cases/locking_test.rb +67 -31
  289. data/test/cases/log_subscriber_test.rb +17 -15
  290. data/test/cases/marshal_serialization_test.rb +78 -5
  291. data/test/cases/message_pack_test.rb +91 -0
  292. data/test/cases/migration/change_schema_test.rb +77 -46
  293. data/test/cases/migration/change_table_test.rb +129 -114
  294. data/test/cases/migration/check_constraint_test.rb +192 -10
  295. data/test/cases/migration/column_attributes_test.rb +4 -9
  296. data/test/cases/migration/column_positioning_test.rb +2 -2
  297. data/test/cases/migration/columns_test.rb +118 -4
  298. data/test/cases/migration/command_recorder_test.rb +181 -14
  299. data/test/cases/migration/compatibility_test.rb +883 -196
  300. data/test/cases/migration/create_join_table_test.rb +8 -1
  301. data/test/cases/migration/exclusion_constraint_test.rb +192 -0
  302. data/test/cases/migration/foreign_key_test.rb +356 -14
  303. data/test/cases/migration/helper.rb +4 -1
  304. data/test/cases/migration/index_test.rb +67 -2
  305. data/test/cases/migration/invalid_options_test.rb +129 -0
  306. data/test/cases/migration/logger_test.rb +7 -4
  307. data/test/cases/migration/pending_migrations_test.rb +103 -60
  308. data/test/cases/migration/references_foreign_key_test.rb +73 -4
  309. data/test/cases/migration/references_index_test.rb +25 -27
  310. data/test/cases/migration/references_statements_test.rb +27 -3
  311. data/test/cases/migration/rename_table_test.rb +39 -54
  312. data/test/cases/migration/schema_definitions_test.rb +109 -0
  313. data/test/cases/migration/unique_constraint_test.rb +248 -0
  314. data/test/cases/migration_test.rb +677 -220
  315. data/test/cases/migrator_test.rb +102 -75
  316. data/test/cases/multi_db_migrator_test.rb +55 -34
  317. data/test/cases/multiparameter_attributes_test.rb +26 -29
  318. data/test/cases/multiple_db_test.rb +42 -19
  319. data/test/cases/nested_attributes_test.rb +124 -6
  320. data/test/cases/nested_attributes_with_callbacks_test.rb +2 -2
  321. data/test/cases/normalized_attribute_test.rb +117 -0
  322. data/test/cases/null_relation_test.rb +35 -2
  323. data/test/cases/persistence/reload_association_cache_test.rb +20 -0
  324. data/test/cases/persistence_test.rb +629 -22
  325. data/test/cases/pooled_connections_test.rb +57 -56
  326. data/test/cases/prepared_statement_status_test.rb +8 -3
  327. data/test/cases/primary_class_test.rb +134 -0
  328. data/test/cases/primary_keys_test.rb +171 -55
  329. data/test/cases/query_cache_test.rb +558 -263
  330. data/test/cases/query_logs_test.rb +293 -0
  331. data/test/cases/quoting_test.rb +39 -72
  332. data/test/cases/readonly_test.rb +50 -12
  333. data/test/cases/reaper_test.rb +22 -6
  334. data/test/cases/reflection_test.rb +207 -9
  335. data/test/cases/relation/and_test.rb +43 -0
  336. data/test/cases/relation/delegation_test.rb +32 -5
  337. data/test/cases/relation/delete_all_test.rb +27 -6
  338. data/test/cases/relation/field_ordered_values_test.rb +128 -0
  339. data/test/cases/relation/load_async_test.rb +650 -0
  340. data/test/cases/relation/merging_test.rb +80 -109
  341. data/test/cases/relation/mutation_test.rb +12 -7
  342. data/test/cases/relation/or_test.rb +11 -8
  343. data/test/cases/relation/order_test.rb +90 -0
  344. data/test/cases/relation/predicate_builder_test.rb +21 -6
  345. data/test/cases/relation/select_test.rb +162 -3
  346. data/test/cases/relation/structural_compatibility_test.rb +38 -0
  347. data/test/cases/relation/update_all_test.rb +81 -27
  348. data/test/cases/relation/where_chain_test.rb +190 -3
  349. data/test/cases/relation/where_clause_test.rb +43 -1
  350. data/test/cases/relation/where_test.rb +95 -7
  351. data/test/cases/relation/with_test.rb +165 -0
  352. data/test/cases/relation_test.rb +42 -37
  353. data/test/cases/relations_test.rb +436 -138
  354. data/test/cases/reload_models_test.rb +18 -14
  355. data/test/cases/reserved_word_test.rb +2 -1
  356. data/test/cases/result_test.rb +14 -22
  357. data/test/cases/sanitize_test.rb +89 -27
  358. data/test/cases/schema_dumper_test.rb +535 -62
  359. data/test/cases/scoping/default_scoping_test.rb +219 -35
  360. data/test/cases/scoping/named_scoping_test.rb +25 -46
  361. data/test/cases/scoping/relation_scoping_test.rb +112 -4
  362. data/test/cases/secure_password_test.rb +108 -0
  363. data/test/cases/secure_token_test.rb +72 -0
  364. data/test/cases/serialization_test.rb +1 -1
  365. data/test/cases/serialized_attribute_test.rb +305 -60
  366. data/test/cases/shard_keys_test.rb +125 -0
  367. data/test/cases/shard_selector_test.rb +45 -0
  368. data/test/cases/signed_id_test.rb +57 -5
  369. data/test/cases/statement_cache_test.rb +31 -30
  370. data/test/cases/statement_invalid_test.rb +8 -4
  371. data/test/cases/store_test.rb +73 -9
  372. data/test/cases/strict_loading_test.rb +327 -13
  373. data/test/cases/table_metadata_test.rb +16 -0
  374. data/test/cases/tasks/database_tasks_test.rb +517 -244
  375. data/test/cases/test_case.rb +254 -60
  376. data/test/cases/test_case_test.rb +69 -0
  377. data/test/cases/test_databases_test.rb +7 -3
  378. data/test/cases/test_fixtures_test.rb +19 -40
  379. data/test/cases/time_precision_test.rb +17 -5
  380. data/test/cases/timestamp_test.rb +124 -16
  381. data/test/cases/token_for_test.rb +165 -0
  382. data/test/cases/touch_later_test.rb +43 -1
  383. data/test/cases/transaction_callbacks_test.rb +325 -8
  384. data/test/cases/transaction_instrumentation_test.rb +453 -0
  385. data/test/cases/transaction_isolation_test.rb +12 -8
  386. data/test/cases/transactions_test.rb +629 -112
  387. data/test/cases/type/date_time_test.rb +7 -1
  388. data/test/cases/type/time_test.rb +9 -0
  389. data/test/cases/type/type_map_test.rb +108 -73
  390. data/test/cases/type/unsigned_integer_test.rb +12 -0
  391. data/test/cases/type_caster/connection_test.rb +19 -0
  392. data/test/cases/type_test.rb +1 -1
  393. data/test/cases/unconnected_test.rb +7 -7
  394. data/test/cases/unsafe_raw_sql_test.rb +39 -8
  395. data/test/cases/validations/absence_validation_test.rb +1 -1
  396. data/test/cases/validations/association_validation_test.rb +25 -3
  397. data/test/cases/validations/numericality_validation_test.rb +3 -9
  398. data/test/cases/validations/presence_validation_test.rb +1 -1
  399. data/test/cases/validations/uniqueness_validation_test.rb +280 -40
  400. data/test/cases/validations_test.rb +2 -2
  401. data/test/cases/view_test.rb +33 -22
  402. data/test/cases/yaml_serialization_test.rb +23 -17
  403. data/test/config.example.yml +58 -56
  404. data/test/config.rb +1 -0
  405. data/test/fixtures/1_need_quoting.yml +2 -0
  406. data/test/fixtures/accounts.yml +5 -0
  407. data/test/fixtures/aircrafts.yml +7 -0
  408. data/test/fixtures/book_identifiers.yml +11 -0
  409. data/test/fixtures/books.yml +5 -4
  410. data/test/fixtures/cake_designers.yml +5 -0
  411. data/test/fixtures/cars.yml +6 -0
  412. data/test/fixtures/chefs.yml +5 -0
  413. data/test/fixtures/clothing_items.yml +23 -0
  414. data/test/fixtures/clubs.yml +1 -1
  415. data/test/fixtures/comments.yml +2 -1
  416. data/test/fixtures/cpk_authors.yml +8 -0
  417. data/test/fixtures/cpk_books.yml +21 -0
  418. data/test/fixtures/cpk_order_agreements.yml +13 -0
  419. data/test/fixtures/cpk_order_tags.yml +15 -0
  420. data/test/fixtures/cpk_orders.yml +11 -0
  421. data/test/fixtures/cpk_posts.yml +12 -0
  422. data/test/fixtures/cpk_reviews.yml +13 -0
  423. data/test/fixtures/cpk_tags.yml +11 -0
  424. data/test/fixtures/drink_designers.yml +5 -0
  425. data/test/fixtures/encrypted_book_that_ignores_cases.yml +4 -0
  426. data/test/fixtures/encrypted_books.yml +4 -0
  427. data/test/fixtures/fk_object_to_point_to.yml +2 -0
  428. data/test/fixtures/memberships.yml +15 -15
  429. data/test/fixtures/paragraphs.yml +5 -0
  430. data/test/fixtures/parrots.yml +4 -0
  431. data/test/fixtures/people.yml +2 -0
  432. data/test/fixtures/pirates.yml +2 -2
  433. data/test/fixtures/primary_key_error/primary_key_error.yml +6 -0
  434. data/test/fixtures/references.yml +3 -3
  435. data/test/fixtures/sharded_blog_posts.yml +14 -0
  436. data/test/fixtures/sharded_blog_posts_tags.yml +27 -0
  437. data/test/fixtures/sharded_blogs.yml +8 -0
  438. data/test/fixtures/sharded_comments.yml +22 -0
  439. data/test/fixtures/sharded_tags.yml +34 -0
  440. data/test/fixtures/sponsors.yml +2 -2
  441. data/test/fixtures/topics.yml +1 -0
  442. data/test/fixtures/treasures.yml +4 -0
  443. data/test/fixtures/virtual_columns.yml +5 -0
  444. data/test/fixtures/warehouse_things.yml +1 -1
  445. data/test/migrations/old_and_new_versions/20210716122844_add_people_description.rb +5 -0
  446. data/test/migrations/old_and_new_versions/20210716123013_add_people_number_of_legs.rb +5 -0
  447. data/test/migrations/old_and_new_versions/230_add_people_hobby.rb +5 -0
  448. data/test/migrations/old_and_new_versions/231_add_people_last_name.rb +5 -0
  449. data/test/migrations/scope/1_unscoped.rb +7 -0
  450. data/test/migrations/scope/2_mysql_only.mysql.rb +7 -0
  451. data/test/models/admin/user.rb +2 -0
  452. data/test/models/admin/user_json.rb +48 -0
  453. data/test/models/attachment.rb +7 -0
  454. data/test/models/author.rb +70 -3
  455. data/test/models/author_encrypted.rb +16 -0
  456. data/test/models/bird.rb +1 -1
  457. data/test/models/book.rb +18 -11
  458. data/test/models/book_destroy_async.rb +1 -1
  459. data/test/models/book_encrypted.rb +106 -0
  460. data/test/models/book_identifier.rb +5 -0
  461. data/test/models/branch.rb +11 -0
  462. data/test/models/bulb.rb +1 -1
  463. data/test/models/car.rb +8 -1
  464. data/test/models/cat.rb +1 -1
  465. data/test/models/category.rb +3 -1
  466. data/test/models/chat_message.rb +8 -0
  467. data/test/models/chef.rb +52 -0
  468. data/test/models/clothing_item.rb +12 -0
  469. data/test/models/club.rb +4 -1
  470. data/test/models/comment.rb +7 -4
  471. data/test/models/comment_overlapping_counter_cache.rb +15 -0
  472. data/test/models/company.rb +16 -2
  473. data/test/models/computer.rb +1 -0
  474. data/test/models/contact.rb +3 -3
  475. data/test/models/contract.rb +5 -1
  476. data/test/models/cpk/author.rb +9 -0
  477. data/test/models/cpk/book.rb +55 -0
  478. data/test/models/cpk/book_destroy_async.rb +9 -0
  479. data/test/models/cpk/car.rb +9 -0
  480. data/test/models/cpk/car_review.rb +9 -0
  481. data/test/models/cpk/chapter.rb +16 -0
  482. data/test/models/cpk/chapter_destroy_async.rb +10 -0
  483. data/test/models/cpk/comment.rb +9 -0
  484. data/test/models/cpk/order.rb +55 -0
  485. data/test/models/cpk/order_agreement.rb +10 -0
  486. data/test/models/cpk/order_tag.rb +10 -0
  487. data/test/models/cpk/post.rb +10 -0
  488. data/test/models/cpk/posts_tag.rb +10 -0
  489. data/test/models/cpk/review.rb +9 -0
  490. data/test/models/cpk/tag.rb +10 -0
  491. data/test/models/cpk.rb +15 -0
  492. data/test/models/customer.rb +3 -1
  493. data/test/models/destroy_async_parent.rb +1 -1
  494. data/test/models/developer.rb +44 -3
  495. data/test/models/discount.rb +4 -0
  496. data/test/models/drink_designer.rb +1 -0
  497. data/test/models/editor.rb +8 -0
  498. data/test/models/editorship.rb +6 -0
  499. data/test/models/entry.rb +5 -0
  500. data/test/models/essay.rb +6 -1
  501. data/test/models/essay_destroy_async.rb +1 -0
  502. data/test/models/eye.rb +87 -21
  503. data/test/models/face.rb +1 -1
  504. data/test/models/friendship.rb +3 -0
  505. data/test/models/hardback.rb +7 -0
  506. data/test/models/hotel.rb +2 -0
  507. data/test/models/human.rb +2 -2
  508. data/test/models/invoice.rb +2 -1
  509. data/test/models/invokes_an_undefined_method.rb +5 -0
  510. data/test/models/line_item.rb +6 -0
  511. data/test/models/member.rb +9 -4
  512. data/test/models/membership.rb +2 -2
  513. data/test/models/message.rb +2 -1
  514. data/test/models/need_quoting.rb +5 -0
  515. data/test/models/paragraph.rb +5 -0
  516. data/test/models/parrot.rb +6 -3
  517. data/test/models/person.rb +7 -4
  518. data/test/models/pirate.rb +4 -1
  519. data/test/models/pk_autopopulated_by_a_trigger_record.rb +5 -0
  520. data/test/models/post.rb +65 -2
  521. data/test/models/post_encrypted.rb +15 -0
  522. data/test/models/post_with_prefetched_pk.rb +15 -0
  523. data/test/models/project.rb +1 -0
  524. data/test/models/publication.rb +16 -0
  525. data/test/models/raises_argument_error.rb +5 -0
  526. data/test/models/raises_no_method_error.rb +5 -0
  527. data/test/models/recipient.rb +5 -0
  528. data/test/models/reference.rb +1 -1
  529. data/test/models/reply.rb +1 -1
  530. data/test/models/room.rb +3 -0
  531. data/test/models/sharded/blog.rb +12 -0
  532. data/test/models/sharded/blog_post.rb +17 -0
  533. data/test/models/sharded/blog_post_destroy_async.rb +14 -0
  534. data/test/models/sharded/blog_post_tag.rb +11 -0
  535. data/test/models/sharded/blog_post_with_revision.rb +11 -0
  536. data/test/models/sharded/comment.rb +12 -0
  537. data/test/models/sharded/comment_destroy_async.rb +12 -0
  538. data/test/models/sharded/tag.rb +11 -0
  539. data/test/models/sharded.rb +8 -0
  540. data/test/models/ship.rb +1 -1
  541. data/test/models/shipping_line.rb +11 -0
  542. data/test/models/subscriber.rb +1 -0
  543. data/test/models/subscription.rb +3 -1
  544. data/test/models/too_long_table_name.rb +5 -0
  545. data/test/models/topic.rb +3 -1
  546. data/test/models/traffic_light.rb +2 -2
  547. data/test/models/traffic_light_encrypted.rb +21 -0
  548. data/test/models/translation.rb +9 -0
  549. data/test/models/treasure.rb +1 -1
  550. data/test/models/tyre.rb +1 -1
  551. data/test/models/user.rb +16 -0
  552. data/test/models/user_with_invalid_relation.rb +28 -0
  553. data/test/models/uuid_comment.rb +5 -0
  554. data/test/models/uuid_entry.rb +5 -0
  555. data/test/models/uuid_message.rb +5 -0
  556. data/test/models/zine.rb +2 -1
  557. data/test/schema/mysql2_specific_schema.rb +26 -12
  558. data/test/schema/postgresql_specific_schema.rb +121 -13
  559. data/test/schema/schema.rb +361 -103
  560. data/test/schema/sqlite_specific_schema.rb +17 -6
  561. data/test/schema/trilogy_specific_schema.rb +96 -0
  562. data/test/support/adapter_helper.rb +104 -0
  563. data/test/support/async_helper.rb +15 -0
  564. data/test/support/config.rb +1 -1
  565. data/test/support/connection.rb +14 -2
  566. data/test/support/ddl_helper.rb +1 -1
  567. data/test/support/fake_adapter.rb +42 -0
  568. data/test/support/load_schema_helper.rb +22 -0
  569. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic.dump +0 -0
  570. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic_associations.dump +0 -0
  571. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic.dump +0 -0
  572. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic_associations.dump +0 -0
  573. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic.dump +0 -0
  574. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic_associations.dump +0 -0
  575. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic.dump +0 -0
  576. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic_associations.dump +0 -0
  577. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic.dump +0 -0
  578. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic_associations.dump +0 -0
  579. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic.dump +0 -0
  580. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic_associations.dump +0 -0
  581. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic.dump +0 -0
  582. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic_associations.dump +0 -0
  583. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic.dump +0 -0
  584. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic_associations.dump +0 -0
  585. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic.dump +0 -0
  586. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic_associations.dump +0 -0
  587. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic.dump +0 -0
  588. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic_associations.dump +0 -0
  589. data/test/support/schema_dumping_helper.rb +15 -9
  590. data/test/support/tools.rb +37 -0
  591. data/test/support/yaml_compatibility_fixtures/rails_4_1_no_symbol.yml +22 -0
  592. metadata +247 -15
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cases/helper"
4
+ require "models/auto_id"
4
5
  require "models/aircraft"
6
+ require "models/dashboard"
7
+ require "models/clothing_item"
5
8
  require "models/post"
6
9
  require "models/comment"
7
10
  require "models/author"
@@ -15,13 +18,103 @@ require "models/project"
15
18
  require "models/minimalistic"
16
19
  require "models/parrot"
17
20
  require "models/minivan"
21
+ require "models/car"
18
22
  require "models/person"
19
23
  require "models/ship"
20
24
  require "models/admin"
21
25
  require "models/admin/user"
26
+ require "models/cpk"
27
+ require "models/chat_message"
28
+ require "models/default"
29
+ require "models/post_with_prefetched_pk"
30
+ require "models/pk_autopopulated_by_a_trigger_record"
22
31
 
23
32
  class PersistenceTest < ActiveRecord::TestCase
24
- fixtures :topics, :companies, :developers, :accounts, :minimalistics, :authors, :author_addresses, :posts, :minivans
33
+ fixtures :topics, :companies, :developers, :accounts, :minimalistics, :authors, :author_addresses,
34
+ :posts, :minivans, :clothing_items, :cpk_books, :people, :cars
35
+
36
+ def test_populates_non_primary_key_autoincremented_column
37
+ topic = TitlePrimaryKeyTopic.create!(title: "title pk topic")
38
+
39
+ assert_not_nil topic.attributes["id"]
40
+ end
41
+
42
+ def test_populates_autoincremented_id_pk_regardless_of_its_position_in_columns_list
43
+ auto_populated_column_names = AutoId.columns.select(&:auto_populated?).map(&:name)
44
+
45
+ # It's important we test a scenario where tables has more than one auto populated column
46
+ # and the first column is not the primary key. Otherwise it will be a regular test not asserting this special case.
47
+ assert auto_populated_column_names.size > 1
48
+ assert_not_equal AutoId.primary_key, auto_populated_column_names.first
49
+
50
+ record = AutoId.create!
51
+ last_id = AutoId.last.id
52
+
53
+ assert_not_nil last_id
54
+ assert last_id > 0
55
+ assert_equal last_id, record.id
56
+ end
57
+
58
+ def test_populates_non_primary_key_autoincremented_column_for_a_cpk_model
59
+ order = Cpk::Order.create(shop_id: 111_222)
60
+
61
+ _shop_id, order_id = order.id
62
+
63
+ assert_not_nil order_id
64
+ end
65
+
66
+ if current_adapter?(:PostgreSQLAdapter)
67
+ def test_fills_auto_populated_columns_on_creation
68
+ record = Default.create
69
+ assert_not_nil record.id
70
+ assert_equal "Ruby on Rails", record.ruby_on_rails
71
+
72
+ if supports_virtual_columns?
73
+ assert_not_nil record.virtual_stored_number
74
+ end
75
+
76
+ assert_not_nil record.random_number
77
+ assert_not_nil record.modified_date
78
+ assert_not_nil record.modified_date_function
79
+ assert_not_nil record.modified_time
80
+ assert_not_nil record.modified_time_without_precision
81
+ assert_not_nil record.modified_time_function
82
+
83
+ assert_equal "A", record.binary_default_function
84
+
85
+ if supports_identity_columns?
86
+ klass = Class.new(ActiveRecord::Base) do
87
+ self.table_name = "postgresql_identity_table"
88
+ end
89
+
90
+ record = klass.create!
91
+ assert_not_nil record.id
92
+ end
93
+ end
94
+ elsif current_adapter?(:SQLite3Adapter)
95
+ def test_fills_auto_populated_columns_on_creation
96
+ record = Default.create
97
+ assert_not_nil record.id
98
+ assert_equal "Ruby on Rails", record.ruby_on_rails
99
+
100
+ assert_not_nil record.random_number
101
+ assert_not_nil record.modified_date
102
+ assert_not_nil record.modified_date_function
103
+ assert_not_nil record.modified_time
104
+ assert_not_nil record.modified_time_without_precision
105
+ assert_not_nil record.modified_time_function
106
+ end
107
+ elsif current_adapter?(:Mysql2Adapter, :TrilogyAdapter)
108
+ def test_fills_auto_populated_columns_on_creation
109
+ record = Default.create
110
+ assert_not_nil record.id
111
+ assert_not_nil record.char1
112
+
113
+ if supports_default_expression? && supports_insert_returning?
114
+ assert_not_nil record.uuid
115
+ end
116
+ end
117
+ end
25
118
 
26
119
  def test_update_many
27
120
  topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
@@ -53,6 +146,29 @@ class PersistenceTest < ActiveRecord::TestCase
53
146
  assert_not_equal "2 updated", Topic.find(2).content
54
147
  end
55
148
 
149
+ def test_update_many_with_active_record_base_object
150
+ error = assert_raises(ArgumentError) do
151
+ Topic.update(Topic.first, "content" => "1 updated")
152
+ end
153
+
154
+ assert_equal "You are passing an instance of ActiveRecord::Base to `update`. " \
155
+ "Please pass the id of the object by calling `.id`.", error.message
156
+
157
+ assert_not_equal "1 updated", Topic.first.content
158
+ end
159
+
160
+ def test_update_many_with_array_of_active_record_base_objects
161
+ error = assert_raise(ArgumentError) do
162
+ Topic.update(Topic.first(2), content: "updated")
163
+ end
164
+
165
+ assert_equal "You are passing an array of ActiveRecord::Base instances to `update`. " \
166
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`.", error.message
167
+
168
+ assert_not_equal "updated", Topic.first.content
169
+ assert_not_equal "updated", Topic.second.content
170
+ end
171
+
56
172
  def test_class_level_update_without_ids
57
173
  topics = Topic.all
58
174
  assert_equal 5, topics.length
@@ -78,6 +194,94 @@ class PersistenceTest < ActiveRecord::TestCase
78
194
  assert_not_equal "2 updated", Topic.find(2).content
79
195
  end
80
196
 
197
+ def test_returns_object_even_if_validations_failed
198
+ assert_equal Developer.all.to_a, Developer.update(salary: 1_000_000)
199
+ end
200
+
201
+ def test_update_many!
202
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
203
+ updated = Topic.update!(topic_data.keys, topic_data.values)
204
+
205
+ assert_equal [1, 2], updated.map(&:id)
206
+ assert_equal "1 updated", Topic.find(1).content
207
+ assert_equal "2 updated", Topic.find(2).content
208
+ end
209
+
210
+ def test_update_many_with_duplicated_ids!
211
+ updated = Topic.update!([1, 1, 2], [
212
+ { "content" => "1 duplicated" }, { "content" => "1 updated" }, { "content" => "2 updated" }
213
+ ])
214
+
215
+ assert_equal [1, 1, 2], updated.map(&:id)
216
+ assert_equal "1 updated", Topic.find(1).content
217
+ assert_equal "2 updated", Topic.find(2).content
218
+ end
219
+
220
+ def test_update_many_with_invalid_id!
221
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" }, 99999 => {} }
222
+
223
+ assert_raise(ActiveRecord::RecordNotFound) do
224
+ Topic.update!(topic_data.keys, topic_data.values)
225
+ end
226
+
227
+ assert_not_equal "1 updated", Topic.find(1).content
228
+ assert_not_equal "2 updated", Topic.find(2).content
229
+ end
230
+
231
+ def test_update_many_with_active_record_base_object!
232
+ error = assert_raises(ArgumentError) do
233
+ Topic.update!(Topic.first, "content" => "1 updated")
234
+ end
235
+
236
+ assert_equal "You are passing an instance of ActiveRecord::Base to `update!`. " \
237
+ "Please pass the id of the object by calling `.id`.", error.message
238
+
239
+ assert_not_equal "1 updated", Topic.first.content
240
+ end
241
+
242
+ def test_update_many_with_array_of_active_record_base_objects!
243
+ error = assert_raise(ArgumentError) do
244
+ Topic.update!(Topic.first(2), content: "updated")
245
+ end
246
+
247
+ assert_equal "You are passing an array of ActiveRecord::Base instances to `update!`. " \
248
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`.", error.message
249
+
250
+ assert_not_equal "updated", Topic.first.content
251
+ assert_not_equal "updated", Topic.second.content
252
+ end
253
+
254
+ def test_class_level_update_without_ids!
255
+ topics = Topic.all
256
+ assert_equal 5, topics.length
257
+ topics.each do |topic|
258
+ assert_not_equal "updated", topic.content
259
+ end
260
+
261
+ updated = Topic.update!(content: "updated")
262
+ assert_equal 5, updated.length
263
+ updated.each do |topic|
264
+ assert_equal "updated", topic.content
265
+ end
266
+ end
267
+
268
+ def test_class_level_update_is_affected_by_scoping!
269
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
270
+
271
+ assert_raise(ActiveRecord::RecordNotFound) do
272
+ Topic.where("1=0").scoping { Topic.update!(topic_data.keys, topic_data.values) }
273
+ end
274
+
275
+ assert_not_equal "1 updated", Topic.find(1).content
276
+ assert_not_equal "2 updated", Topic.find(2).content
277
+ end
278
+
279
+ def test_raises_error_when_validations_failed
280
+ assert_raises(ActiveRecord::RecordInvalid) do
281
+ Developer.update!(salary: 1_000_000)
282
+ end
283
+ end
284
+
81
285
  def test_delete_all
82
286
  assert Topic.count > 0
83
287
 
@@ -177,6 +381,40 @@ class PersistenceTest < ActiveRecord::TestCase
177
381
  assert_equal clients, Client.find([2, 3])
178
382
  end
179
383
 
384
+ def test_destroy_with_single_composite_primary_key
385
+ book = cpk_books(:cpk_great_author_first_book)
386
+
387
+ assert_difference("Cpk::Book.count", -1) do
388
+ destroyed = Cpk::Book.destroy(book.id)
389
+ assert_equal destroyed, book
390
+ end
391
+ end
392
+
393
+ def test_destroy_with_multiple_composite_primary_keys
394
+ books = [
395
+ cpk_books(:cpk_great_author_first_book),
396
+ cpk_books(:cpk_great_author_second_book),
397
+ ]
398
+
399
+ assert_difference("Cpk::Book.count", -2) do
400
+ destroyed = Cpk::Book.destroy(books.map(&:id))
401
+ assert_equal books.sort, destroyed.sort
402
+ assert destroyed.all?(&:frozen?), "destroyed clients should be frozen"
403
+ end
404
+ end
405
+
406
+ def test_destroy_with_invalid_ids_for_a_model_that_expects_composite_keys
407
+ books = [
408
+ cpk_books(:cpk_great_author_first_book),
409
+ cpk_books(:cpk_great_author_second_book),
410
+ ]
411
+
412
+ assert_raise(ActiveRecord::RecordNotFound) do
413
+ ids = books.map { |book| book.id.first }
414
+ Cpk::Book.destroy(ids)
415
+ end
416
+ end
417
+
180
418
  def test_becomes
181
419
  assert_kind_of Reply, topics(:first).becomes(Reply)
182
420
  assert_equal "The First Topic", topics(:first).becomes(Reply).title
@@ -194,7 +432,7 @@ class PersistenceTest < ActiveRecord::TestCase
194
432
  assert_not_predicate company, :valid?
195
433
  original_errors = company.errors
196
434
  client = company.becomes(Client)
197
- assert_equal assert_deprecated { original_errors.keys }, assert_deprecated { client.errors.keys }
435
+ assert_equal original_errors.attribute_names, client.errors.attribute_names
198
436
  end
199
437
 
200
438
  def test_becomes_errors_base
@@ -208,7 +446,7 @@ class PersistenceTest < ActiveRecord::TestCase
208
446
  admin.errors.add :token, :invalid
209
447
  child = admin.becomes(child_class)
210
448
 
211
- assert_equal [:token], assert_deprecated { child.errors.keys }
449
+ assert_equal [:token], child.errors.attribute_names
212
450
  assert_nothing_raised do
213
451
  child.errors.add :foo, :invalid
214
452
  end
@@ -239,6 +477,47 @@ class PersistenceTest < ActiveRecord::TestCase
239
477
  assert_equal %w{name}, client.changed
240
478
  end
241
479
 
480
+ def test_becomes_preserve_record_status
481
+ skip if current_adapter?(:IBM_DBAdapter)
482
+
483
+ company = Company.new(name: "37signals")
484
+ client = company.becomes(Client)
485
+ assert_predicate client, :new_record?
486
+
487
+ company.save
488
+ client = company.becomes(Client)
489
+ assert_predicate client, :persisted?
490
+ assert_predicate client, :previously_new_record?
491
+ end
492
+
493
+ def test_becomes_preserve_mark_for_destruction
494
+ skip if current_adapter?(:IBM_DBAdapter)
495
+
496
+ topic = topics(:first)
497
+ topic.mark_for_destruction
498
+ assert_predicate topic, :marked_for_destruction?
499
+
500
+ reply = topic.becomes(Reply)
501
+ assert_predicate reply, :marked_for_destruction?
502
+ end
503
+
504
+ def test_becomes_initializes_missing_attributes
505
+ company = Company.new(name: "GrowingCompany")
506
+
507
+ client = company.becomes(LargeClient)
508
+
509
+ assert_equal 50, client.extra_size
510
+ end
511
+
512
+ def test_becomes_keeps_extra_attributes
513
+ client = LargeClient.new(name: "ShrinkingCompany")
514
+
515
+ company = client.becomes(Company)
516
+
517
+ assert_equal 50, company.extra_size
518
+ assert_equal 50, client.extra_size
519
+ end
520
+
242
521
  def test_delete_many
243
522
  original_count = Topic.count
244
523
  Topic.delete(deleting = [1, 2])
@@ -296,12 +575,81 @@ class PersistenceTest < ActiveRecord::TestCase
296
575
  assert_equal("New Topic", topic_reloaded.title)
297
576
  end
298
577
 
299
- def test_save!
578
+ def test_create_prefetched_pk
579
+ post = PostWithPrefetchedPk.create!(title: "New Message", body: "New Body")
580
+ assert_equal 123456, post.id
581
+ end
582
+
583
+ def test_create_model_with_uuid_pk_populates_id
584
+ message = ChatMessage.create(content: "New Message")
585
+ assert_not_nil message.id
586
+
587
+ message_reloaded = ChatMessage.find(message.id)
588
+ assert_equal "New Message", message_reloaded.content
589
+ end if current_adapter?(:PostgreSQLAdapter)
590
+
591
+
592
+ def test_create_model_with_custom_named_uuid_pk_populates_id
593
+ message = ChatMessageCustomPk.create(content: "New Message")
594
+ assert_not_nil message.message_id
595
+
596
+ message_reloaded = ChatMessageCustomPk.find(message.message_id)
597
+ assert_equal "New Message", message_reloaded.content
598
+ end if current_adapter?(:PostgreSQLAdapter)
599
+
600
+ def test_build
601
+ topic = Topic.build(title: "New Topic")
602
+ assert_equal "New Topic", topic.title
603
+ assert_not_predicate topic, :persisted?
604
+ end
605
+
606
+ def test_build_many
607
+ topics = Topic.build([{ title: "first" }, { title: "second" }])
608
+ assert_equal ["first", "second"], topics.map(&:title)
609
+ topics.each { |topic| assert_not_predicate topic, :persisted? }
610
+ end
611
+
612
+ def test_build_through_factory_with_block
613
+ topic = Topic.build("title" => "New Topic") do |t|
614
+ t.author_name = "David"
615
+ end
616
+ assert_equal("New Topic", topic.title)
617
+ assert_equal("David", topic.author_name)
618
+ assert_not_predicate topic, :persisted?
619
+ end
620
+
621
+ def test_build_many_through_factory_with_block
622
+ topics = Topic.build([{ "title" => "first" }, { "title" => "second" }]) do |t|
623
+ t.author_name = "David"
624
+ end
625
+ assert_equal 2, topics.size
626
+ topics.each { |topic| assert_not_predicate topic, :persisted? }
627
+ topic1, topic2 = topics
628
+ assert_equal "first", topic1.title
629
+ assert_equal "David", topic1.author_name
630
+ assert_equal "second", topic2.title
631
+ assert_equal "David", topic2.author_name
632
+ end
633
+
634
+ def test_save_valid_record
300
635
  topic = Topic.new(title: "New Topic")
301
636
  assert topic.save!
637
+ end
638
+
639
+ def test_save_invalid_record
640
+ reply = WrongReply.new(title: "New reply")
641
+ error = assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
642
+
643
+ assert_equal "Validation failed: Content Empty", error.message
644
+ end
645
+
646
+ def test_save_destroyed_object
647
+ topic = Topic.create!(title: "New Topic")
648
+ topic.destroy!
649
+
650
+ error = assert_raise(ActiveRecord::RecordNotSaved) { topic.save! }
302
651
 
303
- reply = WrongReply.new
304
- assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
652
+ assert_equal "Failed to save the record", error.message
305
653
  end
306
654
 
307
655
  def test_save_null_string_attributes
@@ -440,7 +788,7 @@ class PersistenceTest < ActiveRecord::TestCase
440
788
 
441
789
  def test_becomes_default_sti_subclass
442
790
  original_type = Topic.columns_hash["type"].default
443
- ActiveRecord::Base.connection.change_column_default :topics, :type, "Reply"
791
+ ActiveRecord::Base.lease_connection.change_column_default :topics, :type, "Reply"
444
792
  Topic.reset_column_information
445
793
 
446
794
  reply = topics(:second)
@@ -450,7 +798,7 @@ class PersistenceTest < ActiveRecord::TestCase
450
798
  assert_instance_of Topic, topic
451
799
 
452
800
  ensure
453
- ActiveRecord::Base.connection.change_column_default :topics, :type, original_type
801
+ ActiveRecord::Base.lease_connection.change_column_default :topics, :type, original_type
454
802
  Topic.reset_column_information
455
803
  end
456
804
 
@@ -470,6 +818,51 @@ class PersistenceTest < ActiveRecord::TestCase
470
818
  assert_equal("David", topic_reloaded.author_name)
471
819
  end
472
820
 
821
+ def test_update_attribute_after_update
822
+ klass = Class.new(Topic) do
823
+ def self.name; "Topic"; end
824
+ after_update :update_author, if: :saved_change_to_title?
825
+ def update_author
826
+ update_attribute("author_name", "David")
827
+ end
828
+ end
829
+ topic = klass.create(title: "New Topic")
830
+ topic.update(title: "Another Topic")
831
+
832
+ topic_reloaded = Topic.find(topic.id)
833
+ assert_equal("Another Topic", topic_reloaded.title)
834
+ assert_equal("David", topic_reloaded.author_name)
835
+ end
836
+
837
+ def test_update_attribute_in_before_validation_respects_callback_chain
838
+ klass = Class.new(Topic) do
839
+ def self.name; "Topic"; end
840
+
841
+ before_validation :set_author_name
842
+ after_create :track_create
843
+ after_update :call_once, if: :saved_change_to_author_name?
844
+
845
+ attr_reader :counter
846
+
847
+ def set_author_name
848
+ update_attribute :author_name, "David"
849
+ end
850
+
851
+ def track_create
852
+ call_once if saved_change_to_author_name?
853
+ end
854
+
855
+ def call_once
856
+ @counter ||= 0
857
+ @counter += 1
858
+ end
859
+ end
860
+
861
+ comment = klass.create(title: "New Topic", author_name: "Not David")
862
+
863
+ assert_equal 1, comment.counter
864
+ end
865
+
473
866
  def test_update_attribute_does_not_run_sql_if_attribute_is_not_changed
474
867
  topic = Topic.create(title: "Another New Topic")
475
868
  assert_no_queries do
@@ -487,7 +880,7 @@ class PersistenceTest < ActiveRecord::TestCase
487
880
  def test_delete
488
881
  topic = Topic.find(1)
489
882
  assert_equal topic, topic.delete, "topic.delete did not return self"
490
- assert topic.frozen?, "topic not frozen after delete"
883
+ assert_predicate topic, :frozen?, "topic not frozen after delete"
491
884
  assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
492
885
  end
493
886
 
@@ -506,17 +899,25 @@ class PersistenceTest < ActiveRecord::TestCase
506
899
  def test_destroy
507
900
  topic = Topic.find(1)
508
901
  assert_equal topic, topic.destroy, "topic.destroy did not return self"
509
- assert topic.frozen?, "topic not frozen after destroy"
902
+ assert_predicate topic, :frozen?, "topic not frozen after destroy"
510
903
  assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
511
904
  end
512
905
 
513
906
  def test_destroy!
514
907
  topic = Topic.find(1)
515
908
  assert_equal topic, topic.destroy!, "topic.destroy! did not return self"
516
- assert topic.frozen?, "topic not frozen after destroy!"
909
+ assert_predicate topic, :frozen?, "topic not frozen after destroy!"
517
910
  assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
518
911
  end
519
912
 
913
+ def test_destroy_for_a_failed_to_destroy_cpk_record
914
+ book = cpk_books(:cpk_great_author_first_book)
915
+ book.fail_destroy = true
916
+ assert_raises(ActiveRecord::RecordNotDestroyed, match: /Failed to destroy Cpk::Book with \["author_id", "id"\]=/) do
917
+ book.destroy!
918
+ end
919
+ end
920
+
520
921
  def test_find_raises_record_not_found_exception
521
922
  assert_raise(ActiveRecord::RecordNotFound) { Topic.find(99999) }
522
923
  end
@@ -551,6 +952,16 @@ class PersistenceTest < ActiveRecord::TestCase
551
952
  assert_nil Topic.find(2).last_read
552
953
  end
553
954
 
955
+ def test_update_all_with_custom_sql_as_value
956
+ person = people(:michael)
957
+ person.update!(cars_count: 0)
958
+
959
+ Person.update_all(cars_count: Arel.sql(<<~SQL))
960
+ select count(*) from cars where cars.person_id = people.id
961
+ SQL
962
+ assert_equal 1, person.reload.cars_count
963
+ end
964
+
554
965
  def test_delete_new_record
555
966
  client = Client.new(name: "37signals")
556
967
  client.delete
@@ -644,6 +1055,69 @@ class PersistenceTest < ActiveRecord::TestCase
644
1055
  assert_not_equal prev_month, developer.updated_at
645
1056
  end
646
1057
 
1058
+ def test_update_attribute!
1059
+ assert_not_predicate Topic.find(1), :approved?
1060
+ Topic.find(1).update_attribute!("approved", true)
1061
+ assert_predicate Topic.find(1), :approved?
1062
+
1063
+ Topic.find(1).update_attribute!(:approved, false)
1064
+ assert_not_predicate Topic.find(1), :approved?
1065
+
1066
+ Topic.find(1).update_attribute!(:change_approved_before_save, true)
1067
+ assert_predicate Topic.find(1), :approved?
1068
+ end
1069
+
1070
+ def test_update_attribute_for_readonly_attribute!
1071
+ minivan = Minivan.find("m1")
1072
+ assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute!(:color, "black") }
1073
+ end
1074
+
1075
+ def test_update_attribute_with_one_updated!
1076
+ t = Topic.first
1077
+ t.update_attribute!(:title, "super_title")
1078
+ assert_equal "super_title", t.title
1079
+ assert_not t.changed?, "topic should not have changed"
1080
+ assert_not t.title_changed?, "title should not have changed"
1081
+ assert_nil t.title_change, "title change should be nil"
1082
+
1083
+ t.reload
1084
+ assert_equal "super_title", t.title
1085
+ end
1086
+
1087
+ def test_update_attribute_for_updated_at_on!
1088
+ developer = Developer.find(1)
1089
+ prev_month = Time.now.prev_month.change(usec: 0)
1090
+
1091
+ developer.update_attribute!(:updated_at, prev_month)
1092
+ assert_equal prev_month, developer.updated_at
1093
+
1094
+ developer.update_attribute!(:salary, 80001)
1095
+ assert_not_equal prev_month, developer.updated_at
1096
+
1097
+ developer.reload
1098
+ assert_not_equal prev_month, developer.updated_at
1099
+ end
1100
+
1101
+ def test_update_attribute_for_aborted_callback!
1102
+ klass = Class.new(Topic) do
1103
+ def self.name; "Topic"; end
1104
+
1105
+ before_update :throw_abort
1106
+
1107
+ def throw_abort
1108
+ throw(:abort)
1109
+ end
1110
+ end
1111
+
1112
+ t = klass.create(title: "New Topic", author_name: "Not David")
1113
+
1114
+ assert_raises(ActiveRecord::RecordNotSaved) { t.update_attribute!(:title, "super_title") }
1115
+
1116
+ t_reloaded = Topic.find(t.id)
1117
+
1118
+ assert_equal "New Topic", t_reloaded.title
1119
+ end
1120
+
647
1121
  def test_update_column
648
1122
  topic = Topic.find(1)
649
1123
  topic.update_column("approved", true)
@@ -722,8 +1196,8 @@ class PersistenceTest < ActiveRecord::TestCase
722
1196
  t.update_column(:title, "super_title")
723
1197
  assert_equal "John", t.author_name
724
1198
  assert_equal "super_title", t.title
725
- assert t.changed?, "topic should have changed"
726
- assert t.author_name_changed?, "author_name should have changed"
1199
+ assert_predicate t, :changed?, "topic should have changed"
1200
+ assert_predicate t, :author_name_changed?, "author_name should have changed"
727
1201
 
728
1202
  t.reload
729
1203
  assert_equal author_name, t.author_name
@@ -821,8 +1295,8 @@ class PersistenceTest < ActiveRecord::TestCase
821
1295
  t.update_columns(title: "super_title")
822
1296
  assert_equal "John", t.author_name
823
1297
  assert_equal "super_title", t.title
824
- assert t.changed?, "topic should have changed"
825
- assert t.author_name_changed?, "author_name should have changed"
1298
+ assert_predicate t, :changed?, "topic should have changed"
1299
+ assert_predicate t, :author_name_changed?, "author_name should have changed"
826
1300
 
827
1301
  t.reload
828
1302
  assert_equal author_name, t.author_name
@@ -969,6 +1443,17 @@ class PersistenceTest < ActiveRecord::TestCase
969
1443
  assert_nothing_raised { Reply.find(should_not_be_destroyed_reply.id) }
970
1444
  end
971
1445
 
1446
+ def test_class_level_delete_with_invalid_ids
1447
+ assert_no_queries do
1448
+ assert_equal 0, Topic.delete(nil)
1449
+ assert_equal 0, Topic.delete([])
1450
+ end
1451
+
1452
+ assert_difference -> { Topic.count }, -1 do
1453
+ assert_equal 1, Topic.delete(topics(:first).id)
1454
+ end
1455
+ end
1456
+
972
1457
  def test_class_level_delete_is_affected_by_scoping
973
1458
  should_not_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
974
1459
  Topic.find(1).replies << should_not_be_destroyed_reply
@@ -1032,9 +1517,9 @@ class PersistenceTest < ActiveRecord::TestCase
1032
1517
  end
1033
1518
 
1034
1519
  def test_reload_via_querycache
1035
- ActiveRecord::Base.connection.enable_query_cache!
1036
- ActiveRecord::Base.connection.clear_query_cache
1037
- assert ActiveRecord::Base.connection.query_cache_enabled, "cache should be on"
1520
+ ActiveRecord::Base.lease_connection.enable_query_cache!
1521
+ ActiveRecord::Base.lease_connection.clear_query_cache
1522
+ assert ActiveRecord::Base.lease_connection.query_cache_enabled, "cache should be on"
1038
1523
  parrot = Parrot.create(name: "Shane")
1039
1524
 
1040
1525
  # populate the cache with the SELECT result
@@ -1042,7 +1527,7 @@ class PersistenceTest < ActiveRecord::TestCase
1042
1527
  assert_equal parrot.id, found_parrot.id
1043
1528
 
1044
1529
  # Manually update the 'name' attribute in the DB directly
1045
- assert_equal 1, ActiveRecord::Base.connection.query_cache.length
1530
+ assert_equal 1, ActiveRecord::Base.lease_connection.query_cache.size
1046
1531
  ActiveRecord::Base.uncached do
1047
1532
  found_parrot.name = "Mary"
1048
1533
  found_parrot.save
@@ -1055,7 +1540,7 @@ class PersistenceTest < ActiveRecord::TestCase
1055
1540
  found_parrot = Parrot.find(parrot.id)
1056
1541
  assert_equal "Mary", found_parrot.name
1057
1542
  ensure
1058
- ActiveRecord::Base.connection.disable_query_cache!
1543
+ ActiveRecord::Base.lease_connection.disable_query_cache!
1059
1544
  end
1060
1545
 
1061
1546
  def test_save_touch_false
@@ -1077,7 +1562,7 @@ class PersistenceTest < ActiveRecord::TestCase
1077
1562
  child_class = Class.new(Topic)
1078
1563
  child_class.new # force schema to load
1079
1564
 
1080
- ActiveRecord::Base.connection.add_column(:topics, :foo, :string)
1565
+ ActiveRecord::Base.lease_connection.add_column(:topics, :foo, :string)
1081
1566
  Topic.reset_column_information
1082
1567
 
1083
1568
  # this should redefine attribute methods
@@ -1087,7 +1572,129 @@ class PersistenceTest < ActiveRecord::TestCase
1087
1572
  assert child_class.instance_methods.include?(:foo_changed?)
1088
1573
  assert_equal "bar", child_class.new(foo: :bar).foo
1089
1574
  ensure
1090
- ActiveRecord::Base.connection.remove_column(:topics, :foo)
1575
+ ActiveRecord::Base.lease_connection.remove_column(:topics, :foo)
1091
1576
  Topic.reset_column_information
1092
1577
  end
1578
+
1579
+ def test_update_uses_query_constraints_config
1580
+ clothing_item = clothing_items(:green_t_shirt)
1581
+ sql = capture_sql { clothing_item.update(description: "Lovely green t-shirt") }.second
1582
+ assert_match(/WHERE .*clothing_type/, sql)
1583
+ assert_match(/WHERE .*color/, sql)
1584
+ end
1585
+
1586
+ def test_save_uses_query_constraints_config
1587
+ clothing_item = clothing_items(:green_t_shirt)
1588
+ clothing_item.description = "Lovely green t-shirt"
1589
+ sql = capture_sql { clothing_item.save }.second
1590
+ assert_match(/WHERE .*clothing_type/, sql)
1591
+ assert_match(/WHERE .*color/, sql)
1592
+ end
1593
+
1594
+ def test_reload_uses_query_constraints_config
1595
+ clothing_item = clothing_items(:green_t_shirt)
1596
+ sql = capture_sql { clothing_item.reload }.first
1597
+ assert_match(/WHERE .*clothing_type/, sql)
1598
+ assert_match(/WHERE .*color/, sql)
1599
+ end
1600
+
1601
+ def test_destroy_uses_query_constraints_config
1602
+ clothing_item = clothing_items(:green_t_shirt)
1603
+ sql = capture_sql { clothing_item.destroy }.second
1604
+ assert_match(/WHERE .*clothing_type/, sql)
1605
+ assert_match(/WHERE .*color/, sql)
1606
+ end
1607
+
1608
+ def test_delete_uses_query_constraints_config
1609
+ clothing_item = clothing_items(:green_t_shirt)
1610
+ sql = capture_sql { clothing_item.delete }.first
1611
+ assert_match(/WHERE .*clothing_type/, sql)
1612
+ assert_match(/WHERE .*color/, sql)
1613
+ end
1614
+
1615
+ def test_update_attribute_uses_query_constraints_config
1616
+ clothing_item = clothing_items(:green_t_shirt)
1617
+ sql = capture_sql { clothing_item.update_attribute(:description, "Lovely green t-shirt") }.second
1618
+ assert_match(/WHERE .*clothing_type/, sql)
1619
+ assert_match(/WHERE .*color/, sql)
1620
+ end
1621
+
1622
+ def test_it_is_possible_to_update_parts_of_the_query_constraints_config
1623
+ clothing_item = clothing_items(:green_t_shirt)
1624
+ clothing_item.color = "blue"
1625
+ clothing_item.description = "Now it's a blue t-shirt"
1626
+ sql = capture_sql { clothing_item.save }.second
1627
+ assert_match(/WHERE .*clothing_type/, sql)
1628
+ assert_match(/WHERE .*color/, sql)
1629
+
1630
+ assert_equal("blue", ClothingItem.find_by(id: clothing_item.id).color)
1631
+ end
1632
+
1633
+ def test_model_with_no_auto_populated_fields_still_returns_primary_key_after_insert
1634
+ record = PkAutopopulatedByATriggerRecord.create
1635
+
1636
+ assert_not_nil record.id
1637
+ assert record.id > 0
1638
+ end if supports_insert_returning? && !current_adapter?(:SQLite3Adapter)
1639
+ end
1640
+
1641
+ class QueryConstraintsTest < ActiveRecord::TestCase
1642
+ fixtures :clothing_items, :dashboards, :topics, :posts
1643
+
1644
+ def test_primary_key_stays_the_same
1645
+ assert_equal("id", ClothingItem.primary_key)
1646
+ end
1647
+
1648
+ def test_query_constraints_list_is_nil_if_primary_key_is_nil
1649
+ klass = Class.new(ActiveRecord::Base) do
1650
+ self.table_name = "developers_projects"
1651
+ end
1652
+
1653
+ assert_nil klass.primary_key
1654
+ assert_nil klass.query_constraints_list
1655
+ end
1656
+
1657
+ def test_query_constraints_list_is_nil_for_non_cpk_model
1658
+ assert_nil Post.query_constraints_list
1659
+ assert_nil Dashboard.query_constraints_list
1660
+ end
1661
+
1662
+ def test_query_constraints_list_equals_to_composite_primary_key
1663
+ assert_equal(["shop_id", "id"], Cpk::Order.query_constraints_list)
1664
+ assert_equal(["author_id", "id"], Cpk::Book.query_constraints_list)
1665
+ end
1666
+
1667
+ def test_child_keeps_parents_query_constraints
1668
+ clothing_item = clothing_items(:green_t_shirt)
1669
+ assert_uses_query_constraints_on_reload(clothing_item, ["clothing_type", "color"])
1670
+
1671
+ used_clothing_item = clothing_items(:used_blue_jeans)
1672
+ assert_uses_query_constraints_on_reload(used_clothing_item, ["clothing_type", "color"])
1673
+ end
1674
+
1675
+ def test_child_keeps_parents_query_contraints_derived_from_composite_pk
1676
+ assert_equal(["author_id", "id"], Cpk::BestSeller.query_constraints_list)
1677
+ end
1678
+
1679
+ def assert_uses_query_constraints_on_reload(object, columns)
1680
+ flunk("columns argument must not be empty") if columns.blank?
1681
+
1682
+ sql = capture_sql { object.reload }.first
1683
+ Array(columns).each do |column|
1684
+ assert_match(/WHERE .*#{column}/, sql)
1685
+ end
1686
+ end
1687
+
1688
+ def test_query_constraints_raises_an_error_when_no_columns_provided
1689
+ assert_raises(ArgumentError) do
1690
+ Class.new(ActiveRecord::Base) do
1691
+ self.table_name = "topics"
1692
+ query_constraints
1693
+ end
1694
+ end
1695
+ end
1696
+
1697
+ def test_child_class_with_query_constraints_overrides_parents
1698
+ assert_equal(["clothing_type", "color", "size"], ClothingItem::Sized.query_constraints_list)
1699
+ end
1093
1700
  end