activerecord 6.1.7 → 7.1.5

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 (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +51 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +39 -35
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
+ # = Active Record Connection Handling
4
5
  module ConnectionHandling
5
6
  RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
6
7
  DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
@@ -38,26 +39,25 @@ module ActiveRecord
38
39
  # )
39
40
  #
40
41
  # In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
41
- # is set (Rails automatically loads the contents of config/database.yml into it),
42
+ # is set (\Rails automatically loads the contents of config/database.yml into it),
42
43
  # a symbol can also be given as argument, representing a key in the
43
44
  # configuration hash:
44
45
  #
45
46
  # ActiveRecord::Base.establish_connection(:production)
46
47
  #
47
- # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
48
+ # The exceptions AdapterNotSpecified, AdapterNotFound, and +ArgumentError+
48
49
  # may be returned on an error.
49
50
  def establish_connection(config_or_env = nil)
50
51
  config_or_env ||= DEFAULT_ENV.call.to_sym
51
- db_config, owner_name = resolve_config_for_connection(config_or_env)
52
- connection_handler.establish_connection(db_config, owner_name: owner_name, role: current_role, shard: current_shard)
52
+ db_config = resolve_config_for_connection(config_or_env)
53
+ connection_handler.establish_connection(db_config, owner_name: self, role: current_role, shard: current_shard)
53
54
  end
54
55
 
55
56
  # Connects a model to the databases specified. The +database+ keyword
56
57
  # takes a hash consisting of a +role+ and a +database_key+.
57
58
  #
58
- # This will create a connection handler for switching between connections,
59
- # look up the config hash using the +database_key+ and finally
60
- # establishes a connection to that config.
59
+ # This will look up the database config using the +database_key+ and
60
+ # establish a connection to that config.
61
61
  #
62
62
  # class AnimalsModel < ApplicationRecord
63
63
  # self.abstract_class = true
@@ -66,7 +66,7 @@ module ActiveRecord
66
66
  # end
67
67
  #
68
68
  # +connects_to+ also supports horizontal sharding. The horizontal sharding API
69
- # also supports read replicas. Connect a model to a list of shards like this:
69
+ # supports read replicas as well. You can connect a model to a list of shards like this:
70
70
  #
71
71
  # class AnimalsModel < ApplicationRecord
72
72
  # self.abstract_class = true
@@ -87,28 +87,25 @@ module ActiveRecord
87
87
 
88
88
  connections = []
89
89
 
90
- database.each do |role, database_key|
91
- db_config, owner_name = resolve_config_for_connection(database_key)
92
- handler = lookup_connection_handler(role.to_sym)
93
-
94
- self.connection_class = true
95
- connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
90
+ if shards.empty?
91
+ shards[:default] = database
96
92
  end
97
93
 
94
+ self.default_shard = shards.keys.first
95
+
98
96
  shards.each do |shard, database_keys|
99
97
  database_keys.each do |role, database_key|
100
- db_config, owner_name = resolve_config_for_connection(database_key)
101
- handler = lookup_connection_handler(role.to_sym)
98
+ db_config = resolve_config_for_connection(database_key)
102
99
 
103
100
  self.connection_class = true
104
- connections << handler.establish_connection(db_config, owner_name: owner_name, role: role, shard: shard.to_sym)
101
+ connections << connection_handler.establish_connection(db_config, owner_name: self, role: role, shard: shard.to_sym)
105
102
  end
106
103
  end
107
104
 
108
105
  connections
109
106
  end
110
107
 
111
- # Connects to a role (ex writing, reading or a custom role) and/or
108
+ # Connects to a role (e.g. writing, reading, or a custom role) and/or
112
109
  # shard for the duration of the block. At the end of the block the
113
110
  # connection will be returned to the original role / shard.
114
111
  #
@@ -134,48 +131,20 @@ module ActiveRecord
134
131
  # ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do
135
132
  # Dog.first # finds first Dog record stored on the shard one replica
136
133
  # end
137
- #
138
- # The database kwarg is deprecated and will be removed in Rails 7.0.0 without replacement.
139
- def connected_to(database: nil, role: nil, shard: nil, prevent_writes: false, &blk)
140
- if legacy_connection_handling
141
- if self != Base
142
- raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
143
- end
144
- else
145
- if self != Base && !abstract_class
146
- raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
147
- end
148
-
149
- if name != connection_specification_name && !primary_class?
150
- raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
151
- end
134
+ def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
135
+ if self != Base && !abstract_class
136
+ raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
152
137
  end
153
138
 
154
- if database && (role || shard)
155
- raise ArgumentError, "`connected_to` cannot accept a `database` argument with any other arguments."
156
- elsif database
157
- ActiveSupport::Deprecation.warn("The database key in `connected_to` is deprecated. It will be removed in Rails 7.0.0 without replacement.")
158
-
159
- if database.is_a?(Hash)
160
- role, database = database.first
161
- role = role.to_sym
162
- end
163
-
164
- db_config, owner_name = resolve_config_for_connection(database)
165
- handler = lookup_connection_handler(role)
166
-
167
- handler.establish_connection(db_config, owner_name: owner_name, role: role)
168
-
169
- with_handler(role, &blk)
170
- elsif role || shard
171
- unless role
172
- raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
173
- end
139
+ if !connection_class? && !primary_class?
140
+ raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
141
+ end
174
142
 
175
- with_role_and_shard(role, shard, prevent_writes, &blk)
176
- else
143
+ unless role || shard
177
144
  raise ArgumentError, "must provide a `shard` and/or `role`."
178
145
  end
146
+
147
+ with_role_and_shard(role, shard, prevent_writes, &blk)
179
148
  end
180
149
 
181
150
  # Connects a role and/or shard to the provided connection names. Optionally +prevent_writes+
@@ -194,17 +163,13 @@ module ActiveRecord
194
163
  def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
195
164
  classes = classes.flatten
196
165
 
197
- if legacy_connection_handling
198
- raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
199
- end
200
-
201
166
  if self != Base || classes.include?(Base)
202
167
  raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
203
168
  end
204
169
 
205
- prevent_writes = true if role == reading_role
170
+ prevent_writes = true if role == ActiveRecord.reading_role
206
171
 
207
- connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes }
172
+ append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
208
173
  yield
