activerecord 7.2.2.1 → 8.1.2

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +564 -753
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +2 -1
  5. data/lib/active_record/associations/alias_tracker.rb +6 -4
  6. data/lib/active_record/associations/association.rb +35 -11
  7. data/lib/active_record/associations/belongs_to_association.rb +18 -2
  8. data/lib/active_record/associations/builder/association.rb +23 -11
  9. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  10. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  11. data/lib/active_record/associations/builder/has_one.rb +1 -1
  12. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  13. data/lib/active_record/associations/collection_association.rb +10 -8
  14. data/lib/active_record/associations/collection_proxy.rb +22 -4
  15. data/lib/active_record/associations/deprecation.rb +88 -0
  16. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  17. data/lib/active_record/associations/errors.rb +3 -0
  18. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  19. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  20. data/lib/active_record/associations/join_dependency.rb +4 -2
  21. data/lib/active_record/associations/preloader/association.rb +2 -2
  22. data/lib/active_record/associations/preloader/batch.rb +7 -1
  23. data/lib/active_record/associations/preloader/branch.rb +1 -0
  24. data/lib/active_record/associations/singular_association.rb +8 -3
  25. data/lib/active_record/associations.rb +192 -24
  26. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  27. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  28. data/lib/active_record/attribute_methods/query.rb +34 -0
  29. data/lib/active_record/attribute_methods/serialization.rb +17 -4
  30. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  31. data/lib/active_record/attribute_methods.rb +24 -19
  32. data/lib/active_record/attributes.rb +40 -26
  33. data/lib/active_record/autosave_association.rb +91 -39
  34. data/lib/active_record/base.rb +3 -4
  35. data/lib/active_record/coders/json.rb +14 -5
  36. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
  37. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  38. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
  39. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
  40. data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
  41. data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
  42. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
  43. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  45. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  46. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
  47. data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
  48. data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
  49. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
  50. data/lib/active_record/connection_adapters/column.rb +17 -4
  51. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  52. data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
  53. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  54. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  55. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
  56. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
  57. data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
  58. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  59. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  60. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  62. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  65. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  66. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  67. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
  68. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  69. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
  70. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
  71. data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
  72. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
  73. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
  74. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  75. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
  78. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  79. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
  80. data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
  81. data/lib/active_record/connection_adapters.rb +1 -56
  82. data/lib/active_record/connection_handling.rb +37 -10
  83. data/lib/active_record/core.rb +61 -25
  84. data/lib/active_record/counter_cache.rb +34 -9
  85. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  86. data/lib/active_record/database_configurations/database_config.rb +9 -1
  87. data/lib/active_record/database_configurations/hash_config.rb +67 -9
  88. data/lib/active_record/database_configurations/url_config.rb +13 -3
  89. data/lib/active_record/database_configurations.rb +7 -3
  90. data/lib/active_record/delegated_type.rb +19 -19
  91. data/lib/active_record/dynamic_matchers.rb +54 -69
  92. data/lib/active_record/encryption/config.rb +3 -1
  93. data/lib/active_record/encryption/encryptable_record.rb +9 -9
  94. data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
  95. data/lib/active_record/encryption/encryptor.rb +49 -28
  96. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  97. data/lib/active_record/encryption/scheme.rb +9 -2
  98. data/lib/active_record/enum.rb +46 -42
  99. data/lib/active_record/errors.rb +36 -12
  100. data/lib/active_record/explain.rb +1 -1
  101. data/lib/active_record/explain_registry.rb +51 -2
  102. data/lib/active_record/filter_attribute_handler.rb +73 -0
  103. data/lib/active_record/fixture_set/table_row.rb +19 -2
  104. data/lib/active_record/fixtures.rb +2 -4
  105. data/lib/active_record/future_result.rb +13 -9
  106. data/lib/active_record/gem_version.rb +3 -3
  107. data/lib/active_record/inheritance.rb +1 -1
  108. data/lib/active_record/insert_all.rb +12 -7
  109. data/lib/active_record/locking/optimistic.rb +8 -1
  110. data/lib/active_record/locking/pessimistic.rb +5 -0
  111. data/lib/active_record/log_subscriber.rb +3 -13
  112. data/lib/active_record/middleware/shard_selector.rb +34 -17
  113. data/lib/active_record/migration/command_recorder.rb +44 -11
  114. data/lib/active_record/migration/compatibility.rb +37 -24
  115. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  116. data/lib/active_record/migration.rb +50 -43
  117. data/lib/active_record/model_schema.rb +38 -13
  118. data/lib/active_record/nested_attributes.rb +6 -6
  119. data/lib/active_record/persistence.rb +162 -133
  120. data/lib/active_record/query_cache.rb +22 -15
  121. data/lib/active_record/query_logs.rb +104 -52
  122. data/lib/active_record/query_logs_formatter.rb +17 -28
  123. data/lib/active_record/querying.rb +12 -12
  124. data/lib/active_record/railtie.rb +37 -32
  125. data/lib/active_record/railties/controller_runtime.rb +11 -6
  126. data/lib/active_record/railties/databases.rake +26 -37
  127. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  128. data/lib/active_record/railties/job_runtime.rb +10 -11
  129. data/lib/active_record/reflection.rb +53 -21
  130. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  131. data/lib/active_record/relation/batches.rb +147 -73
  132. data/lib/active_record/relation/calculations.rb +80 -63
  133. data/lib/active_record/relation/delegation.rb +25 -15
  134. data/lib/active_record/relation/finder_methods.rb +54 -37
  135. data/lib/active_record/relation/merger.rb +8 -8
  136. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
  137. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  138. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  139. data/lib/active_record/relation/predicate_builder.rb +22 -7
  140. data/lib/active_record/relation/query_attribute.rb +4 -2
  141. data/lib/active_record/relation/query_methods.rb +156 -95
  142. data/lib/active_record/relation/spawn_methods.rb +7 -7
  143. data/lib/active_record/relation/where_clause.rb +10 -11
  144. data/lib/active_record/relation.rb +122 -80
  145. data/lib/active_record/result.rb +109 -24
  146. data/lib/active_record/runtime_registry.rb +42 -58
  147. data/lib/active_record/sanitization.rb +9 -6
  148. data/lib/active_record/schema_dumper.rb +47 -22
  149. data/lib/active_record/schema_migration.rb +2 -1
  150. data/lib/active_record/scoping/named.rb +5 -2
  151. data/lib/active_record/scoping.rb +0 -1
  152. data/lib/active_record/secure_token.rb +3 -3
  153. data/lib/active_record/signed_id.rb +47 -18
  154. data/lib/active_record/statement_cache.rb +24 -20
  155. data/lib/active_record/store.rb +51 -22
  156. data/lib/active_record/structured_event_subscriber.rb +85 -0
  157. data/lib/active_record/table_metadata.rb +6 -23
  158. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  159. data/lib/active_record/tasks/database_tasks.rb +85 -85
  160. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  161. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  162. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
  163. data/lib/active_record/test_databases.rb +14 -4
  164. data/lib/active_record/test_fixtures.rb +39 -2
  165. data/lib/active_record/testing/query_assertions.rb +8 -2
  166. data/lib/active_record/timestamp.rb +4 -2
  167. data/lib/active_record/token_for.rb +1 -1
  168. data/lib/active_record/transaction.rb +2 -5
  169. data/lib/active_record/transactions.rb +39 -16
  170. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  171. data/lib/active_record/type/internal/timezone.rb +7 -0
  172. data/lib/active_record/type/json.rb +15 -2
  173. data/lib/active_record/type/serialized.rb +11 -4
  174. data/lib/active_record/type/type_map.rb +1 -1
  175. data/lib/active_record/type_caster/connection.rb +2 -1
  176. data/lib/active_record/validations/associated.rb +1 -1
  177. data/lib/active_record/validations/uniqueness.rb +8 -8
  178. data/lib/active_record.rb +85 -50
  179. data/lib/arel/alias_predication.rb +2 -0
  180. data/lib/arel/collectors/bind.rb +2 -2
  181. data/lib/arel/collectors/sql_string.rb +1 -1
  182. data/lib/arel/collectors/substitute_binds.rb +2 -2
  183. data/lib/arel/crud.rb +8 -11
  184. data/lib/arel/delete_manager.rb +5 -0
  185. data/lib/arel/nodes/binary.rb +1 -1
  186. data/lib/arel/nodes/count.rb +2 -2
  187. data/lib/arel/nodes/delete_statement.rb +4 -2
  188. data/lib/arel/nodes/function.rb +4 -10
  189. data/lib/arel/nodes/named_function.rb +2 -2
  190. data/lib/arel/nodes/node.rb +2 -2
  191. data/lib/arel/nodes/sql_literal.rb +1 -1
  192. data/lib/arel/nodes/update_statement.rb +4 -2
  193. data/lib/arel/nodes.rb +0 -2
  194. data/lib/arel/select_manager.rb +13 -4
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/update_manager.rb +5 -0
  197. data/lib/arel/visitors/dot.rb +2 -3
  198. data/lib/arel/visitors/postgresql.rb +55 -0
  199. data/lib/arel/visitors/sqlite.rb +55 -8
  200. data/lib/arel/visitors/to_sql.rb +6 -22
  201. data/lib/arel.rb +3 -1
  202. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  203. metadata +17 -17
  204. data/lib/active_record/explain_subscriber.rb +0 -34
  205. data/lib/active_record/normalization.rb +0 -163
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
@@ -28,5 +28,10 @@ module Arel # :nodoc: all
28
28
  @ast.havings << expr
