activerecord 7.2.2.1 → 8.0.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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +523 -677
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +1 -0
  5. data/lib/active_record/associations/alias_tracker.rb +6 -4
  6. data/lib/active_record/associations/association.rb +34 -10
  7. data/lib/active_record/associations/belongs_to_association.rb +18 -2
  8. data/lib/active_record/associations/builder/association.rb +7 -6
  9. data/lib/active_record/associations/collection_association.rb +10 -8
  10. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  11. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  12. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  13. data/lib/active_record/associations/join_dependency.rb +2 -2
  14. data/lib/active_record/associations/preloader/association.rb +2 -2
  15. data/lib/active_record/associations/preloader/batch.rb +7 -1
  16. data/lib/active_record/associations/singular_association.rb +8 -3
  17. data/lib/active_record/associations.rb +34 -4
  18. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  19. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  20. data/lib/active_record/attribute_methods/query.rb +34 -0
  21. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  22. data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
  23. data/lib/active_record/attribute_methods.rb +24 -19
  24. data/lib/active_record/attributes.rb +37 -26
  25. data/lib/active_record/autosave_association.rb +91 -39
  26. data/lib/active_record/base.rb +2 -2
  27. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +34 -25
  28. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  29. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  30. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +55 -47
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +91 -44
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -8
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  34. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  35. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
  36. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +40 -10
  37. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  38. data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -70
  39. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +35 -46
  40. data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
  41. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  42. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +50 -45
  43. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +84 -94
  44. data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -9
  45. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  46. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -2
  47. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +72 -43
  48. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  49. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  50. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  51. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
  52. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +20 -24
  53. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
  54. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +60 -17
  55. data/lib/active_record/connection_adapters/postgresql_adapter.rb +61 -99
  56. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  57. data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
  58. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +80 -100
  59. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
  60. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  61. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  62. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +10 -1
  63. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +63 -17
  64. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  65. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  66. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
  67. data/lib/active_record/connection_adapters.rb +0 -56
  68. data/lib/active_record/connection_handling.rb +35 -9
  69. data/lib/active_record/core.rb +57 -22
  70. data/lib/active_record/counter_cache.rb +1 -1
  71. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  72. data/lib/active_record/database_configurations/database_config.rb +4 -0
  73. data/lib/active_record/database_configurations/hash_config.rb +16 -2
  74. data/lib/active_record/delegated_type.rb +18 -18
  75. data/lib/active_record/encryption/config.rb +3 -1
  76. data/lib/active_record/encryption/encryptable_record.rb +5 -5
  77. data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
  78. data/lib/active_record/encryption/encryptor.rb +37 -28
  79. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  80. data/lib/active_record/encryption/scheme.rb +8 -1
  81. data/lib/active_record/enum.rb +22 -34
  82. data/lib/active_record/errors.rb +16 -8
  83. data/lib/active_record/fixture_set/table_row.rb +19 -2
  84. data/lib/active_record/fixtures.rb +0 -2
  85. data/lib/active_record/future_result.rb +15 -9
  86. data/lib/active_record/gem_version.rb +4 -4
  87. data/lib/active_record/insert_all.rb +3 -3
  88. data/lib/active_record/locking/optimistic.rb +1 -1
  89. data/lib/active_record/log_subscriber.rb +5 -11
  90. data/lib/active_record/migration/command_recorder.rb +32 -12
  91. data/lib/active_record/migration/compatibility.rb +5 -2
  92. data/lib/active_record/migration.rb +40 -43
  93. data/lib/active_record/model_schema.rb +3 -4
  94. data/lib/active_record/nested_attributes.rb +4 -6
  95. data/lib/active_record/persistence.rb +128 -130
  96. data/lib/active_record/query_logs.rb +106 -50
  97. data/lib/active_record/query_logs_formatter.rb +17 -28
  98. data/lib/active_record/querying.rb +12 -12
  99. data/lib/active_record/railtie.rb +4 -28
  100. data/lib/active_record/railties/databases.rake +11 -34
  101. data/lib/active_record/reflection.rb +18 -21
  102. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  103. data/lib/active_record/relation/batches.rb +132 -72
  104. data/lib/active_record/relation/calculations.rb +71 -65
  105. data/lib/active_record/relation/delegation.rb +25 -14
  106. data/lib/active_record/relation/finder_methods.rb +32 -31
  107. data/lib/active_record/relation/merger.rb +8 -8
  108. data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
  109. data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -0
  110. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  111. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  112. data/lib/active_record/relation/predicate_builder.rb +13 -0
  113. data/lib/active_record/relation/query_attribute.rb +1 -1
  114. data/lib/active_record/relation/query_methods.rb +121 -70
  115. data/lib/active_record/relation/spawn_methods.rb +7 -7
  116. data/lib/active_record/relation/where_clause.rb +9 -3
  117. data/lib/active_record/relation.rb +95 -67
  118. data/lib/active_record/result.rb +66 -4
  119. data/lib/active_record/sanitization.rb +7 -6
  120. data/lib/active_record/schema_dumper.rb +34 -11
  121. data/lib/active_record/schema_migration.rb +2 -1
  122. data/lib/active_record/scoping/named.rb +5 -2
  123. data/lib/active_record/secure_token.rb +3 -3
  124. data/lib/active_record/signed_id.rb +7 -6
  125. data/lib/active_record/statement_cache.rb +14 -14
  126. data/lib/active_record/store.rb +7 -3
  127. data/lib/active_record/table_metadata.rb +1 -3
  128. data/lib/active_record/tasks/database_tasks.rb +69 -60
  129. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  130. data/lib/active_record/tasks/postgresql_database_tasks.rb +9 -1
  131. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  132. data/lib/active_record/test_databases.rb +1 -1
  133. data/lib/active_record/test_fixtures.rb +12 -0
  134. data/lib/active_record/token_for.rb +1 -1
  135. data/lib/active_record/transactions.rb +8 -7
  136. data/lib/active_record/type/serialized.rb +5 -0
  137. data/lib/active_record/validations/uniqueness.rb +8 -8
  138. data/lib/active_record.rb +22 -49
  139. data/lib/arel/collectors/bind.rb +2 -2
  140. data/lib/arel/collectors/sql_string.rb +1 -1
  141. data/lib/arel/collectors/substitute_binds.rb +2 -2
  142. data/lib/arel/crud.rb +2 -0
  143. data/lib/arel/delete_manager.rb +5 -0
  144. data/lib/arel/nodes/binary.rb +1 -1
  145. data/lib/arel/nodes/delete_statement.rb +4 -2
  146. data/lib/arel/nodes/node.rb +1 -1
  147. data/lib/arel/nodes/sql_literal.rb +1 -1
  148. data/lib/arel/nodes/update_statement.rb +4 -2
  149. data/lib/arel/predications.rb +1 -3
  150. data/lib/arel/select_manager.rb +6 -2
  151. data/lib/arel/table.rb +3 -7
  152. data/lib/arel/update_manager.rb +5 -0
  153. data/lib/arel/visitors/dot.rb +2 -0
  154. data/lib/arel/visitors/to_sql.rb +3 -1
  155. metadata +11 -15
  156. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -28,6 +28,10 @@ module ActiveRecord
