activerecord 8.0.0 → 8.1.4

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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1381 -241
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +1 -1
  5. data/lib/active_record/associations/alias_tracker.rb +6 -4
  6. data/lib/active_record/associations/association.rb +35 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -1
  8. data/lib/active_record/associations/belongs_to_association.rb +20 -4
  9. data/lib/active_record/associations/builder/association.rb +16 -5
  10. data/lib/active_record/associations/builder/belongs_to.rb +36 -8
  11. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  12. data/lib/active_record/associations/builder/has_one.rb +1 -1
  13. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  14. data/lib/active_record/associations/collection_association.rb +9 -5
  15. data/lib/active_record/associations/collection_proxy.rb +26 -4
  16. data/lib/active_record/associations/deprecation.rb +88 -0
  17. data/lib/active_record/associations/errors.rb +3 -0
  18. data/lib/active_record/associations/foreign_association.rb +3 -1
  19. data/lib/active_record/associations/has_one_association.rb +1 -0
  20. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  21. data/lib/active_record/associations/join_dependency.rb +5 -4
  22. data/lib/active_record/associations/preloader/association.rb +1 -1
  23. data/lib/active_record/associations/preloader/batch.rb +7 -1
  24. data/lib/active_record/associations/preloader/branch.rb +1 -0
  25. data/lib/active_record/associations.rb +159 -21
  26. data/lib/active_record/attribute_methods/primary_key.rb +2 -1
  27. data/lib/active_record/attribute_methods/query.rb +34 -0
  28. data/lib/active_record/attribute_methods/serialization.rb +19 -6
  29. data/lib/active_record/attribute_methods/time_zone_conversion.rb +10 -2
  30. data/lib/active_record/attribute_methods.rb +24 -17
  31. data/lib/active_record/attributes.rb +40 -26
  32. data/lib/active_record/autosave_association.rb +22 -12
  33. data/lib/active_record/base.rb +3 -4
  34. data/lib/active_record/callbacks.rb +1 -2
  35. data/lib/active_record/coders/column_serializer.rb +1 -1
  36. data/lib/active_record/coders/json.rb +16 -6
  37. data/lib/active_record/coders/yaml_column.rb +2 -2
  38. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +19 -18
  39. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -3
  40. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -12
  41. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +474 -112
  42. data/lib/active_record/connection_adapters/abstract/database_statements.rb +68 -41
  43. data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -9
  44. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
  45. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
  46. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +31 -35
  47. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  48. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +94 -28
  49. data/lib/active_record/connection_adapters/abstract/transaction.rb +25 -3
  50. data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -64
  51. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +133 -40
  52. data/lib/active_record/connection_adapters/column.rb +14 -4
  53. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  54. data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -1
  55. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  56. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
  57. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +40 -25
  58. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +66 -15
  59. data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
  60. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  61. data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
  62. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +29 -33
  63. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
  64. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
  65. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  66. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  67. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  68. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +8 -6
  69. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -33
  70. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +70 -32
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +99 -54
  72. data/lib/active_record/connection_adapters/postgresql_adapter.rb +40 -12
  73. data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
  74. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -23
  75. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
  76. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +15 -3
  77. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +7 -14
  78. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +68 -37
  79. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  80. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +8 -3
  81. data/lib/active_record/connection_adapters/trilogy_adapter.rb +16 -2
  82. data/lib/active_record/connection_adapters.rb +1 -0
  83. data/lib/active_record/connection_handling.rb +15 -10
  84. data/lib/active_record/core.rb +44 -12
  85. data/lib/active_record/counter_cache.rb +36 -9
  86. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  87. data/lib/active_record/database_configurations/database_config.rb +5 -1
  88. data/lib/active_record/database_configurations/hash_config.rb +66 -9
  89. data/lib/active_record/database_configurations/url_config.rb +15 -3
  90. data/lib/active_record/database_configurations.rb +7 -3
  91. data/lib/active_record/delegated_type.rb +19 -19
  92. data/lib/active_record/disable_joins_association_relation.rb +5 -1
  93. data/lib/active_record/dynamic_matchers.rb +54 -69
  94. data/lib/active_record/encryption/encryptable_record.rb +5 -5
  95. data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
  96. data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
  97. data/lib/active_record/encryption/encryptor.rb +39 -25
  98. data/lib/active_record/encryption/scheme.rb +1 -1
  99. data/lib/active_record/enum.rb +37 -20
  100. data/lib/active_record/errors.rb +23 -7
  101. data/lib/active_record/explain.rb +1 -1
  102. data/lib/active_record/explain_registry.rb +51 -2
  103. data/lib/active_record/filter_attribute_handler.rb +76 -0
  104. data/lib/active_record/fixture_set/table_row.rb +19 -2
  105. data/lib/active_record/fixtures.rb +2 -2
  106. data/lib/active_record/future_result.rb +5 -3
  107. data/lib/active_record/gem_version.rb +2 -2
  108. data/lib/active_record/inheritance.rb +9 -4
  109. data/lib/active_record/insert_all.rb +14 -9
  110. data/lib/active_record/locking/optimistic.rb +7 -0
  111. data/lib/active_record/locking/pessimistic.rb +5 -0
  112. data/lib/active_record/log_subscriber.rb +30 -22
  113. data/lib/active_record/message_pack.rb +13 -0
  114. data/lib/active_record/middleware/shard_selector.rb +34 -17
  115. data/lib/active_record/migration/command_recorder.rb +32 -6
  116. data/lib/active_record/migration/compatibility.rb +34 -24
  117. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  118. data/lib/active_record/migration.rb +31 -21
  119. data/lib/active_record/model_schema.rb +38 -12
  120. data/lib/active_record/nested_attributes.rb +10 -6
  121. data/lib/active_record/persistence.rb +35 -3
  122. data/lib/active_record/query_cache.rb +22 -15
  123. data/lib/active_record/query_logs.rb +7 -7
  124. data/lib/active_record/querying.rb +17 -5
  125. data/lib/active_record/railtie.rb +35 -6
  126. data/lib/active_record/railties/controller_runtime.rb +11 -6
  127. data/lib/active_record/railties/databases.rake +24 -20
  128. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  129. data/lib/active_record/railties/job_runtime.rb +10 -11
  130. data/lib/active_record/reflection.rb +36 -1
  131. data/lib/active_record/relation/batches.rb +25 -11
  132. data/lib/active_record/relation/calculations.rb +62 -41
  133. data/lib/active_record/relation/delegation.rb +0 -1
  134. data/lib/active_record/relation/finder_methods.rb +76 -45
  135. data/lib/active_record/relation/merger.rb +4 -2
  136. data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
  137. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
  138. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -7
  139. data/lib/active_record/relation/predicate_builder.rb +10 -8
  140. data/lib/active_record/relation/query_attribute.rb +4 -2
  141. data/lib/active_record/relation/query_methods.rb +106 -45
  142. data/lib/active_record/relation/spawn_methods.rb +6 -6
  143. data/lib/active_record/relation/where_clause.rb +10 -11
  144. data/lib/active_record/relation.rb +63 -31
  145. data/lib/active_record/result.rb +44 -21
  146. data/lib/active_record/runtime_registry.rb +42 -58
  147. data/lib/active_record/sanitization.rb +2 -0
  148. data/lib/active_record/schema.rb +1 -1
  149. data/lib/active_record/schema_dumper.rb +41 -21
  150. data/lib/active_record/scoping.rb +0 -1
  151. data/lib/active_record/secure_token.rb +3 -3
  152. data/lib/active_record/signed_id.rb +48 -19
  153. data/lib/active_record/statement_cache.rb +16 -12
  154. data/lib/active_record/store.rb +46 -19
  155. data/lib/active_record/structured_event_subscriber.rb +85 -0
  156. data/lib/active_record/table_metadata.rb +5 -20
  157. data/lib/active_record/tasks/abstract_tasks.rb +83 -0
  158. data/lib/active_record/tasks/database_tasks.rb +44 -45
  159. data/lib/active_record/tasks/mysql_database_tasks.rb +4 -56
  160. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  161. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
  162. data/lib/active_record/test_databases.rb +18 -4
  163. data/lib/active_record/test_fixtures.rb +40 -6
  164. data/lib/active_record/testing/query_assertions.rb +8 -2
  165. data/lib/active_record/timestamp.rb +4 -2
  166. data/lib/active_record/transaction.rb +2 -5
  167. data/lib/active_record/transactions.rb +58 -32
  168. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  169. data/lib/active_record/type/internal/timezone.rb +7 -0
  170. data/lib/active_record/type/json.rb +13 -2
  171. data/lib/active_record/type/serialized.rb +16 -4
  172. data/lib/active_record/type/type_map.rb +1 -1
  173. data/lib/active_record/type_caster/connection.rb +2 -1
  174. data/lib/active_record/validations/associated.rb +1 -1
  175. data/lib/active_record.rb +72 -7
  176. data/lib/arel/alias_predication.rb +2 -0
  177. data/lib/arel/collectors/bind.rb +1 -1
  178. data/lib/arel/collectors/sql_string.rb +1 -1
  179. data/lib/arel/collectors/substitute_binds.rb +2 -2
  180. data/lib/arel/crud.rb +8 -11
  181. data/lib/arel/delete_manager.rb +5 -0
  182. data/lib/arel/nodes/binary.rb +1 -1
  183. data/lib/arel/nodes/count.rb +2 -2
  184. data/lib/arel/nodes/delete_statement.rb +4 -2
  185. data/lib/arel/nodes/function.rb +4 -10
  186. data/lib/arel/nodes/named_function.rb +2 -2
  187. data/lib/arel/nodes/node.rb +2 -2
  188. data/lib/arel/nodes/sql_literal.rb +1 -1
  189. data/lib/arel/nodes/update_statement.rb +4 -2
  190. data/lib/arel/nodes.rb +0 -2
  191. data/lib/arel/predications.rb +1 -3
  192. data/lib/arel/select_manager.rb +13 -4
  193. data/lib/arel/update_manager.rb +5 -0
  194. data/lib/arel/visitors/dot.rb +2 -3
  195. data/lib/arel/visitors/postgresql.rb +55 -0
  196. data/lib/arel/visitors/sqlite.rb +55 -8
  197. data/lib/arel/visitors/to_sql.rb +7 -23
  198. data/lib/arel.rb +3 -1
  199. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  200. metadata +16 -15
  201. data/lib/active_record/explain_subscriber.rb +0 -34
  202. data/lib/active_record/normalization.rb +0 -163
