activerecord 7.0.7.2 → 7.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1353 -1492
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +15 -16
  5. data/lib/active_record/aggregations.rb +16 -13
  6. data/lib/active_record/association_relation.rb +1 -1
  7. data/lib/active_record/associations/association.rb +18 -3
  8. data/lib/active_record/associations/association_scope.rb +16 -9
  9. data/lib/active_record/associations/belongs_to_association.rb +14 -6
  10. data/lib/active_record/associations/builder/association.rb +3 -3
  11. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  13. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  14. data/lib/active_record/associations/collection_association.rb +18 -10
  15. data/lib/active_record/associations/collection_proxy.rb +21 -11
  16. data/lib/active_record/associations/foreign_association.rb +10 -3
  17. data/lib/active_record/associations/has_many_association.rb +20 -13
  18. data/lib/active_record/associations/has_many_through_association.rb +10 -6
  19. data/lib/active_record/associations/has_one_association.rb +10 -3
  20. data/lib/active_record/associations/join_dependency.rb +10 -8
  21. data/lib/active_record/associations/preloader/association.rb +27 -6
  22. data/lib/active_record/associations/preloader.rb +12 -9
  23. data/lib/active_record/associations/singular_association.rb +1 -1
  24. data/lib/active_record/associations/through_association.rb +22 -11
  25. data/lib/active_record/associations.rb +193 -97
  26. data/lib/active_record/attribute_assignment.rb +0 -2
  27. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  28. data/lib/active_record/attribute_methods/dirty.rb +40 -26
  29. data/lib/active_record/attribute_methods/primary_key.rb +76 -24
  30. data/lib/active_record/attribute_methods/query.rb +28 -16
  31. data/lib/active_record/attribute_methods/read.rb +18 -5
  32. data/lib/active_record/attribute_methods/serialization.rb +150 -31
  33. data/lib/active_record/attribute_methods/write.rb +3 -3
  34. data/lib/active_record/attribute_methods.rb +105 -21
  35. data/lib/active_record/attributes.rb +3 -3
  36. data/lib/active_record/autosave_association.rb +55 -9
  37. data/lib/active_record/base.rb +7 -2
  38. data/lib/active_record/callbacks.rb +10 -24
  39. data/lib/active_record/coders/column_serializer.rb +61 -0
  40. data/lib/active_record/coders/json.rb +1 -1
  41. data/lib/active_record/coders/yaml_column.rb +70 -42
  42. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
  43. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  44. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
  45. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
  46. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  47. data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
  48. data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
  49. data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
  50. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  51. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  52. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
  53. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
  54. data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
  55. data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
  56. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
  57. data/lib/active_record/connection_adapters/column.rb +9 -0
  58. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  59. data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -144
  60. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
  61. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  62. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
  63. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -12
  65. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
  66. data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
  67. data/lib/active_record/connection_adapters/pool_config.rb +14 -5
  68. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  69. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
  70. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
  71. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  72. data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
  73. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  74. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  75. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
  76. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
  79. data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
  80. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  81. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
  82. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
  83. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  84. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
  85. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +163 -81
  86. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  87. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
  88. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  89. data/lib/active_record/connection_adapters.rb +3 -1
  90. data/lib/active_record/connection_handling.rb +71 -94
  91. data/lib/active_record/core.rb +128 -138
  92. data/lib/active_record/counter_cache.rb +46 -25
  93. data/lib/active_record/database_configurations/database_config.rb +9 -3
  94. data/lib/active_record/database_configurations/hash_config.rb +22 -12
  95. data/lib/active_record/database_configurations/url_config.rb +17 -11
  96. data/lib/active_record/database_configurations.rb +86 -33
  97. data/lib/active_record/delegated_type.rb +8 -3
  98. data/lib/active_record/deprecator.rb +7 -0
  99. data/lib/active_record/destroy_association_async_job.rb +2 -0
  100. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  101. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  102. data/lib/active_record/encryption/config.rb +25 -1
  103. data/lib/active_record/encryption/configurable.rb +12 -19
  104. data/lib/active_record/encryption/context.rb +10 -3
  105. data/lib/active_record/encryption/contexts.rb +5 -1
  106. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  107. data/lib/active_record/encryption/encryptable_record.rb +36 -18
  108. data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
  109. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
  110. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
  111. data/lib/active_record/encryption/key_generator.rb +12 -1
  112. data/lib/active_record/encryption/message_serializer.rb +2 -0
  113. data/lib/active_record/encryption/properties.rb +3 -3
  114. data/lib/active_record/encryption/scheme.rb +19 -22
  115. data/lib/active_record/encryption.rb +1 -0
  116. data/lib/active_record/enum.rb +113 -26
  117. data/lib/active_record/errors.rb +89 -15
  118. data/lib/active_record/explain.rb +23 -3
  119. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  120. data/lib/active_record/fixture_set/render_context.rb +2 -0
  121. data/lib/active_record/fixture_set/table_row.rb +29 -8
  122. data/lib/active_record/fixtures.rb +119 -71
  123. data/lib/active_record/future_result.rb +30 -5
  124. data/lib/active_record/gem_version.rb +4 -4
  125. data/lib/active_record/inheritance.rb +30 -16
  126. data/lib/active_record/insert_all.rb +55 -8
  127. data/lib/active_record/integration.rb +8 -8
  128. data/lib/active_record/internal_metadata.rb +118 -30
  129. data/lib/active_record/locking/pessimistic.rb +5 -2
  130. data/lib/active_record/log_subscriber.rb +29 -12
  131. data/lib/active_record/marshalling.rb +56 -0
  132. data/lib/active_record/message_pack.rb +124 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  134. data/lib/active_record/middleware/database_selector.rb +5 -7
  135. data/lib/active_record/middleware/shard_selector.rb +3 -1
  136. data/lib/active_record/migration/command_recorder.rb +100 -4
  137. data/lib/active_record/migration/compatibility.rb +142 -58
  138. data/lib/active_record/migration/default_strategy.rb +23 -0
  139. data/lib/active_record/migration/execution_strategy.rb +19 -0
  140. data/lib/active_record/migration.rb +265 -112
  141. data/lib/active_record/model_schema.rb +47 -27
  142. data/lib/active_record/nested_attributes.rb +28 -3
  143. data/lib/active_record/normalization.rb +158 -0
  144. data/lib/active_record/persistence.rb +183 -33
  145. data/lib/active_record/promise.rb +84 -0
  146. data/lib/active_record/query_cache.rb +3 -21
  147. data/lib/active_record/query_logs.rb +77 -52
  148. data/lib/active_record/query_logs_formatter.rb +41 -0
  149. data/lib/active_record/querying.rb +15 -2
  150. data/lib/active_record/railtie.rb +107 -45
  151. data/lib/active_record/railties/controller_runtime.rb +10 -5
  152. data/lib/active_record/railties/databases.rake +139 -145
  153. data/lib/active_record/railties/job_runtime.rb +23 -0
  154. data/lib/active_record/readonly_attributes.rb +32 -5
  155. data/lib/active_record/reflection.rb +169 -45
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
  157. data/lib/active_record/relation/batches.rb +190 -61
  158. data/lib/active_record/relation/calculations.rb +152 -63
  159. data/lib/active_record/relation/delegation.rb +22 -8
  160. data/lib/active_record/relation/finder_methods.rb +85 -15
  161. data/lib/active_record/relation/merger.rb +2 -0
  162. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
  163. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  164. data/lib/active_record/relation/predicate_builder.rb +26 -14
  165. data/lib/active_record/relation/query_attribute.rb +2 -1
  166. data/lib/active_record/relation/query_methods.rb +351 -62
  167. data/lib/active_record/relation/spawn_methods.rb +18 -1
  168. data/lib/active_record/relation.rb +76 -35
  169. data/lib/active_record/result.rb +19 -5
  170. data/lib/active_record/runtime_registry.rb +10 -1
  171. data/lib/active_record/sanitization.rb +51 -11
  172. data/lib/active_record/schema.rb +2 -3
  173. data/lib/active_record/schema_dumper.rb +41 -7
  174. data/lib/active_record/schema_migration.rb +68 -33
  175. data/lib/active_record/scoping/default.rb +15 -5
  176. data/lib/active_record/scoping/named.rb +2 -2
  177. data/lib/active_record/scoping.rb +2 -1
  178. data/lib/active_record/secure_password.rb +60 -0
  179. data/lib/active_record/secure_token.rb +21 -3
  180. data/lib/active_record/signed_id.rb +7 -5
  181. data/lib/active_record/store.rb +8 -8
  182. data/lib/active_record/suppressor.rb +3 -1
  183. data/lib/active_record/table_metadata.rb +11 -2
  184. data/lib/active_record/tasks/database_tasks.rb +127 -105
  185. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  186. data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
  187. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -7
  188. data/lib/active_record/test_fixtures.rb +113 -96
  189. data/lib/active_record/timestamp.rb +26 -14
  190. data/lib/active_record/token_for.rb +113 -0
  191. data/lib/active_record/touch_later.rb +11 -6
  192. data/lib/active_record/transactions.rb +36 -10
  193. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  194. data/lib/active_record/type/internal/timezone.rb +7 -2
  195. data/lib/active_record/type/time.rb +4 -0
  196. data/lib/active_record/validations/absence.rb +1 -1
  197. data/lib/active_record/validations/numericality.rb +5 -4
  198. data/lib/active_record/validations/presence.rb +5 -28
  199. data/lib/active_record/validations/uniqueness.rb +47 -2
  200. data/lib/active_record/validations.rb +8 -4
  201. data/lib/active_record/version.rb +1 -1
  202. data/lib/active_record.rb +121 -16
  203. data/lib/arel/errors.rb +10 -0
  204. data/lib/arel/factory_methods.rb +4 -0
  205. data/lib/arel/nodes/and.rb +4 -0
  206. data/lib/arel/nodes/binary.rb +6 -1
  207. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  208. data/lib/arel/nodes/cte.rb +36 -0
  209. data/lib/arel/nodes/fragments.rb +35 -0
  210. data/lib/arel/nodes/homogeneous_in.rb +0 -8
  211. data/lib/arel/nodes/leading_join.rb +8 -0
  212. data/lib/arel/nodes/node.rb +111 -2
  213. data/lib/arel/nodes/sql_literal.rb +6 -0
  214. data/lib/arel/nodes/table_alias.rb +4 -0
  215. data/lib/arel/nodes.rb +4 -0
  216. data/lib/arel/predications.rb +2 -0
  217. data/lib/arel/table.rb +9 -5
  218. data/lib/arel/visitors/mysql.rb +8 -1
  219. data/lib/arel/visitors/to_sql.rb +81 -17
  220. data/lib/arel/visitors/visitor.rb +2 -2
  221. data/lib/arel.rb +16 -2
  222. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  223. data/lib/rails/generators/active_record/migration.rb +3 -1
  224. data/lib/rails/generators/active_record/model/USAGE +113 -0
  225. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  226. metadata +49 -14
  227. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  228. data/lib/active_record/null_relation.rb +0 -63