28
28
  # * +database+
29
29
  # * +source_location+
30
30
  #
31
+ # WARNING: Calculating the +source_location+ of a query can be slow, so you should consider its impact if using it in a production environment.
32
+ #
33
+ # Also see {config.active_record.verbose_query_logs}[https://guides.rubyonrails.org/debugging_rails_applications.html#verbose-query-logs].
34
+ #
31
35
  # Action Controller adds default tags when loaded:
32
36
  #
33
37
  # * +controller+
@@ -72,14 +76,70 @@ module ActiveRecord
72
76
  #
73
77
  # config.active_record.cache_query_log_tags = true
74
78
  module QueryLogs
75
- mattr_accessor :taggings, instance_accessor: false, default: {}
76
- mattr_accessor :tags, instance_accessor: false, default: [ :application ]
77
- mattr_accessor :prepend_comment, instance_accessor: false, default: false
78
- mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
79
- mattr_accessor :tags_formatter, instance_accessor: false
79
+ class GetKeyHandler # :nodoc:
80
+ def initialize(name)
81
+ @name = name
82
+ end
83
+
84
+ def call(context)
85
+ context[@name]
86
+ end
87
+ end
88
+
89
+ class IdentityHandler # :nodoc:
90
+ def initialize(value)
91
+ @value = value
92
+ end
93
+
94
+ def call(_context)
95
+ @value
96
+ end
97
+ end
98
+
99
+ class ZeroArityHandler # :nodoc:
100
+ def initialize(proc)
101
+ @proc = proc
102
+ end
103
+
104
+ def call(_context)
105
+ @proc.call
106
+ end
107
+ end
108
+
109
+ @taggings = {}.freeze
110
+ @tags = [ :application ].freeze
111
+ @prepend_comment = false
112
+ @cache_query_log_tags = false
113
+ @tags_formatter = false
114
+
80
115
  thread_mattr_accessor :cached_comment, instance_accessor: false
