activerecord 7.2.3 → 8.1.3

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 (198) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +612 -1055
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/association_relation.rb +2 -1
  5. data/lib/active_record/associations/association.rb +35 -11
  6. data/lib/active_record/associations/builder/association.rb +23 -11
  7. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  8. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  9. data/lib/active_record/associations/builder/has_one.rb +1 -1
  10. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  11. data/lib/active_record/associations/collection_association.rb +1 -1
  12. data/lib/active_record/associations/collection_proxy.rb +22 -4
  13. data/lib/active_record/associations/deprecation.rb +88 -0
  14. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  15. data/lib/active_record/associations/errors.rb +3 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  17. data/lib/active_record/associations/join_dependency.rb +4 -2
  18. data/lib/active_record/associations/preloader/association.rb +2 -2
  19. data/lib/active_record/associations/preloader/batch.rb +7 -1
  20. data/lib/active_record/associations/preloader/branch.rb +1 -0
  21. data/lib/active_record/associations/singular_association.rb +8 -3
  22. data/lib/active_record/associations.rb +192 -24
  23. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  24. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  25. data/lib/active_record/attribute_methods/query.rb +34 -0
  26. data/lib/active_record/attribute_methods/serialization.rb +16 -3
  27. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  28. data/lib/active_record/attributes.rb +3 -0
  29. data/lib/active_record/autosave_association.rb +69 -27
  30. data/lib/active_record/base.rb +1 -2
  31. data/lib/active_record/coders/json.rb +14 -5
  32. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
  33. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  34. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
  35. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +412 -88
  36. data/lib/active_record/connection_adapters/abstract/database_statements.rb +137 -75
  37. data/lib/active_record/connection_adapters/abstract/query_cache.rb +27 -5
  38. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
  39. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  40. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +32 -35
  41. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  42. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -32
  43. data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
  44. data/lib/active_record/connection_adapters/abstract_adapter.rb +150 -91
  45. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +63 -52
  46. data/lib/active_record/connection_adapters/column.rb +17 -4
  47. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  48. data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
  49. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  50. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  51. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
  52. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
  53. data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -10
  54. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  55. data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
  56. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
  57. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  58. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  59. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  60. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  61. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  62. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  63. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +14 -33
  64. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +71 -32
  65. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +139 -63
  66. data/lib/active_record/connection_adapters/postgresql_adapter.rb +78 -105
  67. data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
  68. data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
  69. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
  70. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
  71. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  72. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  73. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -14
  74. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +102 -37
  75. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  76. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
  77. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
  78. data/lib/active_record/connection_adapters.rb +1 -56
  79. data/lib/active_record/connection_handling.rb +25 -2
  80. data/lib/active_record/core.rb +33 -17
  81. data/lib/active_record/counter_cache.rb +33 -8
  82. data/lib/active_record/database_configurations/database_config.rb +9 -1
  83. data/lib/active_record/database_configurations/hash_config.rb +67 -9
  84. data/lib/active_record/database_configurations/url_config.rb +13 -3
  85. data/lib/active_record/database_configurations.rb +7 -3
  86. data/lib/active_record/delegated_type.rb +1 -1
  87. data/lib/active_record/dynamic_matchers.rb +54 -69
  88. data/lib/active_record/encryption/config.rb +3 -1
  89. data/lib/active_record/encryption/encryptable_record.rb +8 -8
  90. data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
  91. data/lib/active_record/encryption/encryptor.rb +28 -8
  92. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  93. data/lib/active_record/encryption/scheme.rb +9 -2
  94. data/lib/active_record/enum.rb +33 -30
  95. data/lib/active_record/errors.rb +33 -9
  96. data/lib/active_record/explain.rb +1 -1
  97. data/lib/active_record/explain_registry.rb +51 -2
  98. data/lib/active_record/filter_attribute_handler.rb +73 -0
  99. data/lib/active_record/fixtures.rb +2 -4
  100. data/lib/active_record/future_result.rb +15 -9
  101. data/lib/active_record/gem_version.rb +2 -2
  102. data/lib/active_record/inheritance.rb +1 -1
  103. data/lib/active_record/insert_all.rb +14 -9
  104. data/lib/active_record/locking/optimistic.rb +8 -1
  105. data/lib/active_record/locking/pessimistic.rb +5 -0
  106. data/lib/active_record/log_subscriber.rb +3 -13
  107. data/lib/active_record/middleware/shard_selector.rb +34 -17
  108. data/lib/active_record/migration/command_recorder.rb +45 -12
  109. data/lib/active_record/migration/compatibility.rb +37 -24
  110. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  111. data/lib/active_record/migration.rb +48 -42
  112. data/lib/active_record/model_schema.rb +38 -13
  113. data/lib/active_record/nested_attributes.rb +6 -6
  114. data/lib/active_record/persistence.rb +162 -133
  115. data/lib/active_record/query_cache.rb +22 -15
  116. data/lib/active_record/query_logs.rb +100 -52
  117. data/lib/active_record/query_logs_formatter.rb +17 -28
  118. data/lib/active_record/querying.rb +8 -8
  119. data/lib/active_record/railtie.rb +35 -30
  120. data/lib/active_record/railties/controller_runtime.rb +11 -6
  121. data/lib/active_record/railties/databases.rake +26 -38
  122. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  123. data/lib/active_record/railties/job_runtime.rb +10 -11
  124. data/lib/active_record/reflection.rb +53 -21
  125. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  126. data/lib/active_record/relation/batches.rb +147 -73
  127. data/lib/active_record/relation/calculations.rb +52 -40
  128. data/lib/active_record/relation/delegation.rb +25 -15
  129. data/lib/active_record/relation/finder_methods.rb +40 -24
  130. data/lib/active_record/relation/merger.rb +8 -8
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
  132. data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
  133. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  134. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  135. data/lib/active_record/relation/predicate_builder.rb +22 -7
  136. data/lib/active_record/relation/query_attribute.rb +3 -1
  137. data/lib/active_record/relation/query_methods.rb +140 -86
  138. data/lib/active_record/relation/spawn_methods.rb +7 -7
  139. data/lib/active_record/relation/where_clause.rb +2 -9
  140. data/lib/active_record/relation.rb +107 -75
  141. data/lib/active_record/result.rb +109 -24
  142. data/lib/active_record/runtime_registry.rb +42 -58
  143. data/lib/active_record/sanitization.rb +9 -6
  144. data/lib/active_record/schema_dumper.rb +18 -11
  145. data/lib/active_record/schema_migration.rb +2 -1
  146. data/lib/active_record/scoping/named.rb +5 -2
  147. data/lib/active_record/scoping.rb +0 -1
  148. data/lib/active_record/signed_id.rb +43 -15
  149. data/lib/active_record/statement_cache.rb +24 -20
  150. data/lib/active_record/store.rb +51 -22
  151. data/lib/active_record/structured_event_subscriber.rb +85 -0
  152. data/lib/active_record/table_metadata.rb +6 -23
  153. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  154. data/lib/active_record/tasks/database_tasks.rb +85 -85
  155. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  156. data/lib/active_record/tasks/postgresql_database_tasks.rb +7 -40
  157. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
  158. data/lib/active_record/test_databases.rb +14 -4
  159. data/lib/active_record/test_fixtures.rb +39 -2
  160. data/lib/active_record/testing/query_assertions.rb +8 -2
  161. data/lib/active_record/timestamp.rb +4 -2
  162. data/lib/active_record/token_for.rb +1 -1
  163. data/lib/active_record/transaction.rb +2 -5
  164. data/lib/active_record/transactions.rb +37 -16
  165. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  166. data/lib/active_record/type/internal/timezone.rb +7 -0
  167. data/lib/active_record/type/json.rb +13 -2
  168. data/lib/active_record/type/serialized.rb +16 -4
  169. data/lib/active_record/type/type_map.rb +1 -1
  170. data/lib/active_record/type_caster/connection.rb +2 -1
  171. data/lib/active_record/validations/associated.rb +1 -1
  172. data/lib/active_record/validations/uniqueness.rb +8 -8
  173. data/lib/active_record.rb +84 -49
  174. data/lib/arel/alias_predication.rb +2 -0
  175. data/lib/arel/collectors/bind.rb +2 -2
  176. data/lib/arel/collectors/sql_string.rb +1 -1
  177. data/lib/arel/collectors/substitute_binds.rb +2 -2
  178. data/lib/arel/crud.rb +6 -11
  179. data/lib/arel/nodes/binary.rb +1 -1
  180. data/lib/arel/nodes/count.rb +2 -2
  181. data/lib/arel/nodes/function.rb +4 -10
  182. data/lib/arel/nodes/named_function.rb +2 -2
  183. data/lib/arel/nodes/node.rb +2 -2
  184. data/lib/arel/nodes/sql_literal.rb +1 -1
  185. data/lib/arel/nodes.rb +0 -2
  186. data/lib/arel/predications.rb +1 -3
  187. data/lib/arel/select_manager.rb +7 -2
  188. data/lib/arel/table.rb +3 -7
  189. data/lib/arel/visitors/dot.rb +0 -3
  190. data/lib/arel/visitors/postgresql.rb +55 -0
  191. data/lib/arel/visitors/sqlite.rb +55 -8
  192. data/lib/arel/visitors/to_sql.rb +3 -21
  193. data/lib/arel.rb +3 -1
  194. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  195. metadata +16 -13
  196. data/lib/active_record/explain_subscriber.rb +0 -34
  197. data/lib/active_record/normalization.rb +0 -163
  198. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -5,28 +5,22 @@ module Arel # :nodoc: all