@@ -1,14 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/enumerable"
4
- require "active_support/core_ext/hash/indifferent_access"
5
- require "active_support/core_ext/string/filters"
4
+ require "active_support/core_ext/module/delegation"
6
5
  require "active_support/parameter_filter"
7
6
  require "concurrent/map"
8
7
 
9
8
  module ActiveRecord
9
+ # = Active Record \Core
10
10
  module Core
11
11
  extend ActiveSupport::Concern
12
+ include ActiveModel::Access
12
13
 
13
14
  included do
14
15
  ##
@@ -19,11 +20,30 @@ module ActiveRecord
19
20
  # retrieved on both a class and instance level by calling +logger+.
20
21
  class_attribute :logger, instance_writer: false
21
22
 
23
+ class_attribute :_destroy_association_async_job, instance_accessor: false, default: "ActiveRecord::DestroyAssociationAsyncJob"
24
+
25
+ # The job class used to destroy associations in the background.
26
+ def self.destroy_association_async_job
27
+ if _destroy_association_async_job.is_a?(String)
28
+ self._destroy_association_async_job = _destroy_association_async_job.constantize
29
+ end
30
+ _destroy_association_async_job
31
+ rescue NameError => error
32
+ raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
33
+ end
34
+
35
+ singleton_class.alias_method :destroy_association_async_job=, :_destroy_association_async_job=
36
+ delegate :destroy_association_async_job, to: :class
37
+
22
38
  ##
