activerecord 6.1.7 → 7.1.5

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 (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +51 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +39 -35
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -5,13 +5,14 @@ module ActiveRecord
5
5
  class Relation
6
6
  MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
7
7
  :order, :joins, :left_outer_joins, :references,
8
- :extending, :unscope, :optimizer_hints, :annotate]
8
+ :extending, :unscope, :optimizer_hints, :annotate,
9
+ :with]
9
10
 
10
11
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
11
12
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
13
 
13
14
  CLAUSE_METHODS = [:where, :having, :from]
14
- INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]
15
+ INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :with]
15
16
 
16
17
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
17
18
 
@@ -31,6 +32,10 @@ module ActiveRecord
31
32
  @loaded = false
32
33
  @predicate_builder = predicate_builder
33
34
  @delegate_to_klass = false
35
+ @future_result = nil
36
+ @records = nil
37
+ @async = false
38
+ @none = false
34
39
  end
35
40
 
36
41
  def initialize_copy(other)
@@ -38,15 +43,10 @@ module ActiveRecord
38
43
  reset
39
44
  end
40
45
 
41
- def arel_attribute(name) # :nodoc:
42
- table[name]
43
- end
44
- deprecate :arel_attribute
45
-
46
46
  def bind_attribute(name, value) # :nodoc:
47
47
  if reflection = klass._reflect_on_association(name)
48
48
  name = reflection.foreign_key
49
- value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
49
+ value = value.read_attribute(reflection.association_primary_key) unless value.nil?
50
50
  end
51
51
 
52
52
  attr = table[name]
@@ -67,8 +67,12 @@ module ActiveRecord
67
67
  # user = users.new { |user| user.name = 'Oscar' }
68
68
  # user.name # => Oscar
69
69
  def new(attributes = nil, &block)
70
- block = current_scope_restoring_block(&block)
71
- scoping { _new(attributes, &block) }
70
+ if attributes.is_a?(Array)
71
+ attributes.collect { |attr| new(attr, &block) }
72
+ else
73
+ block = current_scope_restoring_block(&block)
74
+ scoping { _new(attributes, &block) }
75
+ end
72
76
  end
73
77
  alias build new
74
78
 
@@ -148,7 +152,7 @@ module ActiveRecord
148
152
  # above can be alternatively written this way:
149
153
  #
150
154
  # # Find the first user named "Scarlett" or create a new one with a
151
- # # different last name.
155
+ # # particular last name.
152
156
  # User.find_or_create_by(first_name: 'Scarlett') do |user|
153
157
  # user.last_name = 'Johansson'
154
158
  # end
@@ -158,38 +162,41 @@ module ActiveRecord
158
162
  # failed due to validation errors it won't be persisted, you get what
159
163
  # #create returns in such situation.
160
164
  #
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.
165
+ # If creation failed because of a unique constraint, this method will
166
+ # assume it encountered a race condition and will try finding the record
167
+ # once more. If somehow the second find still does not find a record
168
+ # because a concurrent DELETE happened, it will then raise an
169
+ # ActiveRecord::RecordNotFound exception.
165
170
  #
166
- # If this might be a problem for your application, please see #create_or_find_by.
171
+ # Please note <b>this method is not atomic</b>, it runs first a SELECT,
172
+ # and if there are no results an INSERT is attempted. So if the table
173
+ # doesn't have a relevant unique constraint it could be the case that
174
+ # you end up with two or more similar records.
167
175
  def find_or_create_by(attributes, &block)
168
- find_by(attributes) || create(attributes, &block)
176
+ find_by(attributes) || create_or_find_by(attributes, &block)
169
177
  end
170
178
 
171
179
  # Like #find_or_create_by, but calls
172
180
  # {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
173
181
  # is raised if the created record is invalid.
174
182
  def find_or_create_by!(attributes, &block)
175
- find_by(attributes) || create!(attributes, &block)
183
+ find_by(attributes) || create_or_find_by!(attributes, &block)
176
184
  end
177
185
 
178
- # Attempts to create a record with the given attributes in a table that has a unique constraint
186
+ # Attempts to create a record with the given attributes in a table that has a unique database constraint
179
187
  # on one or several of its columns. If a row already exists with one or several of these
