activerecord 6.1.7 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +520 -1385
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +31 -31
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +17 -14
  7. data/lib/active_record/association_relation.rb +2 -12
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +60 -21
  10. data/lib/active_record/associations/association_scope.rb +17 -12
  11. data/lib/active_record/associations/belongs_to_association.rb +37 -11
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
  13. data/lib/active_record/associations/builder/association.rb +11 -5
  14. data/lib/active_record/associations/builder/belongs_to.rb +41 -14
  15. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +4 -4
  19. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  20. data/lib/active_record/associations/collection_association.rb +46 -36
  21. data/lib/active_record/associations/collection_proxy.rb +44 -16
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +10 -3
  25. data/lib/active_record/associations/has_many_association.rb +29 -19
  26. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  27. data/lib/active_record/associations/has_one_association.rb +20 -10
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  30. data/lib/active_record/associations/join_dependency.rb +23 -15
  31. data/lib/active_record/associations/nested_error.rb +47 -0
  32. data/lib/active_record/associations/preloader/association.rb +212 -53
  33. data/lib/active_record/associations/preloader/batch.rb +48 -0
  34. data/lib/active_record/associations/preloader/branch.rb +153 -0
  35. data/lib/active_record/associations/preloader/through_association.rb +50 -16
  36. data/lib/active_record/associations/preloader.rb +50 -121
  37. data/lib/active_record/associations/singular_association.rb +15 -3
  38. data/lib/active_record/associations/through_association.rb +25 -14
  39. data/lib/active_record/associations.rb +404 -509
  40. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  41. data/lib/active_record/attribute_assignment.rb +2 -14
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  43. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  44. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  45. data/lib/active_record/attribute_methods/primary_key.rb +47 -27
  46. data/lib/active_record/attribute_methods/query.rb +31 -19
  47. data/lib/active_record/attribute_methods/read.rb +14 -11
  48. data/lib/active_record/attribute_methods/serialization.rb +174 -37
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
  50. data/lib/active_record/attribute_methods/write.rb +12 -15
  51. data/lib/active_record/attribute_methods.rb +164 -52
  52. data/lib/active_record/attributes.rb +51 -49
  53. data/lib/active_record/autosave_association.rb +74 -57
  54. data/lib/active_record/base.rb +27 -5
  55. data/lib/active_record/callbacks.rb +18 -34
  56. data/lib/active_record/coders/column_serializer.rb +61 -0
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +70 -46
  59. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +377 -142
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
  75. data/lib/active_record/connection_adapters/column.rb +13 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
  78. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
  79. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  81. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  82. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
  83. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
  85. data/lib/active_record/connection_adapters/pool_config.rb +26 -16
  86. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  87. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  88. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
  89. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  94. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  100. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
  103. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  104. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  105. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
  106. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  107. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
  108. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  109. data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
  110. data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
  111. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  112. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
  113. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
  114. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
  119. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  120. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  121. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  122. data/lib/active_record/connection_adapters.rb +130 -6
  123. data/lib/active_record/connection_handling.rb +132 -146
  124. data/lib/active_record/core.rb +276 -251
  125. data/lib/active_record/counter_cache.rb +68 -34
  126. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
  127. data/lib/active_record/database_configurations/database_config.rb +34 -10
  128. data/lib/active_record/database_configurations/hash_config.rb +107 -31
  129. data/lib/active_record/database_configurations/url_config.rb +38 -13
  130. data/lib/active_record/database_configurations.rb +96 -60
  131. data/lib/active_record/delegated_type.rb +90 -20
  132. data/lib/active_record/deprecator.rb +7 -0
  133. data/lib/active_record/destroy_association_async_job.rb +4 -2
  134. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  135. data/lib/active_record/dynamic_matchers.rb +3 -3
  136. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +68 -0
  140. data/lib/active_record/encryption/configurable.rb +60 -0
  141. data/lib/active_record/encryption/context.rb +42 -0
  142. data/lib/active_record/encryption/contexts.rb +76 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +170 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +53 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  159. data/lib/active_record/encryption/message_serializer.rb +96 -0
  160. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  161. data/lib/active_record/encryption/properties.rb +76 -0
  162. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  163. data/lib/active_record/encryption/scheme.rb +100 -0
  164. data/lib/active_record/encryption.rb +56 -0
  165. data/lib/active_record/enum.rb +163 -63
  166. data/lib/active_record/errors.rb +210 -27
  167. data/lib/active_record/explain.rb +21 -12
  168. data/lib/active_record/explain_registry.rb +11 -6
  169. data/lib/active_record/explain_subscriber.rb +1 -1
  170. data/lib/active_record/fixture_set/file.rb +15 -1
  171. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  172. data/lib/active_record/fixture_set/render_context.rb +2 -0
  173. data/lib/active_record/fixture_set/table_row.rb +70 -14
  174. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  175. data/lib/active_record/fixtures.rb +179 -112
  176. data/lib/active_record/future_result.rb +178 -0
  177. data/lib/active_record/gem_version.rb +4 -4
  178. data/lib/active_record/inheritance.rb +85 -31
  179. data/lib/active_record/insert_all.rb +148 -32
  180. data/lib/active_record/integration.rb +14 -10
  181. data/lib/active_record/internal_metadata.rb +123 -23
  182. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  183. data/lib/active_record/locking/optimistic.rb +43 -27
  184. data/lib/active_record/locking/pessimistic.rb +15 -6
  185. data/lib/active_record/log_subscriber.rb +41 -29
  186. data/lib/active_record/marshalling.rb +56 -0
  187. data/lib/active_record/message_pack.rb +124 -0
  188. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  189. data/lib/active_record/middleware/database_selector.rb +23 -13
  190. data/lib/active_record/middleware/shard_selector.rb +62 -0
  191. data/lib/active_record/migration/command_recorder.rb +113 -16
  192. data/lib/active_record/migration/compatibility.rb +235 -46
  193. data/lib/active_record/migration/default_strategy.rb +22 -0
  194. data/lib/active_record/migration/execution_strategy.rb +19 -0
  195. data/lib/active_record/migration/join_table.rb +1 -1
  196. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  197. data/lib/active_record/migration.rb +374 -177
  198. data/lib/active_record/model_schema.rb +143 -159
  199. data/lib/active_record/nested_attributes.rb +48 -21
  200. data/lib/active_record/no_touching.rb +3 -3
  201. data/lib/active_record/normalization.rb +163 -0
  202. data/lib/active_record/persistence.rb +282 -283
  203. data/lib/active_record/promise.rb +84 -0
  204. data/lib/active_record/query_cache.rb +19 -25
  205. data/lib/active_record/query_logs.rb +189 -0
  206. data/lib/active_record/query_logs_formatter.rb +41 -0
  207. data/lib/active_record/querying.rb +44 -9
  208. data/lib/active_record/railtie.rb +234 -71
  209. data/lib/active_record/railties/controller_runtime.rb +25 -11
  210. data/lib/active_record/railties/databases.rake +189 -256
  211. data/lib/active_record/railties/job_runtime.rb +23 -0
  212. data/lib/active_record/readonly_attributes.rb +41 -3
  213. data/lib/active_record/reflection.rb +325 -103
  214. data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
  215. data/lib/active_record/relation/batches.rb +198 -63
  216. data/lib/active_record/relation/calculations.rb +300 -111
  217. data/lib/active_record/relation/delegation.rb +33 -22
  218. data/lib/active_record/relation/finder_methods.rb +123 -52
  219. data/lib/active_record/relation/merger.rb +26 -19
  220. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  221. data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
  222. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  223. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  224. data/lib/active_record/relation/predicate_builder.rb +29 -22
  225. data/lib/active_record/relation/query_attribute.rb +30 -12
  226. data/lib/active_record/relation/query_methods.rb +842 -150
  227. data/lib/active_record/relation/record_fetch_warning.rb +10 -9
  228. data/lib/active_record/relation/spawn_methods.rb +7 -6
  229. data/lib/active_record/relation/where_clause.rb +15 -36
  230. data/lib/active_record/relation.rb +736 -145
  231. data/lib/active_record/result.rb +67 -54
  232. data/lib/active_record/runtime_registry.rb +71 -13
  233. data/lib/active_record/sanitization.rb +84 -34
  234. data/lib/active_record/schema.rb +39 -23
  235. data/lib/active_record/schema_dumper.rb +90 -31
  236. data/lib/active_record/schema_migration.rb +74 -23
  237. data/lib/active_record/scoping/default.rb +72 -15
  238. data/lib/active_record/scoping/named.rb +5 -13
  239. data/lib/active_record/scoping.rb +65 -34
  240. data/lib/active_record/secure_password.rb +60 -0
  241. data/lib/active_record/secure_token.rb +21 -3
  242. data/lib/active_record/serialization.rb +6 -1
  243. data/lib/active_record/signed_id.rb +30 -9
  244. data/lib/active_record/statement_cache.rb +7 -7
  245. data/lib/active_record/store.rb +10 -10
  246. data/lib/active_record/suppressor.rb +13 -15
  247. data/lib/active_record/table_metadata.rb +7 -3
  248. data/lib/active_record/tasks/database_tasks.rb +277 -149
  249. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  250. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  251. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  252. data/lib/active_record/test_databases.rb +1 -1
  253. data/lib/active_record/test_fixtures.rb +173 -155
  254. data/lib/active_record/testing/query_assertions.rb +121 -0
  255. data/lib/active_record/timestamp.rb +32 -19
  256. data/lib/active_record/token_for.rb +123 -0
  257. data/lib/active_record/touch_later.rb +12 -7
  258. data/lib/active_record/transaction.rb +132 -0
  259. data/lib/active_record/transactions.rb +118 -41
  260. data/lib/active_record/translation.rb +3 -5
  261. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  262. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  263. data/lib/active_record/type/internal/timezone.rb +7 -2
  264. data/lib/active_record/type/serialized.rb +9 -7
  265. data/lib/active_record/type/time.rb +4 -0
  266. data/lib/active_record/type/type_map.rb +17 -20
  267. data/lib/active_record/type.rb +1 -2
  268. data/lib/active_record/type_caster/connection.rb +4 -4
  269. data/lib/active_record/validations/absence.rb +1 -1
  270. data/lib/active_record/validations/associated.rb +13 -7
  271. data/lib/active_record/validations/numericality.rb +5 -4
  272. data/lib/active_record/validations/presence.rb +5 -28
  273. data/lib/active_record/validations/uniqueness.rb +64 -15
  274. data/lib/active_record/validations.rb +12 -5
  275. data/lib/active_record/version.rb +1 -1
  276. data/lib/active_record.rb +444 -32
  277. data/lib/arel/alias_predication.rb +1 -1
  278. data/lib/arel/attributes/attribute.rb +0 -8
  279. data/lib/arel/collectors/bind.rb +2 -0
  280. data/lib/arel/collectors/composite.rb +7 -0
  281. data/lib/arel/collectors/sql_string.rb +1 -1
  282. data/lib/arel/collectors/substitute_binds.rb +1 -1
  283. data/lib/arel/crud.rb +28 -22
  284. data/lib/arel/delete_manager.rb +18 -4
  285. data/lib/arel/errors.rb +10 -0
  286. data/lib/arel/factory_methods.rb +4 -0
  287. data/lib/arel/filter_predications.rb +9 -0
  288. data/lib/arel/insert_manager.rb +2 -3
  289. data/lib/arel/nodes/binary.rb +6 -7
  290. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  291. data/lib/arel/nodes/casted.rb +1 -1
  292. data/lib/arel/nodes/cte.rb +36 -0
  293. data/lib/arel/nodes/delete_statement.rb +12 -13
  294. data/lib/arel/nodes/filter.rb +10 -0
  295. data/lib/arel/nodes/fragments.rb +35 -0
  296. data/lib/arel/nodes/function.rb +1 -0
  297. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  298. data/lib/arel/nodes/insert_statement.rb +2 -2
  299. data/lib/arel/nodes/leading_join.rb +8 -0
  300. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  301. data/lib/arel/nodes/node.rb +115 -5
  302. data/lib/arel/nodes/select_core.rb +2 -2
  303. data/lib/arel/nodes/select_statement.rb +2 -2
  304. data/lib/arel/nodes/sql_literal.rb +13 -0
  305. data/lib/arel/nodes/table_alias.rb +4 -0
  306. data/lib/arel/nodes/update_statement.rb +8 -3
  307. data/lib/arel/nodes.rb +7 -2
  308. data/lib/arel/predications.rb +14 -4
  309. data/lib/arel/select_manager.rb +11 -5
  310. data/lib/arel/table.rb +9 -6
  311. data/lib/arel/tree_manager.rb +8 -15
  312. data/lib/arel/update_manager.rb +20 -5
  313. data/lib/arel/visitors/dot.rb +81 -90
  314. data/lib/arel/visitors/mysql.rb +23 -5
  315. data/lib/arel/visitors/postgresql.rb +1 -22
  316. data/lib/arel/visitors/to_sql.rb +170 -36
  317. data/lib/arel/visitors/visitor.rb +2 -2
  318. data/lib/arel.rb +23 -4
  319. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  320. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  321. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  322. data/lib/rails/generators/active_record/migration.rb +3 -1
  323. data/lib/rails/generators/active_record/model/USAGE +113 -0
  324. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  325. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  326. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  327. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  328. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  329. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  330. metadata +100 -14
  331. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  332. data/lib/active_record/null_relation.rb +0 -67