23
39
  # :singleton-method:
24
40
  #
25
- # Specifies the job used to destroy associations in the background
26
- class_attribute :destroy_association_async_job, instance_writer: false, instance_predicate: false, default: false
41
+ # Specifies the maximum number of records that will be destroyed in a
42
+ # single background job by the <tt>dependent: :destroy_async</tt>
43
+ # association option. When +nil+ (default), all dependent records will be
44
+ # destroyed in a single background job. If specified, the records to be
45
+ # destroyed will be split into multiple background jobs.
46
+ class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil
27
47
 
28
48
  ##
29
49
  # Contains the database configuration - as is typically stored in config/database.yml -
@@ -33,19 +53,19 @@ module ActiveRecord
33
53
  #
34
54
  # development:
35
55
  # adapter: sqlite3
36
- # database: db/development.sqlite3
56
+ # database: storage/development.sqlite3
37
57
  #
38
58
  # production:
39
59
  # adapter: sqlite3
40
- # database: db/production.sqlite3
60
+ # database: storage/production.sqlite3
41
61
  #
42
62
  # ...would result in ActiveRecord::Base.configurations to look like this:
43
63
  #
44
64
  # #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
45
65
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
46
- # @name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
66
+ # @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
47
67
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
48
- # @name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
68
+ # @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
49
69
  # ]>