180
188
  # unique constraints, the exception such an insertion would normally raise is caught,
181
189
  # and the existing record with those attributes is found using #find_by!.
182
190
  #
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.
191
+ # This is similar to #find_or_create_by, but tries to create the record first. As such it is
192
+ # better suited for cases where the record is most likely not to exist yet.
186
193
  #
187
194
  # There are several drawbacks to #create_or_find_by, though:
188
195
  #
189
- # * The underlying table must have the relevant columns defined with unique constraints.
196
+ # * The underlying table must have the relevant columns defined with unique database constraints.
190
197
  # * A unique constraint violation may be triggered by only one, or at least less than all,
191
198
  # 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,
199
+ # matching record, which will then raise an ActiveRecord::RecordNotFound exception,
193
200
  # rather than a record with the given attributes.
194
201
  # * While we avoid the race condition between SELECT -> INSERT from #find_or_create_by,
195
202
  # we actually have another race condition between INSERT -> SELECT, which can be triggered
@@ -198,7 +205,7 @@ module ActiveRecord
198
205
  # * It relies on exception handling to handle control flow, which may be marginally slower.
199
206
  # * The primary key may auto-increment on each create, even if it fails. This can accelerate
200
207
  # 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
208
+ # key of type int (note: All \Rails apps since 5.1+ have defaulted to bigint, which is not liable
202
209
  # to this problem).
203
210
  #
204
211
  # This method will return a record if all given attributes are covered by unique constraints
@@ -208,7 +215,11 @@ module ActiveRecord
208
215
  def create_or_find_by(attributes, &block)
209
216
  transaction(requires_new: true) { create(attributes, &block) }
210
217
  rescue ActiveRecord::RecordNotUnique
211
- find_by!(attributes)
218
+ if connection.transaction_open?
219
+ where(attributes).lock.find_by!(attributes)
220
+ else
221
+ find_by!(attributes)
222
+ end
212
223
  end
213
224
 
214
225
  # Like #create_or_find_by, but calls
@@ -217,7 +228,11 @@ module ActiveRecord
217
228
  def create_or_find_by!(attributes, &block)
218
229
  transaction(requires_new: true) { create!(attributes, &block) }
219
230
  rescue ActiveRecord::RecordNotUnique
220
- find_by!(attributes)
231
+ if connection.transaction_open?
232
+ where(attributes).lock.find_by!(attributes)
233
+ else
234
+ find_by!(attributes)
235
+ end
221
236
  end
222
237
 
223
238
  # Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
@@ -235,8 +250,8 @@ module ActiveRecord
235
250
  #
236
251
  # Please see further details in the
237
252
  # {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 })
253
+ def explain(*options)
254
+ exec_explain(collecting_queries_for_explain { exec_queries }, options)
240
255
  end
241
256
 
242
257
  # Converts relation objects to Array.
@@ -257,37 +272,71 @@ module ActiveRecord
257
272
 
258
273
  # Returns size of the records.
259
274
  def size
260
- loaded? ? @records.length : count(:all)
275
+ if loaded?
276
+ records.length
277
+ else
278
+ count(:all)
279
+ end
261
280
  end
262
281
 
263
282
  # Returns true if there are no records.
264
283
  def empty?
265
- return @records.empty? if loaded?
266
- !exists?
284
+ return true if @none
285
+
286
+ if loaded?
287
+ records.empty?
288
+ else
289
+ !exists?
290
+ end
267
291
  end
268
292
 
269
293
  # Returns true if there are no records.
270
- def none?
271
- return super if block_given?
294
+ #
295
+ # When a pattern argument is given, this method checks whether elements in
296
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
297
+ #
298
+ # posts.none?(Comment) # => true or false
299
+ def none?(*args)
300
+ return true if @none
301
+
302
+ return super if args.present? || block_given?
272
303
  empty?
273
304
  end
274
305
 
275
306
  # Returns true if there are any records.
276
- def any?
277
- return super if block_given?
307
+ #
308
+ # When a pattern argument is given, this method checks whether elements in
309
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
310
+ #
311
+ # posts.any?(Post) # => true or false
312
+ def any?(*args)
313
+ return false if @none
314
+
315
+ return super if args.present? || block_given?
278
316
  !empty?
279
317
  end