@@ -3,7 +3,49 @@
3
3
  require "active_support/core_ext/enumerable"
4
4
 
5
5
  module ActiveRecord
6
+ # = Active Record \Calculations
6
7
  module Calculations
8
+ class ColumnAliasTracker # :nodoc:
9
+ def initialize(connection)
10
+ @connection = connection
11
+ @aliases = Hash.new(0)
12
+ end
13
+
14
+ def alias_for(field)
15
+ aliased_name = column_alias_for(field)
16
+
17
+ if @aliases[aliased_name] == 0
18
+ @aliases[aliased_name] = 1
19
+ aliased_name
20
+ else
21
+ # Update the count
22
+ count = @aliases[aliased_name] += 1
23
+ "#{truncate(aliased_name)}_#{count}"
24
+ end
25
+ end
26
+
27
+ private
28
+ # Converts the given field to the value that the database adapter returns as
29
+ # a usable column name:
30
+ #
31
+ # column_alias_for("users.id") # => "users_id"
32
+ # column_alias_for("sum(id)") # => "sum_id"
33
+ # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
34
+ # column_alias_for("count(*)") # => "count_all"
35
+ def column_alias_for(field)
36
+ column_alias = +field
37
+ column_alias.gsub!(/\*/, "all")
38
+ column_alias.gsub!(/\W+/, " ")
39
+ column_alias.strip!
40
+ column_alias.gsub!(/ +/, "_")
41
+ @connection.table_alias_for(column_alias)
42
+ end
43
+
44
+ def truncate(name)
45
+ name.slice(0, @connection.table_alias_length - 2)
46
+ end
47
+ end
48
+
7
49
  # Count the records.
