activerecord 7.1.5.1 → 8.0.2

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +369 -2484
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +2 -1
  6. data/lib/active_record/associations/alias_tracker.rb +31 -23
  7. data/lib/active_record/associations/association.rb +43 -12
  8. data/lib/active_record/associations/belongs_to_association.rb +21 -8
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/association.rb +7 -6
  11. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  13. data/lib/active_record/associations/builder/has_many.rb +3 -4
  14. data/lib/active_record/associations/builder/has_one.rb +3 -4
  15. data/lib/active_record/associations/collection_association.rb +17 -9
  16. data/lib/active_record/associations/collection_proxy.rb +14 -1
  17. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  18. data/lib/active_record/associations/errors.rb +265 -0
  19. data/lib/active_record/associations/has_many_association.rb +1 -1
  20. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  21. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  22. data/lib/active_record/associations/nested_error.rb +47 -0
  23. data/lib/active_record/associations/preloader/association.rb +4 -3
  24. data/lib/active_record/associations/preloader/branch.rb +7 -1
  25. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  26. data/lib/active_record/associations/singular_association.rb +14 -3
  27. data/lib/active_record/associations/through_association.rb +1 -1
  28. data/lib/active_record/associations.rb +92 -295
  29. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  30. data/lib/active_record/attribute_assignment.rb +0 -2
  31. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  32. data/lib/active_record/attribute_methods/primary_key.rb +25 -61
  33. data/lib/active_record/attribute_methods/read.rb +1 -13
  34. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  35. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
  36. data/lib/active_record/attribute_methods.rb +71 -75
  37. data/lib/active_record/attributes.rb +63 -49
  38. data/lib/active_record/autosave_association.rb +92 -57
  39. data/lib/active_record/base.rb +2 -3
  40. data/lib/active_record/callbacks.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
  42. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  43. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
  44. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
  45. data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
  46. data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
  47. data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
  48. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  49. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
  50. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
  51. data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
  52. data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
  53. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
  54. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  55. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
  56. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  57. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
  58. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
  59. data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
  60. data/lib/active_record/connection_adapters/pool_config.rb +14 -13
  61. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
  62. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  63. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  66. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  67. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  68. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
  69. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
  70. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
  72. data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
  73. data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
  74. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  75. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
  76. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
  77. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
  78. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  79. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
  80. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
  81. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
  82. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  83. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
  84. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
  85. data/lib/active_record/connection_adapters.rb +65 -0
  86. data/lib/active_record/connection_handling.rb +74 -37
  87. data/lib/active_record/core.rb +132 -51
  88. data/lib/active_record/counter_cache.rb +19 -10
  89. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
  90. data/lib/active_record/database_configurations/database_config.rb +23 -4
  91. data/lib/active_record/database_configurations/hash_config.rb +46 -34
  92. data/lib/active_record/database_configurations/url_config.rb +20 -1
  93. data/lib/active_record/database_configurations.rb +1 -1
  94. data/lib/active_record/delegated_type.rb +41 -17
  95. data/lib/active_record/dynamic_matchers.rb +2 -2
  96. data/lib/active_record/encryption/config.rb +3 -1
  97. data/lib/active_record/encryption/encryptable_record.rb +7 -7
  98. data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
  99. data/lib/active_record/encryption/encryptor.rb +28 -6
  100. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  101. data/lib/active_record/encryption/key_provider.rb +1 -1
  102. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  103. data/lib/active_record/encryption/message_serializer.rb +4 -0
  104. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  105. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  106. data/lib/active_record/encryption/scheme.rb +8 -1
  107. data/lib/active_record/enum.rb +20 -16
  108. data/lib/active_record/errors.rb +54 -20
  109. data/lib/active_record/explain.rb +13 -24
  110. data/lib/active_record/fixtures.rb +37 -33
  111. data/lib/active_record/future_result.rb +21 -13
  112. data/lib/active_record/gem_version.rb +4 -4
  113. data/lib/active_record/inheritance.rb +4 -2
  114. data/lib/active_record/insert_all.rb +19 -16
  115. data/lib/active_record/integration.rb +4 -1
  116. data/lib/active_record/internal_metadata.rb +48 -34
  117. data/lib/active_record/locking/optimistic.rb +8 -7
  118. data/lib/active_record/log_subscriber.rb +5 -32
  119. data/lib/active_record/message_pack.rb +1 -1
  120. data/lib/active_record/migration/command_recorder.rb +33 -14
  121. data/lib/active_record/migration/compatibility.rb +8 -3
  122. data/lib/active_record/migration/default_strategy.rb +4 -5
  123. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  124. data/lib/active_record/migration.rb +104 -98
  125. data/lib/active_record/model_schema.rb +32 -70
  126. data/lib/active_record/nested_attributes.rb +15 -9
  127. data/lib/active_record/normalization.rb +3 -7
  128. data/lib/active_record/persistence.rb +127 -451
  129. data/lib/active_record/query_cache.rb +19 -8
  130. data/lib/active_record/query_logs.rb +104 -37
  131. data/lib/active_record/query_logs_formatter.rb +17 -28
  132. data/lib/active_record/querying.rb +24 -12
  133. data/lib/active_record/railtie.rb +26 -68
  134. data/lib/active_record/railties/controller_runtime.rb +13 -4
  135. data/lib/active_record/railties/databases.rake +43 -61
  136. data/lib/active_record/reflection.rb +112 -53
  137. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  138. data/lib/active_record/relation/batches.rb +138 -72
  139. data/lib/active_record/relation/calculations.rb +122 -82
  140. data/lib/active_record/relation/delegation.rb +30 -22
  141. data/lib/active_record/relation/finder_methods.rb +32 -18
  142. data/lib/active_record/relation/merger.rb +12 -14
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
  145. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  146. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  147. data/lib/active_record/relation/predicate_builder.rb +16 -3
  148. data/lib/active_record/relation/query_attribute.rb +1 -1
  149. data/lib/active_record/relation/query_methods.rb +317 -101
  150. data/lib/active_record/relation/spawn_methods.rb +3 -19
  151. data/lib/active_record/relation/where_clause.rb +7 -19
  152. data/lib/active_record/relation.rb +561 -119
  153. data/lib/active_record/result.rb +95 -46
  154. data/lib/active_record/runtime_registry.rb +39 -0
  155. data/lib/active_record/sanitization.rb +31 -25
  156. data/lib/active_record/schema.rb +8 -6
  157. data/lib/active_record/schema_dumper.rb +53 -20
  158. data/lib/active_record/schema_migration.rb +31 -14
  159. data/lib/active_record/scoping/named.rb +6 -2
  160. data/lib/active_record/signed_id.rb +24 -4
  161. data/lib/active_record/statement_cache.rb +19 -19
  162. data/lib/active_record/store.rb +7 -3
  163. data/lib/active_record/table_metadata.rb +2 -13
  164. data/lib/active_record/tasks/database_tasks.rb +87 -58
  165. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
  166. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  167. data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
  168. data/lib/active_record/test_fixtures.rb +98 -89
  169. data/lib/active_record/testing/query_assertions.rb +121 -0
  170. data/lib/active_record/timestamp.rb +2 -2
  171. data/lib/active_record/token_for.rb +22 -12
  172. data/lib/active_record/touch_later.rb +1 -1
  173. data/lib/active_record/transaction.rb +132 -0
  174. data/lib/active_record/transactions.rb +72 -17
  175. data/lib/active_record/translation.rb +0 -2
  176. data/lib/active_record/type/serialized.rb +1 -3
  177. data/lib/active_record/type_caster/connection.rb +4 -4
  178. data/lib/active_record/validations/associated.rb +9 -3
  179. data/lib/active_record/validations/uniqueness.rb +23 -18
  180. data/lib/active_record/validations.rb +4 -1
  181. data/lib/active_record.rb +138 -57
  182. data/lib/arel/alias_predication.rb +1 -1
  183. data/lib/arel/collectors/bind.rb +4 -2
  184. data/lib/arel/collectors/composite.rb +7 -0
  185. data/lib/arel/collectors/sql_string.rb +2 -2
  186. data/lib/arel/collectors/substitute_binds.rb +3 -3
  187. data/lib/arel/nodes/binary.rb +1 -7
  188. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  189. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  190. data/lib/arel/nodes/node.rb +5 -4
  191. data/lib/arel/nodes/sql_literal.rb +8 -1
  192. data/lib/arel/nodes.rb +2 -2
  193. data/lib/arel/predications.rb +1 -1
  194. data/lib/arel/select_manager.rb +1 -1
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/tree_manager.rb +3 -2
  197. data/lib/arel/update_manager.rb +2 -1
  198. data/lib/arel/visitors/dot.rb +1 -0
  199. data/lib/arel/visitors/mysql.rb +9 -4
  200. data/lib/arel/visitors/postgresql.rb +1 -12
  201. data/lib/arel/visitors/sqlite.rb +25 -0
  202. data/lib/arel/visitors/to_sql.rb +29 -16
  203. data/lib/arel.rb +7 -3
  204. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  205. metadata +18 -16
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -2,44 +2,17 @@
2
2
 
