activerecord 6.0.0 → 7.2.3

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 (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -594
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +34 -34
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +22 -20
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +41 -30
  9. data/lib/active_record/associations/association.rb +106 -41
  10. data/lib/active_record/associations/association_scope.rb +30 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +69 -14
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
  13. data/lib/active_record/associations/builder/association.rb +39 -6
  14. data/lib/active_record/associations/builder/belongs_to.rb +47 -17
  15. data/lib/active_record/associations/builder/collection_association.rb +14 -6
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
  17. data/lib/active_record/associations/builder/has_many.rb +7 -3
  18. data/lib/active_record/associations/builder/has_one.rb +13 -16
  19. data/lib/active_record/associations/builder/singular_association.rb +7 -3
  20. data/lib/active_record/associations/collection_association.rb +90 -53
  21. data/lib/active_record/associations/collection_proxy.rb +54 -19
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +21 -1
  25. data/lib/active_record/associations/has_many_association.rb +41 -10
  26. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  27. data/lib/active_record/associations/has_one_association.rb +33 -9
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
  30. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  31. data/lib/active_record/associations/join_dependency.rb +97 -54
  32. data/lib/active_record/associations/nested_error.rb +47 -0
  33. data/lib/active_record/associations/preloader/association.rb +237 -54
  34. data/lib/active_record/associations/preloader/batch.rb +48 -0
  35. data/lib/active_record/associations/preloader/branch.rb +153 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +51 -17
  37. data/lib/active_record/associations/preloader.rb +55 -121
  38. data/lib/active_record/associations/singular_association.rb +16 -4
  39. data/lib/active_record/associations/through_association.rb +26 -15
  40. data/lib/active_record/associations.rb +454 -440
  41. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  42. data/lib/active_record/attribute_assignment.rb +11 -14
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
  44. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  45. data/lib/active_record/attribute_methods/dirty.rb +75 -34
  46. data/lib/active_record/attribute_methods/primary_key.rb +53 -31
  47. data/lib/active_record/attribute_methods/query.rb +31 -22
  48. data/lib/active_record/attribute_methods/read.rb +16 -17
  49. data/lib/active_record/attribute_methods/serialization.rb +177 -35
  50. data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
  51. data/lib/active_record/attribute_methods/write.rb +16 -28
  52. data/lib/active_record/attribute_methods.rb +227 -100
  53. data/lib/active_record/attributes.rb +94 -56
  54. data/lib/active_record/autosave_association.rb +119 -73
  55. data/lib/active_record/base.rb +31 -21
  56. data/lib/active_record/callbacks.rb +168 -55
  57. data/lib/active_record/coders/column_serializer.rb +61 -0
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +70 -25
  60. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
  76. data/lib/active_record/connection_adapters/column.rb +28 -1
  77. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  78. data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
  79. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
  80. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  81. data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
  82. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
  83. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
  84. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
  85. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  87. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  88. data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
  89. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  90. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  91. data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
  92. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
  95. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  101. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
  106. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  110. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
  111. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
  121. data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  123. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  124. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
  131. data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
  132. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  133. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  134. data/lib/active_record/connection_adapters.rb +176 -0
  135. data/lib/active_record/connection_handling.rb +243 -115
  136. data/lib/active_record/core.rb +481 -199
  137. data/lib/active_record/counter_cache.rb +69 -32
  138. data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
  139. data/lib/active_record/database_configurations/database_config.rb +77 -10
  140. data/lib/active_record/database_configurations/hash_config.rb +148 -26
  141. data/lib/active_record/database_configurations/url_config.rb +44 -45
  142. data/lib/active_record/database_configurations.rb +190 -114
  143. data/lib/active_record/delegated_type.rb +279 -0
  144. data/lib/active_record/deprecator.rb +7 -0
  145. data/lib/active_record/destroy_association_async_job.rb +38 -0
  146. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  147. data/lib/active_record/dynamic_matchers.rb +5 -6
  148. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  149. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  150. data/lib/active_record/encryption/cipher.rb +53 -0
  151. data/lib/active_record/encryption/config.rb +68 -0
  152. data/lib/active_record/encryption/configurable.rb +60 -0
  153. data/lib/active_record/encryption/context.rb +42 -0
  154. data/lib/active_record/encryption/contexts.rb +76 -0
  155. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  156. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  157. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  158. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  159. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  160. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  161. data/lib/active_record/encryption/encryptor.rb +171 -0
  162. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  163. data/lib/active_record/encryption/errors.rb +15 -0
  164. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  165. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  166. data/lib/active_record/encryption/key.rb +28 -0
  167. data/lib/active_record/encryption/key_generator.rb +53 -0
  168. data/lib/active_record/encryption/key_provider.rb +46 -0
  169. data/lib/active_record/encryption/message.rb +33 -0
  170. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  171. data/lib/active_record/encryption/message_serializer.rb +96 -0
  172. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  173. data/lib/active_record/encryption/properties.rb +76 -0
  174. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  175. data/lib/active_record/encryption/scheme.rb +100 -0
  176. data/lib/active_record/encryption.rb +58 -0
  177. data/lib/active_record/enum.rb +224 -73
  178. data/lib/active_record/errors.rb +254 -36
  179. data/lib/active_record/explain.rb +30 -17
  180. data/lib/active_record/explain_registry.rb +11 -6
  181. data/lib/active_record/explain_subscriber.rb +2 -2
  182. data/lib/active_record/fixture_set/file.rb +22 -15
  183. data/lib/active_record/fixture_set/model_metadata.rb +15 -6
  184. data/lib/active_record/fixture_set/render_context.rb +3 -1
  185. data/lib/active_record/fixture_set/table_row.rb +88 -16
  186. data/lib/active_record/fixture_set/table_rows.rb +4 -5
  187. data/lib/active_record/fixtures.rb +229 -116
  188. data/lib/active_record/future_result.rb +178 -0
  189. data/lib/active_record/gem_version.rb +4 -4
  190. data/lib/active_record/inheritance.rb +121 -48
  191. data/lib/active_record/insert_all.rb +178 -29
  192. data/lib/active_record/integration.rb +16 -14
  193. data/lib/active_record/internal_metadata.rb +132 -21
  194. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  195. data/lib/active_record/locking/optimistic.rb +64 -33
  196. data/lib/active_record/locking/pessimistic.rb +21 -8
  197. data/lib/active_record/log_subscriber.rb +61 -30
  198. data/lib/active_record/marshalling.rb +59 -0
  199. data/lib/active_record/message_pack.rb +124 -0
  200. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  201. data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
  202. data/lib/active_record/middleware/database_selector.rb +25 -13
  203. data/lib/active_record/middleware/shard_selector.rb +62 -0
  204. data/lib/active_record/migration/command_recorder.rb +160 -55
  205. data/lib/active_record/migration/compatibility.rb +286 -43
  206. data/lib/active_record/migration/default_strategy.rb +22 -0
  207. data/lib/active_record/migration/execution_strategy.rb +19 -0
  208. data/lib/active_record/migration/join_table.rb +1 -2
  209. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  210. data/lib/active_record/migration.rb +421 -193
  211. data/lib/active_record/model_schema.rb +217 -125
  212. data/lib/active_record/nested_attributes.rb +62 -27
  213. data/lib/active_record/no_touching.rb +4 -4
  214. data/lib/active_record/normalization.rb +163 -0
  215. data/lib/active_record/persistence.rb +322 -319
  216. data/lib/active_record/promise.rb +84 -0
  217. data/lib/active_record/query_cache.rb +18 -15
  218. data/lib/active_record/query_logs.rb +193 -0
  219. data/lib/active_record/query_logs_formatter.rb +41 -0
  220. data/lib/active_record/querying.rb +54 -14
  221. data/lib/active_record/railtie.rb +250 -72
  222. data/lib/active_record/railties/console_sandbox.rb +2 -4
  223. data/lib/active_record/railties/controller_runtime.rb +25 -11
  224. data/lib/active_record/railties/databases.rake +312 -197
  225. data/lib/active_record/railties/job_runtime.rb +23 -0
  226. data/lib/active_record/readonly_attributes.rb +45 -3
  227. data/lib/active_record/reflection.rb +389 -146
  228. data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
  229. data/lib/active_record/relation/batches.rb +214 -73
  230. data/lib/active_record/relation/calculations.rb +379 -124
  231. data/lib/active_record/relation/delegation.rb +36 -23
  232. data/lib/active_record/relation/finder_methods.rb +159 -49
  233. data/lib/active_record/relation/from_clause.rb +5 -1
  234. data/lib/active_record/relation/merger.rb +41 -33
  235. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
  236. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
  237. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
  238. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  239. data/lib/active_record/relation/predicate_builder.rb +79 -53
  240. data/lib/active_record/relation/query_attribute.rb +30 -12
  241. data/lib/active_record/relation/query_methods.rb +1156 -279
  242. data/lib/active_record/relation/record_fetch_warning.rb +12 -11
  243. data/lib/active_record/relation/spawn_methods.rb +10 -9
  244. data/lib/active_record/relation/where_clause.rb +100 -66
  245. data/lib/active_record/relation.rb +829 -194
  246. data/lib/active_record/result.rb +76 -56
  247. data/lib/active_record/runtime_registry.rb +71 -13
  248. data/lib/active_record/sanitization.rb +86 -47
  249. data/lib/active_record/schema.rb +39 -23
  250. data/lib/active_record/schema_dumper.rb +140 -33
  251. data/lib/active_record/schema_migration.rb +74 -29
  252. data/lib/active_record/scoping/default.rb +73 -19
  253. data/lib/active_record/scoping/named.rb +10 -28
  254. data/lib/active_record/scoping.rb +65 -35
  255. data/lib/active_record/secure_password.rb +60 -0
  256. data/lib/active_record/secure_token.rb +34 -8
  257. data/lib/active_record/serialization.rb +11 -4
  258. data/lib/active_record/signed_id.rb +138 -0
  259. data/lib/active_record/statement_cache.rb +26 -10
  260. data/lib/active_record/store.rb +19 -14
  261. data/lib/active_record/suppressor.rb +15 -17
  262. data/lib/active_record/table_metadata.rb +46 -36
  263. data/lib/active_record/tasks/database_tasks.rb +371 -205
  264. data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
  265. data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
  266. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
  267. data/lib/active_record/test_databases.rb +5 -4
  268. data/lib/active_record/test_fixtures.rb +189 -104
  269. data/lib/active_record/testing/query_assertions.rb +121 -0
  270. data/lib/active_record/timestamp.rb +35 -25
  271. data/lib/active_record/token_for.rb +123 -0
  272. data/lib/active_record/touch_later.rb +31 -27
  273. data/lib/active_record/transaction.rb +132 -0
  274. data/lib/active_record/transactions.rb +131 -99
  275. data/lib/active_record/translation.rb +3 -5
  276. data/lib/active_record/type/adapter_specific_registry.rb +33 -18
  277. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  278. data/lib/active_record/type/internal/timezone.rb +7 -2
  279. data/lib/active_record/type/serialized.rb +11 -6
  280. data/lib/active_record/type/time.rb +14 -0
  281. data/lib/active_record/type/type_map.rb +17 -21
  282. data/lib/active_record/type/unsigned_integer.rb +0 -1
  283. data/lib/active_record/type.rb +7 -2
  284. data/lib/active_record/type_caster/connection.rb +4 -5
  285. data/lib/active_record/type_caster/map.rb +8 -5
  286. data/lib/active_record/validations/absence.rb +1 -1
  287. data/lib/active_record/validations/associated.rb +13 -8
  288. data/lib/active_record/validations/numericality.rb +36 -0
  289. data/lib/active_record/validations/presence.rb +5 -28
  290. data/lib/active_record/validations/uniqueness.rb +88 -18
  291. data/lib/active_record/validations.rb +15 -8
  292. data/lib/active_record/version.rb +1 -1
  293. data/lib/active_record.rb +446 -40
  294. data/lib/arel/alias_predication.rb +1 -1
  295. data/lib/arel/attributes/attribute.rb +4 -8
  296. data/lib/arel/collectors/bind.rb +8 -1
  297. data/lib/arel/collectors/composite.rb +15 -0
  298. data/lib/arel/collectors/sql_string.rb +7 -0
  299. data/lib/arel/collectors/substitute_binds.rb +7 -0
  300. data/lib/arel/crud.rb +30 -22
  301. data/lib/arel/delete_manager.rb +23 -4
  302. data/lib/arel/errors.rb +10 -0
  303. data/lib/arel/factory_methods.rb +4 -0
  304. data/lib/arel/filter_predications.rb +9 -0
  305. data/lib/arel/insert_manager.rb +2 -3
  306. data/lib/arel/nodes/binary.rb +82 -9
  307. data/lib/arel/nodes/bind_param.rb +8 -0
  308. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  309. data/lib/arel/nodes/casted.rb +22 -10
  310. data/lib/arel/nodes/cte.rb +36 -0
  311. data/lib/arel/nodes/delete_statement.rb +14 -13
  312. data/lib/arel/nodes/equality.rb +6 -9
  313. data/lib/arel/nodes/filter.rb +10 -0
  314. data/lib/arel/nodes/fragments.rb +35 -0
  315. data/lib/arel/nodes/function.rb +1 -0
  316. data/lib/arel/nodes/grouping.rb +3 -0
  317. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  318. data/lib/arel/nodes/in.rb +8 -1
  319. data/lib/arel/nodes/infix_operation.rb +13 -1
  320. data/lib/arel/nodes/insert_statement.rb +2 -2
  321. data/lib/arel/nodes/join_source.rb +1 -1
  322. data/lib/arel/nodes/leading_join.rb +8 -0
  323. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  324. data/lib/arel/nodes/node.rb +122 -11
  325. data/lib/arel/nodes/ordering.rb +27 -0
  326. data/lib/arel/nodes/select_core.rb +2 -2
  327. data/lib/arel/nodes/select_statement.rb +2 -2
  328. data/lib/arel/nodes/sql_literal.rb +16 -0
  329. data/lib/arel/nodes/table_alias.rb +11 -3
  330. data/lib/arel/nodes/unary.rb +0 -1
  331. data/lib/arel/nodes/update_statement.rb +11 -4
  332. data/lib/arel/nodes.rb +10 -3
  333. data/lib/arel/predications.rb +31 -28
  334. data/lib/arel/select_manager.rb +18 -9
  335. data/lib/arel/table.rb +21 -10
  336. data/lib/arel/tree_manager.rb +8 -15
  337. data/lib/arel/update_manager.rb +25 -5
  338. data/lib/arel/visitors/dot.rb +94 -90
  339. data/lib/arel/visitors/mysql.rb +34 -6
  340. data/lib/arel/visitors/postgresql.rb +5 -16
  341. data/lib/arel/visitors/sqlite.rb +25 -1
  342. data/lib/arel/visitors/to_sql.rb +227 -81
  343. data/lib/arel/visitors/visitor.rb +2 -3
  344. data/lib/arel/visitors.rb +0 -7
  345. data/lib/arel.rb +37 -15
  346. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  347. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  348. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  349. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  350. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
  351. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  352. data/lib/rails/generators/active_record/migration.rb +9 -3
  353. data/lib/rails/generators/active_record/model/USAGE +113 -0
  354. data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
  355. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  356. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  357. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  358. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  359. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  360. metadata +117 -30
  361. data/lib/active_record/attribute_decorators.rb +0 -90
  362. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  363. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  364. data/lib/active_record/define_callbacks.rb +0 -22
  365. data/lib/active_record/null_relation.rb +0 -68
  366. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  367. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  368. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  369. data/lib/arel/attributes.rb +0 -22
  370. data/lib/arel/visitors/depth_first.rb +0 -204
  371. data/lib/arel/visitors/ibm_db.rb +0 -34
  372. data/lib/arel/visitors/informix.rb +0 -62
  373. data/lib/arel/visitors/mssql.rb +0 -157
  374. data/lib/arel/visitors/oracle.rb +0 -159
  375. data/lib/arel/visitors/oracle12.rb +0 -66
  376. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deprecation"
4
+
3
5
  module ActiveRecord
6
+ include ActiveSupport::Deprecation::DeprecatedConstantAccessor
7
+
4
8
  # = Active Record Errors
5
9
  #
6
10
  # Generic Active Record exception class.
@@ -9,7 +13,7 @@ module ActiveRecord
9
13
 
10
14
  # Raised when the single-table inheritance mechanism fails to locate the subclass
11
15
  # (for example due to improper usage of column that
12
- # {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema::ClassMethods#inheritance_column]
16
+ # {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema.inheritance_column]
13
17
  # points to).
14
18
  class SubclassNotFound < ActiveRecordError
15
19
  end
@@ -38,15 +42,77 @@ module ActiveRecord
38
42
  class AdapterNotSpecified < ActiveRecordError
39
43
  end
40
44
 
45
+ # Raised when a model makes a query but it has not specified an associated table.
46
+ class TableNotSpecified < ActiveRecordError
47
+ end
48
+
41
49
  # Raised when Active Record cannot find database adapter specified in
42
50
  # +config/database.yml+ or programmatically.
43
51
  class AdapterNotFound < ActiveRecordError
44
52
  end
45
53
 
54
+ # Superclass for all errors raised from an Active Record adapter.
55
+ class AdapterError < ActiveRecordError
56
+ def initialize(message = nil, connection_pool: nil)
57
+ @connection_pool = connection_pool
58
+ super(message)
59
+ end
60
+
61
+ attr_reader :connection_pool
62
+ end
63
+
46
64
  # Raised when connection to the database could not been established (for example when
47
- # {ActiveRecord::Base.connection=}[rdoc-ref:ConnectionHandling#connection]
65
+ # {ActiveRecord::Base.lease_connection=}[rdoc-ref:ConnectionHandling#lease_connection]
48
66
  # is given a +nil+ object).
49
- class ConnectionNotEstablished < ActiveRecordError
67
+ class ConnectionNotEstablished < AdapterError
68
+ def initialize(message = nil, connection_pool: nil)
69
+ super(message, connection_pool: connection_pool)
70
+ end
71
+
72
+ def set_pool(connection_pool)
73
+ unless @connection_pool
74
+ @connection_pool = connection_pool
75
+ end
76
+
77
+ self
78
+ end
79
+ end
80
+
81
+ # Raised when a connection could not be obtained within the connection
82
+ # acquisition timeout period: because max connections in pool
83
+ # are in use.
84
+ class ConnectionTimeoutError < ConnectionNotEstablished
85
+ end
86
+
87
+ # Raised when connection to the database could not been established because it was not
88
+ # able to connect to the host or when the authorization failed.
89
+ class DatabaseConnectionError < ConnectionNotEstablished
90
+ def initialize(message = nil)
91
+ super(message || "Database connection error")
92
+ end
93
+
94
+ class << self
95
+ def hostname_error(hostname)
96
+ DatabaseConnectionError.new(<<~MSG)
97
+ There is an issue connecting with your hostname: #{hostname}.\n
98
+ Please check your database configuration and ensure there is a valid connection to your database.
99
+ MSG
100
+ end
101
+
102
+ def username_error(username)
103
+ DatabaseConnectionError.new(<<~MSG)
104
+ There is an issue connecting to your database with your username/password, username: #{username}.\n
105
+ Please check your database configuration to ensure the username/password are valid.
106
+ MSG
107
+ end
108
+ end
109
+ end
110
+
111
+ # Raised when a pool was unable to get ahold of all its connections
112
+ # to perform a "group" action such as
113
+ # {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
114
+ # or {ActiveRecord::Base.connection_handler.clear_reloadable_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_reloadable_connections!].
115
+ class ExclusiveConnectionTimeoutError < ConnectionTimeoutError
50
116
  end
51
117
 
52
118
  # Raised when a write to the database is attempted on a read only connection.
@@ -67,8 +133,18 @@ module ActiveRecord
67
133
  end
68
134
 
69
135
  # Raised by {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] and
70
- # {ActiveRecord::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]
71
- # methods when a record is invalid and cannot be saved.
136
+ # {ActiveRecord::Base.update_attribute!}[rdoc-ref:Persistence#update_attribute!]
137
+ # methods when a record failed to validate or cannot be saved due to any of the
138
+ # <tt>before_*</tt> callbacks throwing +:abort+. See
139
+ # ActiveRecord::Callbacks for further details.
140
+ #
141
+ # class Product < ActiveRecord::Base
142
+ # before_save do
143
+ # throw :abort if price < 0
144
+ # end
145
+ # end
146
+ #
147
+ # Product.create! # => raises an ActiveRecord::RecordNotSaved
72
148
  class RecordNotSaved < ActiveRecordError
73
149
  attr_reader :record
74
150
 
@@ -79,15 +155,17 @@ module ActiveRecord
79
155
  end
80
156
 
81
157
  # Raised by {ActiveRecord::Base#destroy!}[rdoc-ref:Persistence#destroy!]
82
- # when a call to {#destroy}[rdoc-ref:Persistence#destroy!]
83
- # would return false.
158
+ # when a record cannot be destroyed due to any of the
159
+ # <tt>before_destroy</tt> callbacks throwing +:abort+. See
160
+ # ActiveRecord::Callbacks for further details.
84
161
  #
85
- # begin
86
- # complex_operation_that_internally_calls_destroy!
87
- # rescue ActiveRecord::RecordNotDestroyed => invalid
88
- # puts invalid.record.errors
162
+ # class User < ActiveRecord::Base
163
+ # before_destroy do
164
+ # throw :abort if still_active?
165
+ # end
89
166
  # end
90
167
  #
168
+ # User.first.destroy! # => raises an ActiveRecord::RecordNotDestroyed
91
169
  class RecordNotDestroyed < ActiveRecordError
92
170
  attr_reader :record
93
171
 
@@ -97,17 +175,36 @@ module ActiveRecord
97
175
  end
98
176
  end
99
177
 
178
+ # Raised when Active Record finds multiple records but only expected one.
179
+ class SoleRecordExceeded < ActiveRecordError
180
+ attr_reader :record
181
+
182
+ def initialize(record = nil)
183
+ @record = record
184
+ super "Wanted only one #{record&.name || "record"}"
185
+ end
186
+ end
187
+
100
188
  # Superclass for all database execution errors.
101
189
  #
102
190
  # Wraps the underlying database error as +cause+.
103
- class StatementInvalid < ActiveRecordError
104
- def initialize(message = nil, sql: nil, binds: nil)
105
- super(message || $!.try(:message))
191
+ class StatementInvalid < AdapterError
192
+ def initialize(message = nil, sql: nil, binds: nil, connection_pool: nil)
193
+ super(message || $!&.message, connection_pool: connection_pool)
106
194
  @sql = sql
107
195
  @binds = binds
108
196
  end
109
197
 
110
198
  attr_reader :sql, :binds
199
+
200
+ def set_query(sql, binds)
201
+ unless @sql
202
+ @sql = sql
203
+ @binds = binds
204
+ end
205
+
206
+ self
207
+ end
111
208
  end
112
209
 
113
210
  # Defunct wrapper class kept for compatibility.
@@ -134,8 +231,13 @@ module ActiveRecord
134
231
  foreign_key: nil,
135
232
  target_table: nil,
136
233
  primary_key: nil,
137
- primary_key_column: nil
234
+ primary_key_column: nil,
235
+ query_parser: nil,
236
+ connection_pool: nil
138
237
  )