81
116
 
82
117
  class << self
118
+ attr_reader :tags, :taggings, :tags_formatter # :nodoc:
119
+ attr_accessor :prepend_comment, :cache_query_log_tags # :nodoc:
120
+
121
+ def taggings=(taggings) # :nodoc:
122
+ @taggings = taggings.freeze
123
+ @handlers = rebuild_handlers
124
+ end
125
+
126
+ def tags=(tags) # :nodoc:
127
+ @tags = tags.freeze
128
+ @handlers = rebuild_handlers
129
+ end
130
+
131
+ def tags_formatter=(format) # :nodoc:
132
+ @formatter = case format
133
+ when :legacy
134
+ LegacyFormatter
135
+ when :sqlcommenter
136
+ SQLCommenter
137
+ else
138
+ raise ArgumentError, "Formatter is unsupported: #{format}"
139
+ end
140
+ @tags_formatter = format
141
+ end
142
+
83
143
  def call(sql, connection) # :nodoc:
84
144
  comment = self.comment(connection)
85
145
 
@@ -96,36 +156,46 @@ module ActiveRecord
96
156
  self.cached_comment = nil
97
157
  end
98
158
 
99
- # Updates the formatter to be what the passed in format is.
100
- def update_formatter(format)
101
- self.tags_formatter =
102
- case format
103
- when :legacy
104
- LegacyFormatter.new
105
- when :sqlcommenter
106
- SQLCommenter.new
107
- else
108
- raise ArgumentError, "Formatter is unsupported: #{formatter}"
109
- end
110
- end
111
-
112
- if Thread.respond_to?(:each_caller_location)
113
- def query_source_location # :nodoc:
114
- Thread.each_caller_location do |location|
115
- frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
116
- return frame if frame
117
- end
118
- nil
119
- end
120
- else
121
- def query_source_location # :nodoc:
122
- LogSubscriber.backtrace_cleaner.clean(caller_locations(1).each).first
159
+ def query_source_location # :nodoc:
160
+ Thread.each_caller_location do |location|
161
+ frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
162
+ return frame if frame
123
163
  end
164
+ nil
124
165
  end
125
166
 
126
167
  ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
127
168
 
128
169
  private