29
29
  self
30
30
  end
31
+
32
+ def comment(value)
33
+ @ast.comment = value
34
+ self
35
+ end
31
36
  end
32
37
  end
@@ -30,7 +30,7 @@ module Arel # :nodoc: all
30
30
  end
31
31
 
32
32
  module FetchAttribute
33
- def fetch_attribute
33
+ def fetch_attribute(&)
34
34
  if left.is_a?(Arel::Attributes::Attribute)
35
35
  yield left
36
36
  elsif right.is_a?(Arel::Attributes::Attribute)
@@ -3,8 +3,8 @@
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
5
  class Count < Arel::Nodes::Function
6
- def initialize(expr, distinct = false, aliaz = nil)
7
- super(expr, aliaz)
6
+ def initialize(expr, distinct = false)
7
+ super(expr)
8
8
  @distinct = distinct
9
9
  end
10
10
  end
@@ -3,7 +3,7 @@
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
5
  class DeleteStatement < Arel::Nodes::Node
6
- attr_accessor :relation, :wheres, :groups, :havings, :orders, :limit, :offset, :key
6
+ attr_accessor :relation, :wheres, :groups, :havings, :orders, :limit, :offset, :comment, :key
7
7
 
8
8
  def initialize(relation = nil, wheres = [])
9
9
  super()