@@ -15,7 +15,9 @@ module ActiveRecord
15
15
  elsif @type.serialized?
16
16
  value_for_database
17
17
  elsif @type.mutable? # If the type is simply mutable, we deep_dup it.
18
- @value_before_type_cast = @value_before_type_cast.deep_dup
18
+ unless @value_before_type_cast.frozen?
19
+ @value_before_type_cast = @value_before_type_cast.deep_dup
20
+ end
19
21
  end
20
22
  end
21
23
 
@@ -35,7 +37,7 @@ module ActiveRecord
35
37
  def nil?
36
38
  unless value_before_type_cast.is_a?(StatementCache::Substitute)
37
39
  value_before_type_cast.nil? ||
38
- type.respond_to?(:subtype) && serializable? && value_for_database.nil?
40
+ (type.respond_to?(:subtype) || type.respond_to?(:normalizer)) && serializable? && value_for_database.nil?
39
41
  end
40
42
  end
41
43
 
@@ -510,7 +510,7 @@ module ActiveRecord
510
510
  # # WITH RECURSIVE post_and_replies AS (
511
511
  # # (SELECT * FROM posts WHERE id = 42)
512
512
  # # UNION ALL
513
- # # (SELECT * FROM posts JOIN posts_and_replies ON posts.in_reply_to_id = posts_and_replies.id)
513
+ # # (SELECT * FROM posts JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id)
514
514
  # # )
