activerecord 6.1.7 → 7.2.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 (333) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +616 -1290
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +31 -31
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +17 -14
  7. data/lib/active_record/association_relation.rb +2 -12
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +60 -21
  10. data/lib/active_record/associations/association_scope.rb +17 -12
  11. data/lib/active_record/associations/belongs_to_association.rb +37 -11
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
  13. data/lib/active_record/associations/builder/association.rb +11 -5
  14. data/lib/active_record/associations/builder/belongs_to.rb +41 -14
  15. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +4 -4
  19. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  20. data/lib/active_record/associations/collection_association.rb +46 -36
  21. data/lib/active_record/associations/collection_proxy.rb +44 -16
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +10 -3
  25. data/lib/active_record/associations/has_many_association.rb +29 -19
  26. data/lib/active_record/associations/has_many_through_association.rb +19 -8
  27. data/lib/active_record/associations/has_one_association.rb +20 -10
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
  30. data/lib/active_record/associations/join_dependency.rb +28 -20
  31. data/lib/active_record/associations/nested_error.rb +47 -0
  32. data/lib/active_record/associations/preloader/association.rb +212 -53
  33. data/lib/active_record/associations/preloader/batch.rb +48 -0
  34. data/lib/active_record/associations/preloader/branch.rb +153 -0
  35. data/lib/active_record/associations/preloader/through_association.rb +50 -16
  36. data/lib/active_record/associations/preloader.rb +50 -121
  37. data/lib/active_record/associations/singular_association.rb +15 -3
  38. data/lib/active_record/associations/through_association.rb +25 -14
  39. data/lib/active_record/associations.rb +429 -522
  40. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  41. data/lib/active_record/attribute_assignment.rb +1 -5
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  43. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  44. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  45. data/lib/active_record/attribute_methods/primary_key.rb +47 -27
  46. data/lib/active_record/attribute_methods/query.rb +31 -19
  47. data/lib/active_record/attribute_methods/read.rb +14 -11
  48. data/lib/active_record/attribute_methods/serialization.rb +174 -37
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +15 -9
  50. data/lib/active_record/attribute_methods/write.rb +12 -15
  51. data/lib/active_record/attribute_methods.rb +164 -52
  52. data/lib/active_record/attributes.rb +57 -54
  53. data/lib/active_record/autosave_association.rb +74 -57
  54. data/lib/active_record/base.rb +27 -5
  55. data/lib/active_record/callbacks.rb +19 -35
  56. data/lib/active_record/coders/column_serializer.rb +61 -0
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +70 -46
  59. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +325 -604
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +230 -64
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +378 -143
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +348 -165
  75. data/lib/active_record/connection_adapters/column.rb +13 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
  78. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
  79. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  81. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  82. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
  83. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
  85. data/lib/active_record/connection_adapters/pool_config.rb +26 -16
  86. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  87. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  88. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
  89. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  94. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  100. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
  103. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  104. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  105. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
  106. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  107. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +403 -77
  108. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  109. data/lib/active_record/connection_adapters/postgresql_adapter.rb +520 -253
  110. data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
  111. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  112. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
  113. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
  114. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
  119. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  120. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  121. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  122. data/lib/active_record/connection_adapters.rb +130 -6
  123. data/lib/active_record/connection_handling.rb +132 -146
  124. data/lib/active_record/core.rb +310 -253
  125. data/lib/active_record/counter_cache.rb +68 -34
  126. data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -4
  127. data/lib/active_record/database_configurations/database_config.rb +34 -10
  128. data/lib/active_record/database_configurations/hash_config.rb +107 -31
  129. data/lib/active_record/database_configurations/url_config.rb +38 -13
  130. data/lib/active_record/database_configurations.rb +96 -60
  131. data/lib/active_record/delegated_type.rb +90 -20
  132. data/lib/active_record/deprecator.rb +7 -0
  133. data/lib/active_record/destroy_association_async_job.rb +4 -2
  134. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  135. data/lib/active_record/dynamic_matchers.rb +3 -3
  136. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +68 -0
  140. data/lib/active_record/encryption/configurable.rb +60 -0
  141. data/lib/active_record/encryption/context.rb +42 -0
  142. data/lib/active_record/encryption/contexts.rb +76 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +170 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +53 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  159. data/lib/active_record/encryption/message_serializer.rb +96 -0
  160. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  161. data/lib/active_record/encryption/properties.rb +76 -0
  162. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  163. data/lib/active_record/encryption/scheme.rb +100 -0
  164. data/lib/active_record/encryption.rb +58 -0
  165. data/lib/active_record/enum.rb +170 -62
  166. data/lib/active_record/errors.rb +210 -27
  167. data/lib/active_record/explain.rb +21 -12
  168. data/lib/active_record/explain_registry.rb +11 -6
  169. data/lib/active_record/explain_subscriber.rb +1 -1
  170. data/lib/active_record/fixture_set/file.rb +15 -1
  171. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  172. data/lib/active_record/fixture_set/render_context.rb +2 -0
  173. data/lib/active_record/fixture_set/table_row.rb +70 -14
  174. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  175. data/lib/active_record/fixtures.rb +179 -112
  176. data/lib/active_record/future_result.rb +178 -0
  177. data/lib/active_record/gem_version.rb +4 -4
  178. data/lib/active_record/inheritance.rb +85 -31
  179. data/lib/active_record/insert_all.rb +148 -32
  180. data/lib/active_record/integration.rb +14 -10
  181. data/lib/active_record/internal_metadata.rb +123 -23
  182. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  183. data/lib/active_record/locking/optimistic.rb +43 -27
  184. data/lib/active_record/locking/pessimistic.rb +15 -6
  185. data/lib/active_record/log_subscriber.rb +41 -29
  186. data/lib/active_record/marshalling.rb +59 -0
  187. data/lib/active_record/message_pack.rb +124 -0
  188. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  189. data/lib/active_record/middleware/database_selector.rb +23 -13
  190. data/lib/active_record/middleware/shard_selector.rb +62 -0
  191. data/lib/active_record/migration/command_recorder.rb +113 -16
  192. data/lib/active_record/migration/compatibility.rb +235 -46
  193. data/lib/active_record/migration/default_strategy.rb +22 -0
  194. data/lib/active_record/migration/execution_strategy.rb +19 -0
  195. data/lib/active_record/migration/join_table.rb +1 -1
  196. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  197. data/lib/active_record/migration.rb +374 -177
  198. data/lib/active_record/model_schema.rb +145 -158
  199. data/lib/active_record/nested_attributes.rb +61 -23
  200. data/lib/active_record/no_touching.rb +3 -3
  201. data/lib/active_record/normalization.rb +163 -0
  202. data/lib/active_record/persistence.rb +282 -283
  203. data/lib/active_record/promise.rb +84 -0
  204. data/lib/active_record/query_cache.rb +18 -25
  205. data/lib/active_record/query_logs.rb +189 -0
  206. data/lib/active_record/query_logs_formatter.rb +41 -0
  207. data/lib/active_record/querying.rb +44 -9
  208. data/lib/active_record/railtie.rb +229 -71
  209. data/lib/active_record/railties/controller_runtime.rb +25 -11
  210. data/lib/active_record/railties/databases.rake +189 -256
  211. data/lib/active_record/railties/job_runtime.rb +23 -0
  212. data/lib/active_record/readonly_attributes.rb +41 -3
  213. data/lib/active_record/reflection.rb +332 -103
  214. data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
  215. data/lib/active_record/relation/batches.rb +200 -65
  216. data/lib/active_record/relation/calculations.rb +301 -112
  217. data/lib/active_record/relation/delegation.rb +33 -22
  218. data/lib/active_record/relation/finder_methods.rb +123 -52
  219. data/lib/active_record/relation/merger.rb +26 -19
  220. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  221. data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
  222. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  223. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  224. data/lib/active_record/relation/predicate_builder.rb +29 -22
  225. data/lib/active_record/relation/query_attribute.rb +30 -12
  226. data/lib/active_record/relation/query_methods.rb +870 -163
  227. data/lib/active_record/relation/record_fetch_warning.rb +10 -9
  228. data/lib/active_record/relation/spawn_methods.rb +7 -6
  229. data/lib/active_record/relation/where_clause.rb +15 -36
  230. data/lib/active_record/relation.rb +736 -145
  231. data/lib/active_record/result.rb +67 -54
  232. data/lib/active_record/runtime_registry.rb +71 -13
  233. data/lib/active_record/sanitization.rb +84 -34
  234. data/lib/active_record/schema.rb +39 -23
  235. data/lib/active_record/schema_dumper.rb +90 -31
  236. data/lib/active_record/schema_migration.rb +74 -23
  237. data/lib/active_record/scoping/default.rb +72 -15
  238. data/lib/active_record/scoping/named.rb +6 -13
  239. data/lib/active_record/scoping.rb +65 -34
  240. data/lib/active_record/secure_password.rb +60 -0
  241. data/lib/active_record/secure_token.rb +21 -3
  242. data/lib/active_record/serialization.rb +6 -1
  243. data/lib/active_record/signed_id.rb +30 -9
  244. data/lib/active_record/statement_cache.rb +7 -7
  245. data/lib/active_record/store.rb +10 -10
  246. data/lib/active_record/suppressor.rb +13 -15
  247. data/lib/active_record/table_metadata.rb +7 -3
  248. data/lib/active_record/tasks/database_tasks.rb +288 -149
  249. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  250. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  251. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  252. data/lib/active_record/test_databases.rb +1 -1
  253. data/lib/active_record/test_fixtures.rb +173 -155
  254. data/lib/active_record/testing/query_assertions.rb +121 -0
  255. data/lib/active_record/timestamp.rb +32 -19
  256. data/lib/active_record/token_for.rb +123 -0
  257. data/lib/active_record/touch_later.rb +12 -7
  258. data/lib/active_record/transaction.rb +132 -0
  259. data/lib/active_record/transactions.rb +118 -41
  260. data/lib/active_record/translation.rb +3 -5
  261. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  262. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  263. data/lib/active_record/type/internal/timezone.rb +7 -2
  264. data/lib/active_record/type/serialized.rb +9 -7
  265. data/lib/active_record/type/time.rb +4 -0
  266. data/lib/active_record/type/type_map.rb +17 -20
  267. data/lib/active_record/type.rb +1 -2
  268. data/lib/active_record/type_caster/connection.rb +4 -4
  269. data/lib/active_record/validations/absence.rb +1 -1
  270. data/lib/active_record/validations/associated.rb +13 -7
  271. data/lib/active_record/validations/numericality.rb +5 -4
  272. data/lib/active_record/validations/presence.rb +5 -28
  273. data/lib/active_record/validations/uniqueness.rb +65 -15
  274. data/lib/active_record/validations.rb +12 -5
  275. data/lib/active_record/version.rb +1 -1
  276. data/lib/active_record.rb +444 -32
  277. data/lib/arel/alias_predication.rb +1 -1
  278. data/lib/arel/attributes/attribute.rb +0 -8
  279. data/lib/arel/collectors/bind.rb +2 -0
  280. data/lib/arel/collectors/composite.rb +7 -0
  281. data/lib/arel/collectors/sql_string.rb +1 -1
  282. data/lib/arel/collectors/substitute_binds.rb +1 -1
  283. data/lib/arel/crud.rb +28 -22
  284. data/lib/arel/delete_manager.rb +18 -4
  285. data/lib/arel/errors.rb +10 -0
  286. data/lib/arel/factory_methods.rb +4 -0
  287. data/lib/arel/filter_predications.rb +9 -0
  288. data/lib/arel/insert_manager.rb +2 -3
  289. data/lib/arel/nodes/binary.rb +6 -7
  290. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  291. data/lib/arel/nodes/casted.rb +1 -1
  292. data/lib/arel/nodes/cte.rb +36 -0
  293. data/lib/arel/nodes/delete_statement.rb +12 -13
  294. data/lib/arel/nodes/filter.rb +10 -0
  295. data/lib/arel/nodes/fragments.rb +35 -0
  296. data/lib/arel/nodes/function.rb +1 -0
  297. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  298. data/lib/arel/nodes/insert_statement.rb +2 -2
  299. data/lib/arel/nodes/leading_join.rb +8 -0
  300. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  301. data/lib/arel/nodes/node.rb +115 -5
  302. data/lib/arel/nodes/select_core.rb +2 -2
  303. data/lib/arel/nodes/select_statement.rb +2 -2
  304. data/lib/arel/nodes/sql_literal.rb +13 -0
  305. data/lib/arel/nodes/table_alias.rb +4 -0
  306. data/lib/arel/nodes/update_statement.rb +8 -3
  307. data/lib/arel/nodes.rb +7 -2
  308. data/lib/arel/predications.rb +14 -4
  309. data/lib/arel/select_manager.rb +11 -5
  310. data/lib/arel/table.rb +9 -6
  311. data/lib/arel/tree_manager.rb +8 -15
  312. data/lib/arel/update_manager.rb +20 -5
  313. data/lib/arel/visitors/dot.rb +81 -90
  314. data/lib/arel/visitors/mysql.rb +23 -5
  315. data/lib/arel/visitors/postgresql.rb +1 -22
  316. data/lib/arel/visitors/sqlite.rb +25 -0
  317. data/lib/arel/visitors/to_sql.rb +170 -36
  318. data/lib/arel/visitors/visitor.rb +2 -2
  319. data/lib/arel.rb +23 -4
  320. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  321. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  322. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  323. data/lib/rails/generators/active_record/migration.rb +3 -1
  324. data/lib/rails/generators/active_record/model/USAGE +113 -0
  325. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  326. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  327. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  328. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  329. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  330. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  331. metadata +103 -17
  332. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  333. data/lib/active_record/null_relation.rb +0 -67