@@ -14,6 +14,7 @@ module Arel # :nodoc: all
14
14
  @orders = []
15
15
  @limit = nil
16
16
  @offset = nil
17
+ @comment = nil
17
18
  @key = nil
18
19
  end
19
20
 
@@ -24,7 +25,7 @@ module Arel # :nodoc: all
24
25
  end
25
26
 
26
27
  def hash
27
- [self.class, @relation, @wheres, @orders, @limit, @offset, @key].hash
28
+ [self.class, @relation, @wheres, @orders, @limit, @offset, @comment, @key].hash
28
29
  end
29
30
 
30
31
  def eql?(other)
@@ -36,6 +37,7 @@ module Arel # :nodoc: all
36
37
  self.havings == other.havings &&
37
38
  self.limit == other.limit &&
38
39
  self.offset == other.offset &&
40
+ self.comment == other.comment &&
39
41
  self.key == other.key
40
42
  end
41
43
  alias :== :eql?
@@ -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)
@@ -3,7 +3,7 @@
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
5
  class UpdateStatement < Arel::Nodes::Node
6
- attr_accessor :relation, :wheres, :values, :groups, :havings, :orders, :limit, :offset, :key
6
+ attr_accessor :relation, :wheres, :values, :groups, :havings, :orders, :limit, :offset, :comment, :key
7
7
 
