activerecord 7.2.2 → 8.0.0.beta1
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 +173 -920
- data/README.rdoc +1 -1
- data/lib/active_record/associations/association.rb +25 -5
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +10 -8
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -9
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +50 -32
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +0 -27
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +27 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -25
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +23 -45
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +41 -93
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -12
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
- data/lib/active_record/connection_handling.rb +22 -0
- data/lib/active_record/core.rb +7 -32
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
- data/lib/active_record/encryption/encryptor.rb +15 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/errors.rb +13 -5
- data/lib/active_record/fixtures.rb +0 -1
- data/lib/active_record/future_result.rb +14 -10
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/marshalling.rb +1 -4
- data/lib/active_record/migration/command_recorder.rb +22 -5
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +35 -33
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_cache.rb +5 -4
- data/lib/active_record/query_logs.rb +98 -40
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +6 -6
- data/lib/active_record/railtie.rb +3 -4
- data/lib/active_record/reflection.rb +9 -7
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +132 -72
- data/lib/active_record/relation/calculations.rb +25 -20
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +18 -18
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +5 -0
- data/lib/active_record/relation/query_methods.rb +81 -75
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation.rb +72 -61
- data/lib/active_record/result.rb +68 -7
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +5 -0
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/statement_cache.rb +12 -12
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +24 -15
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +15 -0
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/visitors/sqlite.rb +0 -25
- metadata +10 -10
@@ -145,10 +145,10 @@ module ActiveRecord
|
|
145
145
|
|
146
146
|
if found.nil?
|
147
147
|
raise_record_not_found_exception!
|
148
|
-
elsif undesired.
|
149
|
-
raise ActiveRecord::SoleRecordExceeded.new(self)
|
150
|
-
else
|
148
|
+
elsif undesired.nil?
|
151
149
|
found
|
150
|
+
else
|
151
|
+
raise ActiveRecord::SoleRecordExceeded.new(model)
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
@@ -376,7 +376,7 @@ module ActiveRecord
|
|
376
376
|
|
377
377
|
skip_query_cache_if_necessary do
|
378
378
|
with_connection do |c|
|
379
|
-
c.select_rows(relation.arel, "#{name} Exists?").size == 1
|
379
|
+
c.select_rows(relation.arel, "#{model.name} Exists?").size == 1
|
380
380
|
end
|
381
381
|
end
|
382
382
|
end
|
@@ -389,7 +389,7 @@ module ActiveRecord
|
|
389
389
|
def include?(record)
|
390
390
|
# The existing implementation relies on receiving an Active Record instance as the input parameter named record.
|
391
391
|
# Any non-Active Record object passed to this implementation is guaranteed to return `false`.
|
392
|
-
return false unless record.is_a?(
|
392
|
+
return false unless record.is_a?(model)
|
393
393
|
|
394
394
|
if loaded? || offset_value || limit_value || having_clause.any?
|
395
395
|
records.include?(record)
|
@@ -415,9 +415,9 @@ module ActiveRecord
|
|
415
415
|
# the expected number of results should be provided in the +expected_size+
|
416
416
|
# argument.
|
417
417
|
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
418
|
-
conditions = " [#{arel.where_sql(
|
418
|
+
conditions = " [#{arel.where_sql(model)}]" unless where_clause.empty?
|
419
419
|
|
420
|
-
name =
|
420
|
+
name = model.name
|
421
421
|
|
422
422
|
if ids.nil?
|
423
423
|
error = +"Couldn't find #{name}"
|
@@ -471,7 +471,7 @@ module ActiveRecord
|
|
471
471
|
)
|
472
472
|
)
|
473
473
|
relation = skip_query_cache_if_necessary do
|
474
|
-
|
474
|
+
model.with_connection do |c|
|
475
475
|
c.distinct_relation_for_primary_key(relation)
|
476
476
|
end
|
477
477
|
end
|
@@ -489,9 +489,9 @@ module ActiveRecord
|
|
489
489
|
end
|
490
490
|
|
491
491
|
def find_with_ids(*ids)
|
492
|
-
raise UnknownPrimaryKey.new(
|
492
|
+
raise UnknownPrimaryKey.new(model) if primary_key.nil?
|
493
493
|
|
494
|
-
expects_array = if
|
494
|
+
expects_array = if model.composite_primary_key?
|
495
495
|
ids.first.first.is_a?(Array)
|
496
496
|
else
|
497
497
|
ids.first.is_a?(Array)
|
@@ -503,7 +503,7 @@ module ActiveRecord
|
|
503
503
|
|
504
504
|
ids = ids.compact.uniq
|
505
505
|
|
506
|
-
model_name =
|
506
|
+
model_name = model.name
|
507
507
|
|
508
508
|
case ids.size
|
509
509
|
when 0
|
@@ -525,7 +525,7 @@ module ActiveRecord
|
|
525
525
|
MSG
|
526
526
|
end
|
527
527
|
|
528
|
-
relation = if
|
528
|
+
relation = if model.composite_primary_key?
|
529
529
|
where(primary_key.zip(id).to_h)
|
530
530
|
else
|
531
531
|
where(primary_key => id)
|
@@ -573,7 +573,7 @@ module ActiveRecord
|
|
573
573
|
result = relation.records
|
574
574
|
|
575
575
|
if result.size == ids.size
|
576
|
-
result.in_order_of(:id, ids.map { |id|
|
576
|
+
result.in_order_of(:id, ids.map { |id| model.type_for_attribute(primary_key).cast(id) })
|
577
577
|
else
|
578
578
|
raise_record_not_found_exception!(ids, result.size, ids.size)
|
579
579
|
end
|
@@ -638,7 +638,7 @@ module ActiveRecord
|
|
638
638
|
end
|
639
639
|
|
640
640
|
def ordered_relation
|
641
|
-
if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
|
641
|
+
if order_values.empty? && (model.implicit_order_column || !model.query_constraints_list.nil? || primary_key)
|
642
642
|
order(_order_columns.map { |column| table[column].asc })
|
643
643
|
else
|
644
644
|
self
|
@@ -648,11 +648,11 @@ module ActiveRecord
|
|
648
648
|
def _order_columns
|
649
649
|
oc = []
|
650
650
|
|
651
|
-
oc << implicit_order_column if implicit_order_column
|
652
|
-
oc << query_constraints_list if query_constraints_list
|
651
|
+
oc << model.implicit_order_column if model.implicit_order_column
|
652
|
+
oc << model.query_constraints_list if model.query_constraints_list
|
653
653
|
|
654
|
-
if primary_key && query_constraints_list.nil?
|
655
|
-
oc << primary_key
|
654
|
+
if model.primary_key && model.query_constraints_list.nil?
|
655
|
+
oc << model.primary_key
|
656
656
|
end
|
657
657
|
|
658
658
|
oc.flatten.uniq.compact
|
@@ -24,7 +24,7 @@ module ActiveRecord
|
|
24
24
|
# the values.
|
25
25
|
def other
|
26
26
|
other = Relation.create(
|
27
|
-
relation.
|
27
|
+
relation.model,
|
28
28
|
table: relation.table,
|
29
29
|
predicate_builder: relation.predicate_builder
|
30
30
|
)
|
@@ -84,7 +84,7 @@ module ActiveRecord
|
|
84
84
|
def merge_select_values
|
85
85
|
return if other.select_values.empty?
|
86
86
|
|
87
|
-
if other.
|
87
|
+
if other.model == relation.model
|
88
88
|
relation.select_values |= other.select_values
|
89
89
|
else
|
90
90
|
relation.select_values |= other.instance_eval do
|
@@ -96,12 +96,12 @@ module ActiveRecord
|
|
96
96
|
def merge_preloads
|
97
97
|
return if other.preload_values.empty? && other.includes_values.empty?
|
98
98
|
|
99
|
-
if other.
|
99
|
+
if other.model == relation.model
|
100
100
|
relation.preload_values |= other.preload_values unless other.preload_values.empty?
|
101
101
|
relation.includes_values |= other.includes_values unless other.includes_values.empty?
|
102
102
|
else
|
103
|
-
reflection = relation.
|
104
|
-
r.class_name == other.
|
103
|
+
reflection = relation.model.reflect_on_all_associations.find do |r|
|
104
|
+
r.class_name == other.model.name
|
105
105
|
end || return
|
106
106
|
|
107
107
|
unless other.preload_values.empty?
|
@@ -117,7 +117,7 @@ module ActiveRecord
|
|
117
117
|
def merge_joins
|
118
118
|
return if other.joins_values.empty?
|
119
119
|
|
120
|
-
if other.
|
120
|
+
if other.model == relation.model
|
121
121
|
relation.joins_values |= other.joins_values
|
122
122
|
else
|
123
123
|
associations, others = other.joins_values.partition do |join|
|
@@ -136,7 +136,7 @@ module ActiveRecord
|
|
136
136
|
def merge_outer_joins
|
137
137
|
return if other.left_outer_joins_values.empty?
|
138
138
|
|
139
|
-
if other.
|
139
|
+
if other.model == relation.model
|
140
140
|
relation.left_outer_joins_values |= other.left_outer_joins_values
|
141
141
|
else
|
142
142
|
associations, others = other.left_outer_joins_values.partition do |join|
|
@@ -185,7 +185,7 @@ module ActiveRecord
|
|
185
185
|
|
186
186
|
def replace_from_clause?
|
187
187
|
relation.from_clause.empty? && !other.from_clause.empty? &&
|
188
|
-
relation.
|
188
|
+
relation.model.base_class == other.model.base_class
|
189
189
|
end
|
190
190
|
end
|
191
191
|
end
|
@@ -9,10 +9,11 @@ module ActiveRecord
|
|
9
9
|
end
|
10
10
|
|
11
11
|
if value.select_values.empty?
|
12
|
-
|
13
|
-
|
12
|
+
model = value.model
|
13
|
+
if model.composite_primary_key?
|
14
|
+
raise ArgumentError, "Cannot map composite primary key #{model.primary_key} to #{attribute.name}"
|
14
15
|
else
|
15
|
-
value = value.select(value.table[
|
16
|
+
value = value.select(value.table[model.primary_key])
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
@@ -77,6 +77,11 @@ module ActiveRecord
|
|
77
77
|
return ["1=0"] if attributes.empty?
|
78
78
|
|
79
79
|
attributes.flat_map do |key, value|
|
80
|
+
if key.is_a?(Array) && key.size == 1
|
81
|
+
key = key.first
|
82
|
+
value = value.flatten
|
83
|
+
end
|
84
|
+
|
80
85
|
if key.is_a?(Array)
|
81
86
|
queries = Array(value).map do |ids_set|
|
82
87
|
raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
|
@@ -92,10 +92,11 @@ module ActiveRecord
|
|
92
92
|
@scope.joins!(association)
|
93
93
|
end
|
94
94
|
|
95
|
+
association_conditions = Array(reflection.association_primary_key).index_with(nil)
|
95
96
|
if reflection.options[:class_name]
|
96
|
-
self.not(association =>
|
97
|
+
self.not(association => association_conditions)
|
97
98
|
else
|
98
|
-
self.not(reflection.table_name =>
|
99
|
+
self.not(reflection.table_name => association_conditions)
|
99
100
|
end
|
100
101
|
end
|
101
102
|
|
@@ -124,10 +125,11 @@ module ActiveRecord
|
|
124
125
|
associations.each do |association|
|
125
126
|
reflection = scope_association_reflection(association)
|
126
127
|
@scope.left_outer_joins!(association)
|
128
|
+
association_conditions = Array(reflection.association_primary_key).index_with(nil)
|
127
129
|
if reflection.options[:class_name]
|
128
|
-
@scope.where!(association =>
|
130
|
+
@scope.where!(association => association_conditions)
|
129
131
|
else
|
130
|
-
@scope.where!(reflection.table_name =>
|
132
|
+
@scope.where!(reflection.table_name => association_conditions)
|
131
133
|
end
|
132
134
|
end
|
133
135
|
|
@@ -136,9 +138,10 @@ module ActiveRecord
|
|
136
138
|
|
137
139
|
private
|
138
140
|
def scope_association_reflection(association)
|
139
|
-
|
141
|
+
model = @scope.model
|
142
|
+
reflection = model._reflect_on_association(association)
|
140
143
|
unless reflection
|
141
|
-
raise ArgumentError.new("An association named `:#{association}` does not exist on the model `#{
|
144
|
+
raise ArgumentError.new("An association named `:#{association}` does not exist on the model `#{model.name}`.")
|
142
145
|
end
|
143
146
|
reflection
|
144
147
|
end
|
@@ -254,6 +257,10 @@ module ActiveRecord
|
|
254
257
|
self
|
255
258
|
end
|
256
259
|
|
260
|
+
def all # :nodoc:
|
261
|
+
spawn
|
262
|
+
end
|
263
|
+
|
257
264
|
# Specify associations +args+ to be eager loaded using a <tt>LEFT OUTER JOIN</tt>.
|
258
265
|
# Performs a single query joining all specified associations. For example:
|
259
266
|
#
|
@@ -696,26 +703,39 @@ module ActiveRecord
|
|
696
703
|
# # WHEN "conversations"."status" = 0 THEN 3
|
697
704
|
# # END ASC
|
698
705
|
#
|
699
|
-
|
700
|
-
|
706
|
+
# +filter+ can be set to +false+ to include all results instead of only the ones specified in +values+.
|
707
|
+
#
|
708
|
+
# Conversation.in_order_of(:status, [:archived, :active], filter: false)
|
709
|
+
# # SELECT "conversations".* FROM "conversations"
|
710
|
+
# # ORDER BY CASE
|
711
|
+
# # WHEN "conversations"."status" = 1 THEN 1
|
712
|
+
# # WHEN "conversations"."status" = 0 THEN 2
|
713
|
+
# # ELSE 3
|
714
|
+
# # END ASC
|
715
|
+
def in_order_of(column, values, filter: true)
|
716
|
+
model.disallow_raw_sql!([column], permit: model.adapter_class.column_name_with_order_matcher)
|
701
717
|
return spawn.none! if values.empty?
|
702
718
|
|
703
719
|
references = column_references([column])
|
704
720
|
self.references_values |= references unless references.empty?
|
705
721
|
|
706
|
-
values = values.map { |value| type_caster.type_cast_for_database(column, value) }
|
722
|
+
values = values.map { |value| model.type_caster.type_cast_for_database(column, value) }
|
707
723
|
arel_column = column.is_a?(Arel::Nodes::SqlLiteral) ? column : order_column(column.to_s)
|
708
724
|
|
709
|
-
|
710
|
-
if values.include?(nil)
|
711
|
-
arel_column.in(values.compact).or(arel_column.eq(nil))
|
712
|
-
else
|
713
|
-
arel_column.in(values)
|
714
|
-
end
|
725
|
+
scope = spawn.order!(build_case_for_value_position(arel_column, values, filter: filter))
|
715
726
|
|
716
|
-
|
717
|
-
|
718
|
-
|
727
|
+
if filter
|
728
|
+
where_clause =
|
729
|
+
if values.include?(nil)
|
730
|
+
arel_column.in(values.compact).or(arel_column.eq(nil))
|
731
|
+
else
|
732
|
+
arel_column.in(values)
|
733
|
+
end
|
734
|
+
|
735
|
+
scope = scope.where!(where_clause)
|
736
|
+
end
|
737
|
+
|
738
|
+
scope
|
719
739
|
end
|
720
740
|
|
721
741
|
# Replaces any existing order defined on the relation with the specified order.
|
@@ -1554,8 +1574,8 @@ module ActiveRecord
|
|
1554
1574
|
records.flatten!(1)
|
1555
1575
|
records.compact!
|
1556
1576
|
|
1557
|
-
unless records.all?(
|
1558
|
-
raise ArgumentError, "You must only pass a single or collection of #{
|
1577
|
+
unless records.all?(model) && relations.all? { |relation| relation.model == model }
|
1578
|
+
raise ArgumentError, "You must only pass a single or collection of #{model.name} objects to ##{__callee__}."
|
1559
1579
|
end
|
1560
1580
|
|
1561
1581
|
spawn.excluding!(records + relations.flat_map(&:ids))
|
@@ -1575,7 +1595,7 @@ module ActiveRecord
|
|
1575
1595
|
|
1576
1596
|
def construct_join_dependency(associations, join_type) # :nodoc:
|
1577
1597
|
ActiveRecord::Associations::JoinDependency.new(
|
1578
|
-
|
1598
|
+
model, table, associations, join_type
|
1579
1599
|
)
|
1580
1600
|
end
|
1581
1601
|
|
@@ -1604,15 +1624,15 @@ module ActiveRecord
|
|
1604
1624
|
elsif opts.include?("?")
|
1605
1625
|
parts = [build_bound_sql_literal(opts, rest)]
|
1606
1626
|
else
|
1607
|
-
parts = [
|
1627
|
+
parts = [model.sanitize_sql(rest.empty? ? opts : [opts, *rest])]
|
1608
1628
|
end
|
1609
1629
|
when Hash
|
1610
1630
|
opts = opts.transform_keys do |key|
|
1611
1631
|
if key.is_a?(Array)
|
1612
|
-
key.map { |k|
|
1632
|
+
key.map { |k| model.attribute_aliases[k.to_s] || k.to_s }
|
1613
1633
|
else
|
1614
1634
|
key = key.to_s
|
1615
|
-
|
1635
|
+
model.attribute_aliases[key] || key
|
1616
1636
|
end
|
1617
1637
|
end
|
1618
1638
|
references = PredicateBuilder.references(opts)
|
@@ -1636,26 +1656,6 @@ module ActiveRecord
|
|
1636
1656
|
self
|
1637
1657
|
end
|
1638
1658
|
|
1639
|
-
protected
|
1640
|
-
def arel_columns(columns)
|
1641
|
-
columns.flat_map do |field|
|
1642
|
-
case field
|
1643
|
-
when Symbol
|
1644
|
-
arel_column(field.to_s) do |attr_name|
|
1645
|
-
adapter_class.quote_table_name(attr_name)
|
1646
|
-
end
|
1647
|
-
when String
|
1648
|
-
arel_column(field, &:itself)
|
1649
|
-
when Proc
|
1650
|
-
field.call
|
1651
|
-
when Hash
|
1652
|
-
arel_columns_from_hash(field)
|
1653
|
-
else
|
1654
|
-
field
|
1655
|
-
end
|
1656
|
-
end
|
1657
|
-
end
|
1658
|
-
|
1659
1659
|
private
|
1660
1660
|
def async
|
1661
1661
|
spawn.async!
|
@@ -1828,7 +1828,7 @@ module ActiveRecord
|
|
1828
1828
|
|
1829
1829
|
joins = joins_values.dup
|
1830
1830
|
if joins.last.is_a?(ActiveRecord::Associations::JoinDependency)
|
1831
|
-
stashed_eager_load = joins.pop if joins.last.base_klass ==
|
1831
|
+
stashed_eager_load = joins.pop if joins.last.base_klass == model
|
1832
1832
|
end
|
1833
1833
|
|
1834
1834
|
joins.each_with_index do |join, i|
|
@@ -1885,8 +1885,8 @@ module ActiveRecord
|
|
1885
1885
|
def build_select(arel)
|
1886
1886
|
if select_values.any?
|
1887
1887
|
arel.project(*arel_columns(select_values))
|
1888
|
-
elsif
|
1889
|
-
arel.project(*
|
1888
|
+
elsif model.ignored_columns.any? || model.enumerate_columns_in_select_statements
|
1889
|
+
arel.project(*model.column_names.map { |field| table[field] })
|
1890
1890
|
else
|
1891
1891
|
arel.project(table[Arel.star])
|
1892
1892
|
end
|
@@ -1910,26 +1910,12 @@ module ActiveRecord
|
|
1910
1910
|
end
|
1911
1911
|
end
|
1912
1912
|
|
1913
|
-
def build_with_expression_from_value(value
|
1913
|
+
def build_with_expression_from_value(value)
|
1914
1914
|
case value
|
1915
1915
|
when Arel::Nodes::SqlLiteral then Arel::Nodes::Grouping.new(value)
|
1916
|
-
when ActiveRecord::Relation
|
1917
|
-
if nested
|
1918
|
-
value.arel.ast
|
1919
|
-
else
|
1920
|
-
value.arel
|
1921
|
-
end
|
1916
|
+
when ActiveRecord::Relation then value.arel
|
1922
1917
|
when Arel::SelectManager then value
|
1923
|
-
when Array
|
1924
|
-
return build_with_expression_from_value(value.first, false) if value.size == 1
|
1925
|
-
|
1926
|
-
parts = value.map do |query|
|
1927
|
-
build_with_expression_from_value(query, true)
|
1928
|
-
end
|
1929
|
-
|
1930
|
-
parts.reduce do |result, value|
|
1931
|
-
Arel::Nodes::UnionAll.new(result, value)
|
1932
|
-
end
|
1918
|
+
when Array then value.map { |q| build_with_expression_from_value(q) }.reduce { |result, value| result.union(:all, value) }
|
1933
1919
|
else
|
1934
1920
|
raise ArgumentError, "Unsupported argument type: `#{value}` #{value.class}"
|
1935
1921
|
end
|
@@ -1939,18 +1925,37 @@ module ActiveRecord
|
|
1939
1925
|
with_table = Arel::Table.new(name)
|
1940
1926
|
|
1941
1927
|
table.join(with_table, kind).on(
|
1942
|
-
with_table[
|
1928
|
+
with_table[model.model_name.to_s.foreign_key].eq(table[model.primary_key])
|
1943
1929
|
).join_sources.first
|
1944
1930
|
end
|
1945
1931
|
|
1932
|
+
def arel_columns(columns)
|
1933
|
+
columns.flat_map do |field|
|
1934
|
+
case field
|
1935
|
+
when Symbol
|
1936
|
+
arel_column(field.to_s) do |attr_name|
|
1937
|
+
model.adapter_class.quote_table_name(attr_name)
|
1938
|
+
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
|
+
else
|
1946
|
+
field
|
1947
|
+
end
|
1948
|
+
end
|
1949
|
+
end
|
1950
|
+
|
1946
1951
|
def arel_column(field)
|
1947
|
-
field =
|
1952
|
+
field = model.attribute_aliases[field] || field
|
1948
1953
|
from = from_clause.name || from_clause.value
|
1949
1954
|
|
1950
|
-
if
|
1955
|
+
if model.columns_hash.key?(field) && (!from || table_name_matches?(from))
|
1951
1956
|
table[field]
|
1952
|
-
elsif /\A
|
1953
|
-
|
1957
|
+
elsif field.match?(/\A\w+\.\w+\z/)
|
1958
|
+
table, column = field.split(".")
|
1954
1959
|
predicate_builder.resolve_arel_attribute(table, column) do
|
1955
1960
|
lookup_table_klass_from_join_dependencies(table)
|
1956
1961
|
end
|
@@ -1961,7 +1966,7 @@ module ActiveRecord
|
|
1961
1966
|
|
1962
1967
|
def table_name_matches?(from)
|
1963
1968
|
table_name = Regexp.escape(table.name)
|
1964
|
-
quoted_table_name = Regexp.escape(adapter_class.quote_table_name(table.name))
|
1969
|
+
quoted_table_name = Regexp.escape(model.adapter_class.quote_table_name(table.name))
|
1965
1970
|
/(?:\A|(?<!FROM)\s)(?:\b#{table_name}\b|#{quoted_table_name})(?!\.)/i.match?(from.to_s)
|
1966
1971
|
end
|
1967
1972
|
|
@@ -2032,7 +2037,7 @@ module ActiveRecord
|
|
2032
2037
|
end
|
2033
2038
|
|
2034
2039
|
def preprocess_order_args(order_args)
|
2035
|
-
|
2040
|
+
model.disallow_raw_sql!(
|
2036
2041
|
flattened_args(order_args),
|
2037
2042
|
permit: model.adapter_class.column_name_with_order_matcher
|
2038
2043
|
)
|
@@ -2070,7 +2075,7 @@ module ActiveRecord
|
|
2070
2075
|
|
2071
2076
|
def sanitize_order_arguments(order_args)
|
2072
2077
|
order_args.map! do |arg|
|
2073
|
-
|
2078
|
+
model.sanitize_sql_for_order(arg)
|
2074
2079
|
end
|
2075
2080
|
end
|
2076
2081
|
|
@@ -2108,17 +2113,18 @@ module ActiveRecord
|
|
2108
2113
|
if attr_name == "count" && !group_values.empty?
|
2109
2114
|
table[attr_name]
|
2110
2115
|
else
|
2111
|
-
Arel.sql(adapter_class.quote_table_name(attr_name), retryable: true)
|
2116
|
+
Arel.sql(model.adapter_class.quote_table_name(attr_name), retryable: true)
|
2112
2117
|
end
|
2113
2118
|
end
|
2114
2119
|
end
|
2115
2120
|
|
2116
|
-
def build_case_for_value_position(column, values)
|
2121
|
+
def build_case_for_value_position(column, values, filter: true)
|
2117
2122
|
node = Arel::Nodes::Case.new
|
2118
2123
|
values.each.with_index(1) do |value, order|
|
2119
2124
|
node.when(column.eq(value)).then(order)
|
2120
2125
|
end
|
2121
2126
|
|
2127
|
+
node = node.else(values.length + 1) unless filter
|
2122
2128
|
Arel::Nodes::Ascending.new(node)
|
2123
2129
|
end
|
2124
2130
|
|
@@ -2202,7 +2208,7 @@ module ActiveRecord
|
|
2202
2208
|
end
|
2203
2209
|
when String, Symbol
|
2204
2210
|
arel_column(key.to_s) do
|
2205
|
-
predicate_builder.resolve_arel_attribute(
|
2211
|
+
predicate_builder.resolve_arel_attribute(model.table_name, key.to_s)
|
2206
2212
|
end.as(columns_aliases.to_s)
|
2207
2213
|
end
|
2208
2214
|
end
|
@@ -20,9 +20,9 @@ module ActiveRecord
|
|
20
20
|
QueryRegistry.reset
|
21
21
|
|
22
22
|
super.tap do |records|
|
23
|
-
if logger && ActiveRecord.warn_on_records_fetched_greater_than
|
23
|
+
if model.logger && ActiveRecord.warn_on_records_fetched_greater_than
|
24
24
|
if records.length > ActiveRecord.warn_on_records_fetched_greater_than
|
25
|
-
logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
|
25
|
+
model.logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -7,7 +7,7 @@ require "active_record/relation/merger"
|
|
7
7
|
module ActiveRecord
|
8
8
|
module SpawnMethods
|
9
9
|
def spawn # :nodoc:
|
10
|
-
already_in_scope?(
|
10
|
+
already_in_scope?(model.scope_registry) ? model.all : clone
|
11
11
|
end
|
12
12
|
|
13
13
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
|