515
515
  # # SELECT * FROM posts
516
516
  #
@@ -576,7 +576,7 @@ module ActiveRecord
576
576
  end
577
577
 
578
578
  def group!(*args) # :nodoc:
579
- self.group_values += args
579
+ self.group_values |= args
580
580
  self
581
581
  end
582
582
 
@@ -721,8 +721,16 @@ module ActiveRecord
721
721
  references = column_references([column])
722
722
  self.references_values |= references unless references.empty?
723
723
 
724
- values = values.map { |value| model.type_caster.type_cast_for_database(column, value) }
725
- arel_column = column.is_a?(Arel::Nodes::SqlLiteral) ? column : order_column(column.to_s)
724
+ if column.is_a?(Arel::Nodes::SqlLiteral)
725
+ arel_column = column
726
+ else
727
+ arel_column = order_column(column.to_s)
728
+
729
+ unless arel_column.is_a?(Arel::Nodes::SqlLiteral)
730
+ values = cast_values_for_in_order_of(values, arel_column.type_caster)
731
+ end
732
+ return spawn.none! if values.empty?
733
+ end
726
734
 
727
735
  scope = spawn.order!(build_case_for_value_position(arel_column, values, filter: filter))
728
736
 
@@ -809,7 +817,7 @@ module ActiveRecord
809
817
  end
