activerecord 7.2.1.1 → 8.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +220 -756
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/associations/association.rb +25 -5
  5. data/lib/active_record/associations/builder/association.rb +7 -6
  6. data/lib/active_record/associations/collection_association.rb +10 -8
  7. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  8. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  9. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  10. data/lib/active_record/associations/join_dependency.rb +4 -4
  11. data/lib/active_record/associations/preloader/association.rb +2 -2
  12. data/lib/active_record/associations/singular_association.rb +8 -3
  13. data/lib/active_record/associations.rb +34 -4
  14. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  15. data/lib/active_record/attribute_assignment.rb +9 -1
  16. data/lib/active_record/attribute_methods/primary_key.rb +2 -7
  17. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -12
  18. data/lib/active_record/attributes.rb +1 -2
  19. data/lib/active_record/autosave_association.rb +69 -27
  20. data/lib/active_record/callbacks.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  22. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  23. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  24. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -9
  25. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  26. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -4
  27. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  28. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  29. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -2
  30. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +34 -7
  31. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  32. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -26
  33. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -42
  34. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  35. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  36. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
  37. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  38. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  39. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  40. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  41. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  42. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  43. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  44. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -11
  45. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -11
  46. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
  47. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +54 -14
  48. data/lib/active_record/connection_adapters/postgresql_adapter.rb +45 -97
  49. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  50. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  51. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  52. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  53. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
  54. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
  55. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  56. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  57. data/lib/active_record/connection_adapters.rb +0 -56
  58. data/lib/active_record/connection_handling.rb +22 -0
  59. data/lib/active_record/core.rb +28 -18
  60. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
  61. data/lib/active_record/encryption/config.rb +3 -1
  62. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  63. data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
  64. data/lib/active_record/encryption/encryptor.rb +15 -8
  65. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  66. data/lib/active_record/encryption/key_provider.rb +1 -1
  67. data/lib/active_record/encryption/scheme.rb +8 -1
  68. data/lib/active_record/encryption.rb +2 -0
  69. data/lib/active_record/enum.rb +54 -75
  70. data/lib/active_record/errors.rb +13 -5
  71. data/lib/active_record/fixtures.rb +0 -2
  72. data/lib/active_record/future_result.rb +14 -10
  73. data/lib/active_record/gem_version.rb +4 -4
  74. data/lib/active_record/insert_all.rb +1 -1
  75. data/lib/active_record/locking/optimistic.rb +1 -1
  76. data/lib/active_record/log_subscriber.rb +5 -11
  77. data/lib/active_record/marshalling.rb +4 -1
  78. data/lib/active_record/migration/command_recorder.rb +22 -5
  79. data/lib/active_record/migration/compatibility.rb +5 -2
  80. data/lib/active_record/migration.rb +35 -38
  81. data/lib/active_record/model_schema.rb +4 -6
  82. data/lib/active_record/nested_attributes.rb +11 -2
  83. data/lib/active_record/persistence.rb +128 -130
  84. data/lib/active_record/query_cache.rb +0 -4
  85. data/lib/active_record/query_logs.rb +102 -50
  86. data/lib/active_record/query_logs_formatter.rb +17 -28
  87. data/lib/active_record/querying.rb +8 -8
  88. data/lib/active_record/railtie.rb +9 -38
  89. data/lib/active_record/railties/databases.rake +1 -1
  90. data/lib/active_record/reflection.rb +23 -23
  91. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  92. data/lib/active_record/relation/batches.rb +132 -72
  93. data/lib/active_record/relation/calculations.rb +41 -40
  94. data/lib/active_record/relation/delegation.rb +25 -14
  95. data/lib/active_record/relation/finder_methods.rb +18 -18
  96. data/lib/active_record/relation/merger.rb +8 -8
  97. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  98. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  99. data/lib/active_record/relation/predicate_builder.rb +14 -1
  100. data/lib/active_record/relation/query_methods.rb +122 -71
  101. data/lib/active_record/relation/spawn_methods.rb +1 -1
  102. data/lib/active_record/relation.rb +79 -61
  103. data/lib/active_record/result.rb +66 -4
  104. data/lib/active_record/sanitization.rb +7 -6
  105. data/lib/active_record/schema_dumper.rb +5 -0
  106. data/lib/active_record/schema_migration.rb +2 -1
  107. data/lib/active_record/scoping/named.rb +5 -2
  108. data/lib/active_record/statement_cache.rb +12 -12
  109. data/lib/active_record/store.rb +7 -3
  110. data/lib/active_record/table_metadata.rb +1 -3
  111. data/lib/active_record/tasks/database_tasks.rb +40 -47
  112. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  113. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  114. data/lib/active_record/test_fixtures.rb +12 -0
  115. data/lib/active_record/testing/query_assertions.rb +2 -2
  116. data/lib/active_record/token_for.rb +1 -1
  117. data/lib/active_record/validations/uniqueness.rb +9 -8
  118. data/lib/active_record.rb +15 -45
  119. data/lib/arel/collectors/bind.rb +1 -1
  120. data/lib/arel/table.rb +3 -7
  121. data/lib/arel/visitors/sqlite.rb +25 -0
  122. metadata +10 -11
  123. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -72,14 +72,70 @@ module ActiveRecord