8
8
  def initialize(relation = nil)
9
9
  super()
@@ -15,6 +15,7 @@ module Arel # :nodoc: all
15
15
  @orders = []
16
16
  @limit = nil
17
17
  @offset = nil
18
+ @comment = nil
18
19
  @key = nil
19
20
  end
20
21
 
@@ -25,7 +26,7 @@ module Arel # :nodoc: all
25
26
  end
26
27
 
27
28
  def hash
28
- [@relation, @wheres, @values, @orders, @limit, @offset, @key].hash
29
+ [@relation, @wheres, @values, @orders, @limit, @offset, @comment, @key].hash
29
30
  end
30
31
 
31
32
  def eql?(other)
@@ -38,6 +39,7 @@ module Arel # :nodoc: all
38
39
  self.orders == other.orders &&
39
40
  self.limit == other.limit &&
40
41
  self.offset == other.offset &&
42
+ self.comment == other.comment &&
41
43
  self.key == other.key
42
44
  end
43
45
  alias :== :eql?
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"
@@ -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
@@ -250,8 +255,12 @@ module Arel # :nodoc: all
250
255
  end
251
256
 
252
257
  def comment(*values)
253
- @ctx.comment = Nodes::Comment.new(values)
254
- self
258
+ if values.any?
259
+ @ctx.comment = Nodes::Comment.new(values)
260
+ self
261
+ else
262
+ @ctx.comment
263
+ end
255
264
  end
256
265
 
257
266
  private
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
@@ -45,5 +45,10 @@ module Arel # :nodoc: all
45
45
  @ast.havings << expr
46
46
  self
47
47
  end
48
+
49
+ def comment(value)
50
+ @ast.comment = value
51
+ self
52
+ end
48
53
  end
49
54
  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)
@@ -153,6 +150,7 @@ module Arel # :nodoc: all
153
150
  visit_edge o, "orders"
154
151
  visit_edge o, "limit"
155
152
  visit_edge o, "offset"
153
+ visit_edge o, "comment"
156
154
  visit_edge o, "key"
157
155
  end
158
156
 
@@ -162,6 +160,7 @@ module Arel # :nodoc: all
162
160
  visit_edge o, "orders"
163
161
  visit_edge o, "limit"
164
162
  visit_edge o, "offset"
163
+ visit_edge o, "comment"
165
164
  visit_edge o, "key"
166
165
  end
167
166
 
@@ -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 "
@@ -35,6 +35,7 @@ module Arel # :nodoc: all
35
35
  collect_nodes_for o.wheres, collector, " WHERE ", " AND "
36
36
  collect_nodes_for o.orders, collector, " ORDER BY "
37
37
  maybe_visit o.limit, collector
38
+ maybe_visit o.comment, collector
38
39
  end
39
40
 
40
41
  def visit_Arel_Nodes_UpdateStatement(o, collector)
@@ -48,6 +49,7 @@ module Arel # :nodoc: all
48
49
  collect_nodes_for o.wheres, collector, " WHERE ", " AND "
49
50
  collect_nodes_for o.orders, collector, " ORDER BY "
50
51
  maybe_visit o.limit, collector
52
+ maybe_visit o.comment, collector
51
53
  end
52
54
 
