activerecord 8.0.0.beta1 → 8.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
#
|