72
72
  #
73
73
  # config.active_record.cache_query_log_tags = true
74
74
  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
75
+ class GetKeyHandler # :nodoc:
76
+ def initialize(name)
77
+ @name = name
78
+ end
79
+
80
+ def call(context)
81
+ context[@name]
82
+ end
83
+ end
84
+
85
+ class IdentityHandler # :nodoc:
86
+ def initialize(value)
87
+ @value = value
88
+ end
89
+
90
+ def call(_context)
91
+ @value
92
+ end
93
+ end
94
+
95
+ class ZeroArityHandler # :nodoc:
96
+ def initialize(proc)
97
+ @proc = proc
98
+ end
99
+
100
+ def call(_context)
101
+ @proc.call
102
+ end
103
+ end
104
+
105
+ @taggings = {}.freeze
106
+ @tags = [ :application ].freeze
107
+ @prepend_comment = false
108
+ @cache_query_log_tags = false
109
+ @tags_formatter = false
110
+
80
111
  thread_mattr_accessor :cached_comment, instance_accessor: false
81
112
 
82
113
  class << self
114
+ attr_reader :tags, :taggings, :tags_formatter # :nodoc:
115
+ attr_accessor :prepend_comment, :cache_query_log_tags # :nodoc:
116
+
117
+ def taggings=(taggings) # :nodoc:
118
+ @taggings = taggings.freeze
119
+ @handlers = rebuild_handlers
120
+ end
121
+
122
+ def tags=(tags) # :nodoc:
123
+ @tags = tags.freeze
124
+ @handlers = rebuild_handlers
125
+ end
126
+
127
+ def tags_formatter=(format) # :nodoc:
128
+ @formatter = case format
129
+ when :legacy
130
+ LegacyFormatter
131
+ when :sqlcommenter
132
+ SQLCommenter
133
+ else
134
+ raise ArgumentError, "Formatter is unsupported: #{format}"
135
+ end
136
+ @tags_formatter = format
137
+ end
138
+
83
139
  def call(sql, connection) # :nodoc:
84
140
  comment = self.comment(connection)
85
141
 
@@ -96,36 +152,46 @@ module ActiveRecord
96
152
  self.cached_comment = nil
97
153
  end
98
154
 
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.path)
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
155
+ def query_source_location # :nodoc:
156
+ Thread.each_caller_location do |location|
157
+ frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
158
+ return frame if frame
123
159
  end
160
+ nil
124
161
  end
125
162
 
126
163
  ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
127
164
 
128
165
  private