3
3
  require "active_record/connection_adapters/abstract_mysql_adapter"
4
4
 
5
- gem "trilogy", "~> 2.4"
5
+ gem "trilogy", "~> 2.7"
6
6
  require "trilogy"
7
7
 
8
8
  require "active_record/connection_adapters/trilogy/database_statements"
9
9
 
10
10
  module ActiveRecord
11
- module ConnectionHandling # :nodoc:
12
- def trilogy_adapter_class
13
- ConnectionAdapters::TrilogyAdapter
14
- end
15
-
16
- # Establishes a connection to the database that's used by all Active Record objects.
17
- def trilogy_connection(config)
18
- configuration = config.dup
19
-
20
- # Set FOUND_ROWS capability on the connection so UPDATE queries returns number of rows
21
- # matched rather than number of rows updated.
22
- configuration[:found_rows] = true
23
-
24
- options = [
25
- configuration[:host],
26
- configuration[:port],
27
- configuration[:database],
28
- configuration[:username],
29
- configuration[:password],
30
- configuration[:socket],
31
- 0
32
- ]
33
-
34
- trilogy_adapter_class.new nil, logger, options, configuration
35
- end
36
- end
37
11
  module ConnectionAdapters
38
12
  class TrilogyAdapter < AbstractMysqlAdapter