5
5
  class Function < Arel::Nodes::NodeExpression
6
6
  include Arel::WindowPredications
7
7
  include Arel::FilterPredications
8
- attr_accessor :expressions, :alias, :distinct
9
8
 
10
- def initialize(expr, aliaz = nil)
9
+ attr_accessor :expressions, :distinct
10
+
11
+ def initialize(expr)
11
12
  super()
12
13
  @expressions = expr
13
- @alias = aliaz && SqlLiteral.new(aliaz)
14
14
  @distinct = false
15
15
  end
16
16
 
17
- def as(aliaz)
18
- self.alias = SqlLiteral.new(aliaz)
19
- self
20
- end
21
-
22
17
  def hash
23
- [@expressions, @alias, @distinct].hash
18
+ [@expressions, @distinct].hash
24
19
  end
25
20
 
26
21
  def eql?(other)
27
22
  self.class == other.class &&
28
23
  self.expressions == other.expressions &&
29
- self.alias == other.alias &&
30
24
  self.distinct == other.distinct
31
25
  end
32
26
  alias :== :eql?
@@ -5,8 +5,8 @@ module Arel # :nodoc: all
5
5
  class NamedFunction < Arel::Nodes::Function
6
6
  attr_accessor :name
7
7
 
8
- def initialize(name, expr, aliaz = nil)
9
- super(expr, aliaz)
8
+ def initialize(name, expr)
9
+ super(expr)
10
10
  @name = name