810
818
 
811
819
  def unscope!(*args) # :nodoc:
812
- self.unscope_values += args
820
+ self.unscope_values |= args
813
821
 
814
822
  args.each do |scope|
815
823
  case scope
@@ -837,6 +845,26 @@ module ActiveRecord
837
845
  self
838
846
  end
839
847
 
848
+ def table_name_qualified_unscope_values
849
+ self.unscope_values.map do |scope|
850
+ case scope
851
+ when Hash
852
+ scope.transform_values do |target_value|
853
+ case target_value
854
+ when Array
855
+ target_value.map { |value| qualify_attribute_with_table_name(value) }
856
+ when Symbol, String
857
+ qualify_attribute_with_table_name(target_value)
858
+ else
859
+ target_value
860
+ end
861
+ end
862
+ else
863
+ scope
864
+ end
865
+ end
866
+ end
867
+
840
868
  # Performs JOINs on +args+. The given symbol(s) should match the name of
841
869
  # the association(s).
842
870
  #
@@ -1048,13 +1076,13 @@ module ActiveRecord
1048
1076
  # Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
1049
1077
  #
1050
1078
  # Post.where(trashed: true).where(trashed: false)
1051
- # # WHERE `trashed` = 1 AND `trashed` = 0
1079
+ # # WHERE `trashed` = true AND `trashed` = false
1052
1080
  #
1053
1081
  # Post.where(trashed: true).rewhere(trashed: false)
1054
- # # WHERE `trashed` = 0
1082
+ # # WHERE `trashed` = false
1055
1083
  #
1056
1084
  # Post.where(active: true).where(trashed: true).rewhere(trashed: false)
1057
- # # WHERE `active` = 1 AND `trashed` = 0
1085
+ # # WHERE `active` = true AND `trashed` = false
1058
1086
  #
1059
1087
  # This is short-hand for <tt>unscope(where: conditions.keys).where(conditions)</tt>.
1060
1088
  # Note that unlike reorder, we're only unscoping the named conditions -- not the entire where statement.
@@ -1076,16 +1104,16 @@ module ActiveRecord
1076
1104
  # end
1077
1105
  #
1078
1106
  # User.where(accepted: true)
1079
- # # WHERE `accepted` = 1
1107
+ # # WHERE `accepted` = true
1080
1108
  #
1081
1109
  # User.where(accepted: true).invert_where
1082
- # # WHERE `accepted` != 1
1110
+ # # WHERE `accepted` != true
1083
1111
  #
1084
1112
  # User.active