166
+ def rebuild_handlers
167
+ handlers = []
168
+ @tags.each do |i|
169
+ if i.is_a?(Hash)
170
+ i.each do |k, v|
171
+ handlers << [k, build_handler(k, v)]
172
+ end
173
+ else
174
+ handlers << [i, build_handler(i)]
175
+ end
176
+ end
177
+ handlers.sort_by! { |(key, _)| key.to_s }
178
+ end
179
+
180
+ def build_handler(name, handler = nil)
181
+ handler ||= @taggings[name]
182
+ if handler.nil?
183
+ GetKeyHandler.new(name)
184
+ elsif handler.respond_to?(:call)
185
+ if handler.arity == 0
186
+ ZeroArityHandler.new(handler)
187
+ else
188
+ handler
189
+ end
190
+ else
191
+ IdentityHandler.new(handler)
192
+ end
193
+ end
194
+
129
195
  # Returns an SQL comment +String+ containing the query log tags.
130
196
  # Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
131
197
  def comment(connection)
@@ -136,10 +202,6 @@ module ActiveRecord
136
202
  end
137
203
  end
138
204
 
139
- def formatter
140
- self.tags_formatter || self.update_formatter(:legacy)
141
- end
142
-
143
205
  def uncached_comment(connection)
144
206
  content = tag_content(connection)
145
207
 
@@ -165,25 +227,15 @@ module ActiveRecord
165
227
  context = ActiveSupport::ExecutionContext.to_h
166
228
  context[:connection] ||= connection
167
229
 
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?
230
+ pairs = @handlers.filter_map do |(key, handler)|
231
+ val = handler.call(context)
232
+ @formatter.format(key, val) unless val.nil?
184
233
  end
185
- self.formatter.format(pairs)
234
+ @formatter.join(pairs)
186
235
  end
187
236
  end
237
+
238
+ @handlers = rebuild_handlers
239
+ self.tags_formatter = :legacy
188
240
  end
189
241
  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
@@ -56,12 +56,10 @@ module ActiveRecord
56
56
  end
57
57
 
58
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|
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
@@ -69,6 +69,7 @@ module ActiveRecord
69
69
  Rails.logger.broadcast_to(console)
70
70
  end
71
71
  ActiveRecord.verbose_query_logs = false
72
+ ActiveRecord::Base.attributes_for_inspect = :all if Rails.env.production?
72
73
  end
73
74
 
74
75
  runner do
@@ -183,30 +184,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
183
184
  end
184
185
  end
185
186
 
186
- initializer "active_record.warn_on_records_fetched_greater_than" do
187
- if config.active_record.warn_on_records_fetched_greater_than
188
- ActiveRecord.deprecator.warn <<~MSG.squish
189
- `config.active_record.warn_on_records_fetched_greater_than` is deprecated and will be
190
- removed in Rails 8.0.
191
- Please subscribe to `sql.active_record` notifications and access the row count field to
192
- detect large result set sizes.
193
- MSG
194
- ActiveSupport.on_load(:active_record) do
195
- require "active_record/relation/record_fetch_warning"
196
- end
197
- end
198
- end
199
-
200
- initializer "active_record.sqlite3_deprecated_warning" do
201
- if config.active_record.key?(:sqlite3_production_warning)
202
- config.active_record.delete(:sqlite3_production_warning)
203
- ActiveRecord.deprecator.warn <<~MSG.squish
204
- The `config.active_record.sqlite3_production_warning` configuration no longer has any effect
205
- and can be safely removed.
206
- MSG
207
- end
208
- end
209
-
210
187
  initializer "active_record.sqlite3_adapter_strict_strings_by_default" do
211
188
  config.after_initialize do
212
189
  if config.active_record.sqlite3_adapter_strict_strings_by_default
@@ -311,6 +288,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
311
288
  initializer "active_record.set_executor_hooks" do
312
289
  ActiveRecord::QueryCache.install_executor_hooks