8
50
  #
9
51
  # Person.count
@@ -30,8 +72,7 @@ module ActiveRecord
30
72
  # of each key would be the #count.
31
73
  #
32
74
  # Article.group(:status, :category).count
33
- # # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
34
- # ["published", "business"]=>0, ["published", "technology"]=>2}
75
+ # # => {["draft", "business"]=>10, ["draft", "technology"]=>4, ["published", "technology"]=>2}
35
76
  #
36
77
  # If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
37
78
  #
@@ -40,6 +81,16 @@ module ActiveRecord
40
81
  #
41
82
  # Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
42
83
  # between databases. In invalid cases, an error from the database is thrown.
84
+ #
85
+ # When given a block, loads all records in the relation, if the relation
86
+ # hasn't been loaded yet. Calls the block with each record in the relation.
87
+ # Returns the number of records for which the block returns a truthy value.
88
+ #
89
+ # Person.count { |person| person.age > 21 }
90
+ # # => counts the number of people older that 21
91
+ #
92
+ # Note: If there are a lot of records in the relation, loading all records
93
+ # could result in performance issues.
43
94
  def count(column_name = nil)
44
95
  if block_given?
45
96
  unless column_name.nil?
@@ -52,6 +103,12 @@ module ActiveRecord
52
103
  end