170
+ def rebuild_handlers
171
+ handlers = []
172
+ @tags.each do |i|
173
+ if i.is_a?(Hash)
174
+ i.each do |k, v|
175
+ handlers << [k, build_handler(k, v)]
176
+ end
177
+ else
178
+ handlers << [i, build_handler(i)]
179
+ end
180
+ end
181
+ handlers.sort_by! { |(key, _)| key.to_s }
182
+ end
183
+
184
+ def build_handler(name, handler = nil)
185
+ handler ||= @taggings[name]
186
+ if handler.nil?
187
+ GetKeyHandler.new(name)
188
+ elsif handler.respond_to?(:call)
189
+ if handler.arity == 0
190
+ ZeroArityHandler.new(handler)
191
+ else
192
+ handler
193
+ end
194
+ else
195
+ IdentityHandler.new(handler)
196
+ end
197
+ end
198
+
129
199
  # Returns an SQL comment +String+ containing the query log tags.
130
200
  # Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
131
201
  def comment(connection)
@@ -136,10 +206,6 @@ module ActiveRecord
136
206
  end
137
207
  end
138
208
 
139
- def formatter
140
- self.tags_formatter || self.update_formatter(:legacy)
141
- end
142
-
143
209
  def uncached_comment(connection)
144
210
  content = tag_content(connection)
145
211
 
@@ -165,25 +231,15 @@ module ActiveRecord
165
231
  context = ActiveSupport::ExecutionContext.to_h
166
232
  context[:connection] ||= connection
167
233
 
168
- pairs = tags.flat_map { |i| [*i] }.filter_map do |tag|
169
- key, handler = tag
170
- handler ||= taggings[key]
171
-
172
- val = if handler.nil?
173
- context[key]
174
- elsif handler.respond_to?(:call)
175
- if handler.arity == 0
176
- handler.call
177
- else
178
- handler.call(context)
179
- end
180
- else
181
- handler
182
- end
183
- [key, val] unless val.nil?
234
+ pairs = @handlers.filter_map do |(key, handler)|
235
+ val = handler.call(context)
236
+ @formatter.format(key, val) unless val.nil?
184
237
  end
185
- self.formatter.format(pairs)
238
+ @formatter.join(pairs)
186
239
  end
187
240
  end
241
+
242
+ @handlers = rebuild_handlers
243
+ self.tags_formatter = :legacy
188
244
  end
189
245
  end
@@ -2,40 +2,29 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module QueryLogs
5
- class LegacyFormatter # :nodoc:
6
- def initialize
7
- @key_value_separator = ":"
8
- end
9
-
10
- # Formats the key value pairs into a string.
11
- def format(pairs)
12
- pairs.map! do |key, value|
13
- "#{key}#{key_value_separator}#{format_value(value)}"
14
- end.join(",")
15
- end
16
-
17
- private
18
- attr_reader :key_value_separator
19
-
20
- def format_value(value)
21
- value
5
+ module LegacyFormatter # :nodoc:
6
+ class << self
7
+ # Formats the key value pairs into a string.
8
+ def format(key, value)
9
+ "#{key}:#{value}"
22
10
  end
23
- end
24
11
 
25
- class SQLCommenter < LegacyFormatter # :nodoc:
26
- def initialize
27
- @key_value_separator = "="
12
+ def join(pairs)
13
+ pairs.join(",")
14
+ end
28
15
  end
16
+ end
29
17
 
30
- def format(pairs)
31
- pairs.sort_by! { |pair| pair.first.to_s }
32
- super
33
- end
18
+ class SQLCommenter # :nodoc:
19
+ class << self
20
+ def format(key, value)
21
+ "#{key}='#{ERB::Util.url_encode(value)}'"
22
+ end
34
23
 
35
- private
36
- def format_value(value)
37
- "'#{ERB::Util.url_encode(value)}'"
24
+ def join(pairs)
25
+ pairs.join(",")
38
26
  end
27
+ end
39
28
  end
40
29
  end
41
30
  end
@@ -46,8 +46,8 @@ module ActiveRecord
46
46
  # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
47
47
  # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
48
48
  #
49
- # Note that building your own SQL query string from user input may expose your application to
50
- # injection attacks (https://guides.rubyonrails.org/security.html#sql-injection).
49
+ # Note that building your own SQL query string from user input {may expose your application to
50
+ # injection attacks}[https://guides.rubyonrails.org/security.html#sql-injection].
51
51
  def find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
