activerecord 7.1.5.1 → 8.0.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 +369 -2484
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +2 -1
  6. data/lib/active_record/associations/alias_tracker.rb +31 -23
  7. data/lib/active_record/associations/association.rb +43 -12
  8. data/lib/active_record/associations/belongs_to_association.rb +21 -8
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/association.rb +7 -6
  11. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  13. data/lib/active_record/associations/builder/has_many.rb +3 -4
  14. data/lib/active_record/associations/builder/has_one.rb +3 -4
  15. data/lib/active_record/associations/collection_association.rb +17 -9
  16. data/lib/active_record/associations/collection_proxy.rb +14 -1
  17. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  18. data/lib/active_record/associations/errors.rb +265 -0
  19. data/lib/active_record/associations/has_many_association.rb +1 -1
  20. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  21. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  22. data/lib/active_record/associations/nested_error.rb +47 -0
  23. data/lib/active_record/associations/preloader/association.rb +4 -3
  24. data/lib/active_record/associations/preloader/branch.rb +7 -1
  25. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  26. data/lib/active_record/associations/singular_association.rb +14 -3
  27. data/lib/active_record/associations/through_association.rb +1 -1
  28. data/lib/active_record/associations.rb +92 -295
  29. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  30. data/lib/active_record/attribute_assignment.rb +0 -2
  31. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  32. data/lib/active_record/attribute_methods/primary_key.rb +25 -61
  33. data/lib/active_record/attribute_methods/read.rb +1 -13
  34. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  35. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
  36. data/lib/active_record/attribute_methods.rb +71 -75
  37. data/lib/active_record/attributes.rb +63 -49
  38. data/lib/active_record/autosave_association.rb +92 -57
  39. data/lib/active_record/base.rb +2 -3
  40. data/lib/active_record/callbacks.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
  42. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  43. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
  44. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
  45. data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
  46. data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
  47. data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
  48. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  49. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
  50. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
  51. data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
  52. data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
  53. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
  54. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  55. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
  56. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  57. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
  58. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
  59. data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
  60. data/lib/active_record/connection_adapters/pool_config.rb +14 -13
  61. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
  62. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  63. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  66. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  67. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  68. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
  69. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
  70. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
  72. data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
  73. data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
  74. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  75. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
  76. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
  77. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
  78. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  79. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
  80. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
  81. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
  82. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  83. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
  84. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
  85. data/lib/active_record/connection_adapters.rb +65 -0
  86. data/lib/active_record/connection_handling.rb +74 -37
  87. data/lib/active_record/core.rb +132 -51
  88. data/lib/active_record/counter_cache.rb +19 -10
  89. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
  90. data/lib/active_record/database_configurations/database_config.rb +23 -4
  91. data/lib/active_record/database_configurations/hash_config.rb +46 -34
  92. data/lib/active_record/database_configurations/url_config.rb +20 -1
  93. data/lib/active_record/database_configurations.rb +1 -1
  94. data/lib/active_record/delegated_type.rb +41 -17
  95. data/lib/active_record/dynamic_matchers.rb +2 -2
  96. data/lib/active_record/encryption/config.rb +3 -1
  97. data/lib/active_record/encryption/encryptable_record.rb +7 -7
  98. data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
  99. data/lib/active_record/encryption/encryptor.rb +28 -6
  100. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  101. data/lib/active_record/encryption/key_provider.rb +1 -1
  102. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  103. data/lib/active_record/encryption/message_serializer.rb +4 -0
  104. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  105. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  106. data/lib/active_record/encryption/scheme.rb +8 -1
  107. data/lib/active_record/enum.rb +20 -16
  108. data/lib/active_record/errors.rb +54 -20
  109. data/lib/active_record/explain.rb +13 -24
  110. data/lib/active_record/fixtures.rb +37 -33
  111. data/lib/active_record/future_result.rb +21 -13
  112. data/lib/active_record/gem_version.rb +4 -4
  113. data/lib/active_record/inheritance.rb +4 -2
  114. data/lib/active_record/insert_all.rb +19 -16
  115. data/lib/active_record/integration.rb +4 -1
  116. data/lib/active_record/internal_metadata.rb +48 -34
  117. data/lib/active_record/locking/optimistic.rb +8 -7
  118. data/lib/active_record/log_subscriber.rb +5 -32
  119. data/lib/active_record/message_pack.rb +1 -1
  120. data/lib/active_record/migration/command_recorder.rb +33 -14
  121. data/lib/active_record/migration/compatibility.rb +8 -3
  122. data/lib/active_record/migration/default_strategy.rb +4 -5
  123. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  124. data/lib/active_record/migration.rb +104 -98
  125. data/lib/active_record/model_schema.rb +32 -70
  126. data/lib/active_record/nested_attributes.rb +15 -9
  127. data/lib/active_record/normalization.rb +3 -7
  128. data/lib/active_record/persistence.rb +127 -451
  129. data/lib/active_record/query_cache.rb +19 -8
  130. data/lib/active_record/query_logs.rb +104 -37
  131. data/lib/active_record/query_logs_formatter.rb +17 -28
  132. data/lib/active_record/querying.rb +24 -12
  133. data/lib/active_record/railtie.rb +26 -68
  134. data/lib/active_record/railties/controller_runtime.rb +13 -4
  135. data/lib/active_record/railties/databases.rake +43 -61
  136. data/lib/active_record/reflection.rb +112 -53
  137. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  138. data/lib/active_record/relation/batches.rb +138 -72
  139. data/lib/active_record/relation/calculations.rb +122 -82
  140. data/lib/active_record/relation/delegation.rb +30 -22
  141. data/lib/active_record/relation/finder_methods.rb +32 -18
  142. data/lib/active_record/relation/merger.rb +12 -14
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
  145. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  146. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  147. data/lib/active_record/relation/predicate_builder.rb +16 -3
  148. data/lib/active_record/relation/query_attribute.rb +1 -1
  149. data/lib/active_record/relation/query_methods.rb +317 -101
  150. data/lib/active_record/relation/spawn_methods.rb +3 -19
  151. data/lib/active_record/relation/where_clause.rb +7 -19
  152. data/lib/active_record/relation.rb +561 -119
  153. data/lib/active_record/result.rb +95 -46
  154. data/lib/active_record/runtime_registry.rb +39 -0
  155. data/lib/active_record/sanitization.rb +31 -25
  156. data/lib/active_record/schema.rb +8 -6
  157. data/lib/active_record/schema_dumper.rb +53 -20
  158. data/lib/active_record/schema_migration.rb +31 -14
  159. data/lib/active_record/scoping/named.rb +6 -2
  160. data/lib/active_record/signed_id.rb +24 -4
  161. data/lib/active_record/statement_cache.rb +19 -19
  162. data/lib/active_record/store.rb +7 -3
  163. data/lib/active_record/table_metadata.rb +2 -13
  164. data/lib/active_record/tasks/database_tasks.rb +87 -58
  165. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
  166. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  167. data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
  168. data/lib/active_record/test_fixtures.rb +98 -89
  169. data/lib/active_record/testing/query_assertions.rb +121 -0
  170. data/lib/active_record/timestamp.rb +2 -2
  171. data/lib/active_record/token_for.rb +22 -12
  172. data/lib/active_record/touch_later.rb +1 -1
  173. data/lib/active_record/transaction.rb +132 -0
  174. data/lib/active_record/transactions.rb +72 -17
  175. data/lib/active_record/translation.rb +0 -2
  176. data/lib/active_record/type/serialized.rb +1 -3
  177. data/lib/active_record/type_caster/connection.rb +4 -4
  178. data/lib/active_record/validations/associated.rb +9 -3
  179. data/lib/active_record/validations/uniqueness.rb +23 -18
  180. data/lib/active_record/validations.rb +4 -1
  181. data/lib/active_record.rb +138 -57
  182. data/lib/arel/alias_predication.rb +1 -1
  183. data/lib/arel/collectors/bind.rb +4 -2
  184. data/lib/arel/collectors/composite.rb +7 -0
  185. data/lib/arel/collectors/sql_string.rb +2 -2
  186. data/lib/arel/collectors/substitute_binds.rb +3 -3
  187. data/lib/arel/nodes/binary.rb +1 -7
  188. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  189. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  190. data/lib/arel/nodes/node.rb +5 -4
  191. data/lib/arel/nodes/sql_literal.rb +8 -1
  192. data/lib/arel/nodes.rb +2 -2
  193. data/lib/arel/predications.rb +1 -1
  194. data/lib/arel/select_manager.rb +1 -1
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/tree_manager.rb +3 -2
  197. data/lib/arel/update_manager.rb +2 -1
  198. data/lib/arel/visitors/dot.rb +1 -0
  199. data/lib/arel/visitors/mysql.rb +9 -4
  200. data/lib/arel/visitors/postgresql.rb +1 -12
  201. data/lib/arel/visitors/sqlite.rb +25 -0
  202. data/lib/arel/visitors/to_sql.rb +29 -16
  203. data/lib/arel.rb +7 -3
  204. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  205. metadata +18 -16
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -3,6 +3,54 @@
3
3
  module ActiveRecord
