activerecord 5.2.8.1 → 6.1.0

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 +849 -630
  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 +5 -4
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +95 -42
  10. data/lib/active_record/associations/association_scope.rb +21 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +50 -46
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
  13. data/lib/active_record/associations/builder/association.rb +23 -21
  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 +31 -29
  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 +41 -20
  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 +71 -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 +133 -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 +45 -8
  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 +2 -15
  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 +203 -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 +381 -146
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
  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 +31 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -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 +44 -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 +14 -6
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -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 +63 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -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/money.rb +2 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  95. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  97. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  100. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
  108. data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
  110. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  113. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  114. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
  115. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  116. data/lib/active_record/connection_adapters.rb +50 -0
  117. data/lib/active_record/connection_handling.rb +285 -33
  118. data/lib/active_record/core.rb +304 -106
  119. data/lib/active_record/counter_cache.rb +8 -30
  120. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  121. data/lib/active_record/database_configurations/database_config.rb +80 -0
  122. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  123. data/lib/active_record/database_configurations/url_config.rb +53 -0
  124. data/lib/active_record/database_configurations.rb +272 -0
  125. data/lib/active_record/delegated_type.rb +209 -0
  126. data/lib/active_record/destroy_association_async_job.rb +36 -0
  127. data/lib/active_record/dynamic_matchers.rb +3 -4
  128. data/lib/active_record/enum.rb +71 -17
  129. data/lib/active_record/errors.rb +62 -19
  130. data/lib/active_record/explain.rb +10 -6
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +10 -17
  133. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  134. data/lib/active_record/fixture_set/render_context.rb +17 -0
  135. data/lib/active_record/fixture_set/table_row.rb +152 -0
  136. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  137. data/lib/active_record/fixtures.rb +197 -481
  138. data/lib/active_record/gem_version.rb +4 -4
  139. data/lib/active_record/inheritance.rb +53 -24
  140. data/lib/active_record/insert_all.rb +208 -0
  141. data/lib/active_record/integration.rb +67 -17
  142. data/lib/active_record/internal_metadata.rb +26 -9
  143. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  144. data/lib/active_record/locking/optimistic.rb +26 -22
  145. data/lib/active_record/locking/pessimistic.rb +9 -5
  146. data/lib/active_record/log_subscriber.rb +34 -35
  147. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  148. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  149. data/lib/active_record/middleware/database_selector.rb +77 -0
  150. data/lib/active_record/migration/command_recorder.rb +96 -44
  151. data/lib/active_record/migration/compatibility.rb +141 -64
  152. data/lib/active_record/migration/join_table.rb +0 -1
  153. data/lib/active_record/migration.rb +205 -156
  154. data/lib/active_record/model_schema.rb +148 -22
  155. data/lib/active_record/nested_attributes.rb +4 -7
  156. data/lib/active_record/no_touching.rb +8 -1
  157. data/lib/active_record/null_relation.rb +0 -1
  158. data/lib/active_record/persistence.rb +267 -59
  159. data/lib/active_record/query_cache.rb +21 -4
  160. data/lib/active_record/querying.rb +40 -23
  161. data/lib/active_record/railtie.rb +113 -74
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +402 -78
  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 +153 -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 +4 -7
  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 +58 -40
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +472 -186
  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 +108 -58
  185. data/lib/active_record/relation.rb +375 -104
  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 -6
  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 +39 -43
  202. data/lib/active_record/tasks/database_tasks.rb +276 -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 +246 -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 +58 -116
  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 +72 -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 +120 -35
  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
  #
@@ -321,17 +446,23 @@ module ActiveRecord
321
446
  end
322
447
 
323
448
  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))
449
+ stmt.table(arel.join_sources.empty? ? table : arel.source)
450
+ stmt.key = table[primary_key]
451
+ stmt.take(arel.limit)
452
+ stmt.offset(arel.offset)
453
+ stmt.order(*arel.orders)
454
+ stmt.wheres = arel.constraints
455
+
456
+ if updates.is_a?(Hash)
457
+ if klass.locking_enabled? &&
458
+ !updates.key?(klass.locking_column) &&
459
+ !updates.key?(klass.locking_column.to_sym)
460
+ attr = table[klass.locking_column]
461
+ updates[attr.name] = _increment_attribute(attr)
462
+ end
463
+ stmt.set _substitute_values(updates)
330
464
  else