@@ -3,20 +3,70 @@
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
- :extending, :unscope, :optimizer_hints, :annotate]
56
+ :extending, :unscope, :optimizer_hints, :annotate,
57
+ :with]
9
58
 
10
59
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
11
60
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
61
 
13
62
  CLAUSE_METHODS = [:where, :having, :from]
14
- INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]
63
+ INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :with, :with_recursive]
15
64
 
16
65
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
17
66
 
18
67
  include Enumerable
19
68
  include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
69
+ include SignedId::RelationMethods, TokenFor::RelationMethods
20
70
 
21
71
  attr_reader :table, :klass, :loaded, :predicate_builder
22
72
  attr_accessor :skip_preloading_value
@@ -31,6 +81,10 @@ module ActiveRecord
31
81
  @loaded = false
32
82
  @predicate_builder = predicate_builder
33
83
  @delegate_to_klass = false
84
+ @future_result = nil
85
+ @records = nil
86
+ @async = false
87
+ @none = false
34
88
  end
35
89
 
36
90
  def initialize_copy(other)
@@ -38,15 +92,10 @@ module ActiveRecord
38
92
  reset
39
93
  end
40
94
 
41
- def arel_attribute(name) # :nodoc:
42
- table[name]
43
- end
44
- deprecate :arel_attribute
45
-
46
95
  def bind_attribute(name, value) # :nodoc:
47
96
  if reflection = klass._reflect_on_association(name)
48
97
  name = reflection.foreign_key
49
- value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
98
+ value = value.read_attribute(reflection.association_primary_key) unless value.nil?
50
99
  end
51
100
 
52
101
  attr = table[name]
@@ -67,8 +116,12 @@ module ActiveRecord
67
116
  # user = users.new { |user| user.name = 'Oscar' }
68
117
  # user.name # => Oscar
69
118
  def new(attributes = nil, &block)
70
- block = current_scope_restoring_block(&block)
71
- scoping { _new(attributes, &block) }
119
+ if attributes.is_a?(Array)
120
+ attributes.collect { |attr| new(attr, &block) }
121
+ else
122
+ block = current_scope_restoring_block(&block)
123
+ scoping { _new(attributes, &block) }
124
+ end
72
125
  end
73
126
  alias build new
74
127
 
@@ -148,7 +201,7 @@ module ActiveRecord
148
201
  # above can be alternatively written this way:
149
202
  #
150
203
  # # Find the first user named "Scarlett" or create a new one with a
151
- # # different last name.
204
+ # # particular last name.
152
205
  # User.find_or_create_by(first_name: 'Scarlett') do |user|
153
206
  # user.last_name = 'Johansson'
154
207
  # end
@@ -158,38 +211,41 @@ module ActiveRecord
158
211
  # failed due to validation errors it won't be persisted, you get what
159
212
  # #create returns in such situation.
160
213
  #
161
- # Please note <b>this method is not atomic</b>, it runs first a SELECT, and if
162
- # there are no results an INSERT is attempted. If there are other threads
163
- # or processes there is a race condition between both calls and it could
164
- # be the case that you end up with two similar records.
214
+ # If creation failed because of a unique constraint, this method will
215
+ # assume it encountered a race condition and will try finding the record
216
+ # once more. If somehow the second find still does not find a record
217
+ # because a concurrent DELETE happened, it will then raise an
218
+ # ActiveRecord::RecordNotFound exception.
165
219
  #
166
- # If this might be a problem for your application, please see #create_or_find_by.
220
+ # Please note <b>this method is not atomic</b>, it runs first a SELECT,
221
+ # and if there are no results an INSERT is attempted. So if the table
222
+ # doesn't have a relevant unique constraint it could be the case that
223
+ # you end up with two or more similar records.
167
224
  def find_or_create_by(attributes, &block)
168
- find_by(attributes) || create(attributes, &block)
225
+ find_by(attributes) || create_or_find_by(attributes, &block)
169
226
  end
170
227
 
171
228
  # Like #find_or_create_by, but calls
172
229
  # {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
173
230
  # is raised if the created record is invalid.
174
231
  def find_or_create_by!(attributes, &block)
175
- find_by(attributes) || create!(attributes, &block)
232
+ find_by(attributes) || create_or_find_by!(attributes, &block)
176
233
  end
177
234
 
178
- # Attempts to create a record with the given attributes in a table that has a unique constraint
235
+ # Attempts to create a record with the given attributes in a table that has a unique database constraint
179
236
  # on one or several of its columns. If a row already exists with one or several of these
180
237
  # unique constraints, the exception such an insertion would normally raise is caught,
181
238
  # and the existing record with those attributes is found using #find_by!.
182
239
  #
183
- # This is similar to #find_or_create_by, but avoids the problem of stale reads between the SELECT
184
- # and the INSERT, as that method needs to first query the table, then attempt to insert a row
185
- # if none is found.
240
+ # This is similar to #find_or_create_by, but tries to create the record first. As such it is
241
+ # better suited for cases where the record is most likely not to exist yet.
186
242
  #
187
243
  # There are several drawbacks to #create_or_find_by, though:
188
244
  #
189
- # * The underlying table must have the relevant columns defined with unique constraints.
245
+ # * The underlying table must have the relevant columns defined with unique database constraints.
190
246
  # * A unique constraint violation may be triggered by only one, or at least less than all,
191
247
  # of the given attributes. This means that the subsequent #find_by! may fail to find a
192
- # matching record, which will then raise an <tt>ActiveRecord::RecordNotFound</tt> exception,
248
+ # matching record, which will then raise an ActiveRecord::RecordNotFound exception,
193
249
  # rather than a record with the given attributes.
194
250
  # * While we avoid the race condition between SELECT -> INSERT from #find_or_create_by,
195
251
  # we actually have another race condition between INSERT -> SELECT, which can be triggered
@@ -198,26 +254,40 @@ module ActiveRecord
198
254
  # * It relies on exception handling to handle control flow, which may be marginally slower.
199
255
  # * The primary key may auto-increment on each create, even if it fails. This can accelerate
200
256
  # the problem of running out of integers, if the underlying table is still stuck on a primary
201
- # key of type int (note: All Rails apps since 5.1+ have defaulted to bigint, which is not liable
257
+ # key of type int (note: All \Rails apps since 5.1+ have defaulted to bigint, which is not liable
202
258
  # to this problem).
259
+ # * Columns with unique database constraints should not have uniqueness validations defined,
260
+ # otherwise #create will fail due to validation errors and #find_by will never be called.
203
261
  #
204
262
  # This method will return a record if all given attributes are covered by unique constraints
205
263
  # (unless the INSERT -> DELETE -> SELECT race condition is triggered), but if creation was attempted
206
264
  # and failed due to validation errors it won't be persisted, you get what #create returns in
207
265
  # such situation.
208
266
  def create_or_find_by(attributes, &block)
209
- transaction(requires_new: true) { create(attributes, &block) }
210
- rescue ActiveRecord::RecordNotUnique
211
- find_by!(attributes)
267
+ with_connection do |connection|
268
+ transaction(requires_new: true) { create(attributes, &block) }
269
+ rescue ActiveRecord::RecordNotUnique
270
+ if connection.transaction_open?
271
+ where(attributes).lock.find_by!(attributes)
272
+ else
273
+ find_by!(attributes)
274
+ end
275
+ end
212
276
  end
213
277
 
214
278
  # Like #create_or_find_by, but calls
215
279
  # {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
216
280
  # is raised if the created record is invalid.
217
281
  def create_or_find_by!(attributes, &block)
218
- transaction(requires_new: true) { create!(attributes, &block) }
219
- rescue ActiveRecord::RecordNotUnique
220
- find_by!(attributes)
282
+ with_connection do |connection|
283
+ transaction(requires_new: true) { create!(attributes, &block) }
284
+ rescue ActiveRecord::RecordNotUnique
285
+ if connection.transaction_open?
286
+ where(attributes).lock.find_by!(attributes)
287
+ else
288
+ find_by!(attributes)
289
+ end
290
+ end
221
291
  end
222
292
 
223
293
  # Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
@@ -230,13 +300,30 @@ module ActiveRecord
230
300
  # returns the result as a string. The string is formatted imitating the
231
301
  # ones printed by the database shell.
232
302
  #