209
174
  ensure
210
175
  connected_to_stack.pop
@@ -218,13 +183,28 @@ module ActiveRecord
218
183
  # It is not recommended to use this method in a request since it
219
184
  # does not yield to a block like +connected_to+.
220
185
  def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
221
- if legacy_connection_handling
222
- raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
223
- end
186
+ prevent_writes = true if role == ActiveRecord.reading_role
224
187
 
225
- prevent_writes = true if role == reading_role
188
+ append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
189
+ end
190
+
191
+ # Prohibit swapping shards while inside of the passed block.
192
+ #
193
+ # In some cases you may want to be able to swap shards but not allow a
194
+ # nested call to connected_to or connected_to_many to swap again. This
195
+ # is useful in cases you're using sharding to provide per-request
196
+ # database isolation.
197
+ def prohibit_shard_swapping(enabled = true)
198
+ prev_value = ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping]
199
+ ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = enabled
200
+ yield
201
+ ensure
202
+ ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = prev_value
203
+ end
226
204
 
227
- self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
205
+ # Determine whether or not shard swapping is currently prohibited
206
+ def shard_swapping_prohibited?
207
+ ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping]
228
208
  end
229
209
 
230
210
  # Prevent writing to the database regardless of role.
@@ -239,40 +219,31 @@ module ActiveRecord
239
219
  # See +READ_QUERY+ for the queries that are blocked by this
240
220
  # method.
241
221
  def while_preventing_writes(enabled = true, &block)