11
11
  end
12
12
 
@@ -6,7 +6,7 @@ module Arel # :nodoc: all
6
6
  #
7
7
  # Active Record uses Arel to compose SQL statements. Instead of building SQL strings directly, it's building an
8
8
  # abstract syntax tree (AST) of the statement using various types of Arel::Nodes::Node. Each node represents a
9
- # fragment of a SQL statement.
9
+ # fragment of an SQL statement.
10
10
  #
11
11
  # The intermediate representation allows Arel to compile the statement into the database's specific SQL dialect
12
12
  # only before sending it without having to care about the nuances of each database when building the statement.
@@ -152,7 +152,7 @@ module Arel # :nodoc: all
152
152
  end
153
153
  end
154
154
 
155
- def fetch_attribute
155
+ def fetch_attribute(&)
156
156
  end
157
157
 
158
158
  def equality?; false; end
@@ -19,7 +19,7 @@ module Arel # :nodoc: all
19
19
  coder.scalar = self.to_s
20
20
  end
21
21
 
22
- def fetch_attribute
22
+ def fetch_attribute(&)
23
23
  end
24
24
 
25
25
  def +(other)
data/lib/arel/nodes.rb CHANGED
@@ -45,8 +45,6 @@ require "arel/nodes/cte"
45
45
  require "arel/nodes/nary"