53
104
  end
54
105
 
106
+ # Same as #count, but performs the query asynchronously and returns an
107
+ # ActiveRecord::Promise.
108
+ def async_count(column_name = nil)
109
+ async.count(column_name)
110
+ end
111
+
55
112
  # Calculates the average value on a given column. Returns +nil+ if there's
56
113
  # no row. See #calculate for examples with options.
57
114
  #
@@ -60,6 +117,12 @@ module ActiveRecord
60
117
  calculate(:average, column_name)
61
118
  end
62
119
 
120
+ # Same as #average, but performs the query asynchronously and returns an
121
+ # ActiveRecord::Promise.
122
+ def async_average(column_name)
123
+ async.average(column_name)
124
+ end
125
+
63
126
  # Calculates the minimum value on a given column. The value is returned
64
127
  # with the same data type of the column, or +nil+ if there's no row. See
65
128
  # #calculate for examples with options.
@@ -69,6 +132,12 @@ module ActiveRecord
69
132
  calculate(:minimum, column_name)
70
133
  end
71
134
 
135
+ # Same as #minimum, but performs the query asynchronously and returns an
136
+ # ActiveRecord::Promise.
137
+ def async_minimum(column_name)
138
+ async.minimum(column_name)
139
+ end
140
+
72
141
  # Calculates the maximum value on a given column. The value is returned
73
142
  # with the same data type of the column, or +nil+ if there's no row. See
74
143
  # #calculate for examples with options.
@@ -78,23 +147,42 @@ module ActiveRecord
78
147
  calculate(:maximum, column_name)
79
148
  end
80
149
 
150
+ # Same as #maximum, but performs the query asynchronously and returns an
151
+ # ActiveRecord::Promise.
152
+ def async_maximum(column_name)
153
+ async.maximum(column_name)
154
+ end
155
+
81
156
  # Calculates the sum of values on a given column. The value is returned
82
157
  # with the same data type of the column, +0+ if there's no row. See
83
158
  # #calculate for examples with options.
84
159
  #
85
160
  # Person.sum(:age) # => 4562