242
- if legacy_connection_handling
243
- connection_handler.while_preventing_writes(enabled, &block)
244
- else
245
- connected_to(role: current_role, prevent_writes: enabled, &block)
246
- end
222
+ connected_to(role: current_role, prevent_writes: enabled, &block)
247
223
  end
248
224
 
249
- # Returns true if role is the current connected role.
225
+ # Returns true if role is the current connected role and/or
226
+ # current connected shard. If no shard is passed, the default will be
227
+ # used.
250
228
  #
251
229
  # ActiveRecord::Base.connected_to(role: :writing) do
252
230
  # ActiveRecord::Base.connected_to?(role: :writing) #=> true
253
231
  # ActiveRecord::Base.connected_to?(role: :reading) #=> false
254
232
  # end
233
+ #
234
+ # ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
235
+ # ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one) #=> true
236
+ # ActiveRecord::Base.connected_to?(role: :reading, shard: :default) #=> false
237
+ # ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one) #=> true
238
+ # end
255
239
  def connected_to?(role:, shard: ActiveRecord::Base.default_shard)
256
240
  current_role == role.to_sym && current_shard == shard.to_sym
257
241
  end
258
242
 
259
- def lookup_connection_handler(handler_key) # :nodoc:
260
- if ActiveRecord::Base.legacy_connection_handling
261
- handler_key ||= ActiveRecord::Base.writing_role
262
- connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
263
- else
264
- ActiveRecord::Base.connection_handler
265
- end
266
- end
267
-
268
243
  # Clears the query cache for all connections associated with the current thread.
269
244
  def clear_query_caches_for_current_thread
270
- if ActiveRecord::Base.legacy_connection_handling
271
- ActiveRecord::Base.connection_handlers.each_value do |handler|
272
- clear_on_handler(handler)
273
- end
274
- else
275
- clear_on_handler(ActiveRecord::Base.connection_handler)
245
+ connection_handler.each_connection_pool do |pool|
246
+ pool.connection.clear_query_cache if pool.active_connection?
276
247
  end
277
248
  end
278
249
 
@@ -285,7 +256,7 @@ module ActiveRecord
285
256
 
286
257
  attr_writer :connection_specification_name
287
258
 
288
- # Return the connection specification name from the current class or its parent.
259
+ # Returns the connection specification name from the current class or its parent.
289
260
  def connection_specification_name
290
261
  if !defined?(@connection_specification_name) || @connection_specification_name.nil?
291
262
  return self == Base ? Base.name : superclass.connection_specification_name
@@ -294,25 +265,14 @@ module ActiveRecord
294
265
  end
295
266
 
296
267
  def primary_class? # :nodoc:
297
- self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
298
- end
299
-
300
- # Returns the configuration of the associated connection as a hash:
301
- #
302
- # ActiveRecord::Base.connection_config
303
- # # => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}
304
- #
305
- # Please use only for reading.
306
- def connection_config
307
- connection_pool.db_config.configuration_hash
268
+ self == Base || application_record_class?
308
269
  end
309
- deprecate connection_config: "Use connection_db_config instead"
310
270
 
311
271
  # Returns the db_config object from the associated connection:
312
272
  #
313
273
  # ActiveRecord::Base.connection_db_config
314
274
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
315
- # @name="primary", @config={pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}>
275
+ # @name="primary", @config={pool: 5, timeout: 5000, database: "storage/development.sqlite3", adapter: "sqlite3"}>
316
276
  #
317
277
  # Use only for reading.
318
278
  def connection_db_config
@@ -333,6 +293,14 @@ module ActiveRecord
333
293
  end
334
294
 
335
295
  def remove_connection(name = nil)
296
+ if name
297
+ ActiveRecord.deprecator.warn(<<-MSG.squish)
298
+ The name argument for `#remove_connection` is deprecated without replacement
299
+ and will be removed in Rails 7.2. `#remove_connection` should always be called
300
+ on the connection class directly, which makes the name argument obsolete.
301
+ MSG
302
+ end
303
+
336
304
  name ||= @connection_specification_name if defined?(@connection_specification_name)
