activerecord 5.2.3 → 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 +898 -532
  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 +10 -19
  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 +27 -28
  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 +54 -12
  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 +48 -35
  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 +76 -47
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +1 -2
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +293 -132
  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 +21 -17
  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 +175 -187
  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 +308 -100
  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 +3 -3
  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 +115 -58
  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 +113 -101
  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 -93
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +65 -40
  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 +487 -199
  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 +6 -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 +51 -8
  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 +59 -117
  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 +117 -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
@@ -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,
@@ -133,11 +131,12 @@ module ActiveRecord
133
131
  relation = apply_join_dependency
134
132
 
135
133
  if operation.to_s.downcase == "count"
136
- relation.distinct!
137
- # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
138
- if (column_name == :all || column_name.nil?) && select_values.empty?
139
- relation.order_values = []
134
+ unless distinct_value || distinct_select?(column_name || select_for_count)
135
+ relation.distinct!
136
+ relation.select_values = [ klass.primary_key || table[Arel.star] ]
140
137
  end
138
+ # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
139
+ relation.order_values = [] if group_values.empty?
141
140
  end
142
141
 
143
142
  relation.calculate(operation, column_name)
@@ -175,14 +174,14 @@ module ActiveRecord
175
174
  # # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
176
175
  # # => [2, 3]
177
176
  #
178
- # Person.pluck('DATEDIFF(updated_at, created_at)')
177
+ # Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
179
178
  # # SELECT DATEDIFF(updated_at, created_at) FROM people
180
179
  # # => ['0', '27761', '173']
181
180
  #
182
181
  # See also #ids.
183
182
  #
184
183
  def pluck(*column_names)
185
- if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
184
+ if loaded? && all_attributes?(column_names)
186
185
  return records.pluck(*column_names)
187
186
  end
188
187
 
@@ -190,14 +189,43 @@ module ActiveRecord
190
189
  relation = apply_join_dependency
191
190
  relation.pluck(*column_names)
192
191
  else
193
- klass.enforce_raw_sql_whitelist(column_names)
192
+ klass.disallow_raw_sql!(column_names)
193
+ columns = arel_columns(column_names)
194
194
  relation = spawn
195
- relation.select_values = column_names
196
- result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
197
- 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)
198
204
  end
199
205
  end
200
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)
224
+ end
225
+
226
+ limit(1).pluck(*column_names).first
227
+ end
228
+
201
229
  # Pluck all the ID's for the relation using the table's primary key
202
230
  #
203
231
  # Person.ids # SELECT people.id FROM people
@@ -207,6 +235,10 @@ module ActiveRecord
207
235
  end
208
236
 
209
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
+
210
242
  def has_include?(column_name)
211
243
  eager_loading? || (includes_values.present? && column_name && column_name != :all)
212
244
  end
@@ -245,20 +277,16 @@ module ActiveRecord
245
277
  def aggregate_column(column_name)
246
278
  return column_name if Arel::Expressions === column_name
247
279
 
248
- if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
249
- @klass.arel_attribute(column_name)
250
- else
251
- 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)
252
282
  end
253
283
  end
254
284
 
255
285
  def operation_over_aggregate_column(column, operation, distinct)
256
- operation == "count" ? column.count(distinct) : column.send(operation)
286
+ operation == "count" ? column.count(distinct) : column.public_send(operation)
257
287
  end
258
288
 
259
289
  def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
260
- column_alias = column_name
261
-
262
290
  if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
263
291
  # Shortcut when limit is zero.
264
292
  return 0 if limit_value == 0
@@ -269,56 +297,55 @@ module ActiveRecord
269
297
  relation = unscope(:order).distinct!(false)
270
298
 
271
299
  column = aggregate_column(column_name)
272
-
273
300
  select_value = operation_over_aggregate_column(column, operation, distinct)
274
- if operation == "sum" && distinct
275
- select_value.distinct = true
276
- end
301
+ select_value.distinct = true if operation == "sum" && distinct
277
302
 
278
- column_alias = select_value.alias
279
- column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
280
303
  relation.select_values = [select_value]
281
304
 
282
305
  query_builder = relation.arel
283
306
  end
284
307
 