1085
- # # WHERE `accepted` = 1 AND `locked` = 0
1113
+ # # WHERE `accepted` = true AND `locked` = false
1086
1114
  #
1087
1115
  # User.active.invert_where
1088
- # # WHERE NOT (`accepted` = 1 AND `locked` = 0)
1116
+ # # WHERE NOT (`accepted` = true AND `locked` = false)
1089
1117
  #
1090
1118
  # Be careful because this inverts all conditions before +invert_where+ call.
1091
1119
  #
@@ -1096,7 +1124,7 @@ module ActiveRecord
1096
1124
  #
1097
1125
  # # It also inverts `where(role: 'admin')` unexpectedly.
1098
1126
  # User.where(role: 'admin').inactive
1099
- # # WHERE NOT (`role` = 'admin' AND `accepted` = 1 AND `locked` = 0)
1127
+ # # WHERE NOT (`role` = 'admin' AND `accepted` = true AND `locked` = false)
1100
1128
  #
1101
1129
  def invert_where
1102
1130
  spawn.invert_where!
@@ -1213,6 +1241,7 @@ module ActiveRecord
1213
1241
  end
1214
1242
 
1215
1243
  def limit!(value) # :nodoc:
1244
+ value = Integer(value) unless value.nil?
1216
1245
  self.limit_value = value
1217
1246
  self
1218
1247
  end
@@ -1299,13 +1328,13 @@ module ActiveRecord
1299
1328
  #
1300
1329
  # users = User.readonly
1301
1330
  # users.first.save
1302
- # => ActiveRecord::ReadOnlyRecord: User is marked as readonly
1331
+ # # => ActiveRecord::ReadOnlyRecord: User is marked as readonly
1303
1332
  #
1304
1333
  # To make a readonly relation writable, pass +false+.
1305
1334
  #
1306
1335
  # users.readonly(false)
1307
1336
  # users.first.save
1308
- # => true
1337
+ # # => true
1309
1338
  def readonly(value = true)
1310
1339
  spawn.readonly!(value)
1311
1340
  end
@@ -1320,7 +1349,7 @@ module ActiveRecord
1320
1349
  #
1321
1350
  # user = User.strict_loading.first
1322
1351
  # user.comments.to_a
1323
- # => ActiveRecord::StrictLoadingViolationError
1352
+ # # => ActiveRecord::StrictLoadingViolationError
1324
1353
  def strict_loading(value = true)
1325
1354
  spawn.strict_loading!(value)
1326
1355
  end
@@ -1465,7 +1494,7 @@ module ActiveRecord
1465
1494
  modules << Module.new(&block) if block
1466
1495
  modules.flatten!
1467
1496
 
1468
- self.extending_values += modules
1497
+ self.extending_values |= modules
1469
1498
  extend(*extending_values) if extending_values.any?
1470
1499
 
1471
1500
  self
@@ -1533,7 +1562,7 @@ module ActiveRecord
1533
1562
 
1534
1563
  # Like #annotate, but modifies relation in place.
1535
1564
  def annotate!(*args) # :nodoc:
1536
- self.annotate_values += args
1565
+ self.annotate_values |= args
1537
1566
  self
1538
1567
  end
1539
1568
 
@@ -1585,14 +1614,14 @@ module ActiveRecord
1585
1614
  alias :without :excluding
1586
1615
 
1587
1616
  def excluding!(records) # :nodoc:
1588
- predicates = [ predicate_builder[primary_key, records].invert ]
1589
- self.where_clause += Relation::WhereClause.new(predicates)
1617
+ ids = records.map { |record| record.is_a?(model) ? record.id : record }
1618
+ self.where_clause += build_where_clause(primary_key => ids).invert
1590
1619
  self
1591
1620
  end
1592
1621
 
1593
1622
  # Returns the Arel object associated with the relation.
1594
1623
  def arel(aliases = nil) # :nodoc:
1595
- @arel ||= with_connection { |c| build_arel(c, aliases) }
1624
+ @arel ||= build_arel(aliases)
1596
1625
  end
1597
1626
 