337
305
  # if removing a connection that has a pool, we reset the
338
306
  # connection_specification_name so it will use the parent
@@ -348,58 +316,61 @@ module ActiveRecord
348
316
  connection.schema_cache.clear!
349
317
  end
350
318
 
351
- delegate :clear_active_connections!, :clear_reloadable_connections!,
352
- :clear_all_connections!, :flush_idle_connections!, to: :connection_handler
319
+ def clear_active_connections!(role = nil)
320
+ deprecation_for_delegation(__method__)
321
+ connection_handler.clear_active_connections!(role)
322
+ end
323
+
324
+ def clear_reloadable_connections!(role = nil)
325
+ deprecation_for_delegation(__method__)
326
+ connection_handler.clear_reloadable_connections!(role)
327
+ end
328
+
329
+ def clear_all_connections!(role = nil)
330
+ deprecation_for_delegation(__method__)
331
+ connection_handler.clear_all_connections!(role)
332
+ end
333
+
334
+ def flush_idle_connections!(role = nil)
335
+ deprecation_for_delegation(__method__)
336
+ connection_handler.flush_idle_connections!(role)
337
+ end
353
338
 
354
339
  private
355
- def clear_on_handler(handler)
356
- handler.all_connection_pools.each do |pool|
357
- pool.connection.clear_query_cache if pool.active_connection?
358
- end
340
+ def deprecation_for_delegation(method)
341
+ ActiveRecord.deprecator.warn(<<-MSG.squish)
342
+ Calling `ActiveRecord::Base.#{method} is deprecated. Please
343
+ call the method directly on the connection handler; for
344
+ example: `ActiveRecord::Base.connection_handler.#{method}`.
345
+ MSG
359
346
  end
360
347
 
361
348
  def resolve_config_for_connection(config_or_env)
362
349
  raise "Anonymous class is not allowed." unless name
363
350
 
364
- owner_name = primary_class? ? Base.name : name
365
- self.connection_specification_name = owner_name
351
+ connection_name = primary_class? ? Base.name : name
352
+ self.connection_specification_name = connection_name
366
353
 
367
- db_config = Base.configurations.resolve(config_or_env)
368
- [db_config, self]
369
- end
370
-
371
- def with_handler(handler_key, &blk)
372
- handler = lookup_connection_handler(handler_key)
373
- swap_connection_handler(handler, &blk)
354
+ Base.configurations.resolve(config_or_env)
374
355
  end
375
356
 
376
357
  def with_role_and_shard(role, shard, prevent_writes)
377
- prevent_writes = true if role == reading_role
378
-
379
- if ActiveRecord::Base.legacy_connection_handling
380
- with_handler(role.to_sym) do
381
- connection_handler.while_preventing_writes(prevent_writes) do
382
- self.connected_to_stack << { shard: shard, klasses: [self] }
383
- yield
384
- end
385
- end
386
- else
387
- self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
388
- return_value = yield
389
- return_value.load if return_value.is_a? ActiveRecord::Relation
390
- return_value
391
- end
392
- ensure
393
- self.connected_to_stack.pop
394
- end
358
+ prevent_writes = true if role == ActiveRecord.reading_role
395
359
 
396
- def swap_connection_handler(handler, &blk) # :nodoc:
397
- old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
360
+ append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
398
361
  return_value = yield
399
362
  return_value.load if return_value.is_a? ActiveRecord::Relation
400
363
  return_value
401
364
  ensure
402
- ActiveRecord::Base.connection_handler = old_handler
365
+ self.connected_to_stack.pop
366
+ end
367
+
368
+ def append_to_connected_to_stack(entry)
369
+ if shard_swapping_prohibited? && entry[:shard].present?
370
+ raise ArgumentError, "cannot swap `shard` while shard swapping is prohibited."
371
+ end
372
+
373
+ connected_to_stack << entry
403
374
  end
404
375
  end
405
376
  end