280
318
 
281
319
  # Returns true if there is exactly one record.
282
- def one?
283
- return super if block_given?
284
- limit_value ? records.one? : size == 1
320
+ #
321
+ # When a pattern argument is given, this method checks whether elements in
322
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
323
+ #
324
+ # posts.one?(Post) # => true or false
325
+ def one?(*args)
326
+ return false if @none
327
+
328
+ return super if args.present? || block_given?
329
+ return records.one? if loaded?
330
+ limited_count == 1
285
331
  end
286
332
 
287
333
  # Returns true if there is more than one record.
288
334
  def many?
335
+ return false if @none
336
+
289
337
  return super if block_given?
290
- limit_value ? records.many? : size > 1
338
+ return records.many? if loaded?
339
+ limited_count > 1
291
340
  end
292
341
 
293
342
  # Returns a stable cache key that can be used to identify this query.
@@ -297,7 +346,7 @@ module ActiveRecord
297
346
  # # => "products/query-1850ab3d302391b85b8693e941286659"
298
347
  #
299
348
  # 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.
349
+ # in \Rails 6.0 and earlier, the cache key will also include a version.
301
350
  #
302
351
  # ActiveRecord::Base.collection_cache_versioning = false
303
352
  # Product.where("name like ?", "%Cosmic Encounter%").cache_key
@@ -344,7 +393,7 @@ module ActiveRecord
344
393
  def compute_cache_version(timestamp_column) # :nodoc:
345
394
  timestamp_column = timestamp_column.to_s
346
395
 
347
- if loaded? || distinct_value
396
+ if loaded?
348
397
  size = records.size
349
398
  if size > 0
350
399
  timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
@@ -357,6 +406,7 @@ module ActiveRecord
357
406
 
358
407
  if collection.has_limit_or_offset?
359
408
  query = collection.select("#{column} AS collection_cache_key_timestamp")
409
+ query._select!(table[Arel.star]) if distinct_value && collection.select_values.empty?
360
410
  subquery_alias = "subquery_for_cache_key"
361
411
  subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
362
412
  arel = query.build_subquery(subquery_alias, select_values % subquery_column)
@@ -377,7 +427,7 @@ module ActiveRecord
377
427
  end
378
428
 
379
429
  if timestamp
380
- "#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
430
+ "#{size}-#{timestamp.utc.to_fs(cache_timestamp_format)}"
381
431
  else
382
432
  "#{size}"
383
433
  end
@@ -398,17 +448,30 @@ module ActiveRecord
398
448
  # Comment.where(post_id: 1).scoping do
399
449
  # Comment.first
400
450
  # end
401
- # # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
451
+ # # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
452
+ #
453
+ # If <tt>all_queries: true</tt> is passed, scoping will apply to all queries
454
+ # for the relation including +update+ and +delete+ on instances.
455
+ # Once +all_queries+ is set to true it cannot be set to false in a
456
+ # nested block.
402
457
  #
403
458
  # Please check unscoped if you want to remove all previous scopes (including
404
459
  # the default_scope) during the execution of a block.
405
- def scoping
406
- already_in_scope? ? yield : _scoping(self) { yield }
460
+ def scoping(all_queries: nil, &block)
461
+ registry = klass.scope_registry
462
+ if global_scope?(registry) && all_queries == false
463
+ raise ArgumentError, "Scoping is set to apply to all queries and cannot be unset in a nested block."
464
+ elsif already_in_scope?(registry)
465
+ yield
466
+ else
467
+ _scoping(self, registry, all_queries, &block)
468
+ end
407
469
  end
408
470
 
409
- def _exec_scope(*args, &block) # :nodoc:
471
+ def _exec_scope(...) # :nodoc:
410
472
  @delegate_to_klass = true
411
- _scoping(nil) { instance_exec(*args, &block) || self }
473
+ registry = klass.scope_registry
474
+ _scoping(nil, registry) { instance_exec(...) || self }
412
475
  ensure
413
476
  @delegate_to_klass = false
414
477
  end
@@ -422,7 +485,8 @@ module ActiveRecord
422
485
  #
423
486
  # ==== Parameters
424
487
  #
