activerecord 7.2.3 → 8.0.4

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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +391 -958
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/association_relation.rb +1 -0
  5. data/lib/active_record/associations/association.rb +34 -10
  6. data/lib/active_record/associations/builder/association.rb +7 -6
  7. data/lib/active_record/associations/collection_association.rb +1 -1
  8. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  9. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  10. data/lib/active_record/associations/preloader/association.rb +2 -2
  11. data/lib/active_record/associations/singular_association.rb +8 -3
  12. data/lib/active_record/associations.rb +34 -4
  13. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  14. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  15. data/lib/active_record/attribute_methods/query.rb +34 -0
  16. data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
  17. data/lib/active_record/autosave_association.rb +69 -27
  18. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +34 -25
  19. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  20. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  21. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +6 -15
  22. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  23. data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
  24. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  25. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  26. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -2
  27. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +34 -7
  28. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  29. data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -43
  30. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +21 -40
  31. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  32. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  33. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +50 -45
  34. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +84 -94
  35. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  36. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  37. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +72 -43
  38. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  39. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  40. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  41. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
  42. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +6 -12
  43. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
  44. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +59 -16
  45. data/lib/active_record/connection_adapters/postgresql_adapter.rb +46 -96
  46. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  47. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +80 -100
  48. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  49. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  50. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +9 -1
  51. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -12
  52. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  53. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  54. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  55. data/lib/active_record/connection_adapters.rb +0 -56
  56. data/lib/active_record/connection_handling.rb +23 -1
  57. data/lib/active_record/core.rb +29 -14
  58. data/lib/active_record/database_configurations/database_config.rb +4 -0
  59. data/lib/active_record/database_configurations/hash_config.rb +16 -2
  60. data/lib/active_record/encryption/config.rb +3 -1
  61. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  62. data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
  63. data/lib/active_record/encryption/encryptor.rb +16 -8
  64. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  65. data/lib/active_record/encryption/scheme.rb +8 -1
  66. data/lib/active_record/enum.rb +9 -22
  67. data/lib/active_record/errors.rb +13 -5
  68. data/lib/active_record/fixtures.rb +0 -2
  69. data/lib/active_record/future_result.rb +13 -9
  70. data/lib/active_record/gem_version.rb +3 -3
  71. data/lib/active_record/insert_all.rb +1 -1
  72. data/lib/active_record/locking/optimistic.rb +1 -1
  73. data/lib/active_record/log_subscriber.rb +5 -11
  74. data/lib/active_record/migration/command_recorder.rb +31 -11
  75. data/lib/active_record/migration/compatibility.rb +5 -2
  76. data/lib/active_record/migration.rb +38 -42
  77. data/lib/active_record/model_schema.rb +3 -4
  78. data/lib/active_record/nested_attributes.rb +4 -6
  79. data/lib/active_record/persistence.rb +128 -130
  80. data/lib/active_record/query_logs.rb +102 -50
  81. data/lib/active_record/query_logs_formatter.rb +17 -28
  82. data/lib/active_record/querying.rb +8 -8
  83. data/lib/active_record/railtie.rb +2 -26
  84. data/lib/active_record/railties/databases.rake +11 -35
  85. data/lib/active_record/reflection.rb +18 -21
  86. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  87. data/lib/active_record/relation/batches.rb +132 -72
  88. data/lib/active_record/relation/calculations.rb +40 -39
  89. data/lib/active_record/relation/delegation.rb +25 -14
  90. data/lib/active_record/relation/finder_methods.rb +18 -18
  91. data/lib/active_record/relation/merger.rb +8 -8
  92. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  93. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  94. data/lib/active_record/relation/predicate_builder.rb +13 -0
  95. data/lib/active_record/relation/query_methods.rb +105 -61
  96. data/lib/active_record/relation/spawn_methods.rb +7 -7
  97. data/lib/active_record/relation.rb +79 -61
  98. data/lib/active_record/result.rb +66 -4
  99. data/lib/active_record/sanitization.rb +7 -6
  100. data/lib/active_record/schema_dumper.rb +5 -0
  101. data/lib/active_record/schema_migration.rb +2 -1
  102. data/lib/active_record/scoping/named.rb +5 -2
  103. data/lib/active_record/statement_cache.rb +14 -14
  104. data/lib/active_record/store.rb +7 -3
  105. data/lib/active_record/table_metadata.rb +1 -3
  106. data/lib/active_record/tasks/database_tasks.rb +69 -60
  107. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  108. data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -1
  109. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  110. data/lib/active_record/test_databases.rb +1 -1
  111. data/lib/active_record/test_fixtures.rb +12 -0
  112. data/lib/active_record/token_for.rb +1 -1
  113. data/lib/active_record/transactions.rb +5 -6
  114. data/lib/active_record/validations/uniqueness.rb +8 -8
  115. data/lib/active_record.rb +21 -48
  116. data/lib/arel/collectors/bind.rb +2 -2
  117. data/lib/arel/collectors/sql_string.rb +1 -1
  118. data/lib/arel/collectors/substitute_binds.rb +2 -2
  119. data/lib/arel/nodes/binary.rb +1 -1
  120. data/lib/arel/nodes/node.rb +1 -1
  121. data/lib/arel/nodes/sql_literal.rb +1 -1
  122. data/lib/arel/table.rb +3 -7
  123. metadata +9 -10
  124. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -76,14 +76,70 @@ module ActiveRecord
