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
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/enumerable"
4
+
3
5
  module ActiveRecord
4
6
  module Calculations
5
7
  # Count the records.
@@ -41,15 +43,13 @@ module ActiveRecord
41
43
  def count(column_name = nil)
42
44
  if block_given?
43
45
  unless column_name.nil?
44
- ActiveSupport::Deprecation.warn \
45
- "When `count' is called with a block, it ignores other arguments. " \
46
- "This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
46
+ raise ArgumentError, "Column name argument is not supported when a block is passed."
47
47
  end
48
48
 
49
- return super()
49
+ super()
50
+ else
51
+ calculate(:count, column_name)
50
52
  end
51
-
52
- calculate(:count, column_name)
53
53
  end
54
54
 
55
55
  # Calculates the average value on a given column. Returns +nil+ if there's
@@ -86,15 +86,13 @@ module ActiveRecord
86
86
  def sum(column_name = nil)
87
87
  if block_given?
88
88
  unless column_name.nil?
89
- ActiveSupport::Deprecation.warn \
90
- "When `sum' is called with a block, it ignores other arguments. " \
91
- "This behavior is now deprecated and will result in an ArgumentError in Rails 6.0."
89
+ raise ArgumentError, "Column name argument is not supported when a block is passed."
92
90
  end
93
91
 
94
- return super()
92
+ super()
93
+ else
94
+ calculate(:sum, column_name)
95
95
  end
96
-
97
- calculate(:sum, column_name)
98
96
  end
99
97
 
100
98
  # This calculates aggregate values in the given column. Methods for #count, #sum, #average,
@@ -138,7 +136,7 @@ module ActiveRecord
138
136
  relation.select_values = [ klass.primary_key || table[Arel.star] ]
139
137
  end
140
138
  # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
141
- relation.order_values = []
139
+ relation.order_values = [] if group_values.empty?
142
140
  end
143
141
 
144
142
  relation.calculate(operation, column_name)
@@ -176,14 +174,14 @@ module ActiveRecord
176
174
  # # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
177
175
  # # => [2, 3]
178
176
  #
179
- # Person.pluck('DATEDIFF(updated_at, created_at)')
177
+ # Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
180
178
  # # SELECT DATEDIFF(updated_at, created_at) FROM people
181
179
  # # => ['0', '27761', '173']
182
180
  #
183
181
  # See also #ids.
184
182
  #
185
183
  def pluck(*column_names)
186
- if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
184
+ if loaded? && all_attributes?(column_names)
187
185
  return records.pluck(*column_names)
188
186
  end
189
187
 
@@ -191,12 +189,41 @@ module ActiveRecord
191
189
  relation = apply_join_dependency
192
190
  relation.pluck(*column_names)
193
191
  else
194
- klass.enforce_raw_sql_whitelist(column_names)
192
+ klass.disallow_raw_sql!(column_names)
193
+ columns = arel_columns(column_names)
195
194
  relation = spawn
196
- relation.select_values = column_names
197
- result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
198
- result.cast_values(klass.attribute_types)
195
+ relation.select_values = columns
196
+ result = skip_query_cache_if_necessary do
197
+ if where_clause.contradiction?
198
+ ActiveRecord::Result.new([], [])
199
+ else
200
+ klass.connection.select_all(relation.arel, nil)
201
+ end
202
+ end
203
+ type_cast_pluck_values(result, columns)
204
+ end
205
+ end
206
+
207
+ # Pick the value(s) from the named column(s) in the current relation.
208
+ # This is short-hand for <tt>relation.limit(1).pluck(*column_names).first</tt>, and is primarily useful
209
+ # when you have a relation that's already narrowed down to a single row.
210
+ #
211
+ # Just like #pluck, #pick will only load the actual value, not the entire record object, so it's also
212
+ # more efficient. The value is, again like with pluck, typecast by the column type.
213
+ #
214
+ # Person.where(id: 1).pick(:name)
215
+ # # SELECT people.name FROM people WHERE id = 1 LIMIT 1
216
+ # # => 'David'
217
+ #
218
+ # Person.where(id: 1).pick(:name, :email_address)
219
+ # # SELECT people.name, people.email_address FROM people WHERE id = 1 LIMIT 1
220
+ # # => [ 'David', 'david@loudthinking.com' ]
221
+ def pick(*column_names)
222
+ if loaded? && all_attributes?(column_names)
223
+ return records.pick(*column_names)
199
224
  end