86
- def sum(column_name = nil)
161
+ #
162
+ # When given a block, loads all records in the relation, if the relation
163
+ # hasn't been loaded yet. Calls the block with each record in the relation.
164
+ # Returns the sum of +initial_value_or_column+ and the block return
165
+ # values:
166
+ #
167
+ # Person.sum { |person| person.age } # => 4562
168
+ # Person.sum(1000) { |person| person.age } # => 5562
169
+ #
170
+ # Note: If there are a lot of records in the relation, loading all records
171
+ # could result in performance issues.
172
+ def sum(initial_value_or_column = 0, &block)
87
173
  if block_given?
88
- unless column_name.nil?
89
- raise ArgumentError, "Column name argument is not supported when a block is passed."
90
- end
91
-
92
- super()
174
+ map(&block).sum(initial_value_or_column)
93
175
  else
94
- calculate(:sum, column_name)
176
+ calculate(:sum, initial_value_or_column)
95
177
  end
96
178
  end
97
179
 
180
+ # Same as #sum, but performs the query asynchronously and returns an
181
+ # ActiveRecord::Promise.
182
+ def async_sum(identity_or_column = nil)
183
+ async.sum(identity_or_column)
184
+ end
185
+
98
186
  # This calculates aggregate values in the given column. Methods for #count, #sum, #average,
99
187
  # #minimum, and #maximum have been added as shortcuts.
100
188
  #
@@ -127,13 +215,26 @@ module ActiveRecord
127
215
  # ...
128
216
  # end
129
217
  def calculate(operation, column_name)
218
+ operation = operation.to_s.downcase
219
+
220
+ if @none
221
+ case operation
222
+ when "count", "sum"
223
+ result = group_values.any? ? Hash.new : 0
224
+ return @async ? Promise::Complete.new(result) : result
225
+ when "average", "minimum", "maximum"
226
+ result = group_values.any? ? Hash.new : nil
227
+ return @async ? Promise::Complete.new(result) : result
228
+ end
229
+ end
230
+
130
231
  if has_include?(column_name)
131
232
  relation = apply_join_dependency
132
233
 
133
- if operation.to_s.downcase == "count"
234
+ if operation == "count"
134
235
  unless distinct_value || distinct_select?(column_name || select_for_count)
135
236
  relation.distinct!
136
- relation.select_values = [ klass.primary_key || table[Arel.star] ]
237
+ relation.select_values = Array(klass.primary_key || table[Arel.star])
137
238
  end
138
239
  # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
139
240
  relation.order_values = [] if group_values.empty?
@@ -146,7 +247,7 @@ module ActiveRecord
146
247
  end
147
248
 
148
249
  # Use #pluck as a shortcut to select one or more attributes without
149
- # loading a bunch of records just to grab the attributes you want.
250
+ # loading an entire record object per row.
150
251
  #
151
252
  # Person.pluck(:name)
152
253
  #
@@ -174,36 +275,62 @@ module ActiveRecord
174
275
  # # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
175
276
  # # => [2, 3]
176
277
  #
278
+ # Comment.joins(:person).pluck(:id, person: [:id])
279
+ # # SELECT comments.id, people.id FROM comments INNER JOIN people on comments.person_id = people.id
280
+ # # => [[1, 2], [2, 2]]
281
+ #
177
282
  # Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))
178
283
  # # SELECT DATEDIFF(updated_at, created_at) FROM people
179
284
  # # => ['0', '27761', '173']
180
285
  #
181
286
  # See also #ids.
182
- #
183
287
  def pluck(*column_names)
288
+ if @none
289
+ if @async
290
+ return Promise::Complete.new([])
291
+ else
292
+ return []
293
+ end
294
+ end
295
+
184
296
  if loaded? && all_attributes?(column_names)
185
- return records.pluck(*column_names)
297
+ result = records.pluck(*column_names)
298
+ if @async
299
+ return Promise::Complete.new(result)
300
+ else
301
+ return result
302
+ end
186
303
  end
187
304
 
188
305
  if has_include?(column_names.first)
189
306
  relation = apply_join_dependency
190
307
  relation.pluck(*column_names)
191
308
  else
192
- klass.disallow_raw_sql!(column_names)
309
+ klass.disallow_raw_sql!(flattened_args(column_names))
193
310
  columns = arel_columns(column_names)
194
311
  relation = spawn
195
312
  relation.select_values = columns
196
313
  result = skip_query_cache_if_necessary do
197
314
  if where_clause.contradiction?
198
- ActiveRecord::Result.new([], [])
315
+ ActiveRecord::Result.empty(async: @async)
199
316
  else
200
- klass.connection.select_all(relation.arel, nil)
317
+ klass.with_connection do |c|
318
+ c.select_all(relation.arel, "#{klass.name} Pluck", async: @async)
319
+ end
201
320
  end