303
+ # User.all.explain
304
+ # # EXPLAIN SELECT `users`.* FROM `users`
305
+ # # ...
306
+ #
233
307
  # Note that this method actually runs the queries, since the results of some
234
308
  # are needed by the next ones when eager loading is going on.
235
309
  #
310
+ # To run EXPLAIN on queries created by +first+, +pluck+ and +count+, call
311
+ # these methods on +explain+:
312
+ #
313
+ # User.all.explain.count
314
+ # # EXPLAIN SELECT COUNT(*) FROM `users`
315
+ # # ...
316
+ #
317
+ # The column name can be passed if required:
318
+ #
319
+ # User.all.explain.maximum(:id)
320
+ # # EXPLAIN SELECT MAX(`users`.`id`) FROM `users`
321
+ # # ...
322
+ #
236
323
  # Please see further details in the
237
324
  # {Active Record Query Interface guide}[https://guides.rubyonrails.org/active_record_querying.html#running-explain].
238
- def explain
239
- exec_explain(collecting_queries_for_explain { exec_queries })
325
+ def explain(*options)
326
+ ExplainProxy.new(self, options)
240
327
  end
241
328
 
242
329
  # Converts relation objects to Array.
@@ -257,37 +344,71 @@ module ActiveRecord
257
344
 
258
345
  # Returns size of the records.
259
346
  def size
260
- loaded? ? @records.length : count(:all)
347
+ if loaded?
348
+ records.length
349
+ else
350
+ count(:all)
351
+ end
261
352
  end
262
353
 
263
354
  # Returns true if there are no records.
264
355
  def empty?
265
- return @records.empty? if loaded?
266
- !exists?
356
+ return true if @none
357
+
358
+ if loaded?
359
+ records.empty?
360
+ else
361
+ !exists?
362
+ end
267
363
  end
268
364
 
269
365
  # Returns true if there are no records.
270
- def none?
271
- return super if block_given?
366
+ #
367
+ # When a pattern argument is given, this method checks whether elements in
368
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
369
+ #
370
+ # posts.none?(Comment) # => true or false
371
+ def none?(*args)
372
+ return true if @none
373
+
374
+ return super if args.present? || block_given?
272
375
  empty?
273
376
  end
274
377
 
275
378
  # Returns true if there are any records.
276
- def any?
277
- return super if block_given?
379
+ #
380
+ # When a pattern argument is given, this method checks whether elements in
381
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
382
+ #
383
+ # posts.any?(Post) # => true or false
384
+ def any?(*args)
385
+ return false if @none
386
+
387
+ return super if args.present? || block_given?
278
388
  !empty?
279
389
  end
280
390
 
281
391
  # Returns true if there is exactly one record.
282
- def one?
283
- return super if block_given?
284
- limit_value ? records.one? : size == 1
392
+ #
393
+ # When a pattern argument is given, this method checks whether elements in
394
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
395
+ #
396
+ # posts.one?(Post) # => true or false
397
+ def one?(*args)
398
+ return false if @none
399
+
400
+ return super if args.present? || block_given?
401
+ return records.one? if loaded?
402
+ limited_count == 1
285
403
  end
286
404
 
287
405
  # Returns true if there is more than one record.
288
406
  def many?
407
+ return false if @none
408
+
289
409
  return super if block_given?
290
- limit_value ? records.many? : size > 1
410
+ return records.many? if loaded?
411
+ limited_count > 1
291
412
  end
292
413
 
293
414
  # Returns a stable cache key that can be used to identify this query.
@@ -297,7 +418,7 @@ module ActiveRecord
297
418
  # # => "products/query-1850ab3d302391b85b8693e941286659"
298
419
  #
299
420
  # If ActiveRecord::Base.collection_cache_versioning is turned off, as it was
300
- # in Rails 6.0 and earlier, the cache key will also include a version.
421
+ # in \Rails 6.0 and earlier, the cache key will also include a version.
301
422
  #
302
423
  # ActiveRecord::Base.collection_cache_versioning = false
303
424
  # Product.where("name like ?", "%Cosmic Encounter%").cache_key
@@ -344,7 +465,7 @@ module ActiveRecord
344
465
  def compute_cache_version(timestamp_column) # :nodoc:
345
466
  timestamp_column = timestamp_column.to_s
346
467
 
347
- if loaded? || distinct_value
468
+ if loaded?
348
469
  size = records.size
349
470
  if size > 0
350
471
  timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
@@ -352,32 +473,35 @@ module ActiveRecord
352
473
  else
353
474
  collection = eager_loading? ? apply_join_dependency : self
354
475
 
355
- column = connection.visitor.compile(table[timestamp_column])
356
- select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
476
+ with_connection do |c|
477
+ column = c.visitor.compile(table[timestamp_column])
478
+ select_values = "COUNT(*) AS #{adapter_class.quote_column_name("size")}, MAX(%s) AS timestamp"
357
479
 
358
- if collection.has_limit_or_offset?
359
- query = collection.select("#{column} AS collection_cache_key_timestamp")
360
- subquery_alias = "subquery_for_cache_key"
361
- subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
362
- arel = query.build_subquery(subquery_alias, select_values % subquery_column)
363
- else
364
- query = collection.unscope(:order)
365
- query.select_values = [select_values % column]
366
- arel = query.arel
367
- end
480
+ if collection.has_limit_or_offset?
481
+ query = collection.select("#{column} AS collection_cache_key_timestamp")
482
+ query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
483
+ subquery_alias = "subquery_for_cache_key"
484
+ subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
485
+ arel = query.build_subquery(subquery_alias, select_values % subquery_column)
486
+ else
487
+ query = collection.unscope(:order)
488
+ query.select_values = [select_values % column]
489
+ arel = query.arel
490
+ end
368
491
 
369
- size, timestamp = connection.select_rows(arel, nil).first
492
+ size, timestamp = c.select_rows(arel, nil).first
370
493
 
371
- if size
372
- column_type = klass.type_for_attribute(timestamp_column)
373
- timestamp = column_type.deserialize(timestamp)
374
- else
375
- size = 0
494
+ if size
495
+ column_type = klass.type_for_attribute(timestamp_column)
496
+ timestamp = column_type.deserialize(timestamp)
497
+ else
498
+ size = 0
499
+ end
376
500
  end
377
501
  end
378
502
 
379
503
  if timestamp
380
- "#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
504
+ "#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
381
505
  else
382
506
  "#{size}"
383
507
  end
@@ -398,17 +522,30 @@ module ActiveRecord
398
522
  # Comment.where(post_id: 1).scoping do
399
523
  # Comment.first
400
524
  # end
401
- # # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
525
+ # # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
526
+ #
527
+ # If <tt>all_queries: true</tt> is passed, scoping will apply to all queries
528
+ # for the relation including +update+ and +delete+ on instances.
529
+ # Once +all_queries+ is set to true it cannot be set to false in a
530
+ # nested block.
402
531
  #
403
532
  # Please check unscoped if you want to remove all previous scopes (including
404
533
  # the default_scope) during the execution of a block.
405
- def scoping
406
- already_in_scope? ? yield : _scoping(self) { yield }
534
+ def scoping(all_queries: nil, &block)
535
+ registry = klass.scope_registry
536
+ if global_scope?(registry) && all_queries == false
537
+ raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
538
+ elsif already_in_scope?(registry)
539
+ yield
540
+ else
541
+ _scoping(self, registry, all_queries, &block)
542
+ end
407
543
  end