39
13
  ER_BAD_DB_ERROR = 1049
40
14
  ER_DBACCESS_DENIED_ERROR = 1044
41
15
  ER_ACCESS_DENIED_ERROR = 1045
42
- ER_SERVER_SHUTDOWN = 1053
43
16
 
44
17
  ADAPTER_NAME = "Trilogy"
45
18
 
@@ -99,16 +72,22 @@ module ActiveRecord
99
72
  end
100
73
  end
101
74
 
102
- def initialize(...)
103
- super
75
+ def initialize(config, *)
76
+ config = config.dup
104
77
 
105
- if @config[:prepared_statements]
78
+ # Trilogy ignores `socket` if `host is set. We want the opposite to allow
79
+ # configuring UNIX domain sockets via `DATABASE_URL`.
80
+ config.delete(:host) if config[:socket]
81
+
82
+ # Set FOUND_ROWS capability on the connection so UPDATE queries returns number of rows
83
+ # matched rather than number of rows updated.
84
+ config[:found_rows] = true
85
+
86
+ if config[:prepared_statements]
106
87
  raise ArgumentError, "Trilogy currently doesn't support prepared statements. Remove `prepared_statements: true` from your database configuration."
107
88
  end
108
89
 
109
- # Trilogy ignore `socket` if `host is set. We want the opposite to allow
110
- # configuring UNIX domain sockets via `DATABASE_URL`.
111
- @config.delete(:host) if @config[:socket]
90
+ super
112
91
  end
113
92
 
114
93
  TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
@@ -137,14 +116,12 @@ module ActiveRecord
137
116
  true
138
117
  end
139
118
 
140
- def quote_string(string)
141
- with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
142
- conn.escape(string)
143
- end
119
+ def connected?
120
+ !(@raw_connection.nil? || @raw_connection.closed?)
144
121
  end