46
46
 
47
47
  # function
48
- # FIXME: Function + Alias can be rewritten as a Function and Alias node.
49
- # We should make Function a Unary node and deprecate the use of "aliaz"
50
48
  require "arel/nodes/function"
51
49
  require "arel/nodes/count"
52
50
  require "arel/nodes/extract"
@@ -231,9 +231,7 @@ module Arel # :nodoc: all
231
231
  private
232
232
  def grouping_any(method_id, others, *extras)
233
233
  nodes = others.map { |expr| send(method_id, expr, *extras) }
234
- Nodes::Grouping.new nodes.inject { |memo, node|
235
- Nodes::Or.new([memo, node])
236
- }
234
+ Nodes::Grouping.new Nodes::Or.new(nodes)
237
235
  end
238
236
 
239
237
  def grouping_all(method_id, others, *extras)
@@ -74,8 +74,13 @@ module Arel # :nodoc: all
74
74
  def group(*columns)
75
75
  columns.each do |column|
76
76
  # FIXME: backwards compat
77
- column = Nodes::SqlLiteral.new(column) if String === column
78
- column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column
77
+ case column
78
+ when Nodes::SqlLiteral
79
+ when String
80
+ column = Nodes::SqlLiteral.new(column)
81
+ when Symbol
82
+ column = Nodes::SqlLiteral.new(column.name)
83
+ end
79
84
 
80
85
  @ctx.groups.push Nodes::Group.new column
81
86
  end
data/lib/arel/table.rb CHANGED
@@ -12,13 +12,9 @@ module Arel # :nodoc: all
12
12
  attr_reader :table_alias
13
13
 
14
14
  def initialize(name, as: nil, klass: nil, type_caster: klass&.type_caster)
15
- @name =
16
- case name
17
- when Symbol then name.to_s
18
- else
19
- name
20
- end
15
+ name = name.name if name.is_a?(Symbol)
21
16
 
17
+ @name = name
22
18
  @klass = klass
23
19
  @type_caster = type_caster
24
20
 
@@ -84,7 +80,7 @@ module Arel # :nodoc: all
84
80
  end
85
81
 
86
82
  def [](name, table = self)
87
- name = name.to_s if name.is_a?(Symbol)
83
+ name = name.name if name.is_a?(Symbol)
88
84
  name = @klass.attribute_aliases[name] || name if @klass
89
85
  Attribute.new(table, name)
90
86
  end
@@ -34,7 +34,6 @@ module Arel # :nodoc: all
34
34
  def visit_Arel_Nodes_Function(o)
35
35
  visit_edge o, "expressions"
36
36
  visit_edge o, "distinct"
37
- visit_edge o, "alias"
38
37
  end
39
38
 
40
39
  def visit_Arel_Nodes_Unary(o)
@@ -108,14 +107,12 @@ module Arel # :nodoc: all
108
107
 
109
108
  def visit_Arel_Nodes_Extract(o)
110
109
  visit_edge o, "expressions"
111
- visit_edge o, "alias"
112
110
  end
113
111
 
114
112
  def visit_Arel_Nodes_NamedFunction(o)
115
113
  visit_edge o, "name"
116
114
  visit_edge o, "expressions"
117
115
  visit_edge o, "distinct"