238
+ @original_message = message
239
+ @query_parser = query_parser
240
+
139
241
  if table
140
242
  type = primary_key_column.bigint? ? :bigint : primary_key_column.type
141
243
  msg = <<~EOM.squish
@@ -153,7 +255,24 @@ module ActiveRecord
153
255
  if message
154
256
  msg << "\nOriginal message: #{message}"
155
257
  end
156
- super(msg, sql: sql, binds: binds)
258
+
259
+ super(msg, sql: sql, binds: binds, connection_pool: connection_pool)
260
+ end
261
+
262
+ def set_query(sql, binds)
263
+ if @query_parser && !@sql
264
+ self.class.new(
265
+ message: @original_message,
266
+ sql: sql,
267
+ binds: binds,
268
+ connection_pool: @connection_pool,
269
+ **@query_parser.call(sql)
270
+ ).tap do |exception|
271
+ exception.set_backtrace backtrace
272
+ end
273
+ else
274
+ super
275
+ end
157
276
  end
158
277
  end
159
278
 
@@ -169,9 +288,22 @@ module ActiveRecord
169
288
  class RangeError < StatementInvalid
170
289
  end
171
290
 
172
- # Raised when number of bind variables in statement given to +:condition+ key
173
- # (for example, when using {ActiveRecord::Base.find}[rdoc-ref:FinderMethods#find] method)
174
- # does not match number of expected values supplied.
291
+ # Raised when a statement produces an SQL warning.
292
+ class SQLWarning < AdapterError
293
+ attr_reader :code, :level
294
+ attr_accessor :sql
295
+
296
+ def initialize(message = nil, code = nil, level = nil, sql = nil, connection_pool = nil)
297
+ super(message, connection_pool: connection_pool)
298
+ @code = code
299
+ @level = level
300
+ @sql = sql
301
+ end
302
+ end
303
+
304
+ # Raised when the number of placeholders in an SQL fragment passed to
305
+ # {ActiveRecord::Base.where}[rdoc-ref:QueryMethods#where]
306
+ # does not match the number of values supplied.
175
307
  #