425
- # * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
488
+ # * +updates+ - A string, array, or hash representing the SET part of an SQL statement. Any strings provided will
489
+ # be type cast, unless you use +Arel.sql+. (Don't pass user-provided values to +Arel.sql+.)
426
490
  #
427
491
  # ==== Examples
428
492
  #
@@ -437,19 +501,13 @@ module ActiveRecord
437
501
  #
438
502
  # # Update all invoices and set the number column to its id value.
439
503
  # Invoice.update_all('number = id')
504
+ #
505
+ # # Update all books with 'Rails' in their title
506
+ # Book.where('title LIKE ?', '%Rails%').update_all(title: Arel.sql("title + ' - volume 1'"))
440
507
  def update_all(updates)
441
508
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
442
509
 
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
510
+ return 0 if @none
453
511
 
454
512
  if updates.is_a?(Hash)
455
513
  if klass.locking_enabled? &&
@@ -458,11 +516,22 @@ module ActiveRecord
458
516
  attr = table[klass.locking_column]
459
517
  updates[attr.name] = _increment_attribute(attr)
460
518
  end
461
- stmt.set _substitute_values(updates)
519
+ values = _substitute_values(updates)
462
520
  else
463
- stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
521
+ values = Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
464
522
  end
465
523
 
524
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel
525
+ arel.source.left = table
526
+
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]
533
+ end
534
+ stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
466
535
  klass.connection.update(stmt, "#{klass} Update All").tap { reset }
467
536
  end
468
537
 
@@ -474,6 +543,14 @@ module ActiveRecord
474
543
  end
475
544
  end
476
545
 
546
+ def update!(id = :all, attributes) # :nodoc:
547
+ if id == :all
548
+ each { |record| record.update!(attributes) }
549
+ else
550
+ klass.update!(id, attributes)
551
+ end
552
+ end
553
+
477
554
  # Updates the counters of the records in the current relation.
478
555
  #
479
556
  # ==== Parameters
@@ -572,6 +649,8 @@ module ActiveRecord
572
649
  # Post.distinct.delete_all
573
650
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
574
651
  def delete_all
652
+ return 0 if @none
653
+
575
654
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
576
655
  value = @values[method]
577
656
  method == :distinct ? value : value&.any?
@@ -583,15 +662,16 @@ module ActiveRecord
583
662
  arel = eager_loading? ? apply_join_dependency.arel : build_arel
584
663
  arel.source.left = table
585
664
 
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
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] }
669
+ else
670
+ table[primary_key]
671
+ end
672
+ stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
593
673
 
594
- klass.connection.delete(stmt, "#{klass} Destroy").tap { reset }
674
+ klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
595
675
  end
596
676
 
597
677
  # Finds and destroys all records matching the specified conditions.
@@ -620,6 +700,47 @@ module ActiveRecord
620
700
  where(*args).delete_all
621
701
  end
622
702
 
703
+ # Schedule the query to be performed from a background thread pool.
704
+ #
705
+ # Post.where(published: true).load_async # => #<ActiveRecord::Relation>
706
+ #
707
+ # When the +Relation+ is iterated, if the background query wasn't executed yet,
708
+ # it will be performed by the foreground thread.
709
+ #
710
+ # Note that {config.active_record.async_query_executor}[https://guides.rubyonrails.org/configuring.html#config-active-record-async-query-executor] must be configured
711
+ # for queries to actually be executed concurrently. Otherwise it defaults to
712
+ # executing them in the foreground.
713
+ #
714
+ # +load_async+ will also fall back to executing in the foreground in the test environment when transactional
715
+ # fixtures are enabled.
716
+ #
717
+ # If the query was actually executed in the background, the Active Record logs will show
718
+ # it by prefixing the log line with <tt>ASYNC</tt>:
719
+ #
720
+ # ASYNC Post Load (0.0ms) (db time 2ms) SELECT "posts".* FROM "posts" LIMIT 100
721
+ def load_async
722
+ return load if !connection.async_enabled?
723
+
724
+ unless loaded?
725
+ result = exec_main_query(async: connection.current_transaction.closed?)
726
+
727
+ if result.is_a?(Array)
728
+ @records = result
729
+ else
730
+ @future_result = result
731
+ end
732
+ @loaded = true
733
+ end
734
+
735
+ self
736
+ end
737
+
738
+ # Returns <tt>true</tt> if the relation was scheduled on the background
739
+ # thread pool.
740
+ def scheduled?
741
+ !!@future_result
742
+ end
743
+
623
744
  # Causes the records to be loaded from the database if they have not
