activerecord 5.2.8.1 → 6.1.6.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1255 -596
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +9 -8
  7. data/lib/active_record/association_relation.rb +30 -10
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +100 -41
  10. data/lib/active_record/associations/association_scope.rb +23 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +55 -48
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -6
  13. data/lib/active_record/associations/builder/association.rb +45 -22
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +8 -17
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +44 -34
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +24 -18
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +69 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +47 -34
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +137 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +46 -9
  47. data/lib/active_record/autosave_association.rb +57 -42
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +1 -2
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +211 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +385 -144
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +167 -69
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -99
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +88 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +59 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +18 -7
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +142 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  94. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  96. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  99. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  100. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  101. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  102. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  104. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  105. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  106. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -120
  107. data/lib/active_record/connection_adapters/schema_cache.rb +159 -21
  108. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  109. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  110. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  111. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  112. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  113. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  114. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  115. data/lib/active_record/connection_adapters.rb +52 -0
  116. data/lib/active_record/connection_handling.rb +293 -33
  117. data/lib/active_record/core.rb +333 -98
  118. data/lib/active_record/counter_cache.rb +8 -30
  119. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  120. data/lib/active_record/database_configurations/database_config.rb +80 -0
  121. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  122. data/lib/active_record/database_configurations/url_config.rb +53 -0
  123. data/lib/active_record/database_configurations.rb +273 -0
  124. data/lib/active_record/delegated_type.rb +209 -0
  125. data/lib/active_record/destroy_association_async_job.rb +36 -0
  126. data/lib/active_record/dynamic_matchers.rb +3 -4
  127. data/lib/active_record/enum.rb +108 -36
  128. data/lib/active_record/errors.rb +62 -19
  129. data/lib/active_record/explain.rb +10 -6
  130. data/lib/active_record/explain_subscriber.rb +1 -1
  131. data/lib/active_record/fixture_set/file.rb +10 -17
  132. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  133. data/lib/active_record/fixture_set/render_context.rb +17 -0
  134. data/lib/active_record/fixture_set/table_row.rb +152 -0
  135. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  136. data/lib/active_record/fixtures.rb +200 -481
  137. data/lib/active_record/gem_version.rb +3 -3
  138. data/lib/active_record/inheritance.rb +53 -24
  139. data/lib/active_record/insert_all.rb +212 -0
  140. data/lib/active_record/integration.rb +67 -17
  141. data/lib/active_record/internal_metadata.rb +28 -9
  142. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  143. data/lib/active_record/locking/optimistic.rb +37 -23
  144. data/lib/active_record/locking/pessimistic.rb +9 -5
  145. data/lib/active_record/log_subscriber.rb +35 -35
  146. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  147. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  148. data/lib/active_record/middleware/database_selector.rb +77 -0
  149. data/lib/active_record/migration/command_recorder.rb +96 -44
  150. data/lib/active_record/migration/compatibility.rb +145 -64
  151. data/lib/active_record/migration/join_table.rb +0 -1
  152. data/lib/active_record/migration.rb +206 -157
  153. data/lib/active_record/model_schema.rb +148 -22
  154. data/lib/active_record/nested_attributes.rb +4 -7
  155. data/lib/active_record/no_touching.rb +8 -1
  156. data/lib/active_record/null_relation.rb +0 -1
  157. data/lib/active_record/persistence.rb +267 -59
  158. data/lib/active_record/query_cache.rb +21 -4
  159. data/lib/active_record/querying.rb +40 -23
  160. data/lib/active_record/railtie.rb +116 -59
  161. data/lib/active_record/railties/console_sandbox.rb +2 -4
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +411 -80
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +109 -93
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +157 -90
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +64 -39
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +62 -45
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +476 -187
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +115 -62
  185. data/lib/active_record/relation.rb +379 -115
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +4 -8
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +49 -6
  199. data/lib/active_record/store.rb +88 -9
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +42 -43
  202. data/lib/active_record/tasks/database_tasks.rb +277 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +287 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +62 -118
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +116 -30
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -5,10 +5,11 @@ 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]
8
+ :extending, :unscope, :optimizer_hints, :annotate]
9
9
 
10
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
10
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
11
11
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
+
12
13
  CLAUSE_METHODS = [:where, :having, :from]
13
14
  INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having]
14
15
 
@@ -18,6 +19,7 @@ module ActiveRecord
18
19
  include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