50
70
  def self.configurations=(config)
51
71
  @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
@@ -71,6 +91,8 @@ module ActiveRecord
71
91
 
72
92
  class_attribute :has_many_inversing, instance_accessor: false, default: false
73
93
 
94
+ class_attribute :run_commit_callbacks_on_first_saved_instances_in_transaction, instance_accessor: false, default: true
95
+
74
96
  class_attribute :default_connection_handler, instance_writer: false
75
97
 
76
98
  class_attribute :default_role, instance_writer: false
@@ -99,33 +121,6 @@ module ActiveRecord
99
121
  ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
100
122
  end
101
123
 
102
- def self.connection_handlers
103
- if ActiveRecord.legacy_connection_handling
104
- else
105
- raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
106
- end
107
-
108
- @@connection_handlers ||= {}
109
- end
110
-
111
- def self.connection_handlers=(handlers)
112
- if ActiveRecord.legacy_connection_handling
113
- ActiveSupport::Deprecation.warn(<<~MSG)
114
- Using legacy connection handling is deprecated. Please set
115
- `legacy_connection_handling` to `false` in your application.
116
-
117
- The new connection handling does not support `connection_handlers`
118
- getter and setter.
119
-
120
- Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling
121
- MSG
122
- else
123
- raise NotImplementedError, "The new connection handling does not support multiple connection handlers."
124
- end
125
-
126
- @@connection_handlers = handlers
127
- end
128
-
129
124
  def self.asynchronous_queries_session # :nodoc:
130
125
  asynchronous_queries_tracker.current_session
131
126
  end
@@ -145,16 +140,12 @@ module ActiveRecord
145
140
  # ActiveRecord::Base.current_role #=> :reading
146
141
  # end
147
142
  def self.current_role
148
- if ActiveRecord.legacy_connection_handling
149
- connection_handlers.key(connection_handler) || default_role
150
- else
151
- connected_to_stack.reverse_each do |hash|
152
- return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
153
- return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
154
- end
155
-
156
- default_role
143
+ connected_to_stack.reverse_each do |hash|
144
+ return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
145
+ return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
157
146
  end
147
+
148
+ default_role
158
149
  end
159
150
 
160
151
  # Returns the symbol representing the current connected shard.
@@ -186,16 +177,12 @@ module ActiveRecord
186
177
  # ActiveRecord::Base.current_preventing_writes #=> false
187
178
  # end
188
179
  def self.current_preventing_writes
189
- if ActiveRecord.legacy_connection_handling
190
- connection_handler.prevent_writes
191
- else
192
- connected_to_stack.reverse_each do |hash|
193
- return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
194
- return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
195
- end
196
-
197
- false
180
+ connected_to_stack.reverse_each do |hash|
181
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
182
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
198
183
  end
184
+
185
+ false
199
186
  end
200
187
 
201
188
  def self.connected_to_stack # :nodoc:
@@ -252,19 +239,6 @@ module ActiveRecord
252
239
  @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
253
240
  end
254
241
 
255
- def inherited(child_class) # :nodoc:
256
- # initialize cache at class definition for thread safety
257
- child_class.initialize_find_by_cache
258
- unless child_class.base_class?
259
- klass = self
260
- until klass.base_class?
261
- klass.initialize_find_by_cache
262
- klass = klass.superclass
263
- end
264
- end
265
- super
266
- end
267
-
268
242
  def find(*ids) # :nodoc:
269
243
  # We don't have cache keys for this stuff yet
270
244
  return super unless ids.length == 1
@@ -274,14 +248,8 @@ module ActiveRecord
274
248
 
275
249
  return super if StatementCache.unsupported_value?(id)
276
250
 
277
- key = primary_key
278
-
279
- statement = cached_find_by_statement(key) { |params|
280
- where(key => params.bind).limit(1)
281
- }
282
-
283
- statement.execute([id], connection).first ||
284
- raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
251
+ cached_find_by([primary_key], [id]) ||
252
+ raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}", name, primary_key, id))
285
253
  end
286
254
 
287
255
  def find_by(*args) # :nodoc:
@@ -313,48 +281,13 @@ module ActiveRecord
313
281
  h[key] = value
314
282
  end
315
283
 