53
55
  def visit_Arel_Nodes_InsertStatement(o, collector)
@@ -75,13 +77,7 @@ module Arel # :nodoc: all
75
77
 
76
78
  def visit_Arel_Nodes_Exists(o, collector)
77
79
  collector << "EXISTS ("
78
- collector = visit(o.expressions, collector) << ")"
79
- if o.alias
80
- collector << " AS "
81
- visit o.alias, collector
82
- else
83
- collector
84
- end
80
+ visit(o.expressions, collector) << ")"
85
81
  end
86
82
 
87
83
  def visit_Arel_Nodes_Casted(o, collector)
@@ -388,13 +384,7 @@ module Arel # :nodoc: all
388
384
  collector << o.name
389
385
  collector << "("
390
386
  collector << "DISTINCT " if o.distinct
391
- collector = inject_join(o.expressions, collector, ", ") << ")"
392
- if o.alias
393
- collector << " AS "
394
- visit o.alias, collector
395
- else
396
- collector
397
- end
387
+ inject_join(o.expressions, collector, ", ") << ")"
398
388
  end
399
389
 
400
390
  def visit_Arel_Nodes_Extract(o, collector)
@@ -763,7 +753,7 @@ module Arel # :nodoc: all
763
753
 
764
754
  def visit_Arel_Nodes_SqlLiteral(o, collector)
765
755
  collector.preparable = false
766
- collector.retryable = o.retryable
756
+ collector.retryable &&= o.retryable
767
757
  collector << o.to_s
768
758
  end
769
759
 
@@ -998,13 +988,7 @@ module Arel # :nodoc: all
998
988
  if o.distinct
999
989
  collector << "DISTINCT "
1000
990
  end
1001
- collector = inject_join(o.expressions, collector, ", ") << ")"
1002
- if o.alias
1003
- collector << " AS "
1004
- visit o.alias, collector
1005
- else
1006
- collector
1007
- end
991
+ inject_join(o.expressions, collector, ", ") << ")"
1008
992
  end
1009
993
 
1010
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,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.2.1
4
+ version: 8.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-12-10 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -16,28 +15,28 @@ dependencies:
16
15
  requirements:
17
16
  - - '='
18
17
  - !ruby/object:Gem::Version
19
- version: 7.2.2.1
18
+ version: 8.1.2
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - '='
25
24
  - !ruby/object:Gem::Version
26
- version: 7.2.2.1
25
+ version: 8.1.2
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: activemodel
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - '='
32
31
  - !ruby/object:Gem::Version
33
- version: 7.2.2.1
32
+ version: 8.1.2
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - '='
39
38
  - !ruby/object:Gem::Version
40
- version: 7.2.2.1
39
+ version: 8.1.2
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: timeout
43
42
  requirement: !ruby/object:Gem::Requirement
@@ -84,6 +83,7 @@ files:
84
83
  - lib/active_record/associations/builder/singular_association.rb
85
84
  - lib/active_record/associations/collection_association.rb
86
85
  - lib/active_record/associations/collection_proxy.rb
86
+ - lib/active_record/associations/deprecation.rb
87
87
  - lib/active_record/associations/disable_joins_association_scope.rb
88
88
  - lib/active_record/associations/errors.rb
89
89
  - lib/active_record/associations/foreign_association.rb
@@ -253,7 +253,7 @@ files:
253
253
  - lib/active_record/errors.rb
254
254
  - lib/active_record/explain.rb
255
255
  - lib/active_record/explain_registry.rb
256
- - lib/active_record/explain_subscriber.rb
256
+ - lib/active_record/filter_attribute_handler.rb
257
257
  - lib/active_record/fixture_set/file.rb
258
258
  - lib/active_record/fixture_set/model_metadata.rb
259
259
  - lib/active_record/fixture_set/render_context.rb
@@ -280,6 +280,7 @@ files:
280
280
  - lib/active_record/migration.rb