145
122
 
146
123
  def active?
147
- !(@raw_connection.nil? || @raw_connection.closed?) && @lock.synchronize { @raw_connection&.ping } || false
124
+ connected? && @lock.synchronize { @raw_connection&.ping; verified! } || false
148
125
  rescue ::Trilogy::Error
149
126
  false
150
127
  end
@@ -172,23 +149,6 @@ module ActiveRecord
172
149
  TYPE_MAP.lookup(type).is_a?(Type::String) || TYPE_MAP.lookup(type).is_a?(Type::Text)
173
150
  end
174
151
 
175
- def each_hash(result)
176
- return to_enum(:each_hash, result) unless block_given?
177
-
178
- keys = result.fields.map(&:to_sym)
179
- result.rows.each do |row|
180
- hash = {}
181
- idx = 0
182
- row.each do |value|
183
- hash[keys[idx]] = value
184
- idx += 1
185
- end
186
- yield hash
187
- end
188
-
189
- nil
190
- end
191
-
192
152
  def error_number(exception)
193
153
  exception.error_code if exception.respond_to?(:error_code)
194
154
  end
@@ -206,7 +166,7 @@ module ActiveRecord
206
166
  end
207
167
 
208
168
  def full_version
209
- schema_cache.database_version.full_version_string
169
+ database_version.full_version_string
210
170
  end
211
171
 
212
172
  def get_full_version
@@ -219,18 +179,12 @@ module ActiveRecord
219
179
  if exception.is_a?(::Trilogy::TimeoutError) && !exception.error_code
220
180
  return ActiveRecord::AdapterTimeout.new(message, sql: sql, binds: binds, connection_pool: @pool)
221
181
  end
222
- error_code = exception.error_code if exception.respond_to?(:error_code)
223
-
224
- case error_code
225
- when ER_SERVER_SHUTDOWN
226
- return ConnectionFailed.new(message, connection_pool: @pool)
227
- end
228
182
 
229
183
  case exception
230
- when Errno::EPIPE, SocketError, IOError
184
+ when ::Trilogy::ConnectionClosed, ::Trilogy::EOFError
231
185
  return ConnectionFailed.new(message, connection_pool: @pool)
232
186
  when ::Trilogy::Error
233
- if /Connection reset by peer|TRILOGY_CLOSED_CONNECTION|TRILOGY_INVALID_SEQUENCE_ID|TRILOGY_UNEXPECTED_PACKET/.match?(exception.message)
187
+ if exception.is_a?(SystemCallError) || exception.message.include?("TRILOGY_INVALID_SEQUENCE_ID")
234
188
  return ConnectionFailed.new(message, connection_pool: @pool)
235
189
  end
236
190
  end
@@ -1,9 +1,74 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/string/filters"
4
+
3
5
  module ActiveRecord
4
6
  module ConnectionAdapters
5
7
  extend ActiveSupport::Autoload
6
8
 