316
- keys = hash.keys
317
- statement = cached_find_by_statement(keys) { |params|
318
- wheres = keys.index_with { params.bind }
319
- where(wheres).limit(1)
320
- }
321
-
322
- begin
323
- statement.execute(hash.values, connection).first
324
- rescue TypeError
325
- raise ActiveRecord::StatementInvalid
326
- end
284
+ cached_find_by(hash.keys, hash.values)
327
285
  end
328
286
 
329
287
  def find_by!(*args) # :nodoc:
330
288
  find_by(*args) || where(*args).raise_record_not_found_exception!
331
289
  end
332
290
 
333
- %w(
334
- reading_role writing_role legacy_connection_handling default_timezone index_nested_attribute_errors
335
- verbose_query_logs queues warn_on_records_fetched_greater_than maintain_test_schema
336
- application_record_class action_on_strict_loading_violation schema_format error_on_ignored_order
337
- timestamped_migrations dump_schema_after_migration dump_schemas suppress_multiple_database_warning
338
- ).each do |attr|
339
- module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
340
- def #{attr}
341
- ActiveSupport::Deprecation.warn(<<~MSG)
342
- ActiveRecord::Base.#{attr} is deprecated and will be removed in Rails 7.1.
343
- Use `ActiveRecord.#{attr}` instead.
344
- MSG
345
- ActiveRecord.#{attr}
346
- end
347
-
348
- def #{attr}=(value)
349
- ActiveSupport::Deprecation.warn(<<~MSG)
350
- ActiveRecord::Base.#{attr}= is deprecated and will be removed in Rails 7.1.
351
- Use `ActiveRecord.#{attr}=` instead.
352
- MSG
353
- ActiveRecord.#{attr} = value
354
- end
355
- RUBY
356
- end
357
-
358
291
  def initialize_generated_modules # :nodoc:
359
292
  generated_association_methods
360
293
  end
@@ -371,10 +304,10 @@ module ActiveRecord
371
304
 
372
305
  # Returns columns which shouldn't be exposed while calling +#inspect+.
373
306
  def filter_attributes
374
- if defined?(@filter_attributes)
375
- @filter_attributes
376
- else
307
+ if @filter_attributes.nil?
377
308
  superclass.filter_attributes
309
+ else
310
+ @filter_attributes
378
311
  end
379
312
  end
380
313
 
@@ -385,13 +318,13 @@ module ActiveRecord
385
318
  end
386
319
 
387
320
  def inspection_filter # :nodoc:
388
- if defined?(@filter_attributes)
321
+ if @filter_attributes.nil?
322
+ superclass.inspection_filter
323
+ else
389
324
  @inspection_filter ||= begin
390
325
  mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
391
326
  ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
392
327
  end
393
- else
394
- superclass.inspection_filter
395
328
  end
396
329
  end
397
330
 
@@ -416,7 +349,7 @@ module ActiveRecord
416
349
  object.is_a?(self)
417
350
  end
418
351
 
419
- # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
352
+ # Returns an instance of +Arel::Table+ loaded with the current table name.
420
353
  def arel_table # :nodoc:
421
354
  @arel_table ||= Arel::Table.new(table_name, klass: self)
422
355
  end
@@ -435,6 +368,28 @@ module ActiveRecord
435
368
  end
436
369
 
437
370
  private
371
+ def inherited(subclass)
372
+ super
373
+
374
+ # initialize cache at class definition for thread safety
375
+ subclass.initialize_find_by_cache
376
+ unless subclass.base_class?
377
+ klass = self
378
+ until klass.base_class?
379
+ klass.initialize_find_by_cache
380
+ klass = klass.superclass
381
+ end
382
+ end
383
+
384
+ subclass.class_eval do
385
+ @arel_table = nil
386
+ @predicate_builder = nil
387
+ @inspection_filter = nil
388
+ @filter_attributes = nil
389
+ @generated_association_methods = nil
390
+ end
391
+ end
392
+
438
393
  def relation
439
394
  relation = Relation.create(self)
440
395
 
@@ -448,6 +403,19 @@ module ActiveRecord
448
403
  def table_metadata
449
404
  TableMetadata.new(self, arel_table)
450
405
  end
406
+
407
+ def cached_find_by(keys, values)
408
+ statement = cached_find_by_statement(keys) { |params|
409
+ wheres = keys.index_with { params.bind }
410
+ where(wheres).limit(1)
411
+ }
412
+
413
+ begin
414
+ statement.execute(values, connection).first
415
+ rescue TypeError
416
+ raise ActiveRecord::StatementInvalid
417
+ end
418
+ end
451
419
  end
452
420
 
453
421
  # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
