activerecord 7.2.1.1 → 8.0.0.rc1

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 (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