4
4
  # = Active Record \Relation
5
5
  class Relation
6
+ class ExplainProxy # :nodoc:
7
+ def initialize(relation, options)
8
+ @relation = relation
9
+ @options = options
10
+ end
11
+
12
+ def inspect
13
+ exec_explain { @relation.send(:exec_queries) }
14
+ end
15
+
16
+ def average(column_name)
17
+ exec_explain { @relation.average(column_name) }
18
+ end
19
+
20
+ def count(column_name = nil)
21
+ exec_explain { @relation.count(column_name) }
22
+ end
23
+
24
+ def first(limit = nil)
25
+ exec_explain { @relation.first(limit) }
26
+ end
27
+
28
+ def last(limit = nil)
29
+ exec_explain { @relation.last(limit) }
30
+ end
31
+
32
+ def maximum(column_name)
33
+ exec_explain { @relation.maximum(column_name) }
34
+ end
35
+
36
+ def minimum(column_name)
37
+ exec_explain { @relation.minimum(column_name) }
38
+ end
39
+
40
+ def pluck(*column_names)
41
+ exec_explain { @relation.pluck(*column_names) }
42
+ end
43
+
44
+ def sum(identity_or_column = nil)
45
+ exec_explain { @relation.sum(identity_or_column) }
46
+ end
47
+
48
+ private
49
+ def exec_explain(&block)
50
+ @relation.exec_explain(@relation.collecting_queries_for_explain { block.call }, @options)
51
+ end
52
+ end
53
+
6
54
  MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
7
55
  :order, :joins, :left_outer_joins, :references,
8
56
  :extending, :unscope, :optimizer_hints, :annotate,
@@ -12,26 +60,34 @@ module ActiveRecord
12
60
  :reverse_order, :distinct, :create_with, :skip_query_cache]
13
61
 
14
62
  CLAUSE_METHODS = [:where, :having, :from]
15
- INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :with]
63
+ INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :with, :with_recursive]
16
64
 
17
65
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
18
66
 
19
67
  include Enumerable
20
68
  include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
69
+ include SignedId::RelationMethods, TokenFor::RelationMethods
21
70
 
22
- attr_reader :table, :klass, :loaded, :predicate_builder
71
+ attr_reader :table, :model, :loaded, :predicate_builder
23
72
  attr_accessor :skip_preloading_value
24
- alias :model :klass
73
+ alias :klass :model
25
74
  alias :loaded? :loaded