202
321
  end
203
- type_cast_pluck_values(result, columns)
322
+ result.then do |result|
323
+ type_cast_pluck_values(result, columns)
324
+ end
204
325
  end
205
326
  end
206
327
 
328
+ # Same as #pluck, but performs the query asynchronously and returns an
329
+ # ActiveRecord::Promise.
330
+ def async_pluck(*column_names)
331
+ async.pluck(*column_names)
332
+ end
333
+
207
334
  # Pick the value(s) from the named column(s) in the current relation.
208
335
  # This is short-hand for <tt>relation.limit(1).pluck(*column_names).first</tt>, and is primarily useful
209
336
  # when you have a relation that's already narrowed down to a single row.
@@ -220,18 +347,63 @@ module ActiveRecord
220
347
  # # => [ 'David', 'david@loudthinking.com' ]
221
348
  def pick(*column_names)
222
349
  if loaded? && all_attributes?(column_names)
223
- return records.pick(*column_names)
350
+ result = records.pick(*column_names)
351
+ return @async ? Promise::Complete.new(result) : result
224
352
  end
225
353
 
226
- limit(1).pluck(*column_names).first
354
+ limit(1).pluck(*column_names).then(&:first)
355
+ end
356
+
357
+ # Same as #pick, but performs the query asynchronously and returns an
358
+ # ActiveRecord::Promise.
359
+ def async_pick(*column_names)
360
+ async.pick(*column_names)
227
361
  end
228
362
 
229
- # Pluck all the ID's for the relation using the table's primary key
363
+ # Returns the base model's ID's for the relation using the table's primary key
230
364
  #
231
365
  # Person.ids # SELECT people.id FROM people
232
- # Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.person_id = people.id
366
+ # Person.joins(:company).ids # SELECT people.id FROM people INNER JOIN companies ON companies.id = people.company_id
233
367
  def ids
234
- pluck primary_key
368
+ primary_key_array = Array(primary_key)
369
+
370
+ if loaded?
371
+ result = records.map do |record|
372
+ if primary_key_array.one?
373
+ record._read_attribute(primary_key_array.first)
374
+ else
375
+ primary_key_array.map { |column| record._read_attribute(column) }
376
+ end
377
+ end
378
+ return @async ? Promise::Complete.new(result) : result
379
+ end
380
+
381
+ if has_include?(primary_key)
382
+ relation = apply_join_dependency.group(*primary_key_array)
383
+ return relation.ids
384
+ end
385
+
386
+ columns = arel_columns(primary_key_array)
387
+ relation = spawn
388
+ relation.select_values = columns
389
+
390
+ result = if relation.where_clause.contradiction?
391
+ ActiveRecord::Result.empty
392
+ else
393
+ skip_query_cache_if_necessary do
394
+ klass.with_connection do |c|
395
+ c.select_all(relation, "#{klass.name} Ids", async: @async)
396
+ end
397
+ end
398
+ end
399
+
400
+ result.then { |result| type_cast_pluck_values(result, columns) }
401
+ end
402
+
403
+ # Same as #ids, but performs the query asynchronously and returns an
404
+ # ActiveRecord::Promise.
405
+ def async_ids
406
+ async.ids
235
407
  end
236
408
 
237
409
  private
@@ -278,7 +450,7 @@ module ActiveRecord
278
450
  return column_name if Arel::Expressions === column_name
279
451
 
280
452
  arel_column(column_name.to_s) do |name|
281
- Arel.sql(column_name == :all ? "*" : name)
453
+ column_name == :all ? Arel.sql("*", retryable: true) : Arel.sql(name)
282
454
  end
283
455
  end
284
456
 
@@ -286,11 +458,12 @@ module ActiveRecord
286
458
  operation == "count" ? column.count(distinct) : column.public_send(operation)
287
459
  end
288
460
 
289
- def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
290
- if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
461
+ def execute_simple_calculation(operation, column_name, distinct) # :nodoc:
462
+ if build_count_subquery?(operation, column_name, distinct)
291
463
  # Shortcut when limit is zero.
292
464
  return 0 if limit_value == 0
293
465
 
466
+ relation = self
294
467
  query_builder = build_count_subquery(spawn, column_name, distinct)
295
468
  else
296
469
  # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
@@ -305,29 +478,31 @@ module ActiveRecord
305
478
  query_builder = relation.arel
306
479
  end
307
480
 