1598
1627
  def construct_join_dependency(associations, join_type) # :nodoc:
@@ -1626,7 +1655,7 @@ module ActiveRecord
1626
1655
  elsif opts.include?("?")
1627
1656
  parts = [build_bound_sql_literal(opts, rest)]
1628
1657
  else
1629
- parts = [model.sanitize_sql(rest.empty? ? opts : [opts, *rest])]
1658
+ parts = [Arel.sql(model.sanitize_sql([opts, *rest]))]
1630
1659
  end
1631
1660
  when Hash
1632
1661
  opts = opts.transform_keys do |key|
@@ -1653,13 +1682,12 @@ module ActiveRecord
1653
1682
  end
1654
1683
  alias :build_having_clause :build_where_clause
1655
1684
 
1656
- def async!
1685
+ def async! # :nodoc:
1657
1686
  @async = true
1658
1687
  self
1659
1688
  end
1660
1689
 
1661
- protected
1662
- def arel_columns(columns)
1690
+ def arel_columns(columns) # :nodoc:
1663
1691
  columns.flat_map do |field|
1664
1692
  case field
1665
1693
  when Symbol, String
@@ -1747,32 +1775,27 @@ module ActiveRecord
1747
1775
  raise UnmodifiableRelation if @loaded || @arel
1748
1776
  end
1749
1777
 
1750
- def build_arel(connection, aliases = nil)
1778
+ def build_arel(aliases)
1751
1779
  arel = Arel::SelectManager.new(table)
1752
1780
 
1753
1781
  build_joins(arel.join_sources, aliases)
1754
1782
 
1755
1783
  arel.where(where_clause.ast) unless where_clause.empty?
1756
1784
  arel.having(having_clause.ast) unless having_clause.empty?
1757
- arel.take(build_cast_value("LIMIT", connection.sanitize_limit(limit_value))) if limit_value
1785
+ arel.take(build_cast_value("LIMIT", limit_value)) if limit_value
1758
1786
  arel.skip(build_cast_value("OFFSET", offset_value.to_i)) if offset_value
1759
- arel.group(*arel_columns(group_values.uniq)) unless group_values.empty?
1787
+ arel.group(*arel_columns(group_values)) unless group_values.empty?
1760
1788
 
1761
1789
  build_order(arel)
1762
1790
  build_with(arel)
1763
1791
  build_select(arel)
1764
1792
 
1765
1793
  arel.optimizer_hints(*optimizer_hints_values) unless optimizer_hints_values.empty?
1794
+ arel.comment(*annotate_values) unless annotate_values.empty?
1766
1795
  arel.distinct(distinct_value)
1767
1796
  arel.from(build_from) unless from_clause.empty?
1768
1797
  arel.lock(lock_value) if lock_value
1769
1798
 
1770
- unless annotate_values.empty?
1771
- annotates = annotate_values
1772
- annotates = annotates.uniq if annotates.size > 1
1773
- arel.comment(*annotates)
1774
- end
1775
-
1776
1799
  arel
1777
1800
  end
1778
1801
 
@@ -1903,7 +1926,7 @@ module ActiveRecord
1903
1926
  def build_select(arel)
1904
1927
  if select_values.any?
1905
1928
  arel.project(*arel_columns(select_values))
1906
- elsif model.ignored_columns.any? || model.enumerate_columns_in_select_statements
1929
+ elsif model.ignored_columns.any? || model.enumerate_columns_in_select_statements || model.only_columns.any?
1907
1930
  arel.project(*model.column_names.map { |field| table[field] })
1908
1931
  else
1909
1932
  arel.project(table[Arel.star])
@@ -1928,7 +1951,8 @@ module ActiveRecord
1928
1951
 
1929
1952
  def build_with_expression_from_value(value, nested = false)
1930
1953
  case value
1931
- when Arel::Nodes::SqlLiteral then Arel::Nodes::Grouping.new(value)
1954
+ when Arel::Nodes::SqlLiteral, Arel::Nodes::BoundSqlLiteral
1955
+ Arel::Nodes::Grouping.new(value)
1932
1956
  when ActiveRecord::Relation