176
308
  # For example, when there are two placeholders with only one value supplied:
177
309
  #
@@ -181,6 +313,35 @@ module ActiveRecord
181
313
 
182
314
  # Raised when a given database does not exist.
183
315
  class NoDatabaseError < StatementInvalid
316
+ include ActiveSupport::ActionableError
317
+
318
+ action "Create database" do
319
+ ActiveRecord::Tasks::DatabaseTasks.create_current
320
+ end
321
+
322
+ def initialize(message = nil, connection_pool: nil)
323
+ super(message || "Database not found", connection_pool: connection_pool)
324
+ end
325
+
326
+ class << self
327
+ def db_error(db_name)
328
+ NoDatabaseError.new(<<~MSG)
329
+ We could not find your database: #{db_name}. Available database configurations can be found in config/database.yml.
330
+
331
+ To resolve this error:
332
+
333
+ - Did you not create the database, or did you delete it? To create the database, run:
334
+
335
+ bin/rails db:create
336
+
337
+ - Has the database name changed? Verify that config/database.yml contains the correct database name.
338
+ MSG
339
+ end
340
+ end
341
+ end
342
+
343
+ # Raised when creating a database if it exists.
344
+ class DatabaseAlreadyExists < StatementInvalid
184
345
  end
185
346
 