@@ -455,7 +423,7 @@ module ActiveRecord
455
423
  # In both instances, valid attribute keys are determined by the column names of the associated table --
456
424
  # hence you can't have attributes that aren't part of the table columns.
457
425
  #
458
- # ==== Example:
426
+ # ==== Example
459
427
  # # Instantiates a single new object
460
428
  # User.new(first_name: 'Jamie')
461
429
  def initialize(attributes = nil)
@@ -533,12 +501,17 @@ module ActiveRecord
533
501
  # only, not its associations. The extent of a "deep" copy is application
534
502
  # specific and is therefore left to the application to implement according
535
503
  # to its need.
536
- # The dup method does not preserve the timestamps (created|updated)_(at|on).
504
+ # The dup method does not preserve the timestamps (created|updated)_(at|on)
505
+ # and locking column.
537
506
 
538
507
  ##
539
508
  def initialize_dup(other) # :nodoc:
540
509
  @attributes = @attributes.deep_dup
541
- @attributes.reset(@primary_key)
510
+ if self.class.composite_primary_key?
511
+ @primary_key.each { |key| @attributes.reset(key) }
512
+ else
513
+ @attributes.reset(@primary_key)
514
+ end
542
515
 
543
516
  _run_initialize_callbacks
544
517
 
@@ -580,7 +553,7 @@ module ActiveRecord
580
553
  def ==(comparison_object)
581
554
  super ||
582
555
  comparison_object.instance_of?(self.class) &&
583
- !id.nil? &&
556
+ primary_key_values_present? &&
584
557
  comparison_object.id == id
585
558
  end
586
559
  alias :eql? :==
@@ -590,7 +563,7 @@ module ActiveRecord
590
563
  def hash
591
564
  id = self.id
592
565
 
593
- if id
566
+ if primary_key_values_present?
594
567
  self.class.hash ^ id.hash
595
568
  else
596
569
  super
@@ -645,22 +618,27 @@ module ActiveRecord
645
618
  # user.comments
646
619
  # => ActiveRecord::StrictLoadingViolationError
647
620
  #
648
- # === Parameters:
621
+ # ==== Parameters
649
622
  #
650
- # * value - Boolean specifying whether to enable or disable strict loading.
651
- # * mode - Symbol specifying strict loading mode. Defaults to :all. Using
652
- # :n_plus_one_only mode will only raise an error if an association
653
- # that will lead to an n plus one query is lazily loaded.
623
+ # * +value+ - Boolean specifying whether to enable or disable strict loading.
624
+ # * <tt>:mode</tt> - Symbol specifying strict loading mode. Defaults to :all. Using
625
+ # :n_plus_one_only mode will only raise an error if an association that
626
+ # will lead to an n plus one query is lazily loaded.
654
627
  #
655
- # === Example:
628
+ # ==== Examples
656
629
  #
657
630
  # user = User.first
658
631
  # user.strict_loading!(false) # => false
659
632
  # user.comments
660
633
  # => #<ActiveRecord::Associations::CollectionProxy>
634
+ #
635
+ # user.strict_loading!(mode: :n_plus_one_only)
636
+ # user.address.city # => "Tatooine"
637
+ # user.comments
638
+ # => ActiveRecord::StrictLoadingViolationError
661
639
  def strict_loading!(value = true, mode: :all)
662
640
  unless [:all, :n_plus_one_only].include?(mode)
663
- raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only]."
641
+ raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
664
642
  end
665
643
 
666
644
  @strict_loading_mode = mode
@@ -688,7 +666,7 @@ module ActiveRecord
688
666
  # We check defined?(@attributes) not to issue warnings if the object is
689
667
  # allocated but not initialized.
690
668
  inspection = if defined?(@attributes) && @attributes
691
- self.class.attribute_names.filter_map do |name|
669
+ attribute_names.filter_map do |name|
692
670
  if _has_attribute?(name)
693
671
  "#{name}: #{attribute_for_inspect(name)}"
694
672
  end
@@ -725,15 +703,26 @@ module ActiveRecord
725
703
  end
726
704
  end
727
705
 
728
- # Returns a hash of the given methods with their names as keys and returned values as values.
729
- def slice(*methods)
730
- methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
731
- end
732
-
706
+ ##
707
+ # :method: values_at
708
+ #
709
+ # :call-seq: values_at(*methods)
710
+ #
733
711
  # Returns an array of the values returned by the given methods.