313
290
  ActiveRecord::AsynchronousQueriesTracker.install_executor_hooks
291
+ ActiveRecord::ConnectionAdapters::ConnectionPool.install_executor_hooks
314
292
  end
315
293
 
316
294
  initializer "active_record.add_watchable_files" do |app|
@@ -356,16 +334,19 @@ To keep using the current cache store, you can turn off cache versioning entirel
356
334
  end
357
335
 
358
336
  initializer "active_record_encryption.configuration" do |app|
359
- ActiveSupport.on_load(:active_record) do
360
- ActiveRecord::Encryption.configure \
337
+ ActiveSupport.on_load(:active_record_encryption) do
338
+ ActiveRecord::Encryption.configure(
361
339
  primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
362
340
  deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
363
341
  key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
364
342
  **app.config.active_record.encryption
343
+ )
365
344
 
366
345
  auto_filtered_parameters = ActiveRecord::Encryption::AutoFilteredParameters.new(app)
367
346
  auto_filtered_parameters.enable if ActiveRecord::Encryption.config.add_to_filter_parameters
347
+ end
368
348
 
349
+ ActiveSupport.on_load(:active_record) do
369
350
  # Support extended queries for deterministic attributes and validations
370
351
  if ActiveRecord::Encryption.config.extend_queries
371
352
  ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
@@ -385,7 +366,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
385
366
  config.after_initialize do
386
367
  if app.config.active_record.query_log_tags_enabled
387
368
  ActiveRecord.query_transformers << ActiveRecord::QueryLogs
388
- ActiveRecord::QueryLogs.taggings.merge!(
369
+ ActiveRecord::QueryLogs.taggings = ActiveRecord::QueryLogs.taggings.merge(
389
370
  application: Rails.application.class.name.split("::").first,
390
371
  pid: -> { Process.pid.to_s },
391
372
  socket: ->(context) { context[:connection].pool.db_config.socket },
@@ -400,7 +381,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
400
381
  end
401
382
 
402
383
  if app.config.active_record.query_log_tags_format
403
- 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
404
385
  end
405
386
 
406
387
  if app.config.active_record.cache_query_log_tags
@@ -432,15 +413,5 @@ To keep using the current cache store, you can turn off cache versioning entirel
432
413
  end
433
414
  end
434
415
  end
435
-
436
- initializer "active_record.attributes_for_inspect" do |app|
437
- ActiveSupport.on_load(:active_record) do
438
- if app.config.consider_all_requests_local
439
- if app.config.active_record.attributes_for_inspect.nil?
440
- ActiveRecord::Base.attributes_for_inspect = :all
441
- end
442
- end
443
- end
444
- end
445
416
  end
446
417
  end
@@ -176,7 +176,7 @@ db_namespace = namespace :db do
176
176
  end
177
177
 
178
178
  # desc 'Resets your database using your migrations for the current environment'
179
- task reset: ["db:drop", "db:create", "db:migrate"]
179
+ task reset: ["db:drop", "db:create", "db:schema:dump", "db:migrate"]
180
180
 
181
181
  desc 'Run the "up" for a given migration VERSION.'
182
182
  task up: :load_config do
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  normalized_reflections.stringify_keys
80
80
  end
81
81
 
82
- def normalized_reflections # :nodoc
82
+ def normalized_reflections # :nodoc:
83
83
  @__reflections ||= begin
84
84
  ref = {}
85
85
 
@@ -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,8 +1235,11 @@ 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:
1242
- scopes = @previous_reflection.join_scopes(table, predicate_builder, klass, record) + super
1238
+ def join_scopes(table, predicate_builder = nil, klass = self.klass, record = nil) # :nodoc:
1239
+ scopes = super
1240
+ unless @previous_reflection.through_reflection?
1241
+ scopes += @previous_reflection.join_scopes(table, predicate_builder, klass, record)
1242
+ end
1243
1243
  scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
1244
1244
  end
1245
1245
 
@@ -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