186
347
  # Raised when PostgreSQL returns 'cached plan must not change result type' and
@@ -220,6 +381,16 @@ module ActiveRecord
220
381
  class ReadOnlyRecord < ActiveRecordError
221
382
  end
222
383
 
384
+ # Raised on attempt to lazily load records that are marked as strict loading.
385
+ #
386
+ # You can resolve this error by eager loading marked records before accessing
387
+ # them. The
388
+ # {Eager Loading Associations}[https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations]
389
+ # guide covers solutions, such as using
390
+ # {ActiveRecord::Base.includes}[rdoc-ref:QueryMethods#includes].
391
+ class StrictLoadingViolationError < ActiveRecordError
392
+ end
393
+
223
394
  # {ActiveRecord::Base.transaction}[rdoc-ref:Transactions::ClassMethods#transaction]
224
395
  # uses this exception to distinguish a deliberate rollback from other exceptional situations.
225
396
  # Normally, raising an exception will cause the
@@ -239,7 +410,7 @@ module ActiveRecord
239
410
  # # The system must fail on Friday so that our support department
240
411
  # # won't be out of job. We silently rollback this transaction
241
412
  # # without telling the user.
242
- # raise ActiveRecord::Rollback, "Call tech support!"
413
+ # raise ActiveRecord::Rollback
243
414
  # end