408
544
 
409
- def _exec_scope(*args, &block) # :nodoc:
545
+ def _exec_scope(...) # :nodoc:
410
546
  @delegate_to_klass = true
411
- _scoping(nil) { instance_exec(*args, &block) || self }
547
+ registry = klass.scope_registry
548
+ _scoping(nil, registry) { instance_exec(...) || self }
412
549
  ensure
413
550
  @delegate_to_klass = false
414
551
  end
@@ -422,7 +559,8 @@ module ActiveRecord
422
559
  #
423
560
  # ==== Parameters
424
561
  #
425
- # * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
562
+ # * +updates+ - A string, array, or hash representing the SET part of an SQL statement. Any strings provided will
563
+ # be type cast, unless you use +Arel.sql+. (Don't pass user-provided values to +Arel.sql+.)
426
564
  #
427
565
  # ==== Examples
428
566
  #
@@ -437,19 +575,13 @@ module ActiveRecord
437
575
  #
438
576
  # # Update all invoices and set the number column to its id value.
439
577
  # Invoice.update_all('number = id')
578
+ #
579
+ # # Update all books with 'Rails' in their title
580
+ # Book.where('title LIKE ?', '%Rails%').update_all(title: Arel.sql("title + ' - volume 1'"))
440
581
  def update_all(updates)
441
582
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
442
583
 
443
- arel = eager_loading? ? apply_join_dependency.arel : build_arel
444
- arel.source.left = table
445
-
446
- stmt = Arel::UpdateManager.new
447
- stmt.table(arel.source)
448
- stmt.key = table[primary_key]
449
- stmt.take(arel.limit)
450
- stmt.offset(arel.offset)
451
- stmt.order(*arel.orders)
452
- stmt.wheres = arel.constraints
584
+ return 0 if @none
453
585
 
454
586
  if updates.is_a?(Hash)
455
587
  if klass.locking_enabled? &&
@@ -458,12 +590,25 @@ module ActiveRecord
458
590
  attr = table[klass.locking_column]
459
591
  updates[attr.name] = _increment_attribute(attr)
460
592
  end
461
- stmt.set _substitute_values(updates)
593
+ values = _substitute_values(updates)
462
594
  else
463
- stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
595
+ values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
464
596
  end
465
597
 
466
- klass.connection.update(stmt, "#{klass} Update All").tap { reset }
598
+ klass.with_connection do |c|
599
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
600
+ arel.source.left = table
601
+
602
+ group_values_arel_columns = arel_columns(group_values.uniq)
603
+ having_clause_ast = having_clause.ast unless having_clause.empty?
604
+ key = if klass.composite_primary_key?
605
+ primary_key.map { |pk| table[pk] }
606
+ else
607
+ table[primary_key]
608
+ end
609
+ stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
610
+ c.update(stmt, "#{klass} Update All").tap { reset }
611
+ end
467
612
  end
468
613
 
469
614
  def update(id = :all, attributes) # :nodoc:
@@ -474,6 +619,291 @@ module ActiveRecord
474
619
  end
475
620
  end
476
621
 