285
- result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder, nil) }
286
- row = result.first
287
- value = row && row.values.first
288
- type = result.column_types.fetch(column_alias) do
289
- type_for(column_name)
290
- end
308
+ result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
291
309
 
292
- 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
293
315
  end
294
316
 
295
317
  def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
296
- 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
297
329
 
298
- if group_attrs.first.respond_to?(:to_sym)
299
- association = @klass._reflect_on_association(group_attrs.first)
300
- associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
301
- group_fields = Array(associated ? association.foreign_key : group_attrs)
302
- else
303
- 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
304
334
  end
305
335
  group_fields = arel_columns(group_fields)
306
336
 
307
- 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
+ }
308
341
  group_columns = group_aliases.zip(group_fields)
309
342
 
310
- if operation == "count" && column_name == :all
311
- aggregate_alias = "count_all"
312
- else
313
- aggregate_alias = column_alias_for([operation, column_name].join(" "))
314
- 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)
315
347
 
316
- select_values = [
317
- operation_over_aggregate_column(
318
- aggregate_column(column_name),
319
- operation,
320
- distinct).as(aggregate_alias)
321
- ]
348
+ select_values = [select_value]
322
349
  select_values += self.select_values unless having_clause.empty?
323
350
 
324
351
  select_values.concat group_columns.map { |aliaz, field|
@@ -338,43 +365,50 @@ module ActiveRecord
338
365
  if association
339
366
  key_ids = calculated_data.collect { |row| row[group_aliases.first] }
340
367
  key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
341
- key_records = Hash[key_records.map { |r| [r.id, r] }]
368
+ key_records = key_records.index_by(&:id)
342
369
  end
343
370
 
344
- Hash[calculated_data.map do |row|
345
- key = group_columns.map { |aliaz, col_name|
346
- type = type_for(col_name) do
347
- calculated_data.column_types.fetch(aliaz, Type.default_value)
348
- end
349
- type_cast_calculated_value(row[aliaz], type)
350
- }
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] }
351
386
  key = key.first if key.size == 1
352
387
  key = key_records[key] if associated
353
388
 
354
- type = calculated_data.column_types.fetch(aggregate_alias) { type_for(column_name) }
355
- [key, type_cast_calculated_value(row[aggregate_alias], type, operation)]
356
- 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
357
395
  end
358
396
 
359
- # 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
360
398
  # a usable column name:
361
399
  #
362
400
  # column_alias_for("users.id") # => "users_id"
363
401
  # column_alias_for("sum(id)") # => "sum_id"
364
402
  # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
365
403
  # column_alias_for("count(*)") # => "count_all"
366
- def column_alias_for(keys)
367
- if keys.respond_to? :name
368
- keys = "#{keys.relation.name}.#{keys.name}"
369
- end
370
-
371
- table_name = keys.to_s.downcase
372
- table_name.gsub!(/\*/, "all")
373
- table_name.gsub!(/\W+/, " ")
374
- table_name.strip!
375
- table_name.gsub!(/ +/, "_")
376
-
377
- @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)
378
412
  end
379
413
 
380
414
  def type_for(field, &block)
@@ -382,12 +416,41 @@ module ActiveRecord
382
416
  @klass.type_for_attribute(field_name, &block)
383
417
  end
384
418
 
385
- 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)
386
445
  case operation
387
- when "count" then value.to_i
388
- when "sum" then type.deserialize(value || 0)
389
- when "average" then value && value.respond_to?(:to_d) ? value.to_d : value
390
- 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
391
454
  end
392
455
  end
393
456
 
@@ -402,16 +465,17 @@ module ActiveRecord
402
465
 
403
466
  def build_count_subquery(relation, column_name, distinct)
404
467
  if column_name == :all
468
+ column_alias = Arel.star
405
469
  relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
406
470
  else
407
471
  column_alias = Arel.sql("count_column")
408
472
  relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
409
473
  end
410
474
 
411
- subquery = relation.arel.as(Arel.sql("subquery_for_count"))
412
- 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)
413
477
 
414
- Arel::SelectManager.new(subquery).project(select_value)
478
+ relation.build_subquery(subquery_alias, select_value)
415
479
  end
416
480
  end
417
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