624
745
  # been loaded already. You can use this if for some reason you need
625
746
  # to explicitly load some records before actually using them. The
@@ -627,7 +748,7 @@ module ActiveRecord
627
748
  #
628
749
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
629
750
  def load(&block)
630
- unless loaded?
751
+ if !loaded? || scheduled?
631
752
  @records = exec_queries(&block)
632
753
  @loaded = true
633
754
  end
@@ -642,29 +763,30 @@ module ActiveRecord
642
763
  end
643
764
 
644
765
  def reset
766
+ @future_result&.cancel
767
+ @future_result = nil
645
768
  @delegate_to_klass = false
646
769
  @to_sql = @arel = @loaded = @should_eager_load = nil
647
770
  @offsets = @take = nil
648
771
  @cache_keys = nil
649
- @records = [].freeze
772
+ @cache_versions = nil
773
+ @records = nil
650
774
  self
651
775
  end
652
776
 
653
777
  # Returns sql statement for the relation.
654
778
  #
655
779
  # User.where(name: 'Oscar').to_sql
656
- # # => SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
780
+ # # SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
657
781
  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
666
- conn.unprepared_statement { conn.to_sql(arel) }
782
+ @to_sql ||= if eager_loading?
783
+ apply_join_dependency do |relation, join_dependency|
784
+ relation = join_dependency.apply_column_aliases(relation)
785
+ relation.to_sql
667
786
  end
787
+ else
788
+ conn = klass.connection
789
+ conn.unprepared_statement { conn.to_sql(arel) }
668
790
  end
669
791
  end
670
792
 
@@ -672,7 +794,7 @@ module ActiveRecord
672
794
  #
673
795
  # User.where(name: 'Oscar').where_values_hash
674
796
  # # => {name: "Oscar"}
675
- def where_values_hash(relation_table_name = klass.table_name)
797
+ def where_values_hash(relation_table_name = klass.table_name) # :nodoc:
676
798
  where_clause.to_h(relation_table_name)
677
799
  end
678
800
 
@@ -692,7 +814,7 @@ module ActiveRecord
692
814
  # Joins that are also marked for preloading. In which case we should just eager load them.
693
815
  # Note that this is a naive implementation because we could have strings and symbols which
694
816
  # 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] }
817
+ # nested hashes which partially match, e.g. <tt>{ a: :b } & { a: [:b, :c] }</tt>
696
818
  def joined_includes_values
697
819
  includes_values & joins_values
698
820
  end
@@ -709,8 +831,13 @@ module ActiveRecord
709
831
  end
710
832
  end
711
833
 
712
- def pretty_print(q)
713
- q.pp(records)
834
+ def pretty_print(pp)
835
+ subject = loaded? ? records : annotate("loading for pp")
836
+ entries = subject.take([limit_value, 11].compact.min)
837
+
838
+ entries[10] = "..." if entries.size == 11
839
+
840
+ pp.pp(entries)
714
841
  end
715
842
 
716
843
  # Returns true if relation is blank.
@@ -722,6 +849,10 @@ module ActiveRecord
722
849
  @values.dup
723
850
  end
724
851
 
852
+ def values_for_queries # :nodoc:
853
+ @values.except(:extending, :skip_query_cache, :strict_loading)
854
+ end
855
+
725
856
  def inspect
726
857
  subject = loaded? ? records : annotate("loading for inspect")
727
858
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
@@ -756,11 +887,9 @@ module ActiveRecord
756
887
  def preload_associations(records) # :nodoc:
757
888
  preload = preload_values
758
889
  preload += includes_values unless eager_loading?
759
- preloader = nil
760
890
  scope = strict_loading_value ? StrictLoadingScope : nil
761
891
  preload.each do |associations|
762
- preloader ||= build_preloader
763
- preloader.preload records, associations, scope
892
+ ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call
764
893
  end
765
894
  end
766
895
 
@@ -770,13 +899,13 @@ module ActiveRecord
770
899
  @loaded = true
771
900
  end