19
20
 
20
21
  attr_reader :table, :klass, :loaded, :predicate_builder
22
+ attr_accessor :skip_preloading_value
21
23
  alias :model :klass
22
24
  alias :loaded? :loaded
23
25
  alias :locked? :lock_value
@@ -26,7 +28,6 @@ module ActiveRecord
26
28
  @klass = klass
27
29
  @table = table
28
30
  @values = values
29
- @offsets = {}
30
31
  @loaded = false
31
32
  @predicate_builder = predicate_builder
32
33
  @delegate_to_klass = false
@@ -38,7 +39,19 @@ module ActiveRecord
38
39
  end
39
40
 
40
41
  def arel_attribute(name) # :nodoc:
41
- klass.arel_attribute(name, table)
42
+ table[name]
43
+ end
44
+ deprecate :arel_attribute
45
+
46
+ def bind_attribute(name, value) # :nodoc:
47
+ if reflection = klass._reflect_on_association(name)
48
+ name = reflection.foreign_key
49
+ value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
50
+ end
51
+
52
+ attr = table[name]
53
+ bind = predicate_builder.build_bind_attribute(attr.name, value)
54
+ yield attr, bind
42
55
  end
43
56
 
44
57
  # Initializes new record from relation while maintaining the current
@@ -54,9 +67,9 @@ module ActiveRecord
54
67
  # user = users.new { |user| user.name = 'Oscar' }
55
68
  # user.name # => Oscar
56
69
  def new(attributes = nil, &block)
57
- scoping { klass.new(values_for_create(attributes), &block) }
70
+ block = current_scope_restoring_block(&block)
71
+ scoping { _new(attributes, &block) }
58
72
  end
59
-
60
73
  alias build new
61
74
 
62
75
  # Tries to create a new record with the same scoped attributes
@@ -82,7 +95,8 @@ module ActiveRecord
82
95
  if attributes.is_a?(Array)
83
96
  attributes.collect { |attr| create(attr, &block) }
84
97
  else
85
- scoping { klass.create(values_for_create(attributes), &block) }
98
+ block = current_scope_restoring_block(&block)
99
+ scoping { _create(attributes, &block) }
86
100
  end
87
101
  end
88
102
 
@@ -96,7 +110,8 @@ module ActiveRecord
96
110
  if attributes.is_a?(Array)
97
111
  attributes.collect { |attr| create!(attr, &block) }
98
112
  else
99
- scoping { klass.create!(values_for_create(attributes), &block) }
113
+ block = current_scope_restoring_block(&block)
114
+ scoping { _create!(attributes, &block) }
100
115
  end
101
116
  end
102
117
 
@@ -143,23 +158,12 @@ module ActiveRecord
143
158
  # failed due to validation errors it won't be persisted, you get what
144
159
  # #create returns in such situation.
145
160
  #
146
- # Please note *this method is not atomic*, it runs first a SELECT, and if
161
+ # Please note <b>this method is not atomic</b>, it runs first a SELECT, and if
147
162
  # there are no results an INSERT is attempted. If there are other threads
148
163
  # or processes there is a race condition between both calls and it could
149
164
  # be the case that you end up with two similar records.
150
165
  #
151
- # Whether that is a problem or not depends on the logic of the
152
- # application, but in the particular case in which rows have a UNIQUE
153
- # constraint an exception may be raised, just retry:
154
- #
155
- # begin
156
- # CreditAccount.transaction(requires_new: true) do
157
- # CreditAccount.find_or_create_by(user_id: user.id)
158
- # end
159
- # rescue ActiveRecord::RecordNotUnique
160
- # retry
161
- # end
162
- #
166
+ # If this might be a problem for your application, please see #create_or_find_by.
163
167
  def find_or_create_by(attributes, &block)
164
168
  find_by(attributes) || create(attributes, &block)
165
169
  end
@@ -171,6 +175,51 @@ module ActiveRecord
171
175
  find_by(attributes) || create!(attributes, &block)
172
176
  end
173
177
 
