activerecord 7.2.2 → 8.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +173 -920
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/associations/association.rb +25 -5
  5. data/lib/active_record/associations/builder/association.rb +7 -6
  6. data/lib/active_record/associations/collection_association.rb +10 -8
  7. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  8. data/lib/active_record/associations/has_many_through_association.rb +4 -9
  9. data/lib/active_record/associations/preloader/association.rb +2 -2
  10. data/lib/active_record/associations/singular_association.rb +8 -3
  11. data/lib/active_record/associations.rb +50 -32
  12. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  13. data/lib/active_record/autosave_association.rb +69 -27
  14. data/lib/active_record/callbacks.rb +1 -1
  15. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  16. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  17. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  18. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +0 -27
  19. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  20. data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -2
  21. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  22. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  23. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +27 -6
  24. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  25. data/lib/active_record/connection_adapters/abstract_adapter.rb +24 -25
  26. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +23 -45
  27. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  28. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  29. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
  30. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  31. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -8
  32. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  33. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  34. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
  35. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -8
  36. data/lib/active_record/connection_adapters/postgresql_adapter.rb +41 -93
  37. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  38. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  39. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  40. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  41. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -1
  42. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -12
  43. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  44. data/lib/active_record/connection_adapters/trilogy_adapter.rb +0 -17
  45. data/lib/active_record/connection_handling.rb +22 -0
  46. data/lib/active_record/core.rb +7 -32
  47. data/lib/active_record/encryption/config.rb +3 -1
  48. data/lib/active_record/encryption/encryptable_record.rb +4 -4
  49. data/lib/active_record/encryption/encrypted_attribute_type.rb +10 -1
  50. data/lib/active_record/encryption/encryptor.rb +15 -8
  51. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  52. data/lib/active_record/encryption/scheme.rb +8 -1
  53. data/lib/active_record/errors.rb +13 -5
  54. data/lib/active_record/fixtures.rb +0 -1
  55. data/lib/active_record/future_result.rb +14 -10
  56. data/lib/active_record/gem_version.rb +4 -4
  57. data/lib/active_record/insert_all.rb +1 -1
  58. data/lib/active_record/marshalling.rb +1 -4
  59. data/lib/active_record/migration/command_recorder.rb +22 -5
  60. data/lib/active_record/migration/compatibility.rb +5 -2
  61. data/lib/active_record/migration.rb +35 -33
  62. data/lib/active_record/model_schema.rb +1 -1
  63. data/lib/active_record/nested_attributes.rb +4 -6
  64. data/lib/active_record/persistence.rb +128 -130
  65. data/lib/active_record/query_cache.rb +5 -4
  66. data/lib/active_record/query_logs.rb +98 -40
  67. data/lib/active_record/query_logs_formatter.rb +17 -28
  68. data/lib/active_record/querying.rb +6 -6
  69. data/lib/active_record/railtie.rb +3 -4
  70. data/lib/active_record/reflection.rb +9 -7
  71. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  72. data/lib/active_record/relation/batches.rb +132 -72
  73. data/lib/active_record/relation/calculations.rb +25 -20
  74. data/lib/active_record/relation/delegation.rb +25 -14
  75. data/lib/active_record/relation/finder_methods.rb +18 -18
  76. data/lib/active_record/relation/merger.rb +8 -8
  77. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  78. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  79. data/lib/active_record/relation/predicate_builder.rb +5 -0
  80. data/lib/active_record/relation/query_methods.rb +81 -75
  81. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  82. data/lib/active_record/relation/spawn_methods.rb +1 -1
  83. data/lib/active_record/relation.rb +72 -61
  84. data/lib/active_record/result.rb +68 -7
  85. data/lib/active_record/sanitization.rb +7 -6
  86. data/lib/active_record/schema_dumper.rb +5 -0
  87. data/lib/active_record/schema_migration.rb +2 -1
  88. data/lib/active_record/scoping/named.rb +5 -2
  89. data/lib/active_record/statement_cache.rb +12 -12
  90. data/lib/active_record/store.rb +7 -3
  91. data/lib/active_record/tasks/database_tasks.rb +24 -15
  92. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  93. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  94. data/lib/active_record/test_fixtures.rb +12 -0
  95. data/lib/active_record/testing/query_assertions.rb +2 -2
  96. data/lib/active_record/token_for.rb +1 -1
  97. data/lib/active_record/validations/uniqueness.rb +8 -8
  98. data/lib/active_record.rb +15 -0
  99. data/lib/arel/collectors/bind.rb +1 -1
  100. data/lib/arel/visitors/sqlite.rb +0 -25
  101. 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.present?
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?(klass)
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(klass)}]" unless where_clause.empty?
418
+ conditions = " [#{arel.where_sql(model)}]" unless where_clause.empty?
419
419
 