1933
1957
  if nested
1934
1958
  value.arel.ast
@@ -2001,8 +2025,10 @@ module ActiveRecord
2001
2025
  yield field
2002
2026
  elsif Arel.arel_node?(field)
2003
2027
  field
2028
+ elsif is_symbol
2029
+ Arel.sql(model.adapter_class.quote_table_name(field), retryable: true)
2004
2030
  else
2005
- Arel.sql(is_symbol ? model.adapter_class.quote_table_name(field) : field)
2031
+ Arel.sql(field)
2006
2032
  end
2007
2033
  end
2008
2034
 
@@ -2014,9 +2040,15 @@ module ActiveRecord
2014
2040
 
2015
2041
  def reverse_sql_order(order_query)
2016
2042
  if order_query.empty?
2017
- return [table[primary_key].desc] if primary_key
2018
- raise IrreversibleOrderError,
2019
- "Relation has no current order and table has no primary key to be used as default order"
2043
+ if !_reverse_order_columns.empty?
2044
+ return _reverse_order_columns.map { |column| table[column].desc }
2045
+ end
2046
+
2047
+ raise IrreversibleOrderError, <<~MSG.squish
2048
+ Relation has no order values, and #{model} has no order columns to use as a default.
2049
+ Set at least one of `implicit_order_column`, or `primary_key` on the model when no
2050
+ `order `is specified on the relation.
2051
+ MSG
2020
2052
  end
2021
2053
 
2022
2054
  order_query.flat_map do |o|
@@ -2041,6 +2073,13 @@ module ActiveRecord
2041
2073
  end
2042
2074
  end
2043
2075
 
2076
+ def _reverse_order_columns
2077
+ roc = []
2078
+ roc << model.implicit_order_column if model.implicit_order_column
2079
+ roc << model.primary_key if model.primary_key
2080
+ roc.flatten.uniq.compact
2081
+ end
2082
+
2044
2083
  def does_not_support_reverse?(order)
2045
2084
  # Account for String subclasses like Arel::Nodes::SqlLiteral that
2046
2085
  # override methods like #count.
@@ -2194,6 +2233,10 @@ module ActiveRecord
2194
2233
  end
2195
2234
  end
2196
2235
 
2236
+ def qualify_attribute_with_table_name(attr)
2237
+ attr.to_s.include?(".") ? attr : predicate_builder.resolve_arel_attribute(table_name, attr)
2238
+ end
2239
+
2197
2240
  # Checks to make sure that the arguments are not blank. Note that if some
2198
2241
  # blank-like object were initially passed into the query method, then this
2199
2242
  # method will not raise an error.
@@ -2231,6 +2274,24 @@ module ActiveRecord
2231
2274
  end
2232
2275
  end
2233
2276
 
2277
+ def cast_values_for_in_order_of(values, type_caster)
2278
+ bad_value = Symbol # use some object that can not be a valid value
2279
+
2280
+ values = values.map do |value|
2281
+ serialized = type_caster.serialize(value) if type_caster.serializable?(value)
2282
+
2283
+ if value.nil?
2284
+ nil
2285
+ elsif !serialized.nil?
2286
+ serialized
2287
+ else
2288
+ bad_value
2289
+ end
2290
+ end
2291
+
2292
+ values.without(bad_value)
2293
+ end
2294
+
2234
2295
  def arel_column_aliases_from_hash(fields)
2235
2296
  fields.flat_map do |key, columns_aliases|
2236
2297
  table_name = key.is_a?(Symbol) ? key.name : key
@@ -2267,11 +2328,11 @@ module ActiveRecord
2267
2328
  values = other.values
2268
2329
  STRUCTURAL_VALUE_METHODS.reject do |method|
2269
2330
  v1, v2 = @values[method], values[method]