622
+ def update!(id = :all, attributes) # :nodoc:
623
+ if id == :all
624
+ each { |record| record.update!(attributes) }
625
+ else
626
+ klass.update!(id, attributes)
627
+ end
628
+ end
629
+
630
+
631
+ # Inserts a single record into the database in a single SQL INSERT
632
+ # statement. It does not instantiate any models nor does it trigger
633
+ # Active Record callbacks or validations. Though passed values
634
+ # go through Active Record's type casting and serialization.
635
+ #
636
+ # See #insert_all for documentation.
637
+ def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
638
+ insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
639
+ end
640
+
641
+ # Inserts multiple records into the database in a single SQL INSERT
642
+ # statement. It does not instantiate any models nor does it trigger
643
+ # Active Record callbacks or validations. Though passed values
644
+ # go through Active Record's type casting and serialization.
645
+ #
646
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
647
+ # the attributes for a single row and must have the same keys.
648
+ #
649
+ # Rows are considered to be unique by every unique index on the table. Any
650
+ # duplicate rows are skipped.
651
+ # Override with <tt>:unique_by</tt> (see below).
652
+ #
653
+ # Returns an ActiveRecord::Result with its contents based on
654
+ # <tt>:returning</tt> (see below).
655
+ #
656
+ # ==== Options
657
+ #
658
+ # [:returning]
659
+ # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
660
+ # inserted records, which by default is the primary key.
661
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
662
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
663
+ # clause entirely.
664
+ #
665
+ # You can also pass an SQL string if you need more control on the return values
666
+ # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
667
+ #
668
+ # [:unique_by]
669
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
670
+ # by every unique index on the table. Any duplicate rows are skipped.
671
+ #
672
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
673
+ #
674
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
675
+ # row has an existing id, or is not unique by another unique index,
676
+ # ActiveRecord::RecordNotUnique is raised.
677
+ #
678
+ # Unique indexes can be identified by columns or name:
679
+ #
680
+ # unique_by: :isbn
681
+ # unique_by: %i[ author_id name ]
682
+ # unique_by: :index_books_on_isbn
683
+ #
684
+ # [:record_timestamps]
685
+ # By default, automatic setting of timestamp columns is controlled by
686
+ # the model's <tt>record_timestamps</tt> config, matching typical
687
+ # behavior.
688
+ #
689
+ # To override this and force automatic setting of timestamp columns one
690
+ # way or the other, pass <tt>:record_timestamps</tt>:
691
+ #
692
+ # record_timestamps: true # Always set timestamps automatically
693
+ # record_timestamps: false # Never set timestamps automatically
694
+ #
695
+ # Because it relies on the index information from the database
696
+ # <tt>:unique_by</tt> is recommended to be paired with
697
+ # Active Record's schema_cache.
698
+ #
699
+ # ==== Example
700
+ #
701
+ # # Insert records and skip inserting any duplicates.
702
+ # # Here "Eloquent Ruby" is skipped because its id is not unique.
703
+ #
704
+ # Book.insert_all([
705
+ # { id: 1, title: "Rework", author: "David" },
706
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
707
+ # ])
708
+ #
709
+ # # insert_all works on chained scopes, and you can use create_with
710
+ # # to set default attributes for all inserted records.
711
+ #
712
+ # author.books.create_with(created_at: Time.now).insert_all([
713
+ # { id: 1, title: "Rework" },
714
+ # { id: 2, title: "Eloquent Ruby" }
715
+ # ])
716
+ def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
717
+ InsertAll.execute(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
718
+ end
719
+
720
+ # Inserts a single record into the database in a single SQL INSERT
721
+ # statement. It does not instantiate any models nor does it trigger
722
+ # Active Record callbacks or validations. Though passed values
723
+ # go through Active Record's type casting and serialization.
724
+ #
725
+ # See #insert_all! for more.
726
+ def insert!(attributes, returning: nil, record_timestamps: nil)
727
+ insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
728
+ end
729
+
730
+ # Inserts multiple records into the database in a single SQL INSERT
731
+ # statement. It does not instantiate any models nor does it trigger
732
+ # Active Record callbacks or validations. Though passed values
733
+ # go through Active Record's type casting and serialization.
734
+ #
735
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
736
+ # the attributes for a single row and must have the same keys.
737
+ #
738
+ # Raises ActiveRecord::RecordNotUnique if any rows violate a
739
+ # unique index on the table. In that case, no rows are inserted.
740
+ #
741
+ # To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
742
+ #
743
+ # Returns an ActiveRecord::Result with its contents based on
744
+ # <tt>:returning</tt> (see below).
745
+ #
746
+ # ==== Options
747
+ #
748
+ # [:returning]
749
+ # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
750
+ # inserted records, which by default is the primary key.
751
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
752
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
753
+ # clause entirely.
754
+ #
755
+ # You can also pass an SQL string if you need more control on the return values
756
+ # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
757
+ #
758
+ # [:record_timestamps]
759
+ # By default, automatic setting of timestamp columns is controlled by
760
+ # the model's <tt>record_timestamps</tt> config, matching typical
761
+ # behavior.
762
+ #
763
+ # To override this and force automatic setting of timestamp columns one
764
+ # way or the other, pass <tt>:record_timestamps</tt>:
765
+ #
766
+ # record_timestamps: true # Always set timestamps automatically
767
+ # record_timestamps: false # Never set timestamps automatically
768
+ #
769
+ # ==== Examples
770
+ #
771
+ # # Insert multiple records
772
+ # Book.insert_all!([
773
+ # { title: "Rework", author: "David" },
774
+ # { title: "Eloquent Ruby", author: "Russ" }
775
+ # ])
776
+ #
777
+ # # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
778
+ # # does not have a unique id.
779
+ # Book.insert_all!([
780
+ # { id: 1, title: "Rework", author: "David" },
781
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
782
+ # ])
783
+ def insert_all!(attributes, returning: nil, record_timestamps: nil)
784
+ InsertAll.execute(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps)
785
+ end
786
+
787
+ # Updates or inserts (upserts) a single record into the database in a
788
+ # single SQL INSERT statement. It does not instantiate any models nor does
789
+ # it trigger Active Record callbacks or validations. Though passed values
790
+ # go through Active Record's type casting and serialization.
791
+ #
792
+ # See #upsert_all for documentation.
793
+ def upsert(attributes, **kwargs)
794
+ upsert_all([ attributes ], **kwargs)
795
+ end
796
+
797
+ # Updates or inserts (upserts) multiple records into the database in a
798
+ # single SQL INSERT statement. It does not instantiate any models nor does
799
+ # it trigger Active Record callbacks or validations. Though passed values
800
+ # go through Active Record's type casting and serialization.
801
+ #
802
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
803
+ # the attributes for a single row and must have the same keys.
804
+ #
805
+ # Returns an ActiveRecord::Result with its contents based on
806
+ # <tt>:returning</tt> (see below).
807
+ #
808
+ # By default, +upsert_all+ will update all the columns that can be updated when
809
+ # there is a conflict. These are all the columns except primary keys, read-only
810
+ # columns, and columns covered by the optional +unique_by+.
811
+ #
812
+ # ==== Options
813
+ #
814
+ # [:returning]
815
+ # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
816
+ # inserted records, which by default is the primary key.
817
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
818
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
819
+ # clause entirely.
820
+ #
821
+ # You can also pass an SQL string if you need more control on the return values
822
+ # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
823
+ #
824
+ # [:unique_by]
825
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
826
+ # by every unique index on the table. Any duplicate rows are skipped.
827
+ #
828
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
829
+ #
830
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
831
+ # row has an existing id, or is not unique by another unique index,
832
+ # ActiveRecord::RecordNotUnique is raised.
833
+ #
834
+ # Unique indexes can be identified by columns or name:
835
+ #
836
+ # unique_by: :isbn
837
+ # unique_by: %i[ author_id name ]
838
+ # unique_by: :index_books_on_isbn
839
+ #
840
+ # Because it relies on the index information from the database
841
+ # <tt>:unique_by</tt> is recommended to be paired with
842
+ # Active Record's schema_cache.
843
+ #
844
+ # [:on_duplicate]
845
+ # Configure the SQL update sentence that will be used in case of conflict.
846
+ #
847
+ # NOTE: If you use this option you must provide all the columns you want to update
848
+ # by yourself.
849
+ #
850
+ # Example:
851
+ #
852
+ # Commodity.upsert_all(
853
+ # [
854
+ # { id: 2, name: "Copper", price: 4.84 },
855
+ # { id: 4, name: "Gold", price: 1380.87 },
856
+ # { id: 6, name: "Aluminium", price: 0.35 }
857
+ # ],
858
+ # on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
859
+ # )
860
+ #
861
+ # See the related +:update_only+ option. Both options can't be used at the same time.
862
+ #
863
+ # [:update_only]
864
+ # Provide a list of column names that will be updated in case of conflict. If not provided,
865
+ # +upsert_all+ will update all the columns that can be updated. These are all the columns
866
+ # except primary keys, read-only columns, and columns covered by the optional +unique_by+
867
+ #
868
+ # Example:
869
+ #
870
+ # Commodity.upsert_all(
871
+ # [
872
+ # { id: 2, name: "Copper", price: 4.84 },
873
+ # { id: 4, name: "Gold", price: 1380.87 },
874
+ # { id: 6, name: "Aluminium", price: 0.35 }
875
+ # ],
876
+ # update_only: [:price] # Only prices will be updated
877
+ # )
878
+ #
879
+ # See the related +:on_duplicate+ option. Both options can't be used at the same time.
880
+ #
881
+ # [:record_timestamps]
882
+ # By default, automatic setting of timestamp columns is controlled by
883
+ # the model's <tt>record_timestamps</tt> config, matching typical
884
+ # behavior.
885
+ #
886
+ # To override this and force automatic setting of timestamp columns one
887
+ # way or the other, pass <tt>:record_timestamps</tt>:
888
+ #
889
+ # record_timestamps: true # Always set timestamps automatically
890
+ # record_timestamps: false # Never set timestamps automatically
891
+ #
892
+ # ==== Examples
893
+ #
894
+ # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
895
+ # # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
896
+ #
897
+ # Book.upsert_all([
898
+ # { title: "Rework", author: "David", isbn: "1" },
899
+ # { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
900
+ # ], unique_by: :isbn)
901
+ #
902
+ # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
903
+ def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
904
+ InsertAll.execute(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
905
+ end
906
+
477
907
  # Updates the counters of the records in the current relation.
478
908
  #
479
909
  # ==== Parameters
@@ -572,6 +1002,8 @@ module ActiveRecord
572
1002
  # Post.distinct.delete_all
573
1003
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
574
1004
  def delete_all
1005
+ return 0 if @none
1006
+
575
1007
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
576
1008
  value = @values[method]
577
1009
  method == :distinct ? value : value&.any?
@@ -580,18 +1012,79 @@ module ActiveRecord
580
1012
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
581
1013
  end
582
1014
 
583
- arel = eager_loading? ? apply_join_dependency.arel : build_arel
584
- arel.source.left = table
1015
+ klass.with_connection do |c|
1016
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel(c)
1017
+ arel.source.left = table
585
1018
 
586
- stmt = Arel::DeleteManager.new
587
- stmt.from(arel.source)
588
- stmt.key = table[primary_key]
589
- stmt.take(arel.limit)
590
- stmt.offset(arel.offset)
591
- stmt.order(*arel.orders)
592
- stmt.wheres = arel.constraints
1019
+ group_values_arel_columns = arel_columns(group_values.uniq)
1020
+ having_clause_ast = having_clause.ast unless having_clause.empty?
1021
+ key = if klass.composite_primary_key?
1022
+ primary_key.map { |pk| table[pk] }
1023
+ else
1024
+ table[primary_key]
1025
+ end
1026
+ stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
1027
+
1028
+ c.delete(stmt, "#{klass} Delete All").tap { reset }
1029
+ end
1030
+ end
1031
+
1032
+ # Deletes the row with a primary key matching the +id+ argument, using an
1033
+ # SQL +DELETE+ statement, and returns the number of rows deleted. Active
1034
+ # Record objects are not instantiated, so the object's callbacks are not
1035
+ # executed, including any <tt>:dependent</tt> association options.
1036
+ #
1037
+ # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
1038
+ #
1039
+ # Note: Although it is often much faster than the alternative, #destroy,
1040
+ # skipping callbacks might bypass business logic in your application
1041
+ # that ensures referential integrity or performs other essential jobs.
1042
+ #
1043
+ # ==== Examples
1044
+ #
1045
+ # # Delete a single row
1046
+ # Todo.delete(1)
1047
+ #
1048
+ # # Delete multiple rows
1049
+ # Todo.delete([2,3,4])
1050
+ def delete(id_or_array)
1051
+ return 0 if id_or_array.nil? || (id_or_array.is_a?(Array) && id_or_array.empty?)
1052
+
1053
+ where(model.primary_key => id_or_array).delete_all
1054
+ end
1055
+
1056
+
1057
+ # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
1058
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
1059
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
1060
+ #
1061
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
1062
+ # from the attributes, and then calls destroy on it.
1063
+ #
1064
+ # ==== Parameters
1065
+ #
1066
+ # * +id+ - This should be the id or an array of ids to be destroyed.
1067
+ #
1068
+ # ==== Examples
1069
+ #
1070
+ # # Destroy a single object
1071
+ # Todo.destroy(1)
1072
+ #
1073
+ # # Destroy multiple objects
1074
+ # todos = [1,2,3]
1075
+ # Todo.destroy(todos)
1076
+ def destroy(id)
1077
+ multiple_ids = if model.composite_primary_key?
1078
+ id.first.is_a?(Array)
1079
+ else
1080
+ id.is_a?(Array)
1081
+ end
593
1082
 
594
- klass.connection.delete(stmt, "#{klass} Destroy").tap { reset }
1083
+ if multiple_ids
1084
+ find(id).each(&:destroy)
1085
+ else
1086
+ find(id).destroy
1087
+ end
595
1088
  end
596
1089
 
597
1090
  # Finds and destroys all records matching the specified conditions.
@@ -620,6 +1113,49 @@ module ActiveRecord
620
1113
  where(*args).delete_all
621
1114
  end
622
1115
 
1116
+ # Schedule the query to be performed from a background thread pool.
1117
+ #
1118
+ # Post.where(published: true).load_async # => #<ActiveRecord::Relation>
1119
+ #
1120
+ # When the +Relation+ is iterated, if the background query wasn't executed yet,
1121
+ # it will be performed by the foreground thread.
1122
+ #
1123
+ # Note that {config.active_record.async_query_executor}[https://guides.rubyonrails.org/configuring.html#config-active-record-async-query-executor] must be configured
1124
+ # for queries to actually be executed concurrently. Otherwise it defaults to
1125
+ # executing them in the foreground.
1126
+ #
1127
+ # +load_async+ will also fall back to executing in the foreground in the test environment when transactional
1128
+ # fixtures are enabled.
1129
+ #
1130
+ # If the query was actually executed in the background, the Active Record logs will show
1131
+ # it by prefixing the log line with <tt>ASYNC</tt>:
1132
+ #
1133
+ # ASYNC Post Load (0.0ms) (db time 2ms) SELECT "posts".* FROM "posts" LIMIT 100
1134
+ def load_async
1135
+ with_connection do |c|
1136
+ return load if !c.async_enabled?
1137
+
1138
+ unless loaded?
1139
+ result = exec_main_query(async: c.current_transaction.closed?)
1140
+
1141
+ if result.is_a?(Array)
1142
+ @records = result
1143
+ else
1144
+ @future_result = result
1145
+ end
1146
+ @loaded = true
1147
+ end
1148
+ end
1149
+
1150
+ self
1151
+ end
1152
+
1153
+ # Returns <tt>true</tt> if the relation was scheduled on the background
1154
+ # thread pool.
1155
+ def scheduled?
1156
+ !!@future_result
1157
+ end
1158
+
623
1159
  # Causes the records to be loaded from the database if they have not
624
1160
  # been loaded already. You can use this if for some reason you need
625
1161
  # to explicitly load some records before actually using them. The
@@ -627,7 +1163,7 @@ module ActiveRecord
627
1163
  #
628
1164
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
629
1165
  def load(&block)
630
- unless loaded?
1166
+ if !loaded? || scheduled?
631
1167
  @records = exec_queries(&block)
632
1168
  @loaded = true
633
1169
  end
@@ -642,27 +1178,29 @@ module ActiveRecord
642
1178
  end
643
1179
 
644
1180
  def reset
1181
+ @future_result&.cancel
1182
+ @future_result = nil
645
1183
  @delegate_to_klass = false
646
1184
  @to_sql = @arel = @loaded = @should_eager_load = nil
647
1185
  @offsets = @take = nil
648
1186
  @cache_keys = nil
649
- @records = [].freeze
1187
+ @cache_versions = nil
1188
+ @records = nil
650
1189
  self
651
1190
  end
652
1191
 
653
1192
  # Returns sql statement for the relation.
654
1193
  #
655
1194
  # User.where(name: 'Oscar').to_sql
656
- # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
1195
+ # # SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
657
1196
  def to_sql
658
- @to_sql ||= begin
659
- if eager_loading?
660
- apply_join_dependency do |relation, join_dependency|
661
- relation = join_dependency.apply_column_aliases(relation)
662
- relation.to_sql
663
- end
664
- else
665
- conn = klass.connection
1197
+ @to_sql ||= if eager_loading?
1198
+ apply_join_dependency do |relation, join_dependency|
1199
+ relation = join_dependency.apply_column_aliases(relation)
1200
+ relation.to_sql
1201
+ end
1202
+ else
1203
+ klass.with_connection do |conn|
666
1204
  conn.unprepared_statement { conn.to_sql(arel) }
667
1205
  end
668
1206
  end
@@ -672,7 +1210,7 @@ module ActiveRecord
672
1210
  #
673
1211
  # User.where(name: 'Oscar').where_values_hash
674
1212
  # # => {name: "Oscar"}
675
- def where_values_hash(relation_table_name = klass.table_name)
1213
+ def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
676
1214
  where_clause.to_h(relation_table_name)
677
1215
  end
678
1216
 
@@ -692,7 +1230,7 @@ module ActiveRecord
692
1230
  # Joins that are also marked for preloading. In which case we should just eager load them.
693
1231
  # Note that this is a naive implementation because we could have strings and symbols which
694
1232
  # represent the same association, but that aren't matched by this. Also, we could have
695
- # nested hashes which partially match, e.g. { a: :b } & { a: [:b, :c] }
1233
+ # nested hashes which partially match, e.g. <tt>{ a: :b } & { a: [:b, :c] }</tt>
696
1234
  def joined_includes_values
697
1235
  includes_values & joins_values
698
1236
  end
@@ -709,8 +1247,13 @@ module ActiveRecord
709
1247
  end
710
1248
  end
711
1249
 
712
- def pretty_print(q)
713
- q.pp(records)
1250
+ def pretty_print(pp)
1251
+ subject = loaded? ? records : annotate("loading for pp")
1252
+ entries = subject.take([limit_value, 11].compact.min)
1253
+
1254
+ entries[10] = "..." if entries.size == 11
1255
+
1256
+ pp.pp(entries)
714
1257
  end
715
1258
 
716
1259
  # Returns true if relation is blank.
@@ -722,6 +1265,10 @@ module ActiveRecord
722
1265
  @values.dup
723
1266
  end
724
1267
 
1268
+ def values_for_queries # :nodoc:
1269
+ @values.except(:extending, :skip_query_cache, :strict_loading)
1270
+ end
1271
+
725
1272
  def inspect
726
1273
  subject = loaded? ? records : annotate("loading for inspect")
727
1274
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
@@ -740,7 +1287,7 @@ module ActiveRecord
740
1287
  end
741
1288
 
742
1289
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
743
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
1290
+ ActiveRecord::Associations::AliasTracker.create(connection_pool, table.name, joins, aliases)
744
1291
  end
745
1292
 
746
1293
  class StrictLoadingScope # :nodoc:
@@ -756,11 +1303,9 @@ module ActiveRecord
756
1303
  def preload_associations(records) # :nodoc:
757
1304
  preload = preload_values
758
1305
  preload += includes_values unless eager_loading?
759
- preloader = nil
760
1306
  scope = strict_loading_value ? StrictLoadingScope : nil
761
1307
  preload.each do |associations|
762
- preloader ||= build_preloader
763
- preloader.preload records, associations, scope
1308
+ ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call
764
1309
  end
765
1310
  end
766
1311
 
@@ -770,13 +1315,13 @@ module ActiveRecord
770
1315
  @loaded = true
771
1316
  end
772
1317
 
773
- def null_relation? # :nodoc:
774
- is_a?(NullRelation)
1318
+ private
1319
+ def already_in_scope?(registry)
1320
+ @delegate_to_klass && registry.current_scope(klass, true)
775
1321
  end
776
1322
 
777
- private
778
- def already_in_scope?
779
- @delegate_to_klass && klass.current_scope(true)
1323
+ def global_scope?(registry)
1324
+ registry.global_current_scope(klass, true)
780
1325
  end
781
1326
 
782
1327
  def current_scope_restoring_block(&block)
@@ -799,17 +1344,30 @@ module ActiveRecord
799
1344
  klass.create!(attributes, &block)
800
1345
  end
801
1346
 
802
- def _scoping(scope)
803
- previous, klass.current_scope = klass.current_scope(true), scope
1347
+ def _scoping(scope, registry, all_queries = false)
1348
+ previous = registry.current_scope(klass, true)
1349
+ registry.set_current_scope(klass, scope)
1350
+
1351
+ if all_queries
1352
+ previous_global = registry.global_current_scope(klass, true)
1353
+ registry.set_global_current_scope(klass, scope)
1354
+ end
804
1355
  yield
805
1356
  ensure
806
- klass.current_scope = previous
1357
+ registry.set_current_scope(klass, previous)
1358
+ if all_queries
1359
+ registry.set_global_current_scope(klass, previous_global)
1360
+ end
807
1361
  end
808
1362
 
809
1363
  def _substitute_values(values)
810
1364
  values.map do |name, value|
811
1365
  attr = table[name]
812
- unless Arel.arel_node?(value)
1366
+ if Arel.arel_node?(value)
1367
+ if value.is_a?(Arel::Nodes::SqlLiteral)
1368
+ value = Arel::Nodes::Grouping.new(value)
1369
+ end
1370
+ else
813
1371
  type = klass.type_for_attribute(attr.name)
814
1372
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
815
1373
  end
@@ -826,46 +1384,75 @@ module ActiveRecord
826
1384
 
827
1385
  def exec_queries(&block)
828
1386
  skip_query_cache_if_necessary do
829
- records =
830
- if where_clause.contradiction?
831
- []
832
- elsif eager_loading?
1387
+ rows = if scheduled?
1388
+ future = @future_result
1389
+ @future_result = nil
1390
+ future.result
1391
+ else
1392
+ exec_main_query
1393
+ end
1394
+
1395
+ records = instantiate_records(rows, &block)
1396
+ preload_associations(records) unless skip_preloading_value
1397
+
1398
+ records.each(&:readonly!) if readonly_value
1399
+ records.each { |record| record.strict_loading!(strict_loading_value) } unless strict_loading_value.nil?
1400
+
1401
+ records
1402
+ end
1403
+ end
1404
+
1405
+ def exec_main_query(async: false)
1406
+ if @none
1407
+ if async
1408
+ return FutureResult.wrap([])
1409
+ else
1410
+ return []
1411
+ end
1412
+ end
1413
+
1414
+ skip_query_cache_if_necessary do
1415
+ if where_clause.contradiction?
1416
+ [].freeze
1417
+ elsif eager_loading?
1418
+ klass.with_connection do |c|
833
1419
  apply_join_dependency do |relation, join_dependency|
834
1420
  if relation.null_relation?
835
- []
1421
+ [].freeze
836
1422
  else
837
1423
  relation = join_dependency.apply_column_aliases(relation)
838
- rows = connection.select_all(relation.arel, "SQL")
839
- join_dependency.instantiate(rows, strict_loading_value, &block)
840
- end.freeze
1424
+ @_join_dependency = join_dependency
1425
+ c.select_all(relation.arel, "SQL", async: async)
1426
+ end
841
1427
  end
842
- else
843
- klass.find_by_sql(arel, &block).freeze
844
1428
  end
1429
+ else
1430
+ klass.with_connection do |c|
1431
+ klass._query_by_sql(c, arel, async: async)
1432
+ end
1433
+ end
1434
+ end
1435
+ end
845
1436
 
846
- preload_associations(records) unless skip_preloading_value
847
-
848
- records.each(&:readonly!) if readonly_value
849
- records.each(&:strict_loading!) if strict_loading_value
850
-
1437
+ def instantiate_records(rows, &block)
1438
+ return [].freeze if rows.empty?
1439
+ if eager_loading?
1440
+ records = @_join_dependency.instantiate(rows, strict_loading_value, &block).freeze
1441
+ @_join_dependency = nil
851
1442
  records
1443
+ else
1444
+ klass._load_from_sql(rows, &block).freeze
852
1445
  end
853
1446
  end
854
1447
 
855
- def skip_query_cache_if_necessary
1448
+ def skip_query_cache_if_necessary(&block)
856
1449
  if skip_query_cache_value
857
- uncached do
858
- yield
859
- end
1450
+ uncached(&block)
860
1451
  else
861
1452
  yield
862
1453
  end
863
1454
  end
864
1455
 
865
- def build_preloader
866
- ActiveRecord::Associations::Preloader.new
867
- end
868
-
869
1456
  def references_eager_loaded_tables?
870
1457
  joined_tables = build_joins([]).flat_map do |join|
871
1458
  if join.is_a?(Arel::Nodes::StringJoin)
@@ -889,5 +1476,9 @@ module ActiveRecord
889
1476
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
890
1477
  string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
891
1478
  end
1479
+
1480
+ def limited_count
1481
+ limit_value ? count : limit(2).count
1482
+ end
892
1483
  end
893
1484
  end