118
- visit_edge o, "alias"
119
116
  end
120
117
 
121
118
  def visit_Arel_Nodes_InsertStatement(o)
@@ -4,6 +4,55 @@ module Arel # :nodoc: all
4
4
  module Visitors
5
5
  class PostgreSQL < Arel::Visitors::ToSql
6
6
  private
7
+ def visit_Arel_Nodes_UpdateStatement(o, collector)
8
+ collector.retryable = false
9
+ o = prepare_update_statement(o)
10
+
11
+ collector << "UPDATE "
12
+
13
+ # UPDATE with JOIN is in the form of:
14
+ #
15
+ # UPDATE t1 AS __active_record_update_alias
16
+ # SET ..
17
+ # FROM t1 JOIN t2 ON t2.join_id = t1.join_id ..
18
+ # WHERE t1.id = __active_record_update_alias.id AND ..
19
+ if has_join_sources?(o)
20
+ collector = visit o.relation.left, collector
21
+ collect_nodes_for o.values, collector, " SET "
22
+ collector << " FROM "
23
+ collector = inject_join o.relation.right, collector, " "
24
+ else
25
+ collector = visit o.relation, collector
26
+ collect_nodes_for o.values, collector, " SET "
27
+ end
28
+
29
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
30
+ collect_nodes_for o.orders, collector, " ORDER BY "
31
+ maybe_visit o.limit, collector
32
+ maybe_visit o.comment, collector
33
+ end
34
+
35
+ # In the simple case, PostgreSQL allows us to place FROM or JOINs directly into the UPDATE
36
+ # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
37
+ # these, we must use a subquery.
38
+ def prepare_update_statement(o)
39
+ if o.key && has_join_sources?(o) && !has_group_by_and_having?(o) && !has_limit_or_offset_or_orders?(o)
40
+ # Join clauses cannot reference the target table, so alias the
41
+ # updated table, place the entire relation in the FROM clause, and
42
+ # add a self-join (which requires the primary key)
43
+ stmt = o.clone
44
+ stmt.relation, stmt.wheres = o.relation.clone, o.wheres.clone
45
+ stmt.relation.right = [stmt.relation.left, *stmt.relation.right]
46
+ stmt.relation.left = stmt.relation.left.alias("__active_record_update_alias")
47
+ Array.wrap(o.key).each do |key|
48
+ stmt.wheres << key.eq(stmt.relation.left[key.name])
49
+ end
50
+ stmt
51
+ else
52
+ super
53
+ end
54
+ end
55
+
7
56
  def visit_Arel_Nodes_Matches(o, collector)
8
57
  op = o.case_sensitive ? " LIKE " : " ILIKE "
9
58
  collector = infix_value o, collector, op
@@ -66,6 +115,12 @@ module Arel # :nodoc: all
66
115
  grouping_parentheses o.expr, collector
67
116
  end
68
117
 
118
+ def visit_Arel_Nodes_InnerJoin(o, collector)
119
+ return super if o.right
120
+ collector << "CROSS JOIN "
121
+ visit o.left, collector
122
+ end
123
+
69
124
  def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
70
125
  collector = visit o.left, collector
71
126
  collector << " IS NOT DISTINCT FROM "
@@ -4,6 +4,61 @@ module Arel # :nodoc: all
4
4
  module Visitors
5
5
  class SQLite < Arel::Visitors::ToSql
6
6
  private