734
- def values_at(*methods)
735
- methods.flatten.map! { |method| public_send(method) }
736
- end
712
+ #
713
+ #--
714
+ # Implemented by ActiveModel::Access#values_at.
715
+
716
+ ##
717
+ # :method: slice
718
+ #
719
+ # :call-seq: slice(*methods)
720
+ #
721
+ # Returns a hash of the given methods with their names as keys and returned
722
+ # values as values.
723
+ #
724
+ #--
725
+ # Implemented by ActiveModel::Access#slice.
737
726
 
738
727
  private
739
728
  # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
@@ -763,6 +752,7 @@ module ActiveRecord
763
752
  @strict_loading_mode = :all
764
753
 
765
754
  klass.define_attribute_methods
755
+ klass.generate_alias_attributes
766
756
  end
767
757
 
768
758
  def initialize_internals_callback
@@ -5,6 +5,10 @@ module ActiveRecord
5
5
  module CounterCache
6
6
  extend ActiveSupport::Concern
7
7
 
8
+ included do
9
+ class_attribute :_counter_cache_columns, instance_accessor: false, default: []
10
+ end
11
+
8
12
  module ClassMethods
9
13
  # Resets one or more counter caches to their correct value using an SQL
10
14
  # count query. This is useful when adding new counter caches, or if the
@@ -29,6 +33,7 @@ module ActiveRecord
29
33
  def reset_counters(id, *counters, touch: nil)
30
34
  object = find(id)
31
35
 
36
+ updates = {}
32
37
  counters.each do |counter_association|
33
38
  has_many_association = _reflect_on_association(counter_association)
34
39
  unless has_many_association
@@ -47,19 +52,21 @@ module ActiveRecord
47
52
  reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
48
53
  counter_name = reflection.counter_cache_column
49
54
 
50
- updates = { counter_name => object.send(counter_association).count(:all) }
51
-
52
- if touch
53
- names = touch if touch != true
54
- names = Array.wrap(names)
55
- options = names.extract_options!
56
- touch_updates = touch_attributes_with_time(*names, **options)
57
- updates.merge!(touch_updates)
58
- end
55
+ count_was = object.send(counter_name)
56
+ count = object.send(counter_association).count(:all)
57
+ updates[counter_name] = count if count != count_was
58
+ end
59
59
 
60
- unscoped.where(primary_key => object.id).update_all(updates)
60
+ if touch
61
+ names = touch if touch != true
62
+ names = Array.wrap(names)
63
+ options = names.extract_options!
64
+ touch_updates = touch_attributes_with_time(*names, **options)
65
+ updates.merge!(touch_updates)
61
66
  end
62
67
 
68
+ unscoped.where(primary_key => object.id).update_all(updates) if updates.any?
69
+
63
70
  true
64
71
  end
65
72
 
@@ -80,28 +87,28 @@ module ActiveRecord
80
87
  #
81
88
  # ==== Examples
82
89
  #
83
- # # For the Post with id of 5, decrement the comment_count by 1, and
84
- # # increment the action_count by 1
85
- # Post.update_counters 5, comment_count: -1, action_count: 1
90
+ # # For the Post with id of 5, decrement the comments_count by 1, and
91
+ # # increment the actions_count by 1
92
+ # Post.update_counters 5, comments_count: -1, actions_count: 1
86
93
  # # Executes the following SQL:
87
94
  # # UPDATE posts
88
- # # SET comment_count = COALESCE(comment_count, 0) - 1,
89
- # # action_count = COALESCE(action_count, 0) + 1
95
+ # # SET comments_count = COALESCE(comments_count, 0) - 1,
96
+ # # actions_count = COALESCE(actions_count, 0) + 1
90
97
  # # WHERE id = 5
91
98
  #
92
- # # For the Posts with id of 10 and 15, increment the comment_count by 1
93
- # Post.update_counters [10, 15], comment_count: 1
99
+ # # For the Posts with id of 10 and 15, increment the comments_count by 1
100
+ # Post.update_counters [10, 15], comments_count: 1
94
101
  # # Executes the following SQL:
95
102
  # # UPDATE posts
96
- # # SET comment_count = COALESCE(comment_count, 0) + 1
103
+ # # SET comments_count = COALESCE(comments_count, 0) + 1
97
104
  # # WHERE id IN (10, 15)
98
105
  #
99
- # # For the Posts with id of 10 and 15, increment the comment_count by 1
106
+ # # For the Posts with id of 10 and 15, increment the comments_count by 1
100
107
  # # and update the updated_at value for each counter.
101
- # Post.update_counters [10, 15], comment_count: 1, touch: true
108
+ # Post.update_counters [10, 15], comments_count: 1, touch: true
102
109
  # # Executes the following SQL:
103
110
  # # UPDATE posts
