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.
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.