772
901
 
773
- def null_relation? # :nodoc:
774
- is_a?(NullRelation)
902
+ private
903
+ def already_in_scope?(registry)
904
+ @delegate_to_klass && registry.current_scope(klass, true)
775
905
  end
776
906
 
777
- private
778
- def already_in_scope?
779
- @delegate_to_klass && klass.current_scope(true)
907
+ def global_scope?(registry)
908
+ registry.global_current_scope(klass, true)
780
909
  end
781
910
 
782
911
  def current_scope_restoring_block(&block)
@@ -799,11 +928,20 @@ module ActiveRecord
799
928
  klass.create!(attributes, &block)
800
929
  end
801
930
 
802
- def _scoping(scope)
803
- previous, klass.current_scope = klass.current_scope(true), scope
931
+ def _scoping(scope, registry, all_queries = false)
932
+ previous = registry.current_scope(klass, true)
933
+ registry.set_current_scope(klass, scope)
934
+
935
+ if all_queries
936
+ previous_global = registry.global_current_scope(klass, true)
937
+ registry.set_global_current_scope(klass, scope)
938
+ end
804
939
  yield
805
940
  ensure
806
- klass.current_scope = previous
941
+ registry.set_current_scope(klass, previous)
942
+ if all_queries
943
+ registry.set_global_current_scope(klass, previous_global)
944
+ end
807
945
  end
808
946
 
809
947
  def _substitute_values(values)
@@ -826,44 +964,69 @@ module ActiveRecord
826
964
 
827
965
  def exec_queries(&block)
828
966
  skip_query_cache_if_necessary do
829
- records =
830
- if where_clause.contradiction?
831
- []
832
- elsif eager_loading?
833
- apply_join_dependency do |relation, join_dependency|
834
- if relation.null_relation?
835
- []
836
- else
837
- 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
841
- end
842
- else
843
- klass.find_by_sql(arel, &block).freeze
844
- end
967
+ rows = if scheduled?
968
+ future = @future_result
969
+ @future_result = nil
970
+ future.result
971
+ else
972
+ exec_main_query
973
+ end
845
974
 
975
+ records = instantiate_records(rows, &block)
846
976
  preload_associations(records) unless skip_preloading_value
847
977
 
848
978
  records.each(&:readonly!) if readonly_value
849
- records.each(&:strict_loading!) if strict_loading_value
979
+ records.each { |record| record.strict_loading!(strict_loading_value) } unless strict_loading_value.nil?
850
980
 
851
981
  records
852
982
  end
853
983
  end
854
984
 
855
- def skip_query_cache_if_necessary
856
- if skip_query_cache_value
857
- uncached do
858
- yield
985
+ def exec_main_query(async: false)
986
+ if @none
987
+ if async
988
+ return FutureResult.wrap([])
989
+ else
990
+ return []
859
991
  end
992
+ end
993
+
994
+ skip_query_cache_if_necessary do
995
+ if where_clause.contradiction?
996
+ [].freeze
997
+ 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)
1005
+ end
1006
+ end
1007
+ else
1008
+ klass._query_by_sql(arel, async: async)
1009
+ end
1010
+ end
1011
+ end
1012
+
1013
+ def instantiate_records(rows, &block)
1014
+ return [].freeze if rows.empty?
1015
+ if eager_loading?
1016
+ records = @_join_dependency.instantiate(rows, strict_loading_value, &block).freeze
1017
+ @_join_dependency = nil
1018
+ records
860
1019
  else
861
- yield
1020
+ klass._load_from_sql(rows, &block).freeze
862
1021
  end
863
1022
  end
864
1023
 
865
- def build_preloader
866
- ActiveRecord::Associations::Preloader.new
1024
+ def skip_query_cache_if_necessary(&block)
1025
+ if skip_query_cache_value
1026
+ uncached(&block)
1027
+ else
1028
+ yield
1029
+ end
867
1030
  end
868
1031
 
869
1032
  def references_eager_loaded_tables?
@@ -889,5 +1052,9 @@ module ActiveRecord
889
1052
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
890
1053
  string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
891
1054
  end
1055
+
1056
+ def limited_count
1057
+ limit_value ? count : limit(2).count
1058
+ end
892
1059
  end
893
1060
  end