2270
- if v1.is_a?(Array)
2271
- next true unless v2.is_a?(Array)
2272
- v1 = v1.uniq
2273
- v2 = v2.uniq
2274
- end
2331
+
2332
+ # `and`/`or` are focused to combine where-like clauses, so it relaxes
2333
+ # the difference when other's multi values are uninitialized.
2334
+ next true if v1.is_a?(Array) && v2.nil?
2335
+
2275
2336
  v1 == v2
2276
2337
  end
2277
2338
  end
@@ -52,18 +52,18 @@ module ActiveRecord
52
52
  end
53
53
  end
54
54
 
55
- # Removes from the query the condition(s) specified in +skips+.
55
+ # Removes the condition(s) specified in +skips+ from the query.
56
56
  #
57
- # Post.order('id asc').except(:order) # discards the order condition
58
- # Post.where('id > 10').order('id asc').except(:where) # discards the where condition but keeps the order
57
+ # Post.order('id asc').except(:order) # removes the order condition
58
+ # Post.where('id > 10').order('id asc').except(:where) # removes the where condition but keeps the order
59
59
  def except(*skips)
60
60
  relation_with values.except(*skips)
61
61
  end
62
62
 
63
- # Removes any condition from the query other than the one(s) specified in +onlies+.
63
+ # Keeps only the condition(s) specified in +onlies+ in the query, removing all others.
64
64
  #
65
- # Post.order('id asc').only(:where) # discards the order condition
66
- # Post.order('id asc').only(:where, :order) # uses the specified order
65
+ # Post.order('id asc').only(:where) # keeps only the where condition, removes the order
66
+ # Post.order('id asc').only(:where, :order) # keeps only the where and order conditions
67
67
  def only(*onlies)
68
68
  relation_with values.slice(*onlies)
69
69
  end
@@ -135,10 +135,14 @@ module ActiveRecord
135
135
 
136
136
  def extract_attribute(node)
137
137
  attr_node = nil
138
- Arel.fetch_attribute(node) do |attr|
139
- return if attr_node&.!= attr # all attr nodes should be the same
138
+
139
+ valid_attrs = Arel.fetch_attribute(node) do |attr|
140
+ !attr_node || attr_node == attr # all attr nodes should be the same
141
+ ensure
140
142
  attr_node = attr
141
143
  end
144
+ return unless valid_attrs # all nested nodes should yield an attribute
145
+
142
146
  attr_node
143
147
  end
144
148
 
@@ -172,11 +176,13 @@ module ActiveRecord
172
176
  end
173
177
 
174
178
  def except_predicates(columns)
179
+ return predicates if columns.empty?
180
+
175
181
  attrs = columns.extract! { |node| node.is_a?(Arel::Attribute) }
176
182
  non_attrs = columns.extract! { |node| node.is_a?(Arel::Predications) }
177
183
 
178
184
  predicates.reject do |node|
179
- if !non_attrs.empty? && node.equality? && node.left.is_a?(Arel::Predications)
185
+ if !non_attrs.empty? && equality_node?(node) && node.left.is_a?(Arel::Predications)
180
186
  non_attrs.include?(node.left)
181
187
  end || Arel.fetch_attribute(node) do |attr|
182
188
  attrs.include?(attr) || columns.include?(attr.name.to_s)
@@ -188,7 +194,7 @@ module ActiveRecord
188
194
  non_empty_predicates.map do |node|
189
195
  case node
190
196
  when Arel::Nodes::SqlLiteral, ::String
191
- wrap_sql_literal(node)
197
+ Arel::Nodes::Grouping.new(node)
192
198
  else node
193
199
  end
194
200
  end
@@ -199,13 +205,6 @@ module ActiveRecord
199
205
  predicates - ARRAY_WITH_EMPTY_STRING
200
206
  end
201
207
 
202
- def wrap_sql_literal(node)
203
- if ::String === node
204
- node = Arel.sql(node)
205
- end
206
- Arel::Nodes::Grouping.new(node)
207
- end
208
-
209
208
  def extract_node_value(node)
210
209
  if node.respond_to?(:value_before_type_cast)
211
210
  node.value_before_type_cast