178
+ # Attempts to create a record with the given attributes in a table that has a unique constraint
179
+ # on one or several of its columns. If a row already exists with one or several of these
180
+ # unique constraints, the exception such an insertion would normally raise is caught,
181
+ # and the existing record with those attributes is found using #find_by!.
182
+ #
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.
186
+ #
187
+ # There are several drawbacks to #create_or_find_by, though:
188
+ #
189
+ # * The underlying table must have the relevant columns defined with unique constraints.
190
+ # * A unique constraint violation may be triggered by only one, or at least less than all,
191
+ # 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,
193
+ # rather than a record with the given attributes.
194
+ # * While we avoid the race condition between SELECT -> INSERT from #find_or_create_by,
195
+ # we actually have another race condition between INSERT -> SELECT, which can be triggered
196
+ # if a DELETE between those two statements is run by another client. But for most applications,
197
+ # that's a significantly less likely condition to hit.
198
+ # * It relies on exception handling to handle control flow, which may be marginally slower.
199
+ # * The primary key may auto-increment on each create, even if it fails. This can accelerate
200
+ # 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
202
+ # to this problem).
203
+ #
204
+ # This method will return a record if all given attributes are covered by unique constraints
205
+ # (unless the INSERT -> DELETE -> SELECT race condition is triggered), but if creation was attempted
206
+ # and failed due to validation errors it won't be persisted, you get what #create returns in
207
+ # such situation.
208
+ def create_or_find_by(attributes, &block)
209
+ transaction(requires_new: true) { create(attributes, &block) }
210
+ rescue ActiveRecord::RecordNotUnique
211
+ find_by!(attributes)
212
+ end
213
+
214
+ # Like #create_or_find_by, but calls
215
+ # {create!}[rdoc-ref:Persistence::ClassMethods#create!] so an exception
216
+ # is raised if the created record is invalid.
217
+ def create_or_find_by!(attributes, &block)
218
+ transaction(requires_new: true) { create!(attributes, &block) }
219
+ rescue ActiveRecord::RecordNotUnique
220
+ find_by!(attributes)
221
+ end
222
+
174
223
  # Like #find_or_create_by, but calls {new}[rdoc-ref:Core#new]
175
224
  # instead of {create}[rdoc-ref:Persistence::ClassMethods#create].
176
225
  def find_or_initialize_by(attributes, &block)
@@ -185,7 +234,7 @@ module ActiveRecord
185
234
  # are needed by the next ones when eager loading is going on.
186
235
  #
187
236
  # Please see further details in the
188
- # {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
237
+ # {Active Record Query Interface guide}[https://guides.rubyonrails.org/active_record_querying.html#running-explain].
189
238
  def explain
190
239
  exec_explain(collecting_queries_for_explain { exec_queries })
191
240
  end
@@ -241,30 +290,107 @@ module ActiveRecord
241
290
  limit_value ? records.many? : size > 1
242
291
  end
243
292
 
244
- # Returns a cache key that can be used to identify the records fetched by
245
- # this query. The cache key is built with a fingerprint of the sql query,
246
- # the number of records matched by the query and a timestamp of the last
247
- # updated record. When a new record comes to match the query, or any of
248
- # the existing records is updated or deleted, the cache key changes.
293
+ # Returns a stable cache key that can be used to identify this query.
294
+ # The cache key is built with a fingerprint of the SQL query.
249
295
  #
250
- # Product.where("name like ?", "%Cosmic Encounter%").cache_key
251
- # # => "products/query-1850ab3d302391b85b8693e941286659-1-20150714212553907087000"
296
+ # Product.where("name like ?", "%Cosmic Encounter%").cache_key
297
+ # # => "products/query-1850ab3d302391b85b8693e941286659"
252
298
  #
253
- # If the collection is loaded, the method will iterate through the records
254
- # to generate the timestamp, otherwise it will trigger one SQL query like:
299
+ # 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.
255
301
  #
256
- # SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
302
+ # ActiveRecord::Base.collection_cache_versioning = false
303
+ # Product.where("name like ?", "%Cosmic Encounter%").cache_key
304
+ # # => "products/query-1850ab3d302391b85b8693e941286659-1-20150714212553907087000"
257
305
  #
258
306
  # You can also pass a custom timestamp column to fetch the timestamp of the
259
307
  # last updated record.
260
308
  #
261
309
  # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
262
- #
263
- # You can customize the strategy to generate the key on a per model basis
264
- # overriding ActiveRecord::Base#collection_cache_key.
265
- def cache_key(timestamp_column = :updated_at)
310
+ def cache_key(timestamp_column = "updated_at")
266
311
  @cache_keys ||= {}