281
281
  - lib/active_record/migration/command_recorder.rb
282
282
  - lib/active_record/migration/compatibility.rb
283
+ - lib/active_record/migration/default_schema_versions_formatter.rb
283
284
  - lib/active_record/migration/default_strategy.rb
284
285
  - lib/active_record/migration/execution_strategy.rb
285
286
  - lib/active_record/migration/join_table.rb
@@ -287,7 +288,6 @@ files:
287
288
  - lib/active_record/model_schema.rb
288
289
  - lib/active_record/nested_attributes.rb
289
290
  - lib/active_record/no_touching.rb
290
- - lib/active_record/normalization.rb
291
291
  - lib/active_record/persistence.rb
292
292
  - lib/active_record/promise.rb
293
293
  - lib/active_record/query_cache.rb
@@ -298,6 +298,7 @@ files:
298
298
  - lib/active_record/railties/console_sandbox.rb
299
299
  - lib/active_record/railties/controller_runtime.rb
300
300
  - lib/active_record/railties/databases.rake
301
+ - lib/active_record/railties/job_checkpoints.rb
301
302
  - lib/active_record/railties/job_runtime.rb
302
303
  - lib/active_record/readonly_attributes.rb
303
304
  - lib/active_record/reflection.rb
@@ -318,7 +319,6 @@ files:
318
319
  - lib/active_record/relation/predicate_builder/relation_handler.rb
319
320
  - lib/active_record/relation/query_attribute.rb
320
321
  - lib/active_record/relation/query_methods.rb
321
- - lib/active_record/relation/record_fetch_warning.rb
322
322
  - lib/active_record/relation/spawn_methods.rb
323
323
  - lib/active_record/relation/where_clause.rb
324
324
  - lib/active_record/result.rb
@@ -336,8 +336,10 @@ files:
336
336
  - lib/active_record/signed_id.rb
337
337
  - lib/active_record/statement_cache.rb
338
338
  - lib/active_record/store.rb
339
+ - lib/active_record/structured_event_subscriber.rb
339
340
  - lib/active_record/suppressor.rb
340
341
  - lib/active_record/table_metadata.rb
342
+ - lib/active_record/tasks/abstract_tasks.rb
341
343
  - lib/active_record/tasks/database_tasks.rb
342
344
  - lib/active_record/tasks/mysql_database_tasks.rb
343
345
  - lib/active_record/tasks/postgresql_database_tasks.rb
@@ -476,12 +478,11 @@ licenses:
476
478
  - MIT
477
479
  metadata:
478
480
  bug_tracker_uri: https://github.com/rails/rails/issues
479
- changelog_uri: https://github.com/rails/rails/blob/v7.2.2.1/activerecord/CHANGELOG.md
480
- documentation_uri: https://api.rubyonrails.org/v7.2.2.1/
481
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.2/activerecord/CHANGELOG.md
482
+ documentation_uri: https://api.rubyonrails.org/v8.1.2/
481
483
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
482
- source_code_uri: https://github.com/rails/rails/tree/v7.2.2.1/activerecord
484
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.2/activerecord
483
485
  rubygems_mfa_required: 'true'
484
- post_install_message:
485
486
  rdoc_options:
486
487
  - "--main"
487
488
  - README.rdoc
@@ -491,15 +492,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
491
492
  requirements:
492
493
  - - ">="
493
494
  - !ruby/object:Gem::Version
494
- version: 3.1.0
495
+ version: 3.2.0
495
496
  required_rubygems_version: !ruby/object:Gem::Requirement
496
497
  requirements:
497
498
  - - ">="
498
499
  - !ruby/object:Gem::Version
499
500
  version: '0'
500
501
  requirements: []
501
- rubygems_version: 3.5.22
502
- signing_key:
502
+ rubygems_version: 4.0.3
503
503
  specification_version: 4
504
504
  summary: Object-relational mapper framework (part of Rails).
505
505
  test_files: []