225
+
226
+ limit(1).pluck(*column_names).first
200
227
  end
201
228
 
202
229
  # Pluck all the ID's for the relation using the table's primary key
@@ -208,6 +235,10 @@ module ActiveRecord
208
235
  end
209
236
 
210
237
  private
238
+ def all_attributes?(column_names)
239
+ (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
240
+ end
241
+
211
242
  def has_include?(column_name)
212
243
  eager_loading? || (includes_values.present? && column_name && column_name != :all)
213
244
  end
@@ -246,20 +277,16 @@ module ActiveRecord
246
277
  def aggregate_column(column_name)
247
278
  return column_name if Arel::Expressions === column_name
248
279
 
249
- if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
250
- @klass.arel_attribute(column_name)
251
- else
252
- Arel.sql(column_name == :all ? "*" : column_name.to_s)
280
+ arel_column(column_name.to_s) do |name|
281
+ Arel.sql(column_name == :all ? "*" : name)
253
282
  end
254
283
  end
255
284
 
256
285
  def operation_over_aggregate_column(column, operation, distinct)
257
- operation == "count" ? column.count(distinct) : column.send(operation)
286
+ operation == "count" ? column.count(distinct) : column.public_send(operation)
258
287
  end
259
288
 
260
289
  def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
261
- column_alias = column_name
262
-
263
290
  if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
264
291
  # Shortcut when limit is zero.
265
292
  return 0 if limit_value == 0
@@ -270,56 +297,55 @@ module ActiveRecord
270
297
  relation = unscope(:order).distinct!(false)
271
298
 
272
299
  column = aggregate_column(column_name)
273
-
274
300
  select_value = operation_over_aggregate_column(column, operation, distinct)
275
- if operation == "sum" && distinct
276
- select_value.distinct = true
277
- end
301
+ select_value.distinct = true if operation == "sum" && distinct
278
302
 
279
- column_alias = select_value.alias
280
- column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
281
303
  relation.select_values = [select_value]
282
304
 
283
305
  query_builder = relation.arel
284
306
  end
285
307
 
286
- result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
287
- row = result.first
288
- value = row && row.values.first
289
- type = result.column_types.fetch(column_alias) do
290
- type_for(column_name)
291
- end
308
+ result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
292
309
 
293
- type_cast_calculated_value(value, type, operation)
310
+ type_cast_calculated_value(result.cast_values.first, operation) do |value|
311
+ type = column.try(:type_caster) ||
312
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
313
+ type.deserialize(value)
314
+ end
294
315
  end
295
316
 
296
317
  def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
297
- group_attrs = group_values
318
+ group_fields = group_values
319
+ group_fields = group_fields.uniq if group_fields.size > 1
320
+
321
+ unless group_fields == group_values
322
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
323
+ `#{operation}` with group by duplicated fields does no longer affect to result in Rails 6.2.
324
+ To migrate to Rails 6.2's behavior, use `uniq!(:group)` to deduplicate group fields
325
+ (`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
326
+ MSG
327
+ group_fields = group_values
328
+ end
298
329
 
299
- if group_attrs.first.respond_to?(:to_sym)
300
- association = @klass._reflect_on_association(group_attrs.first)
301
- associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
302
- group_fields = Array(associated ? association.foreign_key : group_attrs)
303
- else
304
- group_fields = group_attrs
330
+ if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
331
+ association = klass._reflect_on_association(group_fields.first)
332
+ associated = association && association.belongs_to? # only count belongs_to associations
333
+ group_fields = Array(association.foreign_key) if associated
305
334
  end
306
335
  group_fields = arel_columns(group_fields)
307
336
 
308
- group_aliases = group_fields.map { |field| column_alias_for(field) }
337
+ group_aliases = group_fields.map { |field|
338
+ field = connection.visitor.compile(field) if Arel.arel_node?(field)
339
+ column_alias_for(field.to_s.downcase)
340
+ }
309
341
  group_columns = group_aliases.zip(group_fields)
310
342
 
311
- if operation == "count" && column_name == :all
312
- aggregate_alias = "count_all"
313
- else
314
- aggregate_alias = column_alias_for([operation, column_name].join(" "))
315
- end
343
+ column = aggregate_column(column_name)
344
+ column_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
345
+ select_value = operation_over_aggregate_column(column, operation, distinct)
346
+ select_value.as(column_alias)
316
347
 
317
- select_values = [
318
- operation_over_aggregate_column(
319
- aggregate_column(column_name),
320
- operation,
321
- distinct).as(aggregate_alias)
322
- ]
348
+ select_values = [select_value]
323
349
  select_values += self.select_values unless having_clause.empty?
324
350
 
325
351
  select_values.concat group_columns.map { |aliaz, field|
@@ -339,43 +365,50 @@ module ActiveRecord
339
365
  if association
340
366
  key_ids = calculated_data.collect { |row| row[group_aliases.first] }
341
367
  key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
342
- key_records = Hash[key_records.map { |r| [r.id, r] }]
368
+ key_records = key_records.index_by(&:id)
343
369
  end
344
370
 
345
- Hash[calculated_data.map do |row|
346
- key = group_columns.map { |aliaz, col_name|
347
- type = type_for(col_name) do
348
- calculated_data.column_types.fetch(aliaz, Type.default_value)
349
- end
350
- type_cast_calculated_value(row[aliaz], type)
351
- }
371
+ key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
372
+ types[aliaz] = type_for(col_name) do
373
+ calculated_data.column_types.fetch(aliaz, Type.default_value)
374
+ end
375
+ end
376
+
377
+ hash_rows = calculated_data.cast_values(key_types).map! do |row|
378
+ calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
379
+ hash[col_name] = row[i]
380
+ end
381
+ end
382
+
383
+ type = nil
384
+ hash_rows.each_with_object({}) do |row, result|
385
+ key = group_aliases.map { |aliaz| row[aliaz] }
352
386
  key = key.first if key.size == 1
353
387
  key = key_records[key] if associated
354
388
 
355
- type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
356
- [key, type_cast_calculated_value(row[aggregate_alias], type, operation)]
357
- end]
389
+ result[key] = type_cast_calculated_value(row[column_alias], operation) do |value|
390
+ type ||= column.try(:type_caster) ||
391
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
392
+ type.deserialize(value)
393
+ end
394
+ end
358
395
  end
359
396
 
360
- # Converts the given keys to the value that the database adapter returns as
397
+ # Converts the given field to the value that the database adapter returns as
361
398
  # a usable column name:
362
399
  #
363
400
  # column_alias_for("users.id") # => "users_id"
364
401
  # column_alias_for("sum(id)") # => "sum_id"
365
402
  # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
366
403
  # column_alias_for("count(*)") # => "count_all"
367
- def column_alias_for(keys)
368
- if keys.respond_to? :name
369
- keys = "#{keys.relation.name}.#{keys.name}"
370
- end
371
-
372
- table_name = keys.to_s.downcase
373
- table_name.gsub!(/\*/, "all")
374
- table_name.gsub!(/\W+/, " ")
375
- table_name.strip!
376
- table_name.gsub!(/ +/, "_")
377
-
378
- @klass.connection.table_alias_for(table_name)
404
+ def column_alias_for(field)
405
+ column_alias = +field
406
+ column_alias.gsub!(/\*/, "all")
407
+ column_alias.gsub!(/\W+/, " ")
408
+ column_alias.strip!
409
+ column_alias.gsub!(/ +/, "_")
410
+
411
+ connection.table_alias_for(column_alias)
379
412
  end
380
413
 
381
414
  def type_for(field, &block)
@@ -383,12 +416,41 @@ module ActiveRecord
383
416
  @klass.type_for_attribute(field_name, &block)
384
417
  end
385
418
 
386
- def type_cast_calculated_value(value, type, operation = nil)
419
+ def lookup_cast_type_from_join_dependencies(name, join_dependencies = build_join_dependencies)
420
+ each_join_dependencies(join_dependencies) do |join|
421
+ type = join.base_klass.attribute_types.fetch(name, nil)
422
+ return type if type
423
+ end
424
+ nil
425
+ end
426
+
427
+ def type_cast_pluck_values(result, columns)
428
+ cast_types = if result.columns.size != columns.size
429
+ klass.attribute_types
430
+ else
431
+ join_dependencies = nil
432
+ columns.map.with_index do |column, i|
433
+ column.try(:type_caster) ||
434
+ klass.attribute_types.fetch(name = result.columns[i]) do
435
+ join_dependencies ||= build_join_dependencies
436
+ lookup_cast_type_from_join_dependencies(name, join_dependencies) ||
437
+ result.column_types[name] || Type.default_value
438
+ end
439
+ end
440
+ end
441
+ result.cast_values(cast_types)
442
+ end
443
+
444
+ def type_cast_calculated_value(value, operation)
387
445
  case operation
388
- when "count" then value.to_i
389
- when "sum" then type.deserialize(value || 0)
390
- when "average" then value && value.respond_to?(:to_d) ? value.to_d : value
391
- else type.deserialize(value)
446
+ when "count"
447
+ value.to_i
448
+ when "sum"
449
+ yield value || 0
450
+ when "average"
451
+ value&.respond_to?(:to_d) ? value.to_d : value
452
+ else # "minimum", "maximum"
453
+ yield value
392
454
  end
393
455
  end
394
456
 
@@ -403,16 +465,17 @@ module ActiveRecord
403
465
 
404
466
  def build_count_subquery(relation, column_name, distinct)
405
467
  if column_name == :all
468
+ column_alias = Arel.star
406
469
  relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
407
470
  else
408
471
  column_alias = Arel.sql("count_column")
409
472
  relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
410
473
  end
411
474
 
412
- subquery = relation.arel.as(Arel.sql("subquery_for_count"))
413
- select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
475
+ subquery_alias = Arel.sql("subquery_for_count")
476
+ select_value = operation_over_aggregate_column(column_alias, "count", false)
414
477
 
415
- Arel::SelectManager.new(subquery).project(select_value)
478
+ relation.build_subquery(subquery_alias, select_value)
416
479
  end
417
480
  end
418
481
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "mutex_m"
4
+ require "active_support/core_ext/module/delegation"
5
+
3
6
  module ActiveRecord
4
7
  module Delegation # :nodoc:
5
8
  module DelegateCache # :nodoc:
@@ -18,7 +21,7 @@ module ActiveRecord
18
21
  include ClassSpecificRelation
19
22
  }
20
23
  include_relation_methods(delegate)
21
- mangled_name = klass.name.gsub("::".freeze, "_".freeze)
24
+ mangled_name = klass.name.gsub("::", "_")
22
25
  const_set mangled_name, delegate
23
26
  private_constant mangled_name
24
27
 
@@ -31,35 +34,49 @@ module ActiveRecord
31
34
  super
32
35
  end
33
36
 
37
+ def generate_relation_method(method)
38
+ generated_relation_methods.generate_method(method)
39
+ end
40
+
34
41
  protected
35
42
  def include_relation_methods(delegate)
36
- superclass.include_relation_methods(delegate) unless base_class == self
43
+ superclass.include_relation_methods(delegate) unless base_class?
37
44
  delegate.include generated_relation_methods
38
45
  end
39
46
 
40
47
  private
41
48
  def generated_relation_methods
42
- @generated_relation_methods ||= Module.new.tap do |mod|
43
- mod_name = "GeneratedRelationMethods"
44
- const_set mod_name, mod
45
- private_constant mod_name
49
+ @generated_relation_methods ||= GeneratedRelationMethods.new.tap do |mod|
50
+ const_set(:GeneratedRelationMethods, mod)
51
+ private_constant :GeneratedRelationMethods
46
52
  end
47
53
  end
54
+ end
48
55
 
49
- def generate_relation_method(method)
50
- if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
51
- generated_relation_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
52
- def #{method}(*args, &block)
53
- scoping { klass.#{method}(*args, &block) }
56
+ class GeneratedRelationMethods < Module # :nodoc:
57
+ include Mutex_m
58
+
59
+ def generate_method(method)
60
+ synchronize do
61
+ return if method_defined?(method)
62
+
63
+ if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
64
+ definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
65
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
66
+ def #{method}(#{definition})
67
+ scoping { klass.#{method}(#{definition}) }
54
68
  end
55
69
  RUBY
56
70
  else
57
- generated_relation_methods.send(:define_method, method) do |*args, &block|
71
+ define_method(method) do |*args, &block|
58
72
  scoping { klass.public_send(method, *args, &block) }
59
73
  end
74
+ ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
60
75
  end
61
76
  end
77
+ end
62
78
  end
79
+ private_constant :GeneratedRelationMethods
63
80
 
64
81
  extend ActiveSupport::Concern
65
82
 
@@ -68,7 +85,7 @@ module ActiveRecord
68
85
  # may vary depending on the klass of a relation, so we create a subclass of Relation
69
86
  # for each different klass, and the delegations are compiled into that subclass only.
70
87
 
71
- delegate :to_xml, :encode_with, :length, :each, :uniq, :join,
88
+ delegate :to_xml, :encode_with, :length, :each, :join,
72
89
  :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
73
90
  :to_sentence, :to_formatted_s, :as_json,
74
91
  :shuffle, :split, :slice, :index, :rindex, to: :records
@@ -78,62 +95,30 @@ module ActiveRecord
78
95
  module ClassSpecificRelation # :nodoc:
79
96
  extend ActiveSupport::Concern
80
97
 
81
- included do
82
- @delegation_mutex = Mutex.new
83
- end
84
-
85
98
  module ClassMethods # :nodoc:
86
99
  def name
87
100
  superclass.name
88
101
  end
89
-
90
- def delegate_to_scoped_klass(method)
91
- @delegation_mutex.synchronize do
92
- return if method_defined?(method)
93
-
94
- if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
95
- module_eval <<-RUBY, __FILE__, __LINE__ + 1
96
- def #{method}(*args, &block)
97
- scoping { @klass.#{method}(*args, &block) }
98
- end
99
- RUBY
100
- else
101
- define_method method do |*args, &block|
102
- scoping { @klass.public_send(method, *args, &block) }
103
- end
104
- end
105
- end
106
- end
107
102
  end
108
103
 
109
104
  private
110
-
111
105
  def method_missing(method, *args, &block)
112
106
  if @klass.respond_to?(method)
113
- self.class.delegate_to_scoped_klass(method)
107
+ @klass.generate_relation_method(method)
114
108
  scoping { @klass.public_send(method, *args, &block) }
115
- elsif @delegate_to_klass && @klass.respond_to?(method, true)
116
- ActiveSupport::Deprecation.warn \
117
- "Delegating missing #{method} method to #{@klass}. " \
118
- "Accessibility of private/protected class methods in :scope is deprecated and will be removed in Rails 6.0."
119
- @klass.send(method, *args, &block)
120
- elsif arel.respond_to?(method)
121
- ActiveSupport::Deprecation.warn \
122
- "Delegating #{method} to arel is deprecated and will be removed in Rails 6.0."
123
- arel.public_send(method, *args, &block)
124
109
  else
125
110
  super
126
111
  end
127
112
  end
113
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
128
114
  end
129
115
 
130
116
  module ClassMethods # :nodoc:
131
- def create(klass, *args)
132
- relation_class_for(klass).new(klass, *args)
117
+ def create(klass, *args, **kwargs)
118
+ relation_class_for(klass).new(klass, *args, **kwargs)
133
119
  end
134
120
 
135
121
  private
136
-
137
122
  def relation_class_for(klass)
138
123
  klass.relation_delegate_class(self)
139
124
  end
@@ -141,7 +126,7 @@ module ActiveRecord
141
126
 
142
127
  private
143
128
  def respond_to_missing?(method, _)
144
- super || @klass.respond_to?(method) || arel.respond_to?(method)
129
+ super || @klass.respond_to?(method)
145
130
  end
146
131
  end
147
132
  end