activerecord 8.0.0.beta1 → 8.0.0.rc2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +102 -2
- data/lib/active_record/association_relation.rb +1 -0
- data/lib/active_record/associations/association.rb +9 -5
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations.rb +28 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -12
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +8 -2
- data/lib/active_record/connection_adapters/abstract_adapter.rb +0 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +6 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +11 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +12 -10
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +0 -2
- data/lib/active_record/connection_adapters.rb +0 -56
- data/lib/active_record/core.rb +43 -14
- data/lib/active_record/database_configurations/database_config.rb +4 -0
- data/lib/active_record/database_configurations/hash_config.rb +8 -0
- data/lib/active_record/enum.rb +9 -22
- data/lib/active_record/fixtures.rb +0 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -11
- data/lib/active_record/marshalling.rb +4 -1
- data/lib/active_record/migration/command_recorder.rb +5 -5
- data/lib/active_record/migration.rb +0 -5
- data/lib/active_record/model_schema.rb +2 -3
- data/lib/active_record/query_cache.rb +0 -4
- data/lib/active_record/query_logs.rb +5 -11
- data/lib/active_record/querying.rb +2 -2
- data/lib/active_record/railtie.rb +2 -25
- data/lib/active_record/railties/databases.rake +2 -17
- data/lib/active_record/reflection.rb +14 -19
- data/lib/active_record/relation/calculations.rb +24 -28
- data/lib/active_record/relation/predicate_builder.rb +8 -0
- data/lib/active_record/relation/query_methods.rb +76 -38
- data/lib/active_record/relation.rb +8 -1
- data/lib/active_record/result.rb +10 -9
- data/lib/active_record/table_metadata.rb +1 -3
- data/lib/active_record/tasks/database_tasks.rb +26 -34
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record.rb +0 -45
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/sqlite.rb +25 -0
- metadata +9 -10
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -69,7 +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
|
72
|
+
ActiveRecord::Base.attributes_for_inspect = :all
|
73
73
|
end
|
74
74
|
|
75
75
|
runner do
|
@@ -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
|
@@ -312,6 +288,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
312
288
|
initializer "active_record.set_executor_hooks" do
|
313
289
|
ActiveRecord::QueryCache.install_executor_hooks
|
314
290
|
ActiveRecord::AsynchronousQueriesTracker.install_executor_hooks
|
291
|
+
ActiveRecord::ConnectionAdapters::ConnectionPool.install_executor_hooks
|
315
292
|
end
|
316
293
|
|
317
294
|
initializer "active_record.add_watchable_files" do |app|
|
@@ -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
|
-
|
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
|
|
@@ -176,7 +161,7 @@ db_namespace = namespace :db do
|
|
176
161
|
end
|
177
162
|
|
178
163
|
# desc 'Resets your database using your migrations for the current environment'
|
179
|
-
task reset: ["db:drop", "db:create", "db:migrate"]
|
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
|
@@ -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 =
|
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
|
-
|
535
|
-
Setting `query_constraints:` option on `#{active_record}.#{macro} :#{name}` is
|
536
|
-
To
|
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
|
|
@@ -1070,7 +1062,7 @@ module ActiveRecord
|
|
1070
1062
|
source_reflection.scopes + super
|
1071
1063
|
end
|
1072
1064
|
|
1073
|
-
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:
|
1074
1066
|
source_reflection.join_scopes(table, predicate_builder, klass, record) + super
|
1075
1067
|
end
|
1076
1068
|
|
@@ -1243,8 +1235,11 @@ module ActiveRecord
|
|
1243
1235
|
@previous_reflection = previous_reflection
|
1244
1236
|
end
|
1245
1237
|
|
1246
|
-
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
|
1247
|
-
scopes =
|
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
|
1248
1243
|
scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
|
1249
1244
|
end
|
1250
1245
|
|
@@ -275,10 +275,14 @@ module ActiveRecord
|
|
275
275
|
# # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
|
276
276
|
# # => [2, 3]
|
277
277
|
#
|
278
|
-
# Comment.joins(:person).pluck(:id, person:
|
279
|
-
# # SELECT comments.id,
|
278
|
+
# Comment.joins(:person).pluck(:id, person: :id)
|
279
|
+
# # SELECT comments.id, person.id FROM comments INNER JOIN people person ON person.id = comments.person_id
|
280
280
|
# # => [[1, 2], [2, 2]]
|
281
281
|
#
|
282
|
+
# Comment.joins(:person).pluck(:id, person: [:id, :name])
|
283
|
+
# # SELECT comments.id, person.id, person.name FROM comments INNER JOIN people person ON person.id = comments.person_id
|
284
|
+
# # => [[1, 2, 'David'], [2, 2, 'David']]
|
285
|
+
#
|
282
286
|
# Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
|
283
287
|
# # SELECT DATEDIFF(updated_at, created_at) FROM people
|
284
288
|
# # => ['0', '27761', '173']
|
@@ -307,8 +311,8 @@ module ActiveRecord
|
|
307
311
|
relation.pluck(*column_names)
|
308
312
|
else
|
309
313
|
model.disallow_raw_sql!(flattened_args(column_names))
|
310
|
-
columns = arel_columns(column_names)
|
311
314
|
relation = spawn
|
315
|
+
columns = relation.arel_columns(column_names)
|
312
316
|
relation.select_values = columns
|
313
317
|
result = skip_query_cache_if_necessary do
|
314
318
|
if where_clause.contradiction?
|
@@ -447,10 +451,13 @@ module ActiveRecord
|
|
447
451
|
end
|
448
452
|
|
449
453
|
def aggregate_column(column_name)
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
+
case column_name
|
455
|
+
when Arel::Expressions
|
456
|
+
column_name
|
457
|
+
when :all
|
458
|
+
Arel.star
|
459
|
+
else
|
460
|
+
arel_column(column_name)
|
454
461
|
end
|
455
462
|
end
|
456
463
|
|
@@ -630,27 +637,12 @@ module ActiveRecord
|
|
630
637
|
end
|
631
638
|
|
632
639
|
def select_for_count
|
633
|
-
if select_values.
|
634
|
-
return select_values.first if select_values.one?
|
635
|
-
|
636
|
-
adapter_class = model.adapter_class
|
637
|
-
select_values.map do |field|
|
638
|
-
column = if Arel.arel_node?(field)
|
639
|
-
field
|
640
|
-
else
|
641
|
-
arel_column(field.to_s) do |attr_name|
|
642
|
-
Arel.sql(attr_name)
|
643
|
-
end
|
644
|
-
end
|
645
|
-
|
646
|
-
if column.is_a?(Arel::Nodes::SqlLiteral)
|
647
|
-
column
|
648
|
-
else
|
649
|
-
"#{adapter_class.quote_table_name(column.relation.name)}.#{adapter_class.quote_column_name(column.name)}"
|
650
|
-
end
|
651
|
-
end.join(", ")
|
652
|
-
else
|
640
|
+
if select_values.empty?
|
653
641
|
:all
|
642
|
+
else
|
643
|
+
with_connection do |conn|
|
644
|
+
arel_columns(select_values).map { |column| conn.visitor.compile(column) }.join(", ")
|
645
|
+
end
|
654
646
|
end
|
655
647
|
end
|
656
648
|
|
@@ -673,7 +665,11 @@ module ActiveRecord
|
|
673
665
|
subquery_alias = Arel.sql("subquery_for_count", retryable: true)
|
674
666
|
select_value = operation_over_aggregate_column(column_alias, "count", false)
|
675
667
|
|
676
|
-
|
668
|
+
if column_name == :all
|
669
|
+
relation.unscope(:order).build_subquery(subquery_alias, select_value)
|
670
|
+
else
|
671
|
+
relation.build_subquery(subquery_alias, select_value)
|
672
|
+
end
|
677
673
|
end
|
678
674
|
end
|
679
675
|
end
|
@@ -72,7 +72,15 @@ module ActiveRecord
|
|
72
72
|
table.associated_table(table_name, &block).arel_table[column_name]
|
73
73
|
end
|
74
74
|
|
75
|
+
def with(table)
|
76
|
+
other = dup
|
77
|
+
other.table = table
|
78
|
+
other
|
79
|
+
end
|
80
|
+
|
75
81
|
protected
|
82
|
+
attr_writer :table
|
83
|
+
|
76
84
|
def expand_from_hash(attributes, &block)
|
77
85
|
return ["1=0"] if attributes.empty?
|
78
86
|
|
@@ -498,7 +498,8 @@ module ActiveRecord
|
|
498
498
|
|
499
499
|
# Like #with, but modifies relation in place.
|
500
500
|
def with!(*args) # :nodoc:
|
501
|
-
|
501
|
+
args = process_with_args(args)
|
502
|
+
self.with_values |= args
|
502
503
|
self
|
503
504
|
end
|
504
505
|
|
@@ -506,7 +507,7 @@ module ActiveRecord
|
|
506
507
|
#
|
507
508
|
# Post.with_recursive(post_and_replies: [Post.where(id: 42), Post.joins('JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id')])
|
508
509
|
# # => ActiveRecord::Relation
|
509
|
-
# # WITH post_and_replies AS (
|
510
|
+
# # WITH RECURSIVE post_and_replies AS (
|
510
511
|
# # (SELECT * FROM posts WHERE id = 42)
|
511
512
|
# # UNION ALL
|
512
513
|
# # (SELECT * FROM posts JOIN posts_and_replies ON posts.in_reply_to_id = posts_and_replies.id)
|
@@ -521,7 +522,8 @@ module ActiveRecord
|
|
521
522
|
|
522
523
|
# Like #with_recursive but modifies the relation in place.
|
523
524
|
def with_recursive!(*args) # :nodoc:
|
524
|
-
|
525
|
+
args = process_with_args(args)
|
526
|
+
self.with_values |= args
|
525
527
|
@with_is_recursive = true
|
526
528
|
self
|
527
529
|
end
|
@@ -1656,6 +1658,22 @@ module ActiveRecord
|
|
1656
1658
|
self
|
1657
1659
|
end
|
1658
1660
|
|
1661
|
+
protected
|
1662
|
+
def arel_columns(columns)
|
1663
|
+
columns.flat_map do |field|
|
1664
|
+
case field
|
1665
|
+
when Symbol, String
|
1666
|
+
arel_column(field)
|
1667
|
+
when Proc
|
1668
|
+
field.call
|
1669
|
+
when Hash
|
1670
|
+
arel_columns_from_hash(field)
|
1671
|
+
else
|
1672
|
+
field
|
1673
|
+
end
|
1674
|
+
end
|
1675
|
+
end
|
1676
|
+
|
1659
1677
|
private
|
1660
1678
|
def async
|
1661
1679
|
spawn.async!
|
@@ -1910,12 +1928,26 @@ module ActiveRecord
|
|
1910
1928
|
end
|
1911
1929
|
end
|
1912
1930
|
|
1913
|
-
def build_with_expression_from_value(value)
|
1931
|
+
def build_with_expression_from_value(value, nested = false)
|
1914
1932
|
case value
|
1915
1933
|
when Arel::Nodes::SqlLiteral then Arel::Nodes::Grouping.new(value)
|
1916
|
-
when ActiveRecord::Relation
|
1934
|
+
when ActiveRecord::Relation
|
1935
|
+
if nested
|
1936
|
+
value.arel.ast
|
1937
|
+
else
|
1938
|
+
value.arel
|
1939
|
+
end
|
1917
1940
|
when Arel::SelectManager then value
|
1918
|
-
when Array
|
1941
|
+
when Array
|
1942
|
+
return build_with_expression_from_value(value.first, false) if value.size == 1
|
1943
|
+
|
1944
|
+
parts = value.map do |query|
|
1945
|
+
build_with_expression_from_value(query, true)
|
1946
|
+
end
|
1947
|
+
|
1948
|
+
parts.reduce do |result, value|
|
1949
|
+
Arel::Nodes::UnionAll.new(result, value)
|
1950
|
+
end
|
1919
1951
|
else
|
1920
1952
|
raise ArgumentError, "Unsupported argument type: `#{value}` #{value.class}"
|
1921
1953
|
end
|
@@ -1929,38 +1961,43 @@ module ActiveRecord
|
|
1929
1961
|
).join_sources.first
|
1930
1962
|
end
|
1931
1963
|
|
1932
|
-
def
|
1933
|
-
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1937
|
-
|
1964
|
+
def arel_columns_from_hash(fields)
|
1965
|
+
fields.flat_map do |table_name, columns|
|
1966
|
+
table_name = table_name.name if table_name.is_a?(Symbol)
|
1967
|
+
case columns
|
1968
|
+
when Symbol, String
|
1969
|
+
arel_column_with_table(table_name, columns.to_s)
|
1970
|
+
when Array
|
1971
|
+
columns.map do |column|
|
1972
|
+
arel_column_with_table(table_name, column.to_s)
|
1938
1973
|
end
|
1939
|
-
when String
|
1940
|
-
arel_column(field, &:itself)
|
1941
|
-
when Proc
|
1942
|
-
field.call
|
1943
|
-
when Hash
|
1944
|
-
arel_columns_from_hash(field)
|
1945
1974
|
else
|
1946
|
-
|
1975
|
+
raise TypeError, "Expected Symbol, String or Array, got: #{columns.class}"
|
1947
1976
|
end
|
1948
1977
|
end
|
1949
1978
|
end
|
1950
1979
|
|
1980
|
+
def arel_column_with_table(table_name, column_name)
|
1981
|
+
self.references_values |= [Arel.sql(table_name, retryable: true)]
|
1982
|
+
predicate_builder.resolve_arel_attribute(table_name, column_name) do
|
1983
|
+
lookup_table_klass_from_join_dependencies(table_name)
|
1984
|
+
end
|
1985
|
+
end
|
1986
|
+
|
1951
1987
|
def arel_column(field)
|
1988
|
+
field = field.name if is_symbol = field.is_a?(Symbol)
|
1989
|
+
|
1952
1990
|
field = model.attribute_aliases[field] || field
|
1953
1991
|
from = from_clause.name || from_clause.value
|
1954
1992
|
|
1955
1993
|
if model.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1956
1994
|
table[field]
|
1957
|
-
elsif
|
1958
|
-
table, column
|
1959
|
-
|
1960
|
-
lookup_table_klass_from_join_dependencies(table)
|
1961
|
-
end
|
1962
|
-
else
|
1995
|
+
elsif /\A(?<table>(?:\w+\.)?\w+)\.(?<column>\w+)\z/ =~ field
|
1996
|
+
arel_column_with_table(table, column)
|
1997
|
+
elsif block_given?
|
1963
1998
|
yield field
|
1999
|
+
else
|
2000
|
+
Arel.sql(is_symbol ? model.adapter_class.quote_table_name(field) : field)
|
1964
2001
|
end
|
1965
2002
|
end
|
1966
2003
|
|
@@ -2182,38 +2219,39 @@ module ActiveRecord
|
|
2182
2219
|
def process_select_args(fields)
|
2183
2220
|
fields.flat_map do |field|
|
2184
2221
|
if field.is_a?(Hash)
|
2185
|
-
|
2222
|
+
arel_column_aliases_from_hash(field)
|
2186
2223
|
else
|
2187
2224
|
field
|
2188
2225
|
end
|
2189
2226
|
end
|
2190
2227
|
end
|
2191
2228
|
|
2192
|
-
def
|
2229
|
+
def arel_column_aliases_from_hash(fields)
|
2193
2230
|
fields.flat_map do |key, columns_aliases|
|
2231
|
+
table_name = key.is_a?(Symbol) ? key.name : key
|
2194
2232
|
case columns_aliases
|
2195
2233
|
when Hash
|
2196
2234
|
columns_aliases.map do |column, column_alias|
|
2197
|
-
|
2198
|
-
|
2199
|
-
self.references_values |= references unless references.empty?
|
2200
|
-
end
|
2201
|
-
arel_column("#{key}.#{column}") do
|
2202
|
-
predicate_builder.resolve_arel_attribute(key.to_s, column)
|
2203
|
-
end.as(column_alias.to_s)
|
2235
|
+
arel_column_with_table(table_name, column.to_s)
|
2236
|
+
.as(model.adapter_class.quote_column_name(column_alias.to_s))
|
2204
2237
|
end
|
2205
2238
|
when Array
|
2206
2239
|
columns_aliases.map do |column|
|
2207
|
-
|
2240
|
+
arel_column_with_table(table_name, column.to_s)
|
2208
2241
|
end
|
2209
2242
|
when String, Symbol
|
2210
|
-
arel_column(key
|
2211
|
-
|
2212
|
-
end.as(columns_aliases.to_s)
|
2243
|
+
arel_column(key)
|
2244
|
+
.as(model.adapter_class.quote_column_name(columns_aliases.to_s))
|
2213
2245
|
end
|
2214
2246
|
end
|
2215
2247
|
end
|
2216
2248
|
|
2249
|
+
def process_with_args(args)
|
2250
|
+
args.flat_map do |arg|
|
2251
|
+
arg.map { |k, v| { k => v } }
|
2252
|
+
end
|
2253
|
+
end
|
2254
|
+
|
2217
2255
|
STRUCTURAL_VALUE_METHODS = (
|
2218
2256
|
Relation::VALUE_METHODS -
|
2219
2257
|
[:extending, :where, :having, :unscope, :references, :annotate, :optimizer_hints]
|
@@ -74,7 +74,14 @@ module ActiveRecord
|
|
74
74
|
alias :loaded? :loaded
|
75
75
|
alias :locked? :lock_value
|
76
76
|
|
77
|
-
def initialize(model, table:
|
77
|
+
def initialize(model, table: nil, predicate_builder: nil, values: {})
|
78
|
+
if table
|
79
|
+
predicate_builder ||= model.predicate_builder.with(TableMetadata.new(model, table))
|
80
|
+
else
|
81
|
+
table = model.arel_table
|
82
|
+
predicate_builder ||= model.predicate_builder
|
83
|
+
end
|
84
|
+
|
78
85
|
@model = model
|
79
86
|
@table = table
|
80
87
|
@values = values
|
data/lib/active_record/result.rb
CHANGED
@@ -127,9 +127,9 @@ module ActiveRecord
|
|
127
127
|
# Returns an +Enumerator+ if no block is given.
|
128
128
|
def each(&block)
|
129
129
|
if block_given?
|
130
|
-
|
130
|
+
hash_rows.each(&block)
|
131
131
|
else
|
132
|
-
|
132
|
+
hash_rows.to_enum { @rows.size }
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
@@ -191,6 +191,7 @@ module ActiveRecord
|
|
191
191
|
def initialize_copy(other)
|
192
192
|
@rows = rows.dup
|
193
193
|
@column_types = column_types.dup
|
194
|
+
@hash_rows = nil
|
194
195
|
end
|
195
196
|
|
196
197
|
def freeze # :nodoc:
|
@@ -212,6 +213,13 @@ module ActiveRecord
|
|
212
213
|
end
|
213
214
|
end
|
214
215
|
|
216
|
+
def indexed_rows # :nodoc:
|
217
|
+
@indexed_rows ||= begin
|
218
|
+
columns = column_indexes
|
219
|
+
@rows.map { |row| IndexedRow.new(columns, row) }.freeze
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
215
223
|
private
|
216
224
|
def column_type(name, index, type_overrides)
|
217
225
|
type_overrides.fetch(name) do
|
@@ -221,13 +229,6 @@ module ActiveRecord
|
|
221
229
|
end
|
222
230
|
end
|
223
231
|
|
224
|
-
def indexed_rows
|
225
|
-
@indexed_rows ||= begin
|
226
|
-
columns = column_indexes
|
227
|
-
@rows.map { |row| IndexedRow.new(columns, row) }.freeze
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
232
|
def hash_rows
|
232
233
|
# We use transform_values to rows.
|
233
234
|
# This is faster because we avoid any reallocs and avoid hashing entirely.
|
@@ -69,9 +69,7 @@ module ActiveRecord
|
|
69
69
|
|
70
70
|
def predicate_builder
|
71
71
|
if klass
|
72
|
-
|
73
|
-
predicate_builder.instance_variable_set(:@table, self)
|
74
|
-
predicate_builder
|
72
|
+
klass.predicate_builder.with(self)
|
75
73
|
else
|
76
74
|
PredicateBuilder.new(self)
|
77
75
|
end
|
@@ -180,7 +180,7 @@ module ActiveRecord
|
|
180
180
|
each_current_configuration(env) do |db_config|
|
181
181
|
database_initialized = initialize_database(db_config)
|
182
182
|
|
183
|
-
seed = true if database_initialized
|
183
|
+
seed = true if database_initialized && db_config.seeds?
|
184
184
|
end
|
185
185
|
|
186
186
|
each_current_environment(env) do |environment|
|
@@ -240,13 +240,32 @@ module ActiveRecord
|
|
240
240
|
end
|
241
241
|
end
|
242
242
|
|
243
|
-
def
|
243
|
+
def migrate_all
|
244
|
+
db_configs = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env)
|
245
|
+
db_configs.each { |db_config| initialize_database(db_config) }
|
246
|
+
|
247
|
+
if db_configs.size == 1 && db_configs.first.primary?
|
248
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate(skip_initialize: true)
|
249
|
+
else
|
250
|
+
mapped_versions = ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions
|
251
|
+
|
252
|
+
mapped_versions.sort.each do |version, db_configs|
|
253
|
+
db_configs.each do |db_config|
|
254
|
+
ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection(db_config) do
|
255
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate(version, skip_initialize: true)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def migrate(version = nil, skip_initialize: false)
|
244
263
|
scope = ENV["SCOPE"]
|
245
264
|
verbose_was, Migration.verbose = Migration.verbose, verbose?
|
246
265
|
|
247
266
|
check_target_version
|
248
267
|
|
249
|
-
initialize_database(migration_connection_pool.db_config)
|
268
|
+
initialize_database(migration_connection_pool.db_config) unless skip_initialize
|
250
269
|
|
251
270
|
migration_connection_pool.migration_context.migrate(target_version) do |migration|
|
252
271
|
if version.blank?
|
@@ -446,26 +465,10 @@ module ActiveRecord
|
|
446
465
|
end
|
447
466
|
end
|
448
467
|
|
449
|
-
def cache_dump_filename(
|
450
|
-
|
451
|
-
schema_cache_path ||
|
452
|
-
|
453
|
-
schema_cache_env ||
|
454
|
-
db_config_or_name.default_schema_cache_path(ActiveRecord::Tasks::DatabaseTasks.db_dir)
|
455
|
-
else
|
456
|
-
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
457
|
-
Passing a database name to `cache_dump_filename` is deprecated and will be removed in Rails 8.0. Pass a
|
458
|
-
`ActiveRecord::DatabaseConfigurations::DatabaseConfig` object instead.
|
459
|
-
MSG
|
460
|
-
|
461
|
-
filename = if ActiveRecord::Base.configurations.primary?(db_config_or_name)
|
462
|
-
"schema_cache.yml"
|
463
|
-
else
|
464
|
-
"#{db_config_or_name}_schema_cache.yml"
|
465
|
-
end
|
466
|
-
|
467
|
-
schema_cache_path || schema_cache_env || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
|
468
|
-
end
|
468
|
+
def cache_dump_filename(db_config, schema_cache_path: nil)
|
469
|
+
schema_cache_path ||
|
470
|
+
db_config.schema_cache_path ||
|
471
|
+
db_config.default_schema_cache_path(ActiveRecord::Tasks::DatabaseTasks.db_dir)
|
469
472
|
end
|
470
473
|
|
471
474
|
def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
|
@@ -536,17 +539,6 @@ module ActiveRecord
|
|
536
539
|
end
|
537
540
|
|
538
541
|
private
|
539
|
-
def schema_cache_env
|
540
|
-
if ENV["SCHEMA_CACHE"]
|
541
|
-
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
542
|
-
Setting `ENV["SCHEMA_CACHE"]` is deprecated and will be removed in Rails 8.0.
|
543
|
-
Configure the `:schema_cache_path` in the database configuration instead.
|
544
|
-
MSG
|
545
|
-
|
546
|
-
nil
|
547
|
-
end
|
548
|
-
end
|
549
|
-
|
550
542
|
def with_temporary_pool(db_config, clobber: false)
|
551
543
|
original_db_config = migration_class.connection_db_config
|
552
544
|
pool = migration_class.connection_handler.establish_connection(db_config, clobber: clobber)
|
@@ -52,7 +52,7 @@ module ActiveRecord
|
|
52
52
|
# assert_queries_match(/LIMIT \?/) { Post.first }
|
53
53
|
#
|
54
54
|
# If the +:include_schema+ option is provided, any queries (including schema related)
|
55
|
-
#
|
55
|
+
# that match the matcher are considered.
|
56
56
|
#
|
57
57
|
# assert_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
58
58
|
#
|
@@ -80,7 +80,7 @@ module ActiveRecord
|
|
80
80
|
# assert_no_queries_match(/SELECT/i) { post.comments }
|
81
81
|
#
|
82
82
|
# If the +:include_schema+ option is provided, any queries (including schema related)
|
83
|
-
#
|
83
|
+
# that match the matcher are counted.
|
84
84
|
#
|
85
85
|
# assert_no_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
86
86
|
#
|