104
- # # SET comment_count = COALESCE(comment_count, 0) + 1,
111
+ # # SET comments_count = COALESCE(comments_count, 0) + 1,
105
112
  # # `updated_at` = '2016-10-13T09:59:23-05:00'
106
113
  # # WHERE id IN (10, 15)
107
114
  def update_counters(id, counters)
@@ -119,6 +126,7 @@ module ActiveRecord
119
126
  #
120
127
  # * +counter_name+ - The name of the field that should be incremented.
121
128
  # * +id+ - The id of the object that should be incremented or an array of ids.
129
+ # * <tt>:by</tt> - The amount by which to increment the value. Defaults to +1+.
122
130
  # * <tt>:touch</tt> - Touch timestamp columns when updating.
123
131
  # Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
124
132
  # touch that column or an array of symbols to touch just those ones.
@@ -129,10 +137,14 @@ module ActiveRecord
129
137
  # DiscussionBoard.increment_counter(:posts_count, 5)
130
138
  #
131
139
  # # Increment the posts_count column for the record with an id of 5
140
+ # # by a specific amount.
141
+ # DiscussionBoard.increment_counter(:posts_count, 5, by: 3)
142
+ #
143
+ # # Increment the posts_count column for the record with an id of 5
132
144
  # # and update the updated_at value.
133
145
  # DiscussionBoard.increment_counter(:posts_count, 5, touch: true)
134
- def increment_counter(counter_name, id, touch: nil)
135
- update_counters(id, counter_name => 1, touch: touch)
146
+ def increment_counter(counter_name, id, by: 1, touch: nil)
147
+ update_counters(id, counter_name => by, touch: touch)
136
148
  end
137
149
 
138
150
  # Decrement a numeric field by one, via a direct SQL update.
@@ -144,6 +156,7 @@ module ActiveRecord
144
156
  #
145
157
  # * +counter_name+ - The name of the field that should be decremented.
146
158
  # * +id+ - The id of the object that should be decremented or an array of ids.
159
+ # * <tt>:by</tt> - The amount by which to decrement the value. Defaults to +1+.
147
160
  # * <tt>:touch</tt> - Touch timestamp columns when updating.
148
161
  # Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
149
162
  # touch that column or an array of symbols to touch just those ones.
@@ -154,10 +167,18 @@ module ActiveRecord
154
167
  # DiscussionBoard.decrement_counter(:posts_count, 5)
155
168
  #
156
169
  # # Decrement the posts_count column for the record with an id of 5
170
+ # by a specific amount.
171
+ # DiscussionBoard.decrement_counter(:posts_count, 5, by: 3)
172
+ #
173
+ # # Decrement the posts_count column for the record with an id of 5
157
174
  # # and update the updated_at value.
158
175
  # DiscussionBoard.decrement_counter(:posts_count, 5, touch: true)
159
- def decrement_counter(counter_name, id, touch: nil)
160
- update_counters(id, counter_name => -1, touch: touch)
176
+ def decrement_counter(counter_name, id, by: 1, touch: nil)
177
+ update_counters(id, counter_name => -by, touch: touch)
178
+ end
179
+
180
+ def counter_cache_column?(name) # :nodoc:
181
+ _counter_cache_columns.include?(name)
161
182
  end
162
183
  end
163
184
 
@@ -3,13 +3,11 @@
3
3
  module ActiveRecord
4
4
  class DatabaseConfigurations
5
5
  # ActiveRecord::Base.configurations will return either a HashConfig or
6
- # UrlConfig respectively. It will never return a DatabaseConfig object,
6
+ # UrlConfig respectively. It will never return a +DatabaseConfig+ object,
7
7
  # as this is the parent class for the types of database configuration objects.
8
8
  class DatabaseConfig # :nodoc:
9
9
  attr_reader :env_name, :name
10
10
 
11
- attr_accessor :owner_name
12
-
13
11
  def initialize(env_name, name)
14
12
  @env_name = env_name
15
13
  @name = name
@@ -19,6 +17,10 @@ module ActiveRecord
19
17
  "#{adapter}_connection"
20
18
  end
21
19
 
20
+ def adapter_class_method
21
+ "#{adapter}_adapter_class"
22
+ end
23
+
22
24
  def host
23
25
  raise NotImplementedError
24
26
  end
@@ -51,6 +53,10 @@ module ActiveRecord
51
53
  raise NotImplementedError
52
54
  end
53
55
 
56
+ def query_cache
57
+ raise NotImplementedError
58
+ end
59
+
54
60
  def checkout_timeout
55
61
  raise NotImplementedError
56
62
  end