420
- name = @klass.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
- klass.with_connection do |c|
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(@klass) if primary_key.nil?
492
+ raise UnknownPrimaryKey.new(model) if primary_key.nil?
493
493
 
494
- expects_array = if klass.composite_primary_key?
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 = @klass.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 klass.composite_primary_key?
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| @klass.type_for_attribute(primary_key).cast(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.klass,
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.klass == relation.klass
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.klass == relation.klass
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.klass.reflect_on_all_associations.find do |r|
104
- r.class_name == other.klass.name
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.klass == relation.klass
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.klass == relation.klass
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.klass.base_class == other.klass.base_class
188
+ relation.model.base_class == other.model.base_class
189
189
  end
190
190
  end
191
191
  end
@@ -37,7 +37,7 @@ module ActiveRecord
37
37
  if value.is_a?(Base)
38
38
  value.class
39
39
  elsif value.is_a?(Relation)
40
- value.klass
40
+ value.model
41
41
  end
42
42
  end
43
43
 
@@ -9,10 +9,11 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  if value.select_values.empty?
12
- if value.klass.composite_primary_key?
13
- raise ArgumentError, "Cannot map composite primary key #{value.klass.primary_key} to #{attribute.name}"
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[value.klass.primary_key])
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 => { reflection.association_primary_key => nil })
97
+ self.not(association => association_conditions)
97
98
  else
98
- self.not(reflection.table_name => { reflection.association_primary_key => nil })
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 => { reflection.association_primary_key => nil })
130
+ @scope.where!(association => association_conditions)
129
131
  else
130
- @scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
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
- reflection = @scope.klass._reflect_on_association(association)
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 `#{@scope.name}`.")
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
- def in_order_of(column, values)
700
- klass.disallow_raw_sql!([column], permit: model.adapter_class.column_name_with_order_matcher)
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
- where_clause =
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
- spawn
717
- .order!(build_case_for_value_position(arel_column, values))
718
- .where!(where_clause)
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?(klass) && relations.all? { |relation| relation.klass == klass }
1558
- raise ArgumentError, "You must only pass a single or collection of #{klass.name} objects to ##{__callee__}."
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
- klass, table, associations, join_type
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 = [klass.sanitize_sql(rest.empty? ? opts : [opts, *rest])]
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| klass.attribute_aliases[k.to_s] || k.to_s }
1632
+ key.map { |k| model.attribute_aliases[k.to_s] || k.to_s }
1613
1633
  else
1614
1634
  key = key.to_s
1615
- klass.attribute_aliases[key] || key
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 == 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 klass.ignored_columns.any? || klass.enumerate_columns_in_select_statements
1889
- arel.project(*klass.column_names.map { |field| table[field] })
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, nested = false)
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[klass.model_name.to_s.foreign_key].eq(table[klass.primary_key])
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 = klass.attribute_aliases[field] || field
1952
+ field = model.attribute_aliases[field] || field
1948
1953
  from = from_clause.name || from_clause.value
1949
1954
 
1950
- if klass.columns_hash.key?(field) && (!from || table_name_matches?(from))
1955
+ if model.columns_hash.key?(field) && (!from || table_name_matches?(from))
1951
1956
  table[field]
1952
- elsif /\A(?<table>(?:\w+\.)?\w+)\.(?<column>\w+)\z/ =~ field
1953
- self.references_values |= [Arel.sql(table, retryable: true)]
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
- @klass.disallow_raw_sql!(
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
- klass.sanitize_sql_for_order(arg)
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(klass.table_name, key.to_s)
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?(klass.scope_registry) ? klass.all : clone
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.