26
75
  alias :locked? :lock_value
27
76
 
28
- def initialize(klass, table: klass.arel_table, predicate_builder: klass.predicate_builder, values: {})
29
- @klass = klass
77
+ def initialize(model, table: nil, predicate_builder: nil, values: {})
78
+ if table
79
+ predicate_builder ||= model.predicate_builder.with(TableMetadata.new(model, table))
80
+ else
81
+ table = model.arel_table
82
+ predicate_builder ||= model.predicate_builder
83
+ end
84
+
85
+ @model = model
30
86
  @table = table
31
87
  @values = values
32
88
  @loaded = false
33
89
  @predicate_builder = predicate_builder
34
- @delegate_to_klass = false
90
+ @delegate_to_model = false
35
91
  @future_result = nil
36
92
  @records = nil
37
93
  @async = false
@@ -44,7 +100,7 @@ module ActiveRecord
44
100
  end
45
101
 
46
102
  def bind_attribute(name, value) # :nodoc:
47
- if reflection = klass._reflect_on_association(name)
103
+ if reflection = model._reflect_on_association(name)
48
104
  name = reflection.foreign_key
49
105
  value = value.read_attribute(reflection.association_primary_key) unless value.nil?
50
106
  end
@@ -207,18 +263,22 @@ module ActiveRecord
207
263
  # the problem of running out of integers, if the underlying table is still stuck on a primary
208
264
  # key of type int (note: All \Rails apps since 5.1+ have defaulted to bigint, which is not liable
209
265
  # to this problem).
266
+ # * Columns with unique database constraints should not have uniqueness validations defined,
267
+ # otherwise #create will fail due to validation errors and #find_by will never be called.
210
268
  #
211
269
  # This method will return a record if all given attributes are covered by unique constraints
212
270
  # (unless the INSERT -> DELETE -> SELECT race condition is triggered), but if creation was attempted
213
271
  # and failed due to validation errors it won't be persisted, you get what #create returns in
214
272
  # such situation.
215
273
  def create_or_find_by(attributes, &block)
216
- transaction(requires_new: true) { create(attributes, &block) }
217
- rescue ActiveRecord::RecordNotUnique
218
- if connection.transaction_open?
219
- where(attributes).lock.find_by!(attributes)
220
- else
221
- find_by!(attributes)
274
+ with_connection do |connection|
275
+ transaction(requires_new: true) { create(attributes, &block) }
276
+ rescue ActiveRecord::RecordNotUnique
277
+ if connection.transaction_open?
278
+ where(attributes).lock.find_by!(attributes)
279
+ else
280
+ find_by!(attributes)
281
+ end
222
282
  end
223
283
  end
224
284
 
@@ -226,12 +286,14 @@ module ActiveRecord
226
286
  # {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
227
287
  # is raised if the created record is invalid.
228
288
  def create_or_find_by!(attributes, &block)
229
- transaction(requires_new: true) { create!(attributes, &block) }
230
- rescue ActiveRecord::RecordNotUnique
231
- if connection.transaction_open?
232
- where(attributes).lock.find_by!(attributes)
233
- else
234
- find_by!(attributes)
289
+ with_connection do |connection|
290
+ transaction(requires_new: true) { create!(attributes, &block) }
291
+ rescue ActiveRecord::RecordNotUnique
292
+ if connection.transaction_open?
293
+ where(attributes).lock.find_by!(attributes)
294
+ else
295
+ find_by!(attributes)
296
+ end
235
297
  end
236
298
  end
237
299
 
@@ -245,13 +307,30 @@ module ActiveRecord
245
307
  # returns the result as a string. The string is formatted imitating the
246
308
  # ones printed by the database shell.
247
309
  #
310
+ # User.all.explain
311
+ # # EXPLAIN SELECT `users`.* FROM `users`
312
+ # # ...
313
+ #
248
314
  # Note that this method actually runs the queries, since the results of some
249
315
  # are needed by the next ones when eager loading is going on.
250
316
  #
317
+ # To run EXPLAIN on queries created by +first+, +pluck+ and +count+, call
318
+ # these methods on +explain+:
319
+ #
320
+ # User.all.explain.count
321
+ # # EXPLAIN SELECT COUNT(*) FROM `users`
322
+ # # ...
323
+ #
324
+ # The column name can be passed if required:
325
+ #
326
+ # User.all.explain.maximum(:id)
327
+ # # EXPLAIN SELECT MAX(`users`.`id`) FROM `users`
328
+ # # ...
329
+ #
251
330
  # Please see further details in the
252
331
  # {Active Record Query Interface guide}[https://guides.rubyonrails.org/active_record_querying.html#running-explain].
253
332
  def explain(*options)
254
- exec_explain(collecting_queries_for_explain { exec_queries }, options)
333
+ ExplainProxy.new(self, options)
255
334
  end
256
335
 
257
336
  # Converts relation objects to Array.
@@ -358,14 +437,14 @@ module ActiveRecord
358
437
  # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
359
438
  def cache_key(timestamp_column = "updated_at")
360
439
  @cache_keys ||= {}
361
- @cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
440
+ @cache_keys[timestamp_column] ||= model.collection_cache_key(self, timestamp_column)
362
441
  end
363
442
 
364
443
  def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
365
444
  query_signature = ActiveSupport::Digest.hexdigest(to_sql)
366
- key = "#{klass.model_name.cache_key}/query-#{query_signature}"
445
+ key = "#{model.model_name.cache_key}/query-#{query_signature}"
367
446
 
368
- if collection_cache_versioning
447
+ if model.collection_cache_versioning
369
448
  key
370
449
  else
371
450
  "#{key}-#{compute_cache_version(timestamp_column)}"
@@ -384,7 +463,7 @@ module ActiveRecord
384
463
  #
385
464
  # SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
386
465
  def cache_version(timestamp_column = :updated_at)