7
+ def visit_Arel_Nodes_UpdateStatement(o, collector)
8
+ collector.retryable = false
9
+ o = prepare_update_statement(o)
10
+
11
+ collector << "UPDATE "
12
+
13
+ # UPDATE with JOIN is in the form of:
14
+ #
15
+ # UPDATE t1 AS __active_record_update_alias
16
+ # SET ..
17
+ # FROM t1 JOIN t2 ON t2.join_id = t1.join_id ..
18
+ # WHERE t1.id = __active_record_update_alias.id AND ..
19
+ if has_join_sources?(o)
20
+ collector = visit o.relation.left, collector
21
+ collect_nodes_for o.values, collector, " SET "
22
+ collector << " FROM "
23
+ collector = inject_join o.relation.right, collector, " "
24
+ else
25
+ collector = visit o.relation, collector
26
+ collect_nodes_for o.values, collector, " SET "
27
+ end
28
+
29
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
30
+ collect_nodes_for o.orders, collector, " ORDER BY "
31
+ maybe_visit o.limit, collector
32
+ maybe_visit o.comment, collector
33
+ end
34
+
35
+ def prepare_update_statement(o)
36
+ # Sqlite need to be built with the SQLITE_ENABLE_UPDATE_DELETE_LIMIT compile-time option
37
+ # to support LIMIT/OFFSET/ORDER in UPDATE and DELETE statements.
38
+ if o.key && has_join_sources?(o) && !has_group_by_and_having?(o) && !has_limit_or_offset_or_orders?(o)
39
+ # Join clauses cannot reference the target table, so alias the
40
+ # updated table, place the entire relation in the FROM clause, and
41
+ # add a self-join (which requires the primary key)
42
+ stmt = o.clone
43
+ stmt.relation, stmt.wheres = o.relation.clone, o.wheres.clone
44
+ stmt.relation.right = [stmt.relation.left, *stmt.relation.right]
45
+ stmt.relation.left = stmt.relation.left.alias("__active_record_update_alias")
46
+ Array.wrap(o.key).each do |key|
47
+ stmt.wheres << key.eq(stmt.relation.left[key.name])
48
+ end
49
+ stmt
50
+ else
51
+ super
52
+ end
53
+ end
54
+
55
+ def visit_Arel_Nodes_TableAlias(o, collector)
56
+ # "AS" is not optional in "{UPDATE | DELETE} table AS alias ..."
57
+ collector = visit o.relation, collector
58
+ collector << " AS "
59
+ collector << quote_table_name(o.name)
60
+ end
61
+
7
62
  # Locks are not supported in SQLite
8
63
  def visit_Arel_Nodes_Lock(o, collector)
9
64
  collector
@@ -14,14 +69,6 @@ module Arel # :nodoc: all
14
69
  super
15
70
  end
16
71
 
17
- def visit_Arel_Nodes_True(o, collector)
18
- collector << "1"
19
- end
20
-
21
- def visit_Arel_Nodes_False(o, collector)
22
- collector << "0"
23
- end
24
-
25
72
  def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
26
73
  collector = visit o.left, collector
27
74
  collector << " IS "
@@ -77,13 +77,7 @@ module Arel # :nodoc: all
77
77
 
78
78
  def visit_Arel_Nodes_Exists(o, collector)
79
79
  collector << "EXISTS ("
80
- collector = visit(o.expressions, collector) << ")"
81
- if o.alias
82
- collector << " AS "
83
- visit o.alias, collector
84
- else
85
- collector
86
- end
80
+ visit(o.expressions, collector) << ")"
87
81
  end
88
82
 
89
83
  def visit_Arel_Nodes_Casted(o, collector)
@@ -390,13 +384,7 @@ module Arel # :nodoc: all
390
384
  collector << o.name
391
385
  collector << "("
392
386
  collector << "DISTINCT " if o.distinct
393
- collector = inject_join(o.expressions, collector, ", ") << ")"
394
- if o.alias
395
- collector << " AS "
396
- visit o.alias, collector
397
- else
398
- collector
399
- end
387
+ inject_join(o.expressions, collector, ", ") << ")"
400
388
  end
401
389
 
402
390
  def visit_Arel_Nodes_Extract(o, collector)
@@ -1000,13 +988,7 @@ module Arel # :nodoc: all
1000
988
  if o.distinct
1001
989
  collector << "DISTINCT "
1002
990
  end