244
415
  # end
245
416
  # # ActiveRecord::Rollback is the only exception that won't be passed on
@@ -260,7 +431,7 @@ module ActiveRecord
260
431
  UnknownAttributeError = ActiveModel::UnknownAttributeError
261
432
 
262
433
  # Raised when an error occurred while doing a mass assignment to an attribute through the
263
- # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
434
+ # {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=] method.
264
435
  # The exception has an +attribute+ property that is the name of the offending attribute.
265
436
  class AttributeAssignmentError < ActiveRecordError
266
437
  attr_reader :exception, :attribute
@@ -273,7 +444,7 @@ module ActiveRecord
273
444
  end
274
445
 
275
446
  # Raised when there are multiple errors while doing a mass assignment through the
276
- # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=]
447
+ # {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=]
277
448
  # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
278
449
  # objects, each corresponding to the error while assigning to an attribute.
279
450
  class MultiparameterAssignmentErrors < ActiveRecordError
@@ -309,10 +480,15 @@ module ActiveRecord
309
480
  # relation.loaded? # => true
310
481
  #
311
482
  # # Methods which try to mutate a loaded relation fail.
312
- # relation.where!(title: 'TODO') # => ActiveRecord::ImmutableRelation
313
- # relation.limit!(5) # => ActiveRecord::ImmutableRelation
314
- class ImmutableRelation < ActiveRecordError
483
+ # relation.where!(title: 'TODO') # => ActiveRecord::UnmodifiableRelation
484
+ # relation.limit!(5) # => ActiveRecord::UnmodifiableRelation
485
+ class UnmodifiableRelation < ActiveRecordError
315
486
  end