9
+ @adapters = {}
10
+
11
+ class << self
12
+ # Registers a custom database adapter.
13
+ #
14
+ # Can also be used to define aliases.
15
+ #
16
+ # == Example
17
+ #
18
+ # ActiveRecord::ConnectionAdapters.register("megadb", "MegaDB::ActiveRecordAdapter", "mega_db/active_record_adapter")
19
+ #
20
+ # ActiveRecord::ConnectionAdapters.register("mysql", "ActiveRecord::ConnectionAdapters::TrilogyAdapter", "active_record/connection_adapters/trilogy_adapter")
21
+ #
22
+ def register(name, class_name, path = class_name.underscore)
23
+ @adapters[name.to_s] = [class_name, path]
24
+ end
25
+
26
+ def resolve(adapter_name) # :nodoc:
27
+ # Require the adapter itself and give useful feedback about
28
+ # 1. Missing adapter gems.
29
+ # 2. Incorrectly registered adapters.
30
+ # 3. Adapter gems' missing dependencies.
31
+ class_name, path_to_adapter = @adapters[adapter_name.to_s]
32
+
33
+ unless class_name
34
+ raise AdapterNotFound, <<~MSG.squish
35
+ Database configuration specifies nonexistent '#{adapter_name}' adapter.
36
+ Available adapters are: #{@adapters.keys.sort.join(", ")}.
37
+ Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary
38
+ adapter gem to your Gemfile if it's not in the list of available adapters.
39
+ MSG
40
+ end
41
+
42
+ unless Object.const_defined?(class_name)
43
+ begin
44
+ require path_to_adapter
45
+ rescue LoadError => error
46
+ # We couldn't require the adapter itself.
47
+ if error.path == path_to_adapter
48
+ # We can assume here that a non-builtin adapter was specified and the path
49
+ # registered by the adapter gem is incorrect.
50
+ raise LoadError, "Error loading the '#{adapter_name}' Active Record adapter. Ensure that the path registered by the adapter gem is correct. #{error.message}", error.backtrace
51
+ else
52
+ # Bubbled up from the adapter require. Prefix the exception message
53
+ # with some guidance about how to address it and reraise.
54
+ raise LoadError, "Error loading the '#{adapter_name}' Active Record adapter. Missing a gem it depends on? #{error.message}", error.backtrace
55
+ end
56
+ end
57
+ end
58
+
59
+ begin
60
+ Object.const_get(class_name)
61
+ rescue NameError => error
62
+ raise AdapterNotFound, "Could not load the #{class_name} Active Record adapter (#{error.message})."
63
+ end
64
+ end
65
+ end
66
+
67
+ register "sqlite3", "ActiveRecord::ConnectionAdapters::SQLite3Adapter", "active_record/connection_adapters/sqlite3_adapter"
68
+ register "mysql2", "ActiveRecord::ConnectionAdapters::Mysql2Adapter", "active_record/connection_adapters/mysql2_adapter"
69
+ register "trilogy", "ActiveRecord::ConnectionAdapters::TrilogyAdapter", "active_record/connection_adapters/trilogy_adapter"
70
+ register "postgresql", "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter", "active_record/connection_adapters/postgresql_adapter"
71
+
7
72
  eager_autoload do
8
73
  autoload :AbstractAdapter
9
74
  end
@@ -87,6 +87,8 @@ module ActiveRecord
87
87
 
88
88
  connections = []
89
89
 
90
+ @shard_keys = shards.keys
91
+
90
92
  if shards.empty?
91
93
  shards[:default] = database
92
94
  end
@@ -175,6 +177,18 @@ module ActiveRecord
175
177
  connected_to_stack.pop
176
178
  end
177
179
 
180
+ # Passes the block to +connected_to+ for every +shard+ the
181
+ # model is configured to connect to (if any), and returns the
182
+ # results in an array.
183
+ #
184
+ # Optionally, +role+ and/or +prevent_writes+ can be passed which
185
+ # will be forwarded to each +connected_to+ call.
186
+ def connected_to_all_shards(role: nil, prevent_writes: false, &blk)
187
+ shard_keys.map do |shard|
188
+ connected_to(shard: shard, role: role, prevent_writes: prevent_writes, &blk)
189
+ end
190
+ end
191
+
178
192
  # Use a specified connection.
179
193
  #
180
194
  # This method is useful for ensuring that a specific connection is
@@ -243,22 +257,64 @@ module ActiveRecord
243
257
  # Clears the query cache for all connections associated with the current thread.
244
258
  def clear_query_caches_for_current_thread
245
259
  connection_handler.each_connection_pool do |pool|
246
- pool.connection.clear_query_cache if pool.active_connection?
260
+ pool.clear_query_cache
247
261
  end
248
262
  end
249
263
 
250
264
  # Returns the connection currently associated with the class. This can
251
265
  # also be used to "borrow" the connection to do database work unrelated
252
266
  # to any of the specific Active Records.
267
+ # The connection will remain leased for the entire duration of the request
268
+ # or job, or until +#release_connection+ is called.
269
+ def lease_connection
270
+ connection_pool.lease_connection
271
+ end
272
+
273
+ # Soft deprecated. Use +#with_connection+ or +#lease_connection+ instead.
253
274
  def connection