267
- @cache_keys[timestamp_column] ||= @klass.collection_cache_key(self, timestamp_column)
312
+ @cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
313
+ end
314
+
315
+ def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
316
+ query_signature = ActiveSupport::Digest.hexdigest(to_sql)
317
+ key = "#{klass.model_name.cache_key}/query-#{query_signature}"
318
+
319
+ if collection_cache_versioning
320
+ key
321
+ else
322
+ "#{key}-#{compute_cache_version(timestamp_column)}"
323
+ end
324
+ end
325
+ private :compute_cache_key
326
+
327
+ # Returns a cache version that can be used together with the cache key to form
328
+ # a recyclable caching scheme. The cache version is built with the number of records
329
+ # matching the query, and the timestamp of the last updated record. When a new record
330
+ # comes to match the query, or any of the existing records is updated or deleted,
331
+ # the cache version changes.
332
+ #
333
+ # If the collection is loaded, the method will iterate through the records
334
+ # to generate the timestamp, otherwise it will trigger one SQL query like:
335
+ #
336
+ # SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
337
+ def cache_version(timestamp_column = :updated_at)
338
+ if collection_cache_versioning
339
+ @cache_versions ||= {}
340
+ @cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
341
+ end
342
+ end
343
+
344
+ def compute_cache_version(timestamp_column) # :nodoc:
345
+ timestamp_column = timestamp_column.to_s
346
+
347
+ if loaded? || distinct_value
348
+ size = records.size
349
+ if size > 0
350
+ timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
351
+ end
352
+ else
353
+ collection = eager_loading? ? apply_join_dependency : self
354
+
355
+ column = connection.visitor.compile(table[timestamp_column])
356
+ select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
357
+
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
368
+
369
+ size, timestamp = connection.select_rows(arel, nil).first
370
+
371
+ if size
372
+ column_type = klass.type_for_attribute(timestamp_column)
373
+ timestamp = column_type.deserialize(timestamp)
374
+ else
375
+ size = 0
376
+ end
377
+ end
378
+
379
+ if timestamp
380
+ "#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
381
+ else
382
+ "#{size}"
383
+ end
384
+ end
385
+ private :compute_cache_version
386
+
387
+ # Returns a cache key along with the version.
388
+ def cache_key_with_version
389
+ if version = cache_version
390
+ "#{cache_key}-#{version}"
391
+ else
392
+ cache_key
393
+ end
268
394
  end
269
395
 
270
396
  # Scope all queries to the current scope.
@@ -277,15 +403,12 @@ module ActiveRecord
277
403
  # Please check unscoped if you want to remove all previous scopes (including
278
404
  # the default_scope) during the execution of a block.
279
405
  def scoping
280
- previous, klass.current_scope = klass.current_scope(true), self unless @delegate_to_klass
281
- yield
282
- ensure
283
- klass.current_scope = previous unless @delegate_to_klass
406
+ already_in_scope? ? yield : _scoping(self) { yield }
284
407
  end
285
408
 
286
409
  def _exec_scope(*args, &block) # :nodoc:
287
410
  @delegate_to_klass = true
288
- instance_exec(*args, &block) || self
411
+ _scoping(nil) { instance_exec(*args, &block) || self }
289
412
  ensure
290
413
  @delegate_to_klass = false
291
414
  end
@@ -293,7 +416,9 @@ module ActiveRecord
293
416
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
294
417
  # statement and sends it straight to the database. It does not instantiate the involved models and it does not
295
418
  # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
296
- # Active Record's normal type casting and serialization.
419
+ # Active Record's normal type casting and serialization. Returns the number of rows affected.
420
+ #
421
+ # Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
297
422
  #
298
423
  # ==== Parameters
299
424
  #
@@ -315,26 +440,30 @@ module ActiveRecord
315
440
  def update_all(updates)
316
441
  raise ArgumentError, "Empty list of attributes to change" if updates.blank?
317
442
 
318
- if eager_loading?
319
- relation = apply_join_dependency
320
- return relation.update_all(updates)
321
- end
443
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel
444
+ arel.source.left = table
322
445
 
323
446
  stmt = Arel::UpdateManager.new