1003
- collector = inject_join(o.expressions, collector, ", ") << ")"
1004
- if o.alias
1005
- collector << " AS "
1006
- visit o.alias, collector
1007
- else
1008
- collector
1009
- end
991
+ inject_join(o.expressions, collector, ", ") << ")"
1010
992
  end
1011
993
 
1012
994
  def is_distinct_from(o, collector)
data/lib/arel.rb CHANGED
@@ -50,7 +50,9 @@ module Arel
50
50
  # Use this option only if the SQL is idempotent, as it could be executed
51
51
  # more than once.
52
52
  def self.sql(sql_string, *positional_binds, retryable: false, **named_binds)
53
- if positional_binds.empty? && named_binds.empty?
53
+ if Arel::Nodes::SqlLiteral === sql_string
54
+ sql_string
55
+ elsif positional_binds.empty? && named_binds.empty?
54
56
  Arel::Nodes::SqlLiteral.new(sql_string, retryable: retryable)
55
57
  else
56
58
  Arel::Nodes::BoundSqlLiteral.new sql_string, positional_binds, named_binds
@@ -5,4 +5,4 @@ Example:
5
5
  `bin/rails generate application_record`
6
6
 
7
7
  This generates the base class. A test is not generated because no
8
- behaviour is included in `ApplicationRecord` by default.
8
+ behavior is included in `ApplicationRecord` by default.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.3
4
+ version: 8.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 7.2.3
18
+ version: 8.1.3
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 7.2.3
25
+ version: 8.1.3
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activemodel
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - '='
31
31
  - !ruby/object:Gem::Version
32
- version: 7.2.3
32
+ version: 8.1.3
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - '='
38
38
  - !ruby/object:Gem::Version
39
- version: 7.2.3
39
+ version: 8.1.3
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: timeout
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -83,6 +83,7 @@ files:
83
83
  - lib/active_record/associations/builder/singular_association.rb
84
84
  - lib/active_record/associations/collection_association.rb
85
85
  - lib/active_record/associations/collection_proxy.rb
86
+ - lib/active_record/associations/deprecation.rb
86
87
  - lib/active_record/associations/disable_joins_association_scope.rb
87
88
  - lib/active_record/associations/errors.rb
88
89
  - lib/active_record/associations/foreign_association.rb
@@ -252,7 +253,7 @@ files:
252
253
  - lib/active_record/errors.rb
253
254
  - lib/active_record/explain.rb
254
255
  - lib/active_record/explain_registry.rb
255
- - lib/active_record/explain_subscriber.rb
256
+ - lib/active_record/filter_attribute_handler.rb
256
257
  - lib/active_record/fixture_set/file.rb
257
258
  - lib/active_record/fixture_set/model_metadata.rb
258
259
  - lib/active_record/fixture_set/render_context.rb
@@ -279,6 +280,7 @@ files:
279
280
  - lib/active_record/migration.rb
280
281
  - lib/active_record/migration/command_recorder.rb
281
282
  - lib/active_record/migration/compatibility.rb
283
+ - lib/active_record/migration/default_schema_versions_formatter.rb
282
284
  - lib/active_record/migration/default_strategy.rb
283
285
  - lib/active_record/migration/execution_strategy.rb
284
286
  - lib/active_record/migration/join_table.rb
@@ -286,7 +288,6 @@ files:
286
288
  - lib/active_record/model_schema.rb
287
289
  - lib/active_record/nested_attributes.rb
288
290
  - lib/active_record/no_touching.rb
289
- - lib/active_record/normalization.rb
290
291
  - lib/active_record/persistence.rb
291
292
  - lib/active_record/promise.rb
292
293
  - lib/active_record/query_cache.rb
@@ -297,6 +298,7 @@ files:
297
298
  - lib/active_record/railties/console_sandbox.rb
298
299
  - lib/active_record/railties/controller_runtime.rb
299
300
  - lib/active_record/railties/databases.rake
301
+ - lib/active_record/railties/job_checkpoints.rb
300
302
  - lib/active_record/railties/job_runtime.rb