387
- if collection_cache_versioning
466
+ if model.collection_cache_versioning
388
467
  @cache_versions ||= {}
389
468
  @cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
390
469
  end
@@ -401,33 +480,35 @@ module ActiveRecord
401
480
  else
402
481
  collection = eager_loading? ? apply_join_dependency : self
403
482
 
404
- column = connection.visitor.compile(table[timestamp_column])
405
- select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
483
+ with_connection do |c|
484
+ column = c.visitor.compile(table[timestamp_column])
485
+ select_values = "COUNT(*) AS #{model.adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
406
486
 
407
- if collection.has_limit_or_offset?
408
- query = collection.select("#{column} AS collection_cache_key_timestamp")
409
- query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
410
- subquery_alias = "subquery_for_cache_key"
411
- subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
412
- arel = query.build_subquery(subquery_alias, select_values % subquery_column)
413
- else
414
- query = collection.unscope(:order)
415
- query.select_values = [select_values % column]
416
- arel = query.arel
417
- end
487
+ if collection.has_limit_or_offset?
488
+ query = collection.select("#{column} AS collection_cache_key_timestamp")
489
+ query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
490
+ subquery_alias = "subquery_for_cache_key"
491
+ subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
492
+ arel = query.build_subquery(subquery_alias, select_values % subquery_column)
493
+ else
494
+ query = collection.unscope(:order)
495
+ query.select_values = [select_values % column]
496
+ arel = query.arel
497
+ end
418
498
 
419
- size, timestamp = connection.select_rows(arel, nil).first
499
+ size, timestamp = c.select_rows(arel, nil).first
420
500
 
421
- if size
422
- column_type = klass.type_for_attribute(timestamp_column)
423
- timestamp = column_type.deserialize(timestamp)
424
- else
425
- size = 0
501
+ if size
502
+ column_type = model.type_for_attribute(timestamp_column)
503
+ timestamp = column_type.deserialize(timestamp)
504
+ else
505
+ size = 0
506
+ end
426
507
  end
427
508
  end
428
509
 
429
510
  if timestamp
430
- "#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
511
+ "#{size}-#{timestamp.utc.to_fs(model.cache_timestamp_format)}"
431
512
  else
432
513
  "#{size}"
433
514
  end
@@ -458,7 +539,7 @@ module ActiveRecord
458
539
  # Please check unscoped if you want to remove all previous scopes (including
459
540
  # the default_scope) during the execution of a block.
460
541
  def scoping(all_queries: nil, &block)
461
- registry = klass.scope_registry
542
+ registry = model.scope_registry
462
543
  if global_scope?(registry) && all_queries == false
463
544
  raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
464
545
  elsif already_in_scope?(registry)
@@ -469,11 +550,11 @@ module ActiveRecord
469
550
  end
470
551
 
471
552
  def _exec_scope(...) # :nodoc:
472
- @delegate_to_klass = true
473
- registry = klass.scope_registry
553
+ @delegate_to_model = true
554
+ registry = model.scope_registry
474
555
  _scoping(nil, registry) { instance_exec(...) || self }
475
556
  ensure
476
- @delegate_to_klass = false
557
+ @delegate_to_model = false
477
558
  end
478
559
 
479
560
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
@@ -510,36 +591,38 @@ module ActiveRecord
510
591
  return 0 if @none
511
592
 
512
593
  if updates.is_a?(Hash)
513
- if klass.locking_enabled? &&
514
- !updates.key?(klass.locking_column) &&
515
- !updates.key?(klass.locking_column.to_sym)
516
- attr = table[klass.locking_column]
594
+ if model.locking_enabled? &&
595
+ !updates.key?(model.locking_column) &&
596
+ !updates.key?(model.locking_column.to_sym)
597
+ attr = table[model.locking_column]
517
598
  updates[attr.name] = _increment_attribute(attr)
518
599
  end
519
600
  values = _substitute_values(updates)
520
601
  else
521
- values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
602
+ values = Arel.sql(model.sanitize_sql_for_assignment(updates, table.name))
522
603
  end
523
604
 
524
- arel = eager_loading? ? apply_join_dependency.arel : build_arel
525
- arel.source.left = table
605
+ model.with_connection do |c|
606
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
607
+ arel.source.left = table
526
608
 
527
- group_values_arel_columns = arel_columns(group_values.uniq)
528
- having_clause_ast = having_clause.ast unless having_clause.empty?
529
- key = if klass.composite_primary_key?
530
- primary_key.map { |pk| table[pk] }
531
- else
532
- table[primary_key]
609
+ group_values_arel_columns = arel_columns(group_values.uniq)
610
+ having_clause_ast = having_clause.ast unless having_clause.empty?
611
+ key = if model.composite_primary_key?
612
+ primary_key.map { |pk| table[pk] }
613
+ else
614
+ table[primary_key]
615
+ end
616
+ stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
617
+ c.update(stmt, "#{model} Update All").tap { reset }
533
618
  end
534
- stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
535
- klass.connection.update(stmt, "#{klass} Update All").tap { reset }
536
619
  end
537
620
 
538
621
  def update(id = :all, attributes) # :nodoc:
539
622
  if id == :all
540
623
  each { |record| record.update(attributes) }
541
624
  else
542
- klass.update(id, attributes)
625
+ model.update(id, attributes)
543
626
  end
544
627
  end
545
628
 
@@ -547,10 +630,287 @@ module ActiveRecord
547
630
  if id == :all
548
631
  each { |record| record.update!(attributes) }
549
632
  else
550
- klass.update!(id, attributes)
633
+ model.update!(id, attributes)
551
634
  end
552
635
  end
553
636
 