331
- stmt.key = arel_attribute(primary_key)
332
- stmt.take(arel.limit)
333
- stmt.order(*arel.orders)
334
- stmt.wheres = arel.constraints
465
+ stmt.set Arel.sql(klass.sanitize_sql_for_assignment(updates, table.name))
335
466
  end
336
467
 
337
468
  @klass.connection.update stmt, "#{@klass} Update All"
@@ -345,6 +476,65 @@ module ActiveRecord
345
476
  end
346
477
  end
347
478
 
479
+ # Updates the counters of the records in the current relation.
480
+ #
481
+ # ==== Parameters
482
+ #
483
+ # * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
484
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
485
+ # * If attributes names are passed, they are updated along with update_at/on attributes.
486
+ #
487
+ # ==== Examples
488
+ #
489
+ # # For Posts by a given author increment the comment_count by 1.
490
+ # Post.where(author_id: author.id).update_counters(comment_count: 1)
491
+ def update_counters(counters)
492
+ touch = counters.delete(:touch)
493
+
494
+ updates = {}
495
+ counters.each do |counter_name, value|
496
+ attr = table[counter_name]
497
+ updates[attr.name] = _increment_attribute(attr, value)
498
+ end
499
+
500
+ if touch
501
+ names = touch if touch != true
502
+ names = Array.wrap(names)
503
+ options = names.extract_options!
504
+ touch_updates = klass.touch_attributes_with_time(*names, **options)
505
+ updates.merge!(touch_updates) unless touch_updates.empty?
506
+ end
507
+
508
+ update_all updates
509
+ end
510
+
511
+ # Touches all records in the current relation, setting the +updated_at+/+updated_on+ attributes to the current time or the time specified.
512
+ # It does not instantiate the involved models, and it does not trigger Active Record callbacks or validations.
513
+ # This method can be passed attribute names and an optional time argument.
514
+ # If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
515
+ # If no time argument is passed, the current time is used as default.
516
+ #
517
+ # === Examples
518
+ #
519
+ # # Touch all records
520
+ # Person.all.touch_all
521
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670'"
522
+ #
523
+ # # Touch multiple records with a custom attribute
524
+ # Person.all.touch_all(:created_at)
525
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670', \"created_at\" = '2018-01-04 22:55:23.132670'"
526
+ #
527
+ # # Touch multiple records with a specified time
528
+ # Person.all.touch_all(time: Time.new(2020, 5, 16, 0, 0, 0))
529
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2020-05-16 00:00:00'"
530
+ #
531
+ # # Touch records with scope
532
+ # Person.where(name: 'David').touch_all
533
+ # # => "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670' WHERE \"people\".\"name\" = 'David'"
534
+ def touch_all(*names, time: nil)
535
+ update_all klass.touch_attributes_with_time(*names, time: time)
536
+ end
537
+
348
538
  # Destroys the records by instantiating each
349
539
  # record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
350
540
  # Each object's callbacks are executed (including <tt>:dependent</tt> association options).
@@ -385,8 +575,8 @@ module ActiveRecord
385
575
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
386
576
  def delete_all
387
577
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
388
- value = get_value(method)
389
- SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
578
+ value = @values[method]
579
+ method == :distinct ? value : value&.any?
390
580
  end
391
581
  if invalid_methods.any?
392
582
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
@@ -398,13 +588,12 @@ module ActiveRecord
398
588
  end
399
589
 
400
590
  stmt = Arel::DeleteManager.new
401
- stmt.from(table)
402
-
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
591
+ stmt.from(arel.join_sources.empty? ? table : arel.source)
592
+ stmt.key = table[primary_key]
593
+ stmt.take(arel.limit)
594
+ stmt.offset(arel.offset)
595
+ stmt.order(*arel.orders)
596
+ stmt.wheres = arel.constraints
408
597
 