487
+ deprecate_constant(
488
+ :ImmutableRelation,
489
+ "ActiveRecord::UnmodifiableRelation",
490
+ deprecator: ActiveRecord.deprecator
491
+ )
316
492
 
317
493
  # TransactionIsolationError will be raised under the following conditions:
318
494
  #
@@ -320,27 +496,51 @@ module ActiveRecord
320
496
  # * You are joining an existing open transaction
321
497
  # * You are creating a nested (savepoint) transaction
322
498
  #
323
- # The mysql2 and postgresql adapters support setting the transaction isolation level.
499
+ # The mysql2, trilogy, and postgresql adapters support setting the transaction isolation level.
324
500
  class TransactionIsolationError < ActiveRecordError
325
501
  end
326
502
 
327
503
  # TransactionRollbackError will be raised when a transaction is rolled
328
504
  # back by the database due to a serialization failure or a deadlock.
329
505
  #
506
+ # These exceptions should not be generally rescued in nested transaction
507
+ # blocks, because they have side-effects in the actual enclosing transaction
508
+ # and internal Active Record state. They can be rescued if you are above the
509
+ # root transaction block, though.
510
+ #
511
+ # In that case, beware of transactional tests, however, because they run test
512
+ # cases in their own umbrella transaction. If you absolutely need to handle
513
+ # these exceptions in tests please consider disabling transactional tests in
514
+ # the affected test class (<tt>self.use_transactional_tests = false</tt>).
515
+ #
516
+ # Due to the aforementioned side-effects, this exception should not be raised
517
+ # manually by users.
518
+ #
330
519
  # See the following:
331
520
  #
332
521
  # * https://www.postgresql.org/docs/current/static/transaction-iso.html
333
- # * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock
522
+ # * https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html#error_er_lock_deadlock
334
523
  class TransactionRollbackError < StatementInvalid
335
524
  end
336
525
 
526
+ # AsynchronousQueryInsideTransactionError will be raised when attempting
527
+ # to perform an asynchronous query from inside a transaction
528
+ class AsynchronousQueryInsideTransactionError < ActiveRecordError
529
+ end
530
+
337
531
  # SerializationFailure will be raised when a transaction is rolled
338
532
  # back by the database due to a serialization failure.
533
+ #
534
+ # This is a subclass of TransactionRollbackError, please make sure to check
535
+ # its documentation to be aware of its caveats.
339
536
  class SerializationFailure < TransactionRollbackError
340
537
  end
341
538
 
342
539
  # Deadlocked will be raised when a transaction is rolled
343
540
  # back by the database when a deadlock is encountered.