637
+
638
+ # Inserts a single record into the database in a single SQL INSERT
639
+ # statement. It does not instantiate any models nor does it trigger
640
+ # Active Record callbacks or validations. Though passed values
641
+ # go through Active Record's type casting and serialization.
642
+ #
643
+ # See #insert_all for documentation.
644
+ def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
645
+ insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
646
+ end
647
+
648
+ # Inserts multiple records into the database in a single SQL INSERT
649
+ # statement. It does not instantiate any models nor does it trigger
650
+ # Active Record callbacks or validations. Though passed values
651
+ # go through Active Record's type casting and serialization.
652
+ #
653
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
654
+ # the attributes for a single row and must have the same keys.
655
+ #
656
+ # Rows are considered to be unique by every unique index on the table. Any
657
+ # duplicate rows are skipped.
658
+ # Override with <tt>:unique_by</tt> (see below).
659
+ #
660
+ # Returns an ActiveRecord::Result with its contents based on
661
+ # <tt>:returning</tt> (see below).
662
+ #
663
+ # ==== Options
664
+ #
665
+ # [:returning]
666
+ # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
667
+ # inserted records, which by default is the primary key.
668
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
669
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
670
+ # clause entirely.
671
+ #
672
+ # You can also pass an SQL string if you need more control on the return values
673
+ # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
674
+ #
675
+ # [:unique_by]
676
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
677
+ # by every unique index on the table. Any duplicate rows are skipped.
678
+ #
679
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
680
+ #
681
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
682
+ # row has an existing id, or is not unique by another unique index,
683
+ # ActiveRecord::RecordNotUnique is raised.
684
+ #
685
+ # Unique indexes can be identified by columns or name:
686
+ #
687
+ # unique_by: :isbn
688
+ # unique_by: %i[ author_id name ]
689
+ # unique_by: :index_books_on_isbn
690
+ #
691
+ # [:record_timestamps]
692
+ # By default, automatic setting of timestamp columns is controlled by
693
+ # the model's <tt>record_timestamps</tt> config, matching typical
694
+ # behavior.
695
+ #
696
+ # To override this and force automatic setting of timestamp columns one
697
+ # way or the other, pass <tt>:record_timestamps</tt>:
698
+ #
699
+ # record_timestamps: true # Always set timestamps automatically
700
+ # record_timestamps: false # Never set timestamps automatically
701
+ #
702
+ # Because it relies on the index information from the database
703
+ # <tt>:unique_by</tt> is recommended to be paired with
704
+ # Active Record's schema_cache.
705
+ #
706
+ # ==== Example
707
+ #
708
+ # # Insert records and skip inserting any duplicates.
709
+ # # Here "Eloquent Ruby" is skipped because its id is not unique.
710
+ #
711
+ # Book.insert_all([
712
+ # { id: 1, title: "Rework", author: "David" },
713
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
714
+ # ])
715
+ #
716
+ # # insert_all works on chained scopes, and you can use create_with
717
+ # # to set default attributes for all inserted records.
718
+ #
719
+ # author.books.create_with(created_at: Time.now).insert_all([
720
+ # { id: 1, title: "Rework" },
721
+ # { id: 2, title: "Eloquent Ruby" }
722
+ # ])
723
+ def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
724
+ InsertAll.execute(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
725
+ end
726
+
727
+ # Inserts a single record into the database in a single SQL INSERT
728
+ # statement. It does not instantiate any models nor does it trigger
729
+ # Active Record callbacks or validations. Though passed values
730
+ # go through Active Record's type casting and serialization.
731
+ #
732
+ # See #insert_all! for more.
733
+ def insert!(attributes, returning: nil, record_timestamps: nil)
734
+ insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
735
+ end
736
+
737
+ # Inserts multiple records into the database in a single SQL INSERT
738
+ # statement. It does not instantiate any models nor does it trigger
739
+ # Active Record callbacks or validations. Though passed values
740
+ # go through Active Record's type casting and serialization.
741
+ #
742
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
743
+ # the attributes for a single row and must have the same keys.
744
+ #
745
+ # Raises ActiveRecord::RecordNotUnique if any rows violate a
746
+ # unique index on the table. In that case, no rows are inserted.
747
+ #
748
+ # To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
749
+ #
750
+ # Returns an ActiveRecord::Result with its contents based on
751
+ # <tt>:returning</tt> (see below).
752
+ #
753
+ # ==== Options
754
+ #
755
+ # [:returning]
756
+ # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
757
+ # inserted records, which by default is the primary key.
758
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
759
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
760
+ # clause entirely.
761
+ #
762
+ # You can also pass an SQL string if you need more control on the return values
763
+ # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
764
+ #
765
+ # [:record_timestamps]
766
+ # By default, automatic setting of timestamp columns is controlled by
767
+ # the model's <tt>record_timestamps</tt> config, matching typical
768
+ # behavior.
769
+ #
770
+ # To override this and force automatic setting of timestamp columns one
771
+ # way or the other, pass <tt>:record_timestamps</tt>:
772
+ #
773
+ # record_timestamps: true # Always set timestamps automatically
774
+ # record_timestamps: false # Never set timestamps automatically
775
+ #
776
+ # ==== Examples
777
+ #
778
+ # # Insert multiple records
779
+ # Book.insert_all!([
780
+ # { title: "Rework", author: "David" },
781
+ # { title: "Eloquent Ruby", author: "Russ" }
782
+ # ])
783
+ #
784
+ # # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
785
+ # # does not have a unique id.
786
+ # Book.insert_all!([
787
+ # { id: 1, title: "Rework", author: "David" },
788
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
789
+ # ])
790
+ def insert_all!(attributes, returning: nil, record_timestamps: nil)
791
+ InsertAll.execute(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps)
792
+ end
793
+
794
+ # Updates or inserts (upserts) a single record into the database in a
795
+ # single SQL INSERT statement. It does not instantiate any models nor does
796
+ # it trigger Active Record callbacks or validations. Though passed values
797
+ # go through Active Record's type casting and serialization.
798
+ #
799
+ # See #upsert_all for documentation.
800
+ def upsert(attributes, **kwargs)
801
+ upsert_all([ attributes ], **kwargs)
802
+ end
803
+
804
+ # Updates or inserts (upserts) multiple records into the database in a
805
+ # single SQL INSERT statement. It does not instantiate any models nor does
806
+ # it trigger Active Record callbacks or validations. Though passed values
807
+ # go through Active Record's type casting and serialization.
808
+ #
809
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
810
+ # the attributes for a single row and must have the same keys.
811
+ #
812
+ # Returns an ActiveRecord::Result with its contents based on
813
+ # <tt>:returning</tt> (see below).
814
+ #
815
+ # By default, +upsert_all+ will update all the columns that can be updated when
816
+ # there is a conflict. These are all the columns except primary keys, read-only
817
+ # columns, and columns covered by the optional +unique_by+.
818
+ #
819
+ # ==== Options
820
+ #
821
+ # [:returning]
822
+ # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
823
+ # upserted records, which by default is the primary key.
824
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
825
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
826
+ # clause entirely.
827
+ #
828
+ # You can also pass an SQL string if you need more control on the return values
829
+ # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
830
+ #
831
+ # [:unique_by]
832
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
833
+ # by every unique index on the table. Any duplicate rows are skipped.
834
+ #
835
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
836
+ #
837
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
838
+ # row has an existing id, or is not unique by another unique index,
839
+ # ActiveRecord::RecordNotUnique is raised.
840
+ #
841
+ # Unique indexes can be identified by columns or name:
842
+ #
843
+ # unique_by: :isbn
844
+ # unique_by: %i[ author_id name ]
845
+ # unique_by: :index_books_on_isbn
846
+ #
847
+ # Because it relies on the index information from the database
848
+ # <tt>:unique_by</tt> is recommended to be paired with
849
+ # Active Record's schema_cache.
850
+ #
851
+ # [:on_duplicate]
852
+ # Configure the SQL update sentence that will be used in case of conflict.
853
+ #
854
+ # NOTE: If you use this option you must provide all the columns you want to update
855
+ # by yourself.
856
+ #
857
+ # Example:
858
+ #
859
+ # Commodity.upsert_all(
860
+ # [
861
+ # { id: 2, name: "Copper", price: 4.84 },
862
+ # { id: 4, name: "Gold", price: 1380.87 },
863
+ # { id: 6, name: "Aluminium", price: 0.35 }
864
+ # ],
865
+ # on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
866
+ # )
867
+ #
868
+ # See the related +:update_only+ option. Both options can't be used at the same time.
869
+ #
870
+ # [:update_only]
871
+ # Provide a list of column names that will be updated in case of conflict. If not provided,
872
+ # +upsert_all+ will update all the columns that can be updated. These are all the columns
873
+ # except primary keys, read-only columns, and columns covered by the optional +unique_by+
874
+ #
875
+ # Example:
876
+ #
877
+ # Commodity.upsert_all(
878
+ # [
879
+ # { id: 2, name: "Copper", price: 4.84 },
880
+ # { id: 4, name: "Gold", price: 1380.87 },
881
+ # { id: 6, name: "Aluminium", price: 0.35 }
882
+ # ],
883
+ # update_only: [:price] # Only prices will be updated
884
+ # )
885
+ #
886
+ # See the related +:on_duplicate+ option. Both options can't be used at the same time.
887
+ #
888
+ # [:record_timestamps]
889
+ # By default, automatic setting of timestamp columns is controlled by
890
+ # the model's <tt>record_timestamps</tt> config, matching typical
891
+ # behavior.
892
+ #
893
+ # To override this and force automatic setting of timestamp columns one
894
+ # way or the other, pass <tt>:record_timestamps</tt>:
895
+ #
896
+ # record_timestamps: true # Always set timestamps automatically
897
+ # record_timestamps: false # Never set timestamps automatically
898
+ #
899
+ # ==== Examples
900
+ #
901
+ # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
902
+ # # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
903
+ #
904
+ # Book.upsert_all([
905
+ # { title: "Rework", author: "David", isbn: "1" },
906
+ # { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
907
+ # ], unique_by: :isbn)
908
+ #
909
+ # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
910
+ def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
911
+ InsertAll.execute(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
912
+ end
913
+
554
914
  # Updates the counters of the records in the current relation.
555
915
  #
556
916
  # ==== Parameters
@@ -576,7 +936,7 @@ module ActiveRecord
576
936
  names = touch if touch != true
577
937
  names = Array.wrap(names)
578
938
  options = names.extract_options!
579
- touch_updates = klass.touch_attributes_with_time(*names, **options)
939
+ touch_updates = model.touch_attributes_with_time(*names, **options)
580
940
  updates.merge!(touch_updates) unless touch_updates.empty?
581
941
  end
582
942
 
@@ -607,7 +967,7 @@ module ActiveRecord
607
967
  # Person.where(name: 'David').touch_all
608
968
  # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
609
969
  def touch_all(*names, time: nil)
610
- update_all klass.touch_attributes_with_time(*names, time: time)
970
+ update_all model.touch_attributes_with_time(*names, time: time)
611
971
  end
612
972
 
613
973
  # Destroys the records by instantiating each
@@ -659,19 +1019,79 @@ module ActiveRecord
659
1019
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
660
1020
  end
661
1021
 
662
- arel = eager_loading? ? apply_join_dependency.arel : build_arel
663
- arel.source.left = table
1022
+ model.with_connection do |c|
1023
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
1024
+ arel.source.left = table
664
1025
 
665
- group_values_arel_columns = arel_columns(group_values.uniq)
666
- having_clause_ast = having_clause.ast unless having_clause.empty?
667
- key = if klass.composite_primary_key?
668
- primary_key.map { |pk| table[pk] }
1026
+ group_values_arel_columns = arel_columns(group_values.uniq)
1027
+ having_clause_ast = having_clause.ast unless having_clause.empty?
1028
+ key = if model.composite_primary_key?
1029
+ primary_key.map { |pk| table[pk] }
1030
+ else
1031
+ table[primary_key]
1032
+ end
1033
+ stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
1034
+
1035
+ c.delete(stmt, "#{model} Delete All").tap { reset }
1036
+ end
1037
+ end
1038
+
1039
+ # Deletes the row with a primary key matching the +id+ argument, using an
1040
+ # SQL +DELETE+ statement, and returns the number of rows deleted. Active
1041
+ # Record objects are not instantiated, so the object's callbacks are not
1042
+ # executed, including any <tt>:dependent</tt> association options.
1043
+ #
1044
+ # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
1045
+ #
1046
+ # Note: Although it is often much faster than the alternative, #destroy,
1047
+ # skipping callbacks might bypass business logic in your application
1048
+ # that ensures referential integrity or performs other essential jobs.
1049
+ #
1050
+ # ==== Examples
1051
+ #
1052
+ # # Delete a single row
1053
+ # Todo.delete(1)
1054
+ #
1055
+ # # Delete multiple rows
1056
+ # Todo.delete([2,3,4])
1057
+ def delete(id_or_array)
1058
+ return 0 if id_or_array.nil? || (id_or_array.is_a?(Array) && id_or_array.empty?)
1059
+
1060
+ where(model.primary_key => id_or_array).delete_all
1061
+ end
1062
+
1063
+
1064
+ # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
1065
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
1066
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
1067
+ #
1068
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
1069
+ # from the attributes, and then calls destroy on it.
1070
+ #
1071
+ # ==== Parameters
1072
+ #
1073
+ # * +id+ - This should be the id or an array of ids to be destroyed.
1074
+ #
1075
+ # ==== Examples
1076
+ #
1077
+ # # Destroy a single object
1078
+ # Todo.destroy(1)
1079
+ #
1080
+ # # Destroy multiple objects
1081
+ # todos = [1,2,3]
1082
+ # Todo.destroy(todos)
1083
+ def destroy(id)
1084
+ multiple_ids = if model.composite_primary_key?
1085
+ id.first.is_a?(Array)
669
1086
  else
670
- table[primary_key]
1087
+ id.is_a?(Array)
671
1088
  end
672
- stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
673
1089
 
674
- klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
1090
+ if multiple_ids
1091
+ find(id).each(&:destroy)
1092
+ else
1093
+ find(id).destroy
1094
+ end
675
1095
  end
676
1096
 
677
1097
  # Finds and destroys all records matching the specified conditions.
@@ -711,30 +1131,39 @@ module ActiveRecord
711
1131
  # for queries to actually be executed concurrently. Otherwise it defaults to
712
1132
  # executing them in the foreground.
713
1133
  #
714
- # +load_async+ will also fall back to executing in the foreground in the test environment when transactional
715
- # fixtures are enabled.
716
- #
717
1134
  # If the query was actually executed in the background, the Active Record logs will show
718
1135
  # it by prefixing the log line with <tt>ASYNC</tt>:
719
1136
  #
720
1137
  # ASYNC Post Load (0.0ms) (db time 2ms) SELECT "posts".* FROM "posts" LIMIT 100
721
1138
  def load_async
722
- return load if !connection.async_enabled?
1139
+ with_connection do |c|
1140
+ return load if !c.async_enabled?
723
1141
 
724
- unless loaded?
725
- result = exec_main_query(async: connection.current_transaction.closed?)
1142
+ unless loaded?
1143
+ result = exec_main_query(async: !c.current_transaction.joinable?)
726
1144
 
727
- if result.is_a?(Array)
728
- @records = result
729
- else
730
- @future_result = result
1145
+ if result.is_a?(Array)
1146
+ @records = result
1147
+ else
1148
+ @future_result = result
1149
+ end
1150
+ @loaded = true
731
1151
  end
732
- @loaded = true
733
1152
  end
734
1153
 
735
1154
  self
736
1155
  end
737
1156
 
1157
+ def then(&block) # :nodoc:
1158
+ if @future_result
1159
+ @future_result.then do
1160
+ yield self
1161
+ end
1162
+ else
1163
+ super
1164
+ end
1165
+ end
1166
+
738
1167
  # Returns <tt>true</tt> if the relation was scheduled on the background
739
1168
  # thread pool.
740
1169
  def scheduled?
@@ -765,7 +1194,7 @@ module ActiveRecord
765
1194
  def reset
766
1195
  @future_result&.cancel
767
1196
  @future_result = nil
768
- @delegate_to_klass = false
1197
+ @delegate_to_model = false
769
1198
  @to_sql = @arel = @loaded = @should_eager_load = nil
770
1199
  @offsets = @take = nil
771
1200
  @cache_keys = nil
@@ -785,8 +1214,9 @@ module ActiveRecord
785
1214
  relation.to_sql
786
1215
  end
787
1216
  else
788
- conn = klass.connection
789
- conn.unprepared_statement { conn.to_sql(arel) }
1217
+ model.with_connection do |conn|
1218
+ conn.unprepared_statement { conn.to_sql(arel) }
1219
+ end
790
1220
  end
791
1221
  end
792
1222
 
@@ -794,12 +1224,12 @@ module ActiveRecord
794
1224
  #
795
1225
  # User.where(name: 'Oscar').where_values_hash
796
1226
  # # => {name: "Oscar"}
797
- def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
1227
+ def where_values_hash(relation_table_name = model.table_name) # :nodoc:
798
1228
  where_clause.to_h(relation_table_name)
799
1229
  end
800
1230
 
801
1231
  def scope_for_create
802
- hash = where_clause.to_h(klass.table_name, equality_only: true)
1232
+ hash = where_clause.to_h(model.table_name, equality_only: true)
803
1233
  create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
804
1234
  hash
805
1235
  end
@@ -845,6 +1275,10 @@ module ActiveRecord
845
1275
  records.blank?
846
1276
  end
847
1277
 
1278
+ def readonly?
1279
+ readonly_value
1280
+ end
1281
+
848
1282
  def values
849
1283
  @values.dup
850
1284
  end
@@ -863,7 +1297,7 @@ module ActiveRecord
863
1297
  end
864
1298
 
865
1299
  def empty_scope? # :nodoc:
866
- @values == klass.unscoped.values
1300
+ @values == model.unscoped.values
867
1301
  end
868
1302
 
869
1303
  def has_limit_or_offset? # :nodoc:
@@ -871,7 +1305,7 @@ module ActiveRecord
871
1305
  end
872
1306
 
873
1307
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
874
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
1308
+ ActiveRecord::Associations::AliasTracker.create(model.connection_pool, table.name, joins, aliases)
875
1309
  end
876
1310
 
877
1311
  class StrictLoadingScope # :nodoc:
@@ -901,54 +1335,58 @@ module ActiveRecord
901
1335
 
902
1336
  private
903
1337
  def already_in_scope?(registry)
904
- @delegate_to_klass && registry.current_scope(klass, true)
1338
+ @delegate_to_model && registry.current_scope(model, true)
905
1339
  end
906
1340
 
907
1341
  def global_scope?(registry)
908
- registry.global_current_scope(klass, true)
1342
+ registry.global_current_scope(model, true)
909
1343
  end
910
1344
 
911
1345
  def current_scope_restoring_block(&block)
912
- current_scope = klass.current_scope(true)
1346
+ current_scope = model.current_scope(true)
913
1347
  -> record do
914
- klass.current_scope = current_scope
1348
+ model.current_scope = current_scope
915
1349
  yield record if block_given?
916
1350
  end
917
1351
  end
918
1352
 
919
1353
  def _new(attributes, &block)
920
- klass.new(attributes, &block)
1354
+ model.new(attributes, &block)
921
1355
  end
922
1356
 
923
1357
  def _create(attributes, &block)
924
- klass.create(attributes, &block)
1358
+ model.create(attributes, &block)
925
1359
  end
926
1360
 
927
1361
  def _create!(attributes, &block)
928
- klass.create!(attributes, &block)
1362
+ model.create!(attributes, &block)
929
1363
  end
930
1364
 
931
1365
  def _scoping(scope, registry, all_queries = false)
932
- previous = registry.current_scope(klass, true)
933
- registry.set_current_scope(klass, scope)
1366
+ previous = registry.current_scope(model, true)
1367
+ registry.set_current_scope(model, scope)
934
1368
 
935
1369
  if all_queries
936
- previous_global = registry.global_current_scope(klass, true)
937
- registry.set_global_current_scope(klass, scope)
1370
+ previous_global = registry.global_current_scope(model, true)
1371
+ registry.set_global_current_scope(model, scope)
938
1372
  end
939
1373
  yield
940
1374
  ensure
941
- registry.set_current_scope(klass, previous)
1375
+ registry.set_current_scope(model, previous)
942
1376
  if all_queries
943
- registry.set_global_current_scope(klass, previous_global)
1377
+ registry.set_global_current_scope(model, previous_global)
944
1378
  end
945
1379
  end
946
1380
 
947
1381
  def _substitute_values(values)
948
1382
  values.map do |name, value|
949
1383
  attr = table[name]
950
- unless Arel.arel_node?(value)
951
- type = klass.type_for_attribute(attr.name)
1384
+ if Arel.arel_node?(value)
1385
+ if value.is_a?(Arel::Nodes::SqlLiteral)
1386
+ value = Arel::Nodes::Grouping.new(value)
1387
+ end
1388
+ else
1389
+ type = model.type_for_attribute(attr.name)
952
1390
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
953
1391
  end
954
1392
  [attr, value]
@@ -995,17 +1433,21 @@ module ActiveRecord
995
1433
  if where_clause.contradiction?
996
1434
  [].freeze
997
1435
  elsif eager_loading?
998
- apply_join_dependency do |relation, join_dependency|
999
- if relation.null_relation?
1000
- [].freeze
1001
- else
1002
- relation = join_dependency.apply_column_aliases(relation)
1003
- @_join_dependency = join_dependency
1004
- connection.select_all(relation.arel, "SQL", async: async)
1436
+ model.with_connection do |c|
1437
+ apply_join_dependency do |relation, join_dependency|
1438
+ if relation.null_relation?
1439
+ [].freeze
1440
+ else
1441
+ relation = join_dependency.apply_column_aliases(relation)
1442
+ @_join_dependency = join_dependency
1443
+ c.select_all(relation.arel, "SQL", async: async)
1444
+ end
1005
1445
  end
1006
1446
  end
1007
1447
  else
1008
- klass._query_by_sql(arel, async: async)
1448
+ model.with_connection do |c|
1449
+ model._query_by_sql(c, arel, async: async)
1450
+ end
1009
1451
  end
1010
1452
  end
1011
1453
  end
@@ -1017,13 +1459,13 @@ module ActiveRecord
1017
1459
  @_join_dependency = nil
1018
1460
  records
1019
1461
  else
1020
- klass._load_from_sql(rows, &block).freeze
1462
+ model._load_from_sql(rows, &block).freeze
1021
1463
  end
1022
1464
  end
1023
1465
 
1024
1466
  def skip_query_cache_if_necessary(&block)
1025
1467
  if skip_query_cache_value
1026
- uncached(&block)
1468
+ model.uncached(&block)
1027
1469
  else
1028
1470
  yield
1029
1471
  end