409
598
  affected = @klass.connection.delete(stmt, "#{@klass} Destroy")
410
599
 
@@ -412,6 +601,32 @@ module ActiveRecord
412
601
  affected
413
602
  end
414
603
 
604
+ # Finds and destroys all records matching the specified conditions.
605
+ # This is short-hand for <tt>relation.where(condition).destroy_all</tt>.
606
+ # Returns the collection of objects that were destroyed.
607
+ #
608
+ # If no record is found, returns empty array.
609
+ #
610
+ # Person.destroy_by(id: 13)
611
+ # Person.destroy_by(name: 'Spartacus', rating: 4)
612
+ # Person.destroy_by("published_at < ?", 2.weeks.ago)
613
+ def destroy_by(*args)
614
+ where(*args).destroy_all
615
+ end
616
+
617
+ # Finds and deletes all records matching the specified conditions.
618
+ # This is short-hand for <tt>relation.where(condition).delete_all</tt>.
619
+ # Returns the number of rows affected.
620
+ #
621
+ # If no record is found, returns <tt>0</tt> as zero rows were affected.
622
+ #
623
+ # Person.delete_by(id: 13)
624
+ # Person.delete_by(name: 'Spartacus', rating: 4)
625
+ # Person.delete_by("published_at < ?", 2.weeks.ago)
626
+ def delete_by(*args)
627
+ where(*args).delete_all
628
+ end
629
+
415
630
  # Causes the records to be loaded from the database if they have not
416
631
  # been loaded already. You can use this if for some reason you need
417
632
  # to explicitly load some records before actually using them. The
@@ -419,7 +634,10 @@ module ActiveRecord
419
634
  #
420
635
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
421
636
  def load(&block)
422
- exec_queries(&block) unless loaded?
637
+ unless loaded?
638
+ @records = exec_queries(&block)
639
+ @loaded = true
640
+ end
423
641
 
424
642
  self
425
643
  end
@@ -433,8 +651,8 @@ module ActiveRecord
433
651
  def reset
434
652
  @delegate_to_klass = false
435
653
  @to_sql = @arel = @loaded = @should_eager_load = nil
654
+ @offsets = @take = nil
436
655
  @records = [].freeze
437
- @offsets = {}
438
656
  self
439
657
  end
440
658
 
@@ -465,7 +683,10 @@ module ActiveRecord
465
683
  end
466
684
 
467
685
  def scope_for_create
468
- where_values_hash.merge!(create_with_value.stringify_keys)
686
+ hash = where_values_hash
687
+ hash.delete(klass.inheritance_column) if klass.finder_needs_type_condition?
688
+ create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
689
+ hash
469
690
  end
470
691
 
471
692
  # Returns true if relation needs eager loading.
@@ -509,7 +730,7 @@ module ActiveRecord
509
730
  end
510
731
 
511
732
  def inspect
512
- subject = loaded? ? records : self
733
+ subject = loaded? ? records : annotate("loading for inspect")
513
734
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
514
735
 
515
736
  entries[10] = "..." if entries.size == 11
@@ -526,52 +747,115 @@ module ActiveRecord
526
747
  end
527
748
 
528
749
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
529
- joins += [aliases] if aliases
530
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
750
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
531
751
  end
532
752
 
533
- protected
753
+ class StrictLoadingScope # :nodoc:
754
+ def self.empty_scope?
755
+ true
756
+ end
757
+
758
+ def self.strict_loading_value
759
+ true
760
+ end
761
+ end
762
+
763
+ def preload_associations(records) # :nodoc:
764
+ preload = preload_values
765
+ preload += includes_values unless eager_loading?
766
+ preloader = nil
767
+ scope = strict_loading_value ? StrictLoadingScope : nil
768
+ preload.each do |associations|
769
+ preloader ||= build_preloader
770
+ preloader.preload records, associations, scope
771
+ end
772
+ end
534
773
 
774
+ protected
535
775
  def load_records(records)
536
776
  @records = records.freeze
537
777
  @loaded = true
538
778
  end
539
779
 