52
52
  result = with_connection do |c|
53
53
  _query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry)
@@ -55,13 +55,11 @@ module ActiveRecord
55
55
  _load_from_sql(result, &block)
56
56
  end
57
57
 
58
- # Same as <tt>#find_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise.
59
- def async_find_by_sql(sql, binds = [], preparable: nil, &block)
60
- result = with_connection do |c|
61
- _query_by_sql(c, sql, binds, preparable: preparable, async: true)
62
- end
63
-
64
- result.then do |result|
58
+ # Same as #find_by_sql but perform the query asynchronously and returns an ActiveRecord::Promise.
59
+ def async_find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
60
+ with_connection do |c|
61
+ _query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry, async: true)
62
+ end.then do |result|
65
63
  _load_from_sql(result, &block)
66
64
  end
67
65
  end
@@ -71,6 +69,8 @@ module ActiveRecord
71
69
  end
72
70
 
73
71
  def _load_from_sql(result_set, &block) # :nodoc:
72
+ return [] if result_set.empty?
73
+
74
74
  column_types = result_set.column_types
75
75
 
76
76
  unless column_types.empty?
@@ -86,10 +86,10 @@ module ActiveRecord
86
86
 
87
87
  message_bus.instrument("instantiation.active_record", payload) do
88
88
  if result_set.includes_column?(inheritance_column)
89
- result_set.map { |record| instantiate(record, column_types, &block) }
89
+ result_set.indexed_rows.map { |record| instantiate(record, column_types, &block) }
90
90
  else
91
91
  # Instantiate a homogeneous set
92
- result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
92
+ result_set.indexed_rows.map { |record| instantiate_instance_of(self, record, column_types, &block) }
93
93
  end
94
94
  end
95
95
  end
@@ -112,7 +112,7 @@ module ActiveRecord
112
112
  end
113
113
  end
114
114
 
115
- # Same as <tt>#count_by_sql</tt> but perform the query asynchronously and returns an ActiveRecord::Promise.
115
+ # Same as #count_by_sql but perform the query asynchronously and returns an ActiveRecord::Promise.
116
116
  def async_count_by_sql(sql)
117
117
  with_connection do |c|
118
118
  c.select_value(sanitize_sql(sql), "#{name} Count", async: true).then(&:to_i)
@@ -23,8 +23,8 @@ module ActiveRecord
23
23
  config.action_dispatch.rescue_responses.merge!(
24
24
  "ActiveRecord::RecordNotFound" => :not_found,
25
25
  "ActiveRecord::StaleObjectError" => :conflict,
26
- "ActiveRecord::RecordInvalid" => :unprocessable_entity,
27
- "ActiveRecord::RecordNotSaved" => :unprocessable_entity
26
+ "ActiveRecord::RecordInvalid" => ActionDispatch::Constants::UNPROCESSABLE_CONTENT,
27
+ "ActiveRecord::RecordNotSaved" => ActionDispatch::Constants::UNPROCESSABLE_CONTENT
28
28
  )
29
29
 
30
30
  config.active_record.use_schema_cache_dump = true
@@ -184,30 +184,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
184
184
  end
185
185
  end
186
186
 
187
- initializer "active_record.warn_on_records_fetched_greater_than" do
188
- if config.active_record.warn_on_records_fetched_greater_than
189
- ActiveRecord.deprecator.warn <<~MSG.squish
190
- `config.active_record.warn_on_records_fetched_greater_than` is deprecated and will be
191
- removed in Rails 8.0.
192
- Please subscribe to `sql.active_record` notifications and access the row count field to
193
- detect large result set sizes.
194
- MSG
195
- ActiveSupport.on_load(:active_record) do
196
- require "active_record/relation/record_fetch_warning"
197
- end
198
- end
199
- end
200
-
201
- initializer "active_record.sqlite3_deprecated_warning" do
202
- if config.active_record.key?(:sqlite3_production_warning)
203
- config.active_record.delete(:sqlite3_production_warning)
204
- ActiveRecord.deprecator.warn <<~MSG.squish
205
- The `config.active_record.sqlite3_production_warning` configuration no longer has any effect
206
- and can be safely removed.
207
- MSG
208
- end
209
- end
210
-
211
187
  initializer "active_record.sqlite3_adapter_strict_strings_by_default" do