76
76
  #
77
77
  # config.active_record.cache_query_log_tags = true
78
78
  module QueryLogs
79
- mattr_accessor :taggings, instance_accessor: false, default: {}
80
- mattr_accessor :tags, instance_accessor: false, default: [ :application ]
81
- mattr_accessor :prepend_comment, instance_accessor: false, default: false
82
- mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
83
- 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
+
84
115
  thread_mattr_accessor :cached_comment, instance_accessor: false
85
116
 
86
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
+
87
143
  def call(sql, connection) # :nodoc:
88
144
  comment = self.comment(connection)
89
145
 
@@ -100,36 +156,46 @@ module ActiveRecord
100
156
  self.cached_comment = nil
101
157
  end
102
158
 
103
- # Updates the formatter to be what the passed in format is.
104
- def update_formatter(format)
105
- self.tags_formatter =
106
- case format
107
- when :legacy
108
- LegacyFormatter.new
109
- when :sqlcommenter
110
- SQLCommenter.new
111
- else
112
- raise ArgumentError, "Formatter is unsupported: #{formatter}"
113
- end
114
- end
115
-
116
- if Thread.respond_to?(:each_caller_location)
117
- def query_source_location # :nodoc:
118
- Thread.each_caller_location do |location|
119
- frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
120
- return frame if frame
121
- end
122
- nil
123
- end
124
- else
125
- def query_source_location # :nodoc:
126
- 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
127
163
  end
164
+ nil
128
165
  end
129
166
 
130
167
  ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
131
168
 
132
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
+
133
199
  # Returns an SQL comment +String+ containing the query log tags.
134
200
  # Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
135
201
  def comment(connection)
@@ -140,10 +206,6 @@ module ActiveRecord
140
206
  end
141
207
  end
142
208
 
143
- def formatter
144
- self.tags_formatter || self.update_formatter(:legacy)
145
- end
146
-
147
209
  def uncached_comment(connection)
148
210
  content = tag_content(connection)
149
211
 
@@ -169,25 +231,15 @@ module ActiveRecord
169
231
  context = ActiveSupport::ExecutionContext.to_h
170
232
  context[:connection] ||= connection
171
233
 
172
- pairs = tags.flat_map { |i| [*i] }.filter_map do |tag|
173
- key, handler = tag
174
- handler ||= taggings[key]
175
-
176
- val = if handler.nil?
177
- context[key]
178
- elsif handler.respond_to?(:call)
179
- if handler.arity == 0
180
- handler.call
181
- else
182
- handler.call(context)
183
- end
184
- else
185
- handler
186
- end
187
- [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?
188
237
  end
189
- self.formatter.format(pairs)
238
+ @formatter.join(pairs)
190
239
  end
191
240
  end
241
+
242
+ @handlers = rebuild_handlers
243
+ self.tags_formatter = :legacy
192
244
  end
193
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
@@ -56,12 +56,10 @@ module ActiveRecord
56
56
  end
57
57
 
58
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, &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
@@ -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,19 +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
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
477
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current(schema_format, ENV["SCHEMA"])
457
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ENV["SCHEMA_FORMAT"], ENV["SCHEMA"])
478
458
  end
479
459
 
480
460
  namespace :dump do
@@ -483,8 +463,7 @@ db_namespace = namespace :db do
483
463
  task name => :load_config do
484
464
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
485
465
  db_config = pool.db_config
486
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
487
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
466
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
488
467
  end
489
468
 
490
469
  db_namespace["schema:dump:#{name}"].reenable
@@ -494,12 +473,11 @@ db_namespace = namespace :db do
494
473
 
495
474
  namespace :load do
496
475
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
497
- 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"
498
477
  task name => "db:test:purge:#{name}" do
499
478
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
500
479
  db_config = pool.db_config
501
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
502
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
480
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
503
481
  end
504
482
  end
505
483
  end
@@ -543,13 +521,12 @@ db_namespace = namespace :db do
543
521
  end
544
522
 
545
523
  namespace :test do
546
- # 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)"
547
525
  task load_schema: %w(db:test:purge) do
548
526
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: "test") do |pool|
549
527
  db_config = pool.db_config
550
528
  ActiveRecord::Schema.verbose = false
551
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
552
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
529
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
553
530
  end
554
531
  end
555
532
 
@@ -574,8 +551,7 @@ db_namespace = namespace :db do
574
551
  ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: "test", name: name) do |pool|
575
552
  db_config = pool.db_config
576
553
  ActiveRecord::Schema.verbose = false
577
- schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
578
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
554
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
579
555
  end
580
556
  end
581
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