541
+ #
542
+ # This is a subclass of TransactionRollbackError, please make sure to check
543
+ # its documentation to be aware of its caveats.
344
544
  class Deadlocked < TransactionRollbackError
345
545
  end
346
546
 
@@ -349,40 +549,58 @@ module ActiveRecord
349
549
  class IrreversibleOrderError < ActiveRecordError
350
550
  end
351
551
 
552
+ # Superclass for errors that have been aborted (either by client or server).
553
+ class QueryAborted < StatementInvalid
554
+ end
555
+
352
556
  # LockWaitTimeout will be raised when lock wait timeout exceeded.
353
557
  class LockWaitTimeout < StatementInvalid
354
558
  end
355
559
 
356
560
  # StatementTimeout will be raised when statement timeout exceeded.
357
- class StatementTimeout < StatementInvalid
561
+ class StatementTimeout < QueryAborted
358
562
  end
359
563
 
360
564
  # QueryCanceled will be raised when canceling statement due to user request.
361
- class QueryCanceled < StatementInvalid
565
+ class QueryCanceled < QueryAborted
566
+ end
567
+
568
+ # AdapterTimeout will be raised when database clients times out while waiting from the server.
569
+ class AdapterTimeout < QueryAborted
570
+ end
571
+
572
+ # ConnectionFailed will be raised when the network connection to the
573
+ # database fails while sending a query or waiting for its result.
574
+ class ConnectionFailed < QueryAborted
362
575
  end
363
576
 
364
577
  # UnknownAttributeReference is raised when an unknown and potentially unsafe
365
- # value is passed to a query method when allow_unsafe_raw_sql is set to
366
- # :disabled. For example, passing a non column name value to a relation's
367
- # #order method might cause this exception.
578
+ # value is passed to a query method. For example, passing a non column name
579
+ # value to a relation's #order method might cause this exception.
368
580
  #
369
581
  # When working around this exception, caution should be taken to avoid SQL
370
582
  # injection vulnerabilities when passing user-provided values to query
371
583
  # methods. Known-safe values can be passed to query methods by wrapping them
372
584
  # in Arel.sql.
373
585
  #
374
- # For example, with allow_unsafe_raw_sql set to :disabled, the following
375
- # code would raise this exception:
586
+ # For example, the following code would raise this exception:
376
587
  #
377
- # Post.order("length(title)").first
588
+ # Post.order("REPLACE(title, 'misc', 'zzzz') asc").pluck(:id)
378
589
  #
379
590
  # The desired result can be accomplished by wrapping the known-safe string
380
591
  # in Arel.sql:
381
592
  #
382
- # Post.order(Arel.sql("length(title)")).first
593
+ # Post.order(Arel.sql("REPLACE(title, 'misc', 'zzzz') asc")).pluck(:id)
383
594
  #
384
595
  # Again, such a workaround should *not* be used when passing user-provided
385
596
  # values, such as request parameters or model attributes to query methods.
386
597
  class UnknownAttributeReference < ActiveRecordError
387
598
  end
599
+
600
+ # DatabaseVersionError will be raised when the database version is not supported, or when
601
+ # the database version cannot be determined.
602
+ class DatabaseVersionError < ActiveRecordError
603
+ end
388
604
  end
605
+
606
+ require "active_record/associations/errors"
@@ -16,17 +16,18 @@ module ActiveRecord
16
16
 
17
17
  # Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
18
18
  # Returns a formatted string ready to be logged.
19
- def exec_explain(queries) # :nodoc:
20
- str = queries.map do |sql, binds|
21
- msg = +"EXPLAIN for: #{sql}"
22
- unless binds.empty?
23
- msg << " "
24
- msg << binds.map { |attr| render_bind(attr) }.inspect
25
- end
26
- msg << "\n"
27
- msg << connection.explain(sql, binds)
28
- end.join("\n")
29
-
19
+ def exec_explain(queries, options = []) # :nodoc:
20
+ str = with_connection do |c|
21
+ queries.map do |sql, binds|
22
+ msg = +"#{build_explain_clause(c, options)} #{sql}"
23
+ unless binds.empty?
24
+ msg << " "
25
+ msg << binds.map { |attr| render_bind(c, attr) }.inspect
26
+ end
27
+ msg << "\n"
28
+ msg << c.explain(sql, binds, options)
29
+ end.join("\n")
30
+ end
30
31
  # Overriding inspect to be more human readable, especially in the console.
31
32
  def str.inspect
32
33
  self
@@ -36,15 +37,27 @@ module ActiveRecord
36
37
  end
37
38
 
38
39
  private
39
-
40
- def render_bind(attr)
41
- value = if attr.type.binary? && attr.value
42
- "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
40
+ def render_bind(connection, attr)
41
+ if ActiveModel::Attribute === attr
42
+ value = if attr.type.binary? && attr.value
43
+ "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
44
+ else
45
+ connection.type_cast(attr.value_for_database)
46
+ end
43
47
  else
44
- connection.type_cast(attr.value_for_database)
48
+ value = connection.type_cast(attr)
49
+ attr = nil
45
50
  end
46
51
 
47
- [attr.name, value]
52
+ [attr&.name, value]
53
+ end
54
+
55
+ def build_explain_clause(connection, options = [])
56
+ if connection.respond_to?(:build_explain_clause, true)
57
+ connection.build_explain_clause(options)
58
+ else
59
+ "EXPLAIN for:"
60
+ end
48
61
  end
49
62
  end
50
63
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/per_thread_registry"
3
+ require "active_support/core_ext/module/delegation"
4
4
 