212
188
  config.after_initialize do
213
189
  if config.active_record.sqlite3_adapter_strict_strings_by_default
@@ -390,7 +366,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
390
366
  config.after_initialize do
391
367
  if app.config.active_record.query_log_tags_enabled
392
368
  ActiveRecord.query_transformers << ActiveRecord::QueryLogs
393
- ActiveRecord::QueryLogs.taggings.merge!(
369
+ ActiveRecord::QueryLogs.taggings = ActiveRecord::QueryLogs.taggings.merge(
394
370
  application: Rails.application.class.name.split("::").first,
395
371
  pid: -> { Process.pid.to_s },
396
372
  socket: ->(context) { context[:connection].pool.db_config.socket },
@@ -405,7 +381,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
405
381
  end
406
382
 
407
383
  if app.config.active_record.query_log_tags_format
408
- ActiveRecord::QueryLogs.update_formatter(app.config.active_record.query_log_tags_format)
384
+ ActiveRecord::QueryLogs.tags_formatter = app.config.active_record.query_log_tags_format
409
385
  end
410
386
 
411
387
  if app.config.active_record.cache_query_log_tags
@@ -87,22 +87,7 @@ db_namespace = namespace :db do
87
87
 
88
88
  desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
89
89
  task migrate: :load_config do
90
- db_configs = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env)
91
-
92
- if db_configs.size == 1 && db_configs.first.primary?
93
- ActiveRecord::Tasks::DatabaseTasks.migrate
94
- else
95
- mapped_versions = ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions
96
-
97
- mapped_versions.sort.each do |version, db_configs|
98
- db_configs.each do |db_config|
99
- ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection(db_config) do
100
- ActiveRecord::Tasks::DatabaseTasks.migrate(version)
101
- end
102
- end
103
- end
104
- end
105
-
90
+ ActiveRecord::Tasks::DatabaseTasks.migrate_all
106
91
  db_namespace["_dump"].invoke
107
92
  end
108
93
 
@@ -175,8 +160,8 @@ db_namespace = namespace :db do
175
160
  end
176
161
  end
177
162
 
178
- # desc 'Resets your database using your migrations for the current environment'
179
- task reset: ["db:drop", "db:create", "db:migrate"]
163
+ desc "Resets your database using your migrations for the current environment"
164
+ task reset: ["db:drop", "db:create", "db:schema:dump", "db:migrate"]
180
165
 
181
166
  desc 'Run the "up" for a given migration VERSION.'
182
167
  task up: :load_config do
@@ -462,18 +447,14 @@ db_namespace = namespace :db do
462
447
  namespace :schema do
463
448
  desc "Create a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
464
449
  task dump: :load_config do
465
- ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each do |pool|
466
- db_config = pool.db_config
467
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
468
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
469
- end
450
+ ActiveRecord::Tasks::DatabaseTasks.dump_all
470
451
 
471
452
  db_namespace["schema:dump"].reenable
472
453
  end
473
454
 
474
455
  desc "Load a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the database"
475
456
  task load: [:load_config, :check_protected_environments] do
476
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord.schema_format, ENV["SCHEMA"])
457
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ENV["SCHEMA_FORMAT"], ENV["SCHEMA"])
477
458
  end
478
459
 
479
460
  namespace :dump do
@@ -482,8 +463,7 @@ db_namespace = namespace :db do
482
463
  task name => :load_config do
483
464
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
484
465
  db_config = pool.db_config