301
303
  - lib/active_record/readonly_attributes.rb
302
304
  - lib/active_record/reflection.rb
@@ -317,7 +319,6 @@ files:
317
319
  - lib/active_record/relation/predicate_builder/relation_handler.rb
318
320
  - lib/active_record/relation/query_attribute.rb
319
321
  - lib/active_record/relation/query_methods.rb
320
- - lib/active_record/relation/record_fetch_warning.rb
321
322
  - lib/active_record/relation/spawn_methods.rb
322
323
  - lib/active_record/relation/where_clause.rb
323
324
  - lib/active_record/result.rb
@@ -335,8 +336,10 @@ files:
335
336
  - lib/active_record/signed_id.rb
336
337
  - lib/active_record/statement_cache.rb
337
338
  - lib/active_record/store.rb
339
+ - lib/active_record/structured_event_subscriber.rb
338
340
  - lib/active_record/suppressor.rb
339
341
  - lib/active_record/table_metadata.rb
342
+ - lib/active_record/tasks/abstract_tasks.rb
340
343
  - lib/active_record/tasks/database_tasks.rb
341
344
  - lib/active_record/tasks/mysql_database_tasks.rb
342
345
  - lib/active_record/tasks/postgresql_database_tasks.rb
@@ -475,10 +478,10 @@ licenses:
475
478
  - MIT
476
479
  metadata:
477
480
  bug_tracker_uri: https://github.com/rails/rails/issues
478
- changelog_uri: https://github.com/rails/rails/blob/v7.2.3/activerecord/CHANGELOG.md
479
- documentation_uri: https://api.rubyonrails.org/v7.2.3/
481
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.3/activerecord/CHANGELOG.md
482
+ documentation_uri: https://api.rubyonrails.org/v8.1.3/
480
483
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
481
- source_code_uri: https://github.com/rails/rails/tree/v7.2.3/activerecord
484
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.3/activerecord
482
485
  rubygems_mfa_required: 'true'
483
486
  rdoc_options:
484
487
  - "--main"
@@ -489,14 +492,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
489
492
  requirements:
490
493
  - - ">="
491
494
  - !ruby/object:Gem::Version
492
- version: 3.1.0
495
+ version: 3.2.0
493
496
  required_rubygems_version: !ruby/object:Gem::Requirement
494
497
  requirements:
495
498
  - - ">="
496
499
  - !ruby/object:Gem::Version
497
500
  version: '0'
498
501
  requirements: []
499
- rubygems_version: 3.6.9
502
+ rubygems_version: 4.0.6
500
503
  specification_version: 4
501
504
  summary: Object-relational mapper framework (part of Rails).
502
505
  test_files: []
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_support/notifications"
4
- require "active_record/explain_registry"
5
-
6
- module ActiveRecord
7
- class ExplainSubscriber # :nodoc:
8
- def start(name, id, payload)
9
- # unused
10
- end
11
-
12
- def finish(name, id, payload)
13
- if ExplainRegistry.collect? && !ignore_payload?(payload)
14
- ExplainRegistry.queries << payload.values_at(:sql, :binds)
15
- end
16
- end
17
-
18
- # SCHEMA queries cannot be EXPLAINed, also we do not want to run EXPLAIN on
19
- # our own EXPLAINs no matter how loopingly beautiful that would be.
20
- #
21
- # On the other hand, we want to monitor the performance of our real database
22
- # queries, not the performance of the access to the query cache.
23
- IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN)
24
- EXPLAINED_SQLS = /\A\s*(\/\*.*\*\/)?\s*(with|select|update|delete|insert)\b/i
25
- def ignore_payload?(payload)
26
- payload[:exception] ||
27
- payload[:cached] ||
28
- IGNORED_PAYLOADS.include?(payload[:name]) ||
29
- !payload[:sql].match?(EXPLAINED_SQLS)
30
- end
31
-
32
- ActiveSupport::Notifications.subscribe("sql.active_record", new)
33
- end
34
- end