5
5
  module ActiveRecord
6
6
  # This is a thread locals registry for EXPLAIN. For example
@@ -8,13 +8,18 @@ module ActiveRecord
8
8
  # ActiveRecord::ExplainRegistry.queries
9
9
  #
10
10
  # returns the collected queries local to the current thread.
11
- #
12
- # See the documentation of ActiveSupport::PerThreadRegistry
13
- # for further details.
14
11
  class ExplainRegistry # :nodoc:
15
- extend ActiveSupport::PerThreadRegistry
12
+ class << self
13
+ delegate :reset, :collect, :collect=, :collect?, :queries, to: :instance
14
+
15
+ private
16
+ def instance
17
+ ActiveSupport::IsolatedExecutionState[:active_record_explain_registry] ||= new
18
+ end
19
+ end
16
20
 
17
- attr_accessor :queries, :collect
21
+ attr_accessor :collect
22
+ attr_reader :queries
18
23
 
19
24
  def initialize
20
25
  reset
@@ -21,12 +21,12 @@ module ActiveRecord
21
21
  # On the other hand, we want to monitor the performance of our real database
22
22
  # queries, not the performance of the access to the query cache.
23
23
  IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN)
24
- EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
24
+ EXPLAINED_SQLS = /\A\s*(\/\*.*\*\/)?\s*(with|select|update|delete|insert)\b/i
25
25
  def ignore_payload?(payload)
26
26
  payload[:exception] ||
27
27
  payload[:cached] ||
28
28
  IGNORED_PAYLOADS.include?(payload[:name]) ||
29
- payload[:sql] !~ EXPLAINED_SQLS
29
+ !payload[:sql].match?(EXPLAINED_SQLS)
30
30
  end
31
31
 
32
32
  ActiveSupport::Notifications.subscribe("sql.active_record", new)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "erb"
4
- require "yaml"
3
+ require "active_support/configuration_file"
5
4
 
6
5
  module ActiveRecord
7
6
  class FixtureSet
@@ -29,6 +28,10 @@ module ActiveRecord
29
28
  config_row["model_class"]
30
29
  end
31
30
 
31
+ def ignored_fixtures
32
+ config_row["ignore"]
33
+ end
34
+
32
35
  private
33
36
  def rows
34
37
  @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" }
@@ -38,31 +41,35 @@ module ActiveRecord
38
41
  @config_row ||= begin
39
42
  row = raw_rows.find { |fixture_name, _| fixture_name == "_fixture" }
40
43
  if row
41
- row.last
44
+ validate_config_row(row.last)
42
45
  else
43
- { 'model_class': nil }
46
+ { 'model_class': nil, 'ignore': nil }
44
47
  end
45
48
  end
46
49
  end
47
50
 
48
51
  def raw_rows
49
52
  @raw_rows ||= begin
50
- data = YAML.load(render(IO.read(@file)))
53
+ data = ActiveSupport::ConfigurationFile.parse(@file, context:
54
+ ActiveRecord::FixtureSet::RenderContext.create_subclass.new.get_binding)
51
55
  data ? validate(data).to_a : []
52
- rescue ArgumentError, Psych::SyntaxError => error
53
- raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
56
+ rescue RuntimeError => error
57
+ raise Fixture::FormatError, error.message
54
58
  end
55
59
  end
56
60
 
57
- def prepare_erb(content)
58
- erb = ERB.new(content)
59
- erb.filename = @file
60
- erb
61
- end
61
+ def validate_config_row(data)
62
+ unless Hash === data
63
+ raise Fixture::FormatError, "Invalid `_fixture` section: `_fixture` must be a hash: #{@file}"
64
+ end
62
65
 
63
- def render(content)
64
- context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
65
- prepare_erb(content).result(context.get_binding)
66
+ begin
67
+ data.assert_valid_keys("model_class", "ignore")
68
+ rescue ArgumentError => error
69
+ raise Fixture::FormatError, "Invalid `_fixture` section: #{error.message}: #{@file}"
70
+ end
71
+
72
+ data
66
73
  end
67
74
 
68
75
  # Validate our unmarshalled data.
@@ -12,17 +12,26 @@ module ActiveRecord
12
12
  end
13
13
 
14
14
  def primary_key_type
15
- @primary_key_type ||= @model_class && @model_class.type_for_attribute(@model_class.primary_key).type
15
+ @primary_key_type ||= @model_class && column_type(@model_class.primary_key)
16
16
  end
17
17
 
18
- def has_primary_key_column?
19
- @has_primary_key_column ||= primary_key_name &&
20
- @model_class.columns.any? { |col| col.name == primary_key_name }
18
+ def column_type(column_name)
19
+ @column_type ||= {}
20
+ return @column_type[column_name] if @column_type.key?(column_name)
21
+
22
+ @column_type[column_name] = @model_class && @model_class.type_for_attribute(column_name).type
23
+ end
24
+
25
+ def has_column?(column_name)
26
+ column_names.include?(column_name)
27
+ end
28
+
29
+ def column_names
30
+ @column_names ||= @model_class ? @model_class.columns.map(&:name).to_set : Set.new
21
31
  end
22
32
 
23
33
  def timestamp_column_names
24
- @timestamp_column_names ||=
25
- %w(created_at created_on updated_at updated_on) & @model_class.column_names
34
+ @model_class.all_timestamp_attributes_in_model
26
35
  end
27
36
 
28
37
  def inheritance_column_name