485
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
486
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
466
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
487
467
  end
488
468
 
489
469
  db_namespace["schema:dump:#{name}"].reenable
@@ -493,12 +473,11 @@ db_namespace = namespace :db do
493
473
 
494
474
  namespace :load do
495
475
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
496
- desc "Load a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the #{name} database"
476
+ desc "Load a database schema file (either db/schema.rb or db/structure.sql, depending on configuration) into the #{name} database"
497
477
  task name => "db:test:purge:#{name}" do
498
478
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
499
479
  db_config = pool.db_config
500
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
501
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
480
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
502
481
  end
503
482
  end
504
483
  end
@@ -542,13 +521,12 @@ db_namespace = namespace :db do
542
521
  end
543
522
 
544
523
  namespace :test do
545
- # desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
524
+ # desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on configuration)"
546
525
  task load_schema: %w(db:test:purge) do
547
526
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: "test") do |pool|
548
527
  db_config = pool.db_config
549
528
  ActiveRecord::Schema.verbose = false
550
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
551
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
529
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
552
530
  end
553
531
  end
554
532
 
@@ -573,8 +551,7 @@ db_namespace = namespace :db do
573
551
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: "test", name: name) do |pool|
574
552
  db_config = pool.db_config
575
553
  ActiveRecord::Schema.verbose = false
576
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
577
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
554
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
578
555
  end
579
556
  end
580
557
  end
@@ -198,7 +198,7 @@ module ActiveRecord
198
198
  end
199
199
 
200
200
  def join_scope(table, foreign_table, foreign_klass)
201
- predicate_builder = predicate_builder(table)
201
+ predicate_builder = klass.predicate_builder.with(TableMetadata.new(klass, table))
202
202
  scope_chain_items = join_scopes(table, predicate_builder)
203
203
  klass_scope = klass_join_scope(table, predicate_builder)
204
204
 
@@ -224,7 +224,7 @@ module ActiveRecord
224
224
  klass_scope
225
225
  end
226
226
 
227
- def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
227
+ def join_scopes(table, predicate_builder = nil, klass = self.klass, record = nil) # :nodoc:
228
228
  if scope
229
229
  [scope_for(build_scope(table, predicate_builder, klass), record)]
230
230
  else
@@ -232,7 +232,7 @@ module ActiveRecord
232
232
  end
233
233
  end
234
234
 
235
- def klass_join_scope(table, predicate_builder) # :nodoc:
235
+ def klass_join_scope(table, predicate_builder = nil) # :nodoc:
236
236
  relation = build_scope(table, predicate_builder)
237
237
  klass.scope_for_association(relation)
238
238
  end
@@ -333,12 +333,8 @@ module ActiveRecord
333
333
  collect_join_chain
334
334
  end
335
335
 
336
- def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
337
- Relation.create(
338
- klass,
339
- table: table,
340
- predicate_builder: predicate_builder
341
- )
336
+ def build_scope(table, predicate_builder = nil, klass = self.klass)
337
+ Relation.create(klass, table:, predicate_builder:)
342
338
  end
343
339
 
344
340
  def strict_loading?
@@ -357,10 +353,6 @@ module ActiveRecord
357
353
  end
358
354
 
359
355
  private
360
- def predicate_builder(table)
361
- PredicateBuilder.new(TableMetadata.new(klass, table))
362
- end
363
-
364
356
  def primary_key(klass)
365
357
  klass.primary_key || raise(UnknownPrimaryKey.new(klass))
366
358
  end
@@ -531,9 +523,9 @@ module ActiveRecord
531
523
  @association_foreign_key = nil
532
524
  @association_primary_key = nil
533
525
  if options[:query_constraints]
534
- ActiveRecord.deprecator.warn <<~MSG.squish
535
- Setting `query_constraints:` option on `#{active_record}.#{macro} :#{name}` is deprecated.
536
- To maintain current behavior, use the `foreign_key` option instead.
526
+ raise ConfigurationError, <<~MSG.squish
527
+ Setting `query_constraints:` option on `#{active_record}.#{macro} :#{name}` is not allowed.
528
+ To get the same behavior, use the `foreign_key` option instead.
537
529
  MSG