324
-
325
- stmt.set Arel.sql(@klass.sanitize_sql_for_assignment(updates))
326
- stmt.table(table)
327
-
328
- if has_join_values? || offset_value
329
- @klass.connection.join_to_update(stmt, arel, arel_attribute(primary_key))
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
453
+
454
+ if updates.is_a?(Hash)
455
+ if klass.locking_enabled? &&
456
+ !updates.key?(klass.locking_column) &&
457
+ !updates.key?(klass.locking_column.to_sym)
458
+ attr = table[klass.locking_column]
459
+ updates[attr.name] = _increment_attribute(attr)
460
+ end
461
+ stmt.set _substitute_values(updates)
330
462
  else
331
- stmt.key = arel_attribute(primary_key)
332
- stmt.take(arel.limit)
333
- stmt.order(*arel.orders)
334
- stmt.wheres = arel.constraints
463
+ stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
335
464
  end
336
465
 
337
- @klass.connection.update stmt, "#{@klass} Update All"
466
+ klass.connection.update(stmt, "#{klass} Update All").tap { reset }
338
467
  end
339
468
 
340
469
  def update(id = :all, attributes) # :nodoc:
@@ -345,6 +474,65 @@ module ActiveRecord
345
474
  end
346
475
  end
347
476
 
477
+ # Updates the counters of the records in the current relation.
478
+ #
479
+ # ==== Parameters
480
+ #
481
+ # * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
482
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
483
+ # * If attributes names are passed, they are updated along with update_at/on attributes.
484
+ #
485
+ # ==== Examples
486
+ #
487
+ # # For Posts by a given author increment the comment_count by 1.
488
+ # Post.where(author_id: author.id).update_counters(comment_count: 1)
489
+ def update_counters(counters)
490
+ touch = counters.delete(:touch)
491
+
492
+ updates = {}
493
+ counters.each do |counter_name, value|
494
+ attr = table[counter_name]
495
+ updates[attr.name] = _increment_attribute(attr, value)
496
+ end
497
+
498
+ if touch
499
+ names = touch if touch != true
500
+ names = Array.wrap(names)
501
+ options = names.extract_options!
502
+ touch_updates = klass.touch_attributes_with_time(*names, **options)
503
+ updates.merge!(touch_updates) unless touch_updates.empty?
504
+ end
505
+
506
+ update_all updates
507
+ end
508
+
509
+ # Touches all records in the current relation, setting the +updated_at+/+updated_on+ attributes to the current time or the time specified.
510
+ # It does not instantiate the involved models, and it does not trigger Active Record callbacks or validations.
511
+ # This method can be passed attribute names and an optional time argument.
512
+ # If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
513
+ # If no time argument is passed, the current time is used as default.
514
+ #
515
+ # === Examples
516
+ #
517
+ # # Touch all records
518
+ # Person.all.touch_all
519
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670'"
520
+ #
521
+ # # Touch multiple records with a custom attribute
522
+ # Person.all.touch_all(:created_at)
523
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670', \"created_at\" = '2018-01-04 22:55:23.132670'"
524
+ #
525
+ # # Touch multiple records with a specified time
526
+ # Person.all.touch_all(time: Time.new(2020, 5, 16, 0, 0, 0))
527
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2020-05-16 00:00:00'"
528
+ #
529
+ # # Touch records with scope
530
+ # Person.where(name: 'David').touch_all
531
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
532
+ def touch_all(*names, time: nil)
533
+ update_all klass.touch_attributes_with_time(*names, time: time)
534
+ end
535
+
348
536
  # Destroys the records by instantiating each
349
537
  # record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
350
538
  # Each object's callbacks are executed (including <tt>:dependent</tt> association options).
@@ -385,31 +573,51 @@ module ActiveRecord
385
573
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
386
574
  def delete_all
387
575
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
388
- value = get_value(method)
389
- SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
576
+ value = @values[method]
577
+ method == :distinct ? value : value&.any?
390
578
  end
391
579
  if invalid_methods.any?
392
580
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
393
581
  end
394
582
 
395
- if eager_loading?
396
- relation = apply_join_dependency
397
- return relation.delete_all
398
- end
583
+ arel = eager_loading? ? apply_join_dependency.arel : build_arel
584
+ arel.source.left = table
399
585
 
400
586
  stmt = Arel::DeleteManager.new
401
- stmt.from(table)
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
402
593
 
403
- if has_join_values? || has_limit_or_offset?
404
- @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
405
- else
406
- stmt.wheres = arel.constraints
407
- end
594
+ klass.connection.delete(stmt, "#{klass} Destroy").tap { reset }
595
+ end
408
596
 
