activerecord 5.2.8.1 → 6.1.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1347 -624
  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 +16 -7
  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 +107 -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 +73 -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 +225 -121
  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 +341 -99
  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 +4 -4
  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 +113 -74
  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 +478 -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 +94 -10
  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 +291 -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 +118 -32
  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