538
530
  end
539
531
 
@@ -562,12 +554,12 @@ module ActiveRecord
562
554
  def foreign_key(infer_from_inverse_of: true)
563
555
  @foreign_key ||= if options[:foreign_key]
564
556
  if options[:foreign_key].is_a?(Array)
565
- options[:foreign_key].map { |fk| fk.to_s.freeze }.freeze
557
+ options[:foreign_key].map { |fk| -fk.to_s.freeze }.freeze
566
558
  else
567
559
  options[:foreign_key].to_s.freeze
568
560
  end
569
561
  elsif options[:query_constraints]
570
- options[:query_constraints].map { |fk| fk.to_s.freeze }.freeze
562
+ options[:query_constraints].map { |fk| -fk.to_s.freeze }.freeze
571
563
  else
572
564
  derived_fk = derive_foreign_key(infer_from_inverse_of: infer_from_inverse_of)
573
565
 
@@ -575,7 +567,12 @@ module ActiveRecord
575
567
  derived_fk = derive_fk_query_constraints(derived_fk)
576
568
  end
577
569
 
578
- derived_fk
570
+ if derived_fk.is_a?(Array)
571
+ derived_fk.map! { |fk| -fk.freeze }
572
+ derived_fk.freeze
573
+ else
574
+ -derived_fk.freeze
575
+ end
579
576
  end
580
577
  end
581
578
 
@@ -1065,7 +1062,7 @@ module ActiveRecord
1065
1062
  source_reflection.scopes + super
1066
1063
  end
1067
1064
 
1068
- def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
1065
+ def join_scopes(table, predicate_builder = nil, klass = self.klass, record = nil) # :nodoc:
1069
1066
  source_reflection.join_scopes(table, predicate_builder, klass, record) + super
1070
1067
  end
1071
1068
 
@@ -1238,7 +1235,7 @@ module ActiveRecord
1238
1235
  @previous_reflection = previous_reflection
1239
1236
  end
1240
1237
 
1241
- def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
1238
+ def join_scopes(table, predicate_builder = nil, klass = self.klass, record = nil) # :nodoc:
1242
1239
  scopes = super
1243
1240
  unless @previous_reflection.through_reflection?
1244
1241
  scopes += @previous_reflection.join_scopes(table, predicate_builder, klass, record)
@@ -5,11 +5,12 @@ module ActiveRecord
5
5
  class BatchEnumerator
6
6
  include Enumerable
7
7
 
8
- def initialize(of: 1000, start: nil, finish: nil, relation:, order: :asc, use_ranges: nil) # :nodoc:
8
+ def initialize(of: 1000, start: nil, finish: nil, relation:, cursor:, order: :asc, use_ranges: nil) # :nodoc:
9
9
  @of = of
10
10
  @relation = relation
11
11
  @start = start
12
12
  @finish = finish
13
+ @cursor = cursor
13
14
  @order = order
14
15
  @use_ranges = use_ranges
15
16
  end
@@ -52,7 +53,7 @@ module ActiveRecord
52
53
  def each_record(&block)
53
54
  return to_enum(:each_record) unless block_given?
54
55
 
55
- @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true, order: @order).each do |relation|
56
+ @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true, cursor: @cursor, order: @order).each do |relation|
56
57
  relation.records.each(&block)
57
58
  end
58
59
  end
@@ -105,7 +106,7 @@ module ActiveRecord
105
106
  # relation.update_all(awesome: true)
106
107
  # end
107
108
  def each(&block)
108
- enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false, order: @order, use_ranges: @use_ranges)
109
+ enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false, cursor: @cursor, order: @order, use_ranges: @use_ranges)
109
110
  return enum.each(&block) if block_given?
110
111
  enum
111
112
  end