780
+ def null_relation? # :nodoc:
781
+ is_a?(NullRelation)
782
+ end
783
+
540
784
  private
785
+ def already_in_scope?
786
+ @delegate_to_klass && klass.current_scope(true)
787
+ end
788
+
789
+ def current_scope_restoring_block(&block)
790
+ current_scope = klass.current_scope(true)
791
+ -> record do
792
+ klass.current_scope = current_scope
793
+ yield record if block_given?
794
+ end
795
+ end
796
+
797
+ def _new(attributes, &block)
798
+ klass.new(attributes, &block)
799
+ end
800
+
801
+ def _create(attributes, &block)
802
+ klass.create(attributes, &block)
803
+ end
804
+
805
+ def _create!(attributes, &block)
806
+ klass.create!(attributes, &block)
807
+ end
808
+
809
+ def _scoping(scope)
810
+ previous, klass.current_scope = klass.current_scope(true), scope
811
+ yield
812
+ ensure
813
+ klass.current_scope = previous
814
+ end
541
815
 
542
- def has_join_values?
543
- joins_values.any? || left_outer_joins_values.any?
816
+ def _substitute_values(values)
817
+ values.map do |name, value|
818
+ attr = table[name]
819
+ unless Arel.arel_node?(value)
820
+ type = klass.type_for_attribute(attr.name)
821
+ value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
822
+ end
823
+ [attr, value]
824
+ end
825
+ end
826
+
827
+ def _increment_attribute(attribute, value = 1)
828
+ bind = predicate_builder.build_bind_attribute(attribute.name, value.abs)
829
+ expr = table.coalesce(Arel::Nodes::UnqualifiedColumn.new(attribute), 0)
830
+ expr = value < 0 ? expr - bind : expr + bind
831
+ expr.expr
544
832
  end
545
833
 
546
834
  def exec_queries(&block)
547
835
  skip_query_cache_if_necessary do
548
- @records =
549
- if eager_loading?
836
+ records =
837
+ if where_clause.contradiction?
838
+ []
839
+ elsif eager_loading?
550
840
  apply_join_dependency do |relation, join_dependency|
551
- if ActiveRecord::NullRelation === relation
841
+ if relation.null_relation?
552
842
  []
553
843
  else
554
844
  relation = join_dependency.apply_column_aliases(relation)
555
845
  rows = connection.select_all(relation.arel, "SQL")
556
- join_dependency.instantiate(rows, &block)
846
+ join_dependency.instantiate(rows, strict_loading_value, &block)
557
847
  end.freeze
558
848
  end
559
849
  else
560
850
  klass.find_by_sql(arel, &block).freeze
561
851
  end
562
852
 
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
853
+ preload_associations(records) unless skip_preloading_value
570
854
 
571
- @records.each(&:readonly!) if readonly_value
855
+ records.each(&:readonly!) if readonly_value
856
+ records.each(&:strict_loading!) if strict_loading_value
572
857
 
573
- @loaded = true
574
- @records
858
+ records
575
859
  end
576
860
  end
577
861
 
@@ -590,40 +874,27 @@ module ActiveRecord
590
874
  end
591
875
 
592
876
  def references_eager_loaded_tables?
593
- joined_tables = arel.join_sources.map do |join|
877
+ joined_tables = build_joins([]).flat_map do |join|
594
878
  if join.is_a?(Arel::Nodes::StringJoin)
595
879
  tables_in_string(join.left)
596
880
  else
597
- [join.left.table_name, join.left.table_alias]
881
+ join.left.name
598
882
  end
599
883
  end
600
884
 
601
- joined_tables += [table.name, table.table_alias]
885
+ joined_tables << table.name
602
886
 
603
887
  # 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
888
+ joined_tables.map!(&:downcase)
605
889
 
606
- (references_values - joined_tables).any?
890
+ !(references_values.map(&:to_s) - joined_tables).empty?
607
891
  end
608
892
 
609
893
  def tables_in_string(string)
610
894
  return [] if string.blank?
611
895
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
612
896
  # 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
897
+ string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
627
898
  end
628
899
  end
629
900
  end