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
@@ -6,6 +6,13 @@ module ActiveRecord
6
6
  module ModelSchema
7
7
  extend ActiveSupport::Concern
8
8
 
9
+ ##
10
+ # :method: id_value
11
+ # :call-seq: id_value
12
+ #
13
+ # Returns the underlying column value for a column named "id". Useful when defining
14
+ # a composite primary key including an "id" column so that the value is readable.
15
+
9
16
  ##
10
17
  # :singleton-method: primary_key_prefix_type
11
18
  # :call-seq: primary_key_prefix_type
@@ -115,23 +122,65 @@ module ActiveRecord
115
122
  #
116
123
  # Sets the column to sort records by when no explicit order clause is used
117
124
  # during an ordered finder call. Useful when the primary key is not an
118
- # auto-incrementing integer, for example when it's a UUID. Note that using
119
- # a non-unique column can result in non-deterministic results.
120
- included do
121
- mattr_accessor :primary_key_prefix_type, instance_writer: false
125
+ # auto-incrementing integer, for example when it's a UUID. Records are subsorted
126
+ # by the primary key if it exists to ensure deterministic results.
127
+
128
+ ##
129
+ # :singleton-method: immutable_strings_by_default=
130
+ # :call-seq: immutable_strings_by_default=(bool)
131
+ #
132
+ # Determines whether columns should infer their type as +:string+ or
133
+ # +:immutable_string+. This setting does not affect the behavior of
134
+ # <tt>attribute :foo, :string</tt>. Defaults to false.
135
+
136
+ ##
137
+ # :singleton-method: inheritance_column
138
+ # :call-seq: inheritance_column
139
+ #
140
+ # The name of the table column which stores the class name on single-table
141
+ # inheritance situations.
142
+ #
143
+ # The default inheritance column name is +type+, which means it's a
144
+ # reserved word inside Active Record. To be able to use single-table
145
+ # inheritance with another column name, or to use the column +type+ in
146
+ # your own model for something else, you can set +inheritance_column+:
147
+ #
148
+ # self.inheritance_column = 'zoink'
149
+ #
150
+ # If you wish to disable single-table inheritance altogether you can set
151
+ # +inheritance_column+ to +nil+
152
+ #
153
+ # self.inheritance_column = nil
154
+
155
+ ##
156
+ # :singleton-method: inheritance_column=
157
+ # :call-seq: inheritance_column=(column)
158
+ #
159
+ # Defines the name of the table column which will store the class name on single-table
160
+ # inheritance situations.
122
161
 
162
+ included do
163
+ class_attribute :primary_key_prefix_type, instance_writer: false
123
164
  class_attribute :table_name_prefix, instance_writer: false, default: ""
124
165
  class_attribute :table_name_suffix, instance_writer: false, default: ""
125
166
  class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
126
167
  class_attribute :internal_metadata_table_name, instance_accessor: false, default: "ar_internal_metadata"
127
168
  class_attribute :pluralize_table_names, instance_writer: false, default: true
128
169
  class_attribute :implicit_order_column, instance_accessor: false
170
+ class_attribute :immutable_strings_by_default, instance_accessor: false
171
+
172
+ class_attribute :inheritance_column, instance_accessor: false, default: "type"
173
+ singleton_class.class_eval do
174
+ alias_method :_inheritance_column=, :inheritance_column=
175
+ private :_inheritance_column=
176
+ alias_method :inheritance_column=, :real_inheritance_column=
177
+ end
129
178
 
130
179
  self.protected_environments = ["production"]
131
- self.inheritance_column = "type"
180
+
132
181
  self.ignored_columns = [].freeze
133
182
 
134
- delegate :type_for_attribute, to: :class
183
+ delegate :type_for_attribute, :column_for_attribute, to: :class
135
184
 
136
185
  initialize_load_schema_monitor
137
186
  end
@@ -143,8 +192,9 @@ module ActiveRecord
143
192
  # artists, records => artists_records
144
193
  # records, artists => artists_records
145
194
  # music_artists, music_records => music_artists_records
195
+ # music.artists, music.records => music.artists_records
146
196
  def self.derive_join_table_name(first_table, second_table) # :nodoc:
147
- [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
197
+ [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*[_.])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
148
198
  end
149
199
 
150
200
  module ClassMethods
@@ -187,6 +237,21 @@ module ActiveRecord
187
237
  # the table name guess for an Invoice class becomes "myapp_invoices".
188
238
  # Invoice::Lineitem becomes "myapp_invoice_lineitems".
189
239
  #
240
+ # Active Model Naming's +model_name+ is the base name used to guess the
241
+ # table name. In case a custom Active Model Name is defined, it will be
242
+ # used for the table name as well:
243
+ #
244
+ # class PostRecord < ActiveRecord::Base
245
+ # class << self
246
+ # def model_name
247
+ # ActiveModel::Name.new(self, nil, "Post")
248
+ # end
249
+ # end
250
+ # end
251
+ #
252
+ # PostRecord.table_name
253
+ # # => "posts"
254
+ #
190
255
  # You can also set your own table name explicitly:
191
256
  #
192
257
  # class Mouse < ActiveRecord::Base
@@ -213,19 +278,21 @@ module ActiveRecord
213
278
  @table_name = value
214
279
  @quoted_table_name = nil
215
280
  @arel_table = nil
216
- @sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
281
+ @sequence_name = nil unless @explicit_sequence_name
217
282
  @predicate_builder = nil
218
283
  end
219
284
 
220
285
  # Returns a quoted version of the table name, used to construct SQL statements.
221
286
  def quoted_table_name
222
- @quoted_table_name ||= connection.quote_table_name(table_name)
287
+ @quoted_table_name ||= adapter_class.quote_table_name(table_name)
223
288
  end
224
289
 
225
290
  # Computes the table name, (re)sets it internally, and returns it.
226
- def reset_table_name #:nodoc:
227
- self.table_name = if abstract_class?
228
- superclass == Base ? nil : superclass.table_name
291
+ def reset_table_name # :nodoc:
292
+ self.table_name = if self == Base
293
+ nil
294
+ elsif abstract_class?
295
+ superclass.table_name
229
296
  elsif superclass.abstract_class?
230
297
  superclass.table_name || compute_table_name
231
298
  else
@@ -233,11 +300,11 @@ module ActiveRecord
233
300
  end
234
301
  end
235
302
 
236
- def full_table_name_prefix #:nodoc:
303
+ def full_table_name_prefix # :nodoc:
237
304
  (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
238
305
  end
239
306
 
240
- def full_table_name_suffix #:nodoc:
307
+ def full_table_name_suffix # :nodoc:
241
308
  (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
242
309
  end
243
310
 
@@ -256,39 +323,50 @@ module ActiveRecord
256
323
  @protected_environments = environments.map(&:to_s)
257
324
  end
258
325
 
259
- # Defines the name of the table column which will store the class name on single-table
260
- # inheritance situations.
261
- #
262
- # The default inheritance column name is +type+, which means it's a
263
- # reserved word inside Active Record. To be able to use single-table
264
- # inheritance with another column name, or to use the column +type+ in
265
- # your own model for something else, you can set +inheritance_column+:
266
- #
267
- # self.inheritance_column = 'zoink'
268
- def inheritance_column
269
- (@inheritance_column ||= nil) || superclass.inheritance_column
270
- end
271
-
272
- # Sets the value of inheritance_column
273
- def inheritance_column=(value)
274
- @inheritance_column = value.to_s
275
- @explicit_inheritance_column = true
326
+ def real_inheritance_column=(value) # :nodoc:
327
+ self._inheritance_column = value.to_s
276
328
  end
277
329
 
278
330
  # The list of columns names the model should ignore. Ignored columns won't have attribute
279
331
  # accessors defined, and won't be referenced in SQL queries.
280
332
  def ignored_columns
281
- if defined?(@ignored_columns)
282
- @ignored_columns
283
- else
284
- superclass.ignored_columns
285
- end
333
+ @ignored_columns || superclass.ignored_columns
286
334
  end
287
335
 
288
336
  # Sets the columns names the model should ignore. Ignored columns won't have attribute
289
337
  # accessors defined, and won't be referenced in SQL queries.
338
+ #
339
+ # A common usage pattern for this method is to ensure all references to an attribute
340
+ # have been removed and deployed, before a migration to drop the column from the database
341
+ # has been deployed and run. Using this two step approach to dropping columns ensures there
342
+ # is no code that raises errors due to having a cached schema in memory at the time the
343
+ # schema migration is run.
344
+ #
345
+ # For example, given a model where you want to drop the "category" attribute, first mark it
346
+ # as ignored:
347
+ #
348
+ # class Project < ActiveRecord::Base
349
+ # # schema:
350
+ # # id :bigint
351
+ # # name :string, limit: 255
352
+ # # category :string, limit: 255
353
+ #
354
+ # self.ignored_columns += [:category]
355
+ # end
356
+ #
357
+ # The schema still contains "category", but now the model omits it, so any meta-driven code or
358
+ # schema caching will not attempt to use the column:
359
+ #
360
+ # Project.columns_hash["category"] => nil
361
+ #
362
+ # You will get an error if accessing that attribute directly, so ensure all usages of the
363
+ # column are removed (automated tests can help you find any usages).
364
+ #
365
+ # user = Project.create!(name: "First Project")
366
+ # user.category # => raises NoMethodError
290
367
  def ignored_columns=(columns)
291
- @ignored_columns = columns.map(&:to_s)
368
+ reload_schema_from_cache
369
+ @ignored_columns = columns.map(&:to_s).freeze
292
370
  end
293
371
 
294
372
  def sequence_name
@@ -299,9 +377,9 @@ module ActiveRecord
299
377
  end
300
378
  end
301
379
 
302
- def reset_sequence_name #:nodoc:
380
+ def reset_sequence_name # :nodoc:
303
381
  @explicit_sequence_name = false
304
- @sequence_name = connection.default_sequence_name(table_name, primary_key)
382
+ @sequence_name = with_connection { |c| c.default_sequence_name(table_name, primary_key) }
305
383
  end
306
384
 
307
385
  # Sets the name of the sequence to use when generating ids to the given
@@ -326,64 +404,67 @@ module ActiveRecord
326
404
  # Determines if the primary key values should be selected from their
327
405
  # corresponding sequence before the insert statement.
328
406
  def prefetch_primary_key?
329
- connection.prefetch_primary_key?(table_name)
407
+ with_connection { |c| c.prefetch_primary_key?(table_name) }
330
408
  end
331
409
 
332
410
  # Returns the next value that will be used as the primary key on
333
411
  # an insert statement.
334
412
  def next_sequence_value
335
- connection.next_sequence_value(sequence_name)
413
+ with_connection { |c| c.next_sequence_value(sequence_name) }
336
414
  end
337
415
 
338
416
  # Indicates whether the table associated with this class exists
339
417
  def table_exists?
340
- connection.schema_cache.data_source_exists?(table_name)
418
+ schema_cache.data_source_exists?(table_name)
341
419
  end
342
420
 
343
421
  def attributes_builder # :nodoc:
344
- unless defined?(@attributes_builder) && @attributes_builder
422
+ @attributes_builder ||= begin
345
423
  defaults = _default_attributes.except(*(column_names - [primary_key]))
346
- @attributes_builder = ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
424
+ ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
347
425
  end
348
- @attributes_builder
349
426
  end
350
427
 
351
428
  def columns_hash # :nodoc:
352
- load_schema
429
+ load_schema unless @columns_hash
353
430
  @columns_hash
354
431
  end
355
432
 
356
433
  def columns
357
- load_schema
358
- @columns ||= columns_hash.values
434
+ @columns ||= columns_hash.values.freeze
359
435
  end
360
436
 
361
- def attribute_types # :nodoc:
362
- load_schema
363
- @attribute_types ||= Hash.new(Type.default_value)
437
+ def _returning_columns_for_insert(connection) # :nodoc:
438
+ @_returning_columns_for_insert ||= begin
439
+ auto_populated_columns = columns.filter_map do |c|
440
+ c.name if connection.return_value_after_insert?(c)
441
+ end
442
+
443
+ auto_populated_columns.empty? ? Array(primary_key) : auto_populated_columns
444
+ end
364
445
  end
365
446
 
366
447
  def yaml_encoder # :nodoc:
367
448
  @yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
368
449
  end
369
450
 
370
- # Returns the type of the attribute with the given name, after applying
371
- # all modifiers. This method is the only valid source of information for
372
- # anything related to the types of a model's attributes. This method will
373
- # access the database and load the model's schema if it is required.
374
- #
375
- # The return value of this method will implement the interface described
376
- # by ActiveModel::Type::Value (though the object itself may not subclass
377
- # it).
378
- #
379
- # +attr_name+ The name of the attribute to retrieve the type for. Must be
380
- # a string or a symbol.
381
- def type_for_attribute(attr_name, &block)
382
- attr_name = attr_name.to_s
383
- if block
384
- attribute_types.fetch(attr_name, &block)
385
- else
386
- attribute_types[attr_name]
451
+ # Returns the column object for the named attribute.
452
+ # Returns an ActiveRecord::ConnectionAdapters::NullColumn if the
453
+ # named attribute does not exist.
454
+ #
455
+ # class Person < ActiveRecord::Base
456
+ # end
457
+ #
458
+ # person = Person.new
459
+ # person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
460
+ # # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
461
+ #
462
+ # person.column_for_attribute(:nothing)
463
+ # # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
464
+ def column_for_attribute(name)
465
+ name = name.to_s
466
+ columns_hash.fetch(name) do
467
+ ConnectionAdapters::NullColumn.new(name)
387
468
  end
388
469
  end
389
470
 
@@ -391,17 +472,12 @@ module ActiveRecord
391
472
  # default values when instantiating the Active Record object for this table.
392
473
  def column_defaults
393
474
  load_schema
394
- @column_defaults ||= _default_attributes.deep_dup.to_hash
395
- end
396
-
397
- def _default_attributes # :nodoc:
398
- load_schema
399
- @default_attributes ||= ActiveModel::AttributeSet.new({})
475
+ @column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
400
476
  end
401
477
 
402
478
  # Returns an array of column names as strings.
403
479
  def column_names
404
- @column_names ||= columns.map(&:name)
480
+ @column_names ||= columns.map(&:name).freeze
405
481
  end
406
482
 
407
483
  def symbol_column_to_string(name_symbol) # :nodoc:
@@ -415,9 +491,8 @@ module ActiveRecord
415
491
  @content_columns ||= columns.reject do |c|
416
492
  c.name == primary_key ||
417
493
  c.name == inheritance_column ||
418
- c.name.end_with?("_id") ||
419
- c.name.end_with?("_count")
420
- end
494
+ c.name.end_with?("_id", "_count")
495
+ end.freeze
421
496
  end
422
497
 
423
498
  # Resets all the cached information about columns, which will cause them
@@ -425,9 +500,9 @@ module ActiveRecord
425
500
  #
426
501
  # The most common usage pattern for this method is probably in a migration,
427
502
  # when just after creating a table you want to populate it with some default
428
- # values, eg:
503
+ # values, e.g.:
429
504
  #
430
- # class CreateJobLevels < ActiveRecord::Migration[5.0]
505
+ # class CreateJobLevels < ActiveRecord::Migration[7.2]
431
506
  # def up
432
507
  # create_table :job_levels do |t|
433
508
  # t.integer :id
@@ -447,77 +522,84 @@ module ActiveRecord
447
522
  # end
448
523
  # end
449
524
  def reset_column_information
450
- connection.clear_cache!
525
+ connection_pool.active_connection&.clear_cache!
451
526
  ([self] + descendants).each(&:undefine_attribute_methods)
452
- connection.schema_cache.clear_data_source_cache!(table_name)
527
+ schema_cache.clear_data_source_cache!(table_name)
453
528
 
454
529
  reload_schema_from_cache
455
530
  initialize_find_by_cache
456
531
  end
457
532
 
458
- protected
459
-
460
- def initialize_load_schema_monitor
461
- @load_schema_monitor = Monitor.new
462
- end
463
-
464
- private
465
-
466
- def inherited(child_class)
467
- super
468
- child_class.initialize_load_schema_monitor
469
- end
470
-
471
- def schema_loaded?
472
- defined?(@schema_loaded) && @schema_loaded
473
- end
474
-
475
- def load_schema
533
+ # Load the model's schema information either from the schema cache
534
+ # or directly from the database.
535
+ def load_schema
536
+ return if schema_loaded?
537
+ @load_schema_monitor.synchronize do
476
538
  return if schema_loaded?
477
- @load_schema_monitor.synchronize do
478
- return if defined?(@columns_hash) && @columns_hash
479
539
 
480
- load_schema!
540
+ load_schema!
481
541
 
482
- @schema_loaded = true
483
- end
542
+ @schema_loaded = true
543
+ rescue
544
+ reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
545
+ raise
484
546
  end
547
+ end
485
548
 
486
- def load_schema!
487
- @columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
488
- @columns_hash.each do |name, column|
489
- define_attribute(
490
- name,
491
- connection.lookup_cast_type_from_column(column),
492
- default: column.default,
493
- user_provided_default: false
494
- )
495
- end
549
+ protected
550
+ def initialize_load_schema_monitor
551
+ @load_schema_monitor = Monitor.new
496
552
  end
497
553
 
498
- def reload_schema_from_cache
554
+ def reload_schema_from_cache(recursive = true)
555
+ @_returning_columns_for_insert = nil
499
556
  @arel_table = nil
500
557
  @column_names = nil
501
558
  @symbol_column_to_string_name_hash = nil
502
- @attribute_types = nil
503
559
  @content_columns = nil
504
- @default_attributes = nil
505
560
  @column_defaults = nil
506
- @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
507
561
  @attributes_builder = nil
508
562
  @columns = nil
509
563
  @columns_hash = nil
510
564
  @schema_loaded = false
511
565
  @attribute_names = nil
512
566
  @yaml_encoder = nil
513
- direct_descendants.each do |descendant|
514
- descendant.send(:reload_schema_from_cache)
567
+ if recursive
568
+ subclasses.each do |descendant|
569
+ descendant.send(:reload_schema_from_cache)
570
+ end
515
571
  end
516
572
  end
517
573
 
574
+ private
575
+ def inherited(child_class)
576
+ super
577
+ child_class.initialize_load_schema_monitor
578
+ child_class.reload_schema_from_cache(false)
579
+ child_class.class_eval do
580
+ @ignored_columns = nil
581
+ end
582
+ end
583
+
584
+ def schema_loaded?
585
+ @schema_loaded
586
+ end
587
+
588
+ def load_schema!
589
+ unless table_name
590
+ raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
591
+ end
592
+
593
+ columns_hash = schema_cache.columns_hash(table_name)
594
+ columns_hash = columns_hash.except(*ignored_columns) unless ignored_columns.empty?
595
+ @columns_hash = columns_hash.freeze
596
+
597
+ _default_attributes # Precompute to cache DB-dependent attribute types
598
+ end
599
+
518
600
  # Guesses the table name, but does not decorate it with prefix and suffix information.
519
- def undecorated_table_name(class_name = base_class.name)
520
- table_name = class_name.to_s.demodulize.underscore
601
+ def undecorated_table_name(model_name)
602
+ table_name = model_name.to_s.demodulize.underscore
521
603
  pluralize_table_names ? table_name.pluralize : table_name
522
604
  end
523
605
 
@@ -531,12 +613,22 @@ module ActiveRecord
531
613
  contained += "_"
532
614
  end
533
615
 
534
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
616
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(model_name)}#{full_table_name_suffix}"
535
617
  else
536
- # STI subclasses always use their superclass' table.
618
+ # STI subclasses always use their superclass's table.
537
619
  base_class.table_name
538
620
  end
539
621
  end
622
+
623
+ def type_for_column(connection, column)
624
+ type = connection.lookup_cast_type_from_column(column)
625
+
626
+ if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
627
+ type = type.to_immutable_string
628
+ end
629
+
630
+ type
631
+ end
540
632
  end
541
633
  end
542
634
  end