254
- retrieve_connection
275
+ pool = connection_pool
276
+ if pool.permanent_lease?
277
+ case ActiveRecord.permanent_connection_checkout
278
+ when :deprecated
279
+ ActiveRecord.deprecator.warn <<~MESSAGE
280
+ Called deprecated `ActiveRecord::Base.connection` method.
281
+
282
+ Either use `with_connection` or `lease_connection`.
283
+ MESSAGE
284
+ when :disallowed
285
+ raise ActiveRecordError, <<~MESSAGE
286
+ Called deprecated `ActiveRecord::Base.connection` method.
287
+
288
+ Either use `with_connection` or `lease_connection`.
289
+ MESSAGE
290
+ end
291
+ pool.lease_connection
292
+ else
293
+ pool.active_connection
294
+ end
295
+ end
296
+
297
+ # Return the currently leased connection into the pool
298
+ def release_connection
299
+ connection_pool.release_connection
300
+ end
301
+
302
+ # Checkouts a connection from the pool, yield it and then check it back in.
303
+ # If a connection was already leased via #lease_connection or a parent call to
304
+ # #with_connection, that same connection is yieled.
305
+ # If #lease_connection is called inside the block, the connection won't be checked
306
+ # back in.
307
+ # If #connection is called inside the block, the connection won't be checked back in
308
+ # unless the +prevent_permanent_checkout+ argument is set to +true+.
309
+ def with_connection(prevent_permanent_checkout: false, &block)
310
+ connection_pool.with_connection(prevent_permanent_checkout: prevent_permanent_checkout, &block)
255
311
  end
256
312
 
257
313
  attr_writer :connection_specification_name
258
314
 
259
315
  # Returns the connection specification name from the current class or its parent.
260
316
  def connection_specification_name
261
- if !defined?(@connection_specification_name) || @connection_specification_name.nil?
317
+ if @connection_specification_name.nil?
262
318
  return self == Base ? Base.name : superclass.connection_specification_name
263
319
  end
264
320
  @connection_specification_name
@@ -279,8 +335,12 @@ module ActiveRecord
279
335
  connection_pool.db_config
280
336
  end
281
337
 
338
+ def adapter_class # :nodoc:
339
+ connection_pool.db_config.adapter_class
340
+ end
341
+
282
342
  def connection_pool
283
- connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard) || raise(ConnectionNotEstablished)
343
+ connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard, strict: true)
284
344
  end
285
345
 
286
346
  def retrieve_connection
@@ -292,16 +352,9 @@ module ActiveRecord
292
352
  connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard)
293
353
  end
294
354
 
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
355
+ def remove_connection
356
+ name = @connection_specification_name if defined?(@connection_specification_name)
303
357
 
304
- name ||= @connection_specification_name if defined?(@connection_specification_name)
305
358
  # if removing a connection that has a pool, we reset the
306
359
  # connection_specification_name so it will use the parent
307
360
  # pool.
@@ -312,39 +365,23 @@ module ActiveRecord
312
365
  connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
313
366
  end
314
367
 
315
- def clear_cache! # :nodoc:
316
- connection.schema_cache.clear!
368
+ def schema_cache # :nodoc:
369
+ connection_pool.schema_cache
317
370
  end
318
371
 
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)
372
+ def clear_cache! # :nodoc:
373
+ connection_pool.schema_cache.clear!
327
374
  end
328
375
 
329
- def clear_all_connections!(role = nil)
330
- deprecation_for_delegation(__method__)
331
- connection_handler.clear_all_connections!(role)
376
+ def shard_keys
377
+ connection_class_for_self.instance_variable_get(:@shard_keys) || []
332
378
  end
333
379
 
334
- def flush_idle_connections!(role = nil)
335
- deprecation_for_delegation(__method__)
336
- connection_handler.flush_idle_connections!(role)
380
+ def sharded?
381
+ shard_keys.any?
337
382
  end
338
383
 
339
384
  private
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
346
- end
347
-
348
385
  def resolve_config_for_connection(config_or_env)
349
386
  raise "Anonymous class is not allowed." unless name
350
387