308
- result = skip_query_cache_if_necessary { @klass.connection.select_all(query_builder) }
481
+ query_result = if relation.where_clause.contradiction?
482
+ ActiveRecord::Result.empty
483
+ else
484
+ skip_query_cache_if_necessary do
485
+ @klass.with_connection do |c|
486
+ c.select_all(query_builder, "#{@klass.name} #{operation.capitalize}", async: @async)
487
+ end
488
+ end
489
+ end
309
490
 
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 = type.subtype if Enum::EnumType === type
314
- type.deserialize(value)
491
+ query_result.then do |result|
492
+ if operation != "count"
493
+ type = column.try(:type_caster) ||
494
+ lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
495
+ type = type.subtype if Enum::EnumType === type
496
+ end
497
+
498
+ type_cast_calculated_value(result.cast_values.first, operation, type)
315
499
  end
316
500
  end
317
501
 
318
- def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
502
+ def execute_grouped_calculation(operation, column_name, distinct) # :nodoc:
319
503
  group_fields = group_values
320
504
  group_fields = group_fields.uniq if group_fields.size > 1
321
505
 
322
- unless group_fields == group_values
323
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
324
- `#{operation}` with group by duplicated fields does no longer affect to result in Rails 7.0.
325
- To migrate to Rails 7.0's behavior, use `uniq!(:group)` to deduplicate group fields
326
- (`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
327
- MSG
328
- group_fields = group_values
329
- end
330
-
331
506
  if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
332
507
  association = klass._reflect_on_association(group_fields.first)
333
508
  associated = association && association.belongs_to? # only count belongs_to associations
@@ -335,86 +510,77 @@ module ActiveRecord
335
510
  end
336
511
  group_fields = arel_columns(group_fields)
337
512
 
338
- group_aliases = group_fields.map { |field|
339
- field = connection.visitor.compile(field) if Arel.arel_node?(field)
340
- column_alias_for(field.to_s.downcase)
341
- }
342
- group_columns = group_aliases.zip(group_fields)
343
-
344
- column = aggregate_column(column_name)
345
- column_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
346
- select_value = operation_over_aggregate_column(column, operation, distinct)
347
- select_value.as(column_alias)
513
+ @klass.with_connection do |connection|
514
+ column_alias_tracker = ColumnAliasTracker.new(connection)
348
515
 
349
- select_values = [select_value]
350
- select_values += self.select_values unless having_clause.empty?
516
+ group_aliases = group_fields.map { |field|
517
+ field = connection.visitor.compile(field) if Arel.arel_node?(field)
518
+ column_alias_tracker.alias_for(field.to_s.downcase)
519
+ }
520
+ group_columns = group_aliases.zip(group_fields)
351
521
 
352
- select_values.concat group_columns.map { |aliaz, field|
353
- if field.respond_to?(:as)
354
- field.as(aliaz)
355
- else
356
- "#{field} AS #{aliaz}"
357
- end
358
- }
522
+ column = aggregate_column(column_name)
523
+ column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
524
+ select_value = operation_over_aggregate_column(column, operation, distinct)
525
+ select_value.as(adapter_class.quote_column_name(column_alias))
359
526
 
360
- relation = except(:group).distinct!(false)
361
- relation.group_values = group_fields
362
- relation.select_values = select_values
527
+ select_values = [select_value]
528
+ select_values += self.select_values unless having_clause.empty?
363
529
 
364
- calculated_data = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, nil) }
530
+ select_values.concat group_columns.map { |aliaz, field|
531
+ aliaz = adapter_class.quote_column_name(aliaz)
532
+ if field.respond_to?(:as)
533
+ field.as(aliaz)
534
+ else
535
+ "#{field} AS #{aliaz}"
536
+ end
537
+ }
365
538
 
366
- if association
367
- key_ids = calculated_data.collect { |row| row[group_aliases.first] }
368
- key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
369
- key_records = key_records.index_by(&:id)
370
- end
539
+ relation = except(:group).distinct!(false)
540
+ relation.group_values = group_fields
541
+ relation.select_values = select_values
371
542
 
372
- key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
373
- types[aliaz] = type_for(col_name) do
374
- calculated_data.column_types.fetch(aliaz, Type.default_value)
543
+ result = skip_query_cache_if_necessary do
544
+ connection.select_all(relation.arel, "#{@klass.name} #{operation.capitalize}", async: @async)
375
545
  end
376
- end
377
546
 
378
- hash_rows = calculated_data.cast_values(key_types).map! do |row|
379
- calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
380
- hash[col_name] = row[i]
381
- end
382
- end
547
+ result.then do |calculated_data|
548
+ if association
549
+ key_ids = calculated_data.collect { |row| row[group_aliases.first] }
550
+ key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
551
+ key_records = key_records.index_by(&:id)
552
+ end
383
553
 
384
- type = nil
385
- hash_rows.each_with_object({}) do |row, result|
386
- key = group_aliases.map { |aliaz| row[aliaz] }
387
- key = key.first if key.size == 1
388
- key = key_records[key] if associated
554
+ key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
555
+ types[aliaz] = col_name.try(:type_caster) ||
556
+ type_for(col_name) do
557
+ calculated_data.column_types.fetch(aliaz, Type.default_value)
558
+ end
559
+ end
560
+
561
+ hash_rows = calculated_data.cast_values(key_types).map! do |row|
562
+ calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
563
+ hash[col_name] = row[i]
564
+ end
565
+ end
389
566
 
390
- result[key] = type_cast_calculated_value(row[column_alias], operation) do |value|
391
- unless type
567
+ if operation != "count"
392
568
  type = column.try(:type_caster) ||
393
569
  lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
394
570
  type = type.subtype if Enum::EnumType === type
395
571
  end
396
- type.deserialize(value)
572
+
573
+ hash_rows.each_with_object({}) do |row, result|
574
+ key = group_aliases.map { |aliaz| row[aliaz] }
575
+ key = key.first if key.size == 1
576
+ key = key_records[key] if associated
577
+
578
+ result[key] = type_cast_calculated_value(row[column_alias], operation, type)
579
+ end
397
580
  end
398
581
  end
399
582
  end
400
583
 
401
- # Converts the given field to the value that the database adapter returns as
402
- # a usable column name:
403
- #
404
- # column_alias_for("users.id") # => "users_id"
405
- # column_alias_for("sum(id)") # => "sum_id"
406
- # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
407
- # column_alias_for("count(*)") # => "count_all"
408
- def column_alias_for(field)
409
- column_alias = +field
410
- column_alias.gsub!(/\*/, "all")
411
- column_alias.gsub!(/\W+/, " ")
412
- column_alias.strip!
413
- column_alias.gsub!(/ +/, "_")
414
-
415
- connection.table_alias_for(column_alias)
416
- end
417
-
418
584
  def type_for(field, &block)
419
585
  field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
420
586
  @klass.type_for_attribute(field_name, &block)
@@ -438,35 +604,58 @@ module ActiveRecord
438
604
  klass.attribute_types.fetch(name = result.columns[i]) do
439
605
  join_dependencies ||= build_join_dependencies
440
606
  lookup_cast_type_from_join_dependencies(name, join_dependencies) ||
441
- result.column_types[name] || Type.default_value
607
+ result.column_types[i] || Type.default_value
442
608
  end
443
609
  end
444
610
  end
445
611
  result.cast_values(cast_types)
446
612
  end
447
613
 
448
- def type_cast_calculated_value(value, operation)
614
+ def type_cast_calculated_value(value, operation, type)
449
615
  case operation
450
616
  when "count"
451
617
  value.to_i
452
618
  when "sum"
453
- yield value || 0
619
+ type.deserialize(value || 0)
454
620
  when "average"
455
- value&.respond_to?(:to_d) ? value.to_d : value
621
+ case type.type
622
+ when :integer, :decimal
623
+ value&.to_d
624
+ else
625
+ type.deserialize(value)
626
+ end
456
627
  else # "minimum", "maximum"
457
- yield value
628
+ type.deserialize(value)
458
629
  end
459
630
  end
460
631
 
461
632
  def select_for_count
462
633
  if select_values.present?
463
634
  return select_values.first if select_values.one?
464
- select_values.join(", ")
635
+
636
+ select_values.map do |field|
637
+ column = arel_column(field.to_s) do |attr_name|
638
+ Arel.sql(attr_name)
639
+ end
640
+
641
+ if column.is_a?(Arel::Nodes::SqlLiteral)
642
+ column
643
+ else
644
+ "#{adapter_class.quote_table_name(column.relation.name)}.#{adapter_class.quote_column_name(column.name)}"
645
+ end
646
+ end.join(", ")
465
647
  else
466
648
  :all
467
649
  end
468
650
  end
469
651
 
652
+ def build_count_subquery?(operation, column_name, distinct)
653
+ # SQLite and older MySQL does not support `COUNT DISTINCT` with `*` or
654
+ # multiple columns, so we need to use subquery for this.
655
+ operation == "count" &&
656
+ (((column_name == :all || select_values.many?) && distinct) || has_limit_or_offset?)
657
+ end
658
+
470
659
  def build_count_subquery(relation, column_name, distinct)
471
660
  if column_name == :all
472
661
  column_alias = Arel.star
@@ -476,7 +665,7 @@ module ActiveRecord
476
665
  relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
477
666
  end
478
667
 
479
- subquery_alias = Arel.sql("subquery_for_count")
668
+ subquery_alias = Arel.sql("subquery_for_count", retryable: true)
480
669
  select_value = operation_over_aggregate_column(column_alias, "count", false)
481
670
 
482
671
  relation.build_subquery(subquery_alias, select_value)