409
- affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
597
+ # Finds and destroys all records matching the specified conditions.
598
+ # This is short-hand for <tt>relation.where(condition).destroy_all</tt>.
599
+ # Returns the collection of objects that were destroyed.
600
+ #
601
+ # If no record is found, returns empty array.
602
+ #
603
+ # Person.destroy_by(id: 13)
604
+ # Person.destroy_by(name: 'Spartacus', rating: 4)
605
+ # Person.destroy_by("published_at < ?", 2.weeks.ago)
606
+ def destroy_by(*args)
607
+ where(*args).destroy_all
608
+ end
410
609
 
411
- reset
412
- affected
610
+ # Finds and deletes all records matching the specified conditions.
611
+ # This is short-hand for <tt>relation.where(condition).delete_all</tt>.
612
+ # Returns the number of rows affected.
613
+ #
614
+ # If no record is found, returns <tt>0</tt> as zero rows were affected.
615
+ #
616
+ # Person.delete_by(id: 13)
617
+ # Person.delete_by(name: 'Spartacus', rating: 4)
618
+ # Person.delete_by("published_at < ?", 2.weeks.ago)
619
+ def delete_by(*args)
620
+ where(*args).delete_all
413
621
  end
414
622
 
415
623
  # Causes the records to be loaded from the database if they have not
@@ -419,7 +627,10 @@ module ActiveRecord
419
627
  #
420
628
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
421
629
  def load(&block)
422
- exec_queries(&block) unless loaded?
630
+ unless loaded?
631
+ @records = exec_queries(&block)
632
+ @loaded = true
633
+ end
423
634
 
424
635
  self
425
636
  end
@@ -433,8 +644,9 @@ module ActiveRecord
433
644
  def reset
434
645
  @delegate_to_klass = false
435
646
  @to_sql = @arel = @loaded = @should_eager_load = nil
647
+ @offsets = @take = nil
648
+ @cache_keys = nil
436
649
  @records = [].freeze
437
- @offsets = {}
438
650
  self
439
651
  end
440
652
 
@@ -465,7 +677,9 @@ module ActiveRecord
465
677
  end
466
678
 
467
679
  def scope_for_create
468
- where_values_hash.merge!(create_with_value.stringify_keys)
680
+ hash = where_clause.to_h(klass.table_name, equality_only: true)
681
+ create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
682
+ hash
469
683
  end
470
684
 
471
685
  # Returns true if relation needs eager loading.
@@ -509,7 +723,7 @@ module ActiveRecord
509
723
  end
510
724
 
511
725
  def inspect
512
- subject = loaded? ? records : self
726
+ subject = loaded? ? records : annotate("loading for inspect")
513
727
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
514
728
 
515
729
  entries[10] = "..." if entries.size == 11
@@ -526,52 +740,115 @@ module ActiveRecord
526
740
  end
527
741
 
528
742
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
529
- joins += [aliases] if aliases
530
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
743
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
531
744
  end
532
745
 
533
- protected
746
+ class StrictLoadingScope # :nodoc:
747
+ def self.empty_scope?
748
+ true
749
+ end
750
+
751
+ def self.strict_loading_value
752
+ true
753
+ end
754
+ end
755
+
756
+ def preload_associations(records) # :nodoc:
757
+ preload = preload_values
758
+ preload += includes_values unless eager_loading?
759
+ preloader = nil
760
+ scope = strict_loading_value ? StrictLoadingScope : nil
761
+ preload.each do |associations|
762
+ preloader ||= build_preloader
763
+ preloader.preload records, associations, scope
764
+ end
765
+ end
534
766
 
767
+ protected
535
768
  def load_records(records)
536
769
  @records = records.freeze
537
770
  @loaded = true
538
771
  end
539
772
 
773
+ def null_relation? # :nodoc:
774
+ is_a?(NullRelation)
775
+ end
776
+
540
777
  private
778
+ def already_in_scope?
779
+ @delegate_to_klass && klass.current_scope(true)
780
+ end
781
+
782
+ def current_scope_restoring_block(&block)
783
+ current_scope = klass.current_scope(true)
784
+ -> record do
785
+ klass.current_scope = current_scope
786
+ yield record if block_given?
787
+ end
788
+ end
789
+
790
+ def _new(attributes, &block)
791
+ klass.new(attributes, &block)
792
+ end
793
+
794
+ def _create(attributes, &block)
795
+ klass.create(attributes, &block)
796
+ end
797
+
798
+ def _create!(attributes, &block)
799
+ klass.create!(attributes, &block)
800
+ end
801
+
802
+ def _scoping(scope)
803
+ previous, klass.current_scope = klass.current_scope(true), scope
804
+ yield
805
+ ensure
806
+ klass.current_scope = previous
807
+ end
541
808
 
542
- def has_join_values?
543
- joins_values.any? || left_outer_joins_values.any?
809
+ def _substitute_values(values)
810
+ values.map do |name, value|
811
+ attr = table[name]
812
+ unless Arel.arel_node?(value)
813
+ type = klass.type_for_attribute(attr.name)
814
+ value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
815
+ end
816
+ [attr, value]
817
+ end
818
+ end
819
+
820
+ def _increment_attribute(attribute, value = 1)
821
+ bind = predicate_builder.build_bind_attribute(attribute.name, value.abs)
822
+ expr = table.coalesce(Arel::Nodes::UnqualifiedColumn.new(attribute), 0)
823
+ expr = value < 0 ? expr - bind : expr + bind
824
+ expr.expr
544
825
  end
545
826
 
546
827
  def exec_queries(&block)
547
828
  skip_query_cache_if_necessary do
548
- @records =
549
- if eager_loading?
829
+ records =
830
+ if where_clause.contradiction?
831
+ []
832
+ elsif eager_loading?
550
833
  apply_join_dependency do |relation, join_dependency|
551
- if ActiveRecord::NullRelation === relation
834
+ if relation.null_relation?
552
835
  []
553
836
  else
554
837
  relation = join_dependency.apply_column_aliases(relation)
555
838
  rows = connection.select_all(relation.arel, "SQL")
556
- join_dependency.instantiate(rows, &block)
839
+ join_dependency.instantiate(rows, strict_loading_value, &block)
557
840
  end.freeze
558
841
  end
559
842
  else
560
843
  klass.find_by_sql(arel, &block).freeze
561
844
  end
562
845
 
563
- preload = preload_values
564
- preload += includes_values unless eager_loading?
565
- preloader = nil
566
- preload.each do |associations|
567
- preloader ||= build_preloader
568
- preloader.preload @records, associations
569
- end
846
+ preload_associations(records) unless skip_preloading_value
570
847
 
571
- @records.each(&:readonly!) if readonly_value
848
+ records.each(&:readonly!) if readonly_value
849
+ records.each(&:strict_loading!) if strict_loading_value
572
850
 
573
- @loaded = true
574
- @records
851
+ records
575
852
  end
576
853
  end
577
854
 
@@ -590,40 +867,27 @@ module ActiveRecord
590
867
  end
591
868
 
592
869
  def references_eager_loaded_tables?
593
- joined_tables = arel.join_sources.map do |join|
870
+ joined_tables = build_joins([]).flat_map do |join|
594
871
  if join.is_a?(Arel::Nodes::StringJoin)
595
872
  tables_in_string(join.left)
596
873
  else
597
- [join.left.table_name, join.left.table_alias]
874
+ join.left.name
598
875
  end
599
876
  end
600
877
 
601
- joined_tables += [table.name, table.table_alias]
878
+ joined_tables << table.name
602
879
 
603
880
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
604
- joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
881
+ joined_tables.map!(&:downcase)
605
882
 
606
- (references_values - joined_tables).any?
883
+ !(references_values.map(&:to_s) - joined_tables).empty?
607
884
  end
608
885
 
609
886
  def tables_in_string(string)
610
887
  return [] if string.blank?
611
888
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
612
889
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
613
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
614
- end
615
-
616
- def values_for_create(attributes = nil)
617
- result = attributes ? where_values_hash.merge!(attributes) : where_values_hash
618
-
619
- # NOTE: if there are same keys in both create_with and result, create_with should be used.
620
- # This is to make sure nested attributes don't get passed to the klass.new,
621
- # while keeping the precedence of the duplicate keys in create_with.
622
- create_with_value.stringify_keys.each do |k, v|
623
- result[k] = v if result.key?(k)
624
- end
625
-
626
- result
890
+ string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
627
891
  end
628
892
  end
629
893
  end