activerecord 6.0.0 → 7.2.3

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 (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -594
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +34 -34
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +22 -20
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +41 -30
  9. data/lib/active_record/associations/association.rb +106 -41
  10. data/lib/active_record/associations/association_scope.rb +30 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +69 -14
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
  13. data/lib/active_record/associations/builder/association.rb +39 -6
  14. data/lib/active_record/associations/builder/belongs_to.rb +47 -17
  15. data/lib/active_record/associations/builder/collection_association.rb +14 -6
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
  17. data/lib/active_record/associations/builder/has_many.rb +7 -3
  18. data/lib/active_record/associations/builder/has_one.rb +13 -16
  19. data/lib/active_record/associations/builder/singular_association.rb +7 -3
  20. data/lib/active_record/associations/collection_association.rb +90 -53
  21. data/lib/active_record/associations/collection_proxy.rb +54 -19
  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 +21 -1
  25. data/lib/active_record/associations/has_many_association.rb +41 -10
  26. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  27. data/lib/active_record/associations/has_one_association.rb +33 -9
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
  30. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  31. data/lib/active_record/associations/join_dependency.rb +97 -54
  32. data/lib/active_record/associations/nested_error.rb +47 -0
  33. data/lib/active_record/associations/preloader/association.rb +237 -54
  34. data/lib/active_record/associations/preloader/batch.rb +48 -0
  35. data/lib/active_record/associations/preloader/branch.rb +153 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +51 -17
  37. data/lib/active_record/associations/preloader.rb +55 -121
  38. data/lib/active_record/associations/singular_association.rb +16 -4
  39. data/lib/active_record/associations/through_association.rb +26 -15
  40. data/lib/active_record/associations.rb +454 -440
  41. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  42. data/lib/active_record/attribute_assignment.rb +11 -14
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
  44. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  45. data/lib/active_record/attribute_methods/dirty.rb +75 -34
  46. data/lib/active_record/attribute_methods/primary_key.rb +53 -31
  47. data/lib/active_record/attribute_methods/query.rb +31 -22
  48. data/lib/active_record/attribute_methods/read.rb +16 -17
  49. data/lib/active_record/attribute_methods/serialization.rb +177 -35
  50. data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
  51. data/lib/active_record/attribute_methods/write.rb +16 -28
  52. data/lib/active_record/attribute_methods.rb +227 -100
  53. data/lib/active_record/attributes.rb +94 -56
  54. data/lib/active_record/autosave_association.rb +119 -73
  55. data/lib/active_record/base.rb +31 -21
  56. data/lib/active_record/callbacks.rb +168 -55
  57. data/lib/active_record/coders/column_serializer.rb +61 -0
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +70 -25
  60. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
  76. data/lib/active_record/connection_adapters/column.rb +28 -1
  77. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  78. data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
  79. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
  80. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  81. data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
  82. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
  83. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
  84. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
  85. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  87. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  88. data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
  89. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  90. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  91. data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
  92. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
  95. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  101. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
  106. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  110. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
  111. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
  121. data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  123. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  124. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
  131. data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
  132. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  133. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  134. data/lib/active_record/connection_adapters.rb +176 -0
  135. data/lib/active_record/connection_handling.rb +243 -115
  136. data/lib/active_record/core.rb +481 -199
  137. data/lib/active_record/counter_cache.rb +69 -32
  138. data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
  139. data/lib/active_record/database_configurations/database_config.rb +77 -10
  140. data/lib/active_record/database_configurations/hash_config.rb +148 -26
  141. data/lib/active_record/database_configurations/url_config.rb +44 -45
  142. data/lib/active_record/database_configurations.rb +190 -114
  143. data/lib/active_record/delegated_type.rb +279 -0
  144. data/lib/active_record/deprecator.rb +7 -0
  145. data/lib/active_record/destroy_association_async_job.rb +38 -0
  146. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  147. data/lib/active_record/dynamic_matchers.rb +5 -6
  148. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  149. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  150. data/lib/active_record/encryption/cipher.rb +53 -0
  151. data/lib/active_record/encryption/config.rb +68 -0
  152. data/lib/active_record/encryption/configurable.rb +60 -0
  153. data/lib/active_record/encryption/context.rb +42 -0
  154. data/lib/active_record/encryption/contexts.rb +76 -0
  155. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  156. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  157. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  158. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  159. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  160. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  161. data/lib/active_record/encryption/encryptor.rb +171 -0
  162. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  163. data/lib/active_record/encryption/errors.rb +15 -0
  164. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  165. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  166. data/lib/active_record/encryption/key.rb +28 -0
  167. data/lib/active_record/encryption/key_generator.rb +53 -0
  168. data/lib/active_record/encryption/key_provider.rb +46 -0
  169. data/lib/active_record/encryption/message.rb +33 -0
  170. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  171. data/lib/active_record/encryption/message_serializer.rb +96 -0
  172. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  173. data/lib/active_record/encryption/properties.rb +76 -0
  174. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  175. data/lib/active_record/encryption/scheme.rb +100 -0
  176. data/lib/active_record/encryption.rb +58 -0
  177. data/lib/active_record/enum.rb +224 -73
  178. data/lib/active_record/errors.rb +254 -36
  179. data/lib/active_record/explain.rb +30 -17
  180. data/lib/active_record/explain_registry.rb +11 -6
  181. data/lib/active_record/explain_subscriber.rb +2 -2
  182. data/lib/active_record/fixture_set/file.rb +22 -15
  183. data/lib/active_record/fixture_set/model_metadata.rb +15 -6
  184. data/lib/active_record/fixture_set/render_context.rb +3 -1
  185. data/lib/active_record/fixture_set/table_row.rb +88 -16
  186. data/lib/active_record/fixture_set/table_rows.rb +4 -5
  187. data/lib/active_record/fixtures.rb +229 -116
  188. data/lib/active_record/future_result.rb +178 -0
  189. data/lib/active_record/gem_version.rb +4 -4
  190. data/lib/active_record/inheritance.rb +121 -48
  191. data/lib/active_record/insert_all.rb +178 -29
  192. data/lib/active_record/integration.rb +16 -14
  193. data/lib/active_record/internal_metadata.rb +132 -21
  194. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  195. data/lib/active_record/locking/optimistic.rb +64 -33
  196. data/lib/active_record/locking/pessimistic.rb +21 -8
  197. data/lib/active_record/log_subscriber.rb +61 -30
  198. data/lib/active_record/marshalling.rb +59 -0
  199. data/lib/active_record/message_pack.rb +124 -0
  200. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  201. data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
  202. data/lib/active_record/middleware/database_selector.rb +25 -13
  203. data/lib/active_record/middleware/shard_selector.rb +62 -0
  204. data/lib/active_record/migration/command_recorder.rb +160 -55
  205. data/lib/active_record/migration/compatibility.rb +286 -43
  206. data/lib/active_record/migration/default_strategy.rb +22 -0
  207. data/lib/active_record/migration/execution_strategy.rb +19 -0
  208. data/lib/active_record/migration/join_table.rb +1 -2
  209. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  210. data/lib/active_record/migration.rb +421 -193
  211. data/lib/active_record/model_schema.rb +217 -125
  212. data/lib/active_record/nested_attributes.rb +62 -27
  213. data/lib/active_record/no_touching.rb +4 -4
  214. data/lib/active_record/normalization.rb +163 -0
  215. data/lib/active_record/persistence.rb +322 -319
  216. data/lib/active_record/promise.rb +84 -0
  217. data/lib/active_record/query_cache.rb +18 -15
  218. data/lib/active_record/query_logs.rb +193 -0
  219. data/lib/active_record/query_logs_formatter.rb +41 -0
  220. data/lib/active_record/querying.rb +54 -14
  221. data/lib/active_record/railtie.rb +250 -72
  222. data/lib/active_record/railties/console_sandbox.rb +2 -4
  223. data/lib/active_record/railties/controller_runtime.rb +25 -11
  224. data/lib/active_record/railties/databases.rake +312 -197
  225. data/lib/active_record/railties/job_runtime.rb +23 -0
  226. data/lib/active_record/readonly_attributes.rb +45 -3
  227. data/lib/active_record/reflection.rb +389 -146
  228. data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
  229. data/lib/active_record/relation/batches.rb +214 -73
  230. data/lib/active_record/relation/calculations.rb +379 -124
  231. data/lib/active_record/relation/delegation.rb +36 -23
  232. data/lib/active_record/relation/finder_methods.rb +159 -49
  233. data/lib/active_record/relation/from_clause.rb +5 -1
  234. data/lib/active_record/relation/merger.rb +41 -33
  235. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
  236. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
  237. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
  238. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  239. data/lib/active_record/relation/predicate_builder.rb +79 -53
  240. data/lib/active_record/relation/query_attribute.rb +30 -12
  241. data/lib/active_record/relation/query_methods.rb +1156 -279
  242. data/lib/active_record/relation/record_fetch_warning.rb +12 -11
  243. data/lib/active_record/relation/spawn_methods.rb +10 -9
  244. data/lib/active_record/relation/where_clause.rb +100 -66
  245. data/lib/active_record/relation.rb +829 -194
  246. data/lib/active_record/result.rb +76 -56
  247. data/lib/active_record/runtime_registry.rb +71 -13
  248. data/lib/active_record/sanitization.rb +86 -47
  249. data/lib/active_record/schema.rb +39 -23
  250. data/lib/active_record/schema_dumper.rb +140 -33
  251. data/lib/active_record/schema_migration.rb +74 -29
  252. data/lib/active_record/scoping/default.rb +73 -19
  253. data/lib/active_record/scoping/named.rb +10 -28
  254. data/lib/active_record/scoping.rb +65 -35
  255. data/lib/active_record/secure_password.rb +60 -0
  256. data/lib/active_record/secure_token.rb +34 -8
  257. data/lib/active_record/serialization.rb +11 -4
  258. data/lib/active_record/signed_id.rb +138 -0
  259. data/lib/active_record/statement_cache.rb +26 -10
  260. data/lib/active_record/store.rb +19 -14
  261. data/lib/active_record/suppressor.rb +15 -17
  262. data/lib/active_record/table_metadata.rb +46 -36
  263. data/lib/active_record/tasks/database_tasks.rb +371 -205
  264. data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
  265. data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
  266. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
  267. data/lib/active_record/test_databases.rb +5 -4
  268. data/lib/active_record/test_fixtures.rb +189 -104
  269. data/lib/active_record/testing/query_assertions.rb +121 -0
  270. data/lib/active_record/timestamp.rb +35 -25
  271. data/lib/active_record/token_for.rb +123 -0
  272. data/lib/active_record/touch_later.rb +31 -27
  273. data/lib/active_record/transaction.rb +132 -0
  274. data/lib/active_record/transactions.rb +131 -99
  275. data/lib/active_record/translation.rb +3 -5
  276. data/lib/active_record/type/adapter_specific_registry.rb +33 -18
  277. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  278. data/lib/active_record/type/internal/timezone.rb +7 -2
  279. data/lib/active_record/type/serialized.rb +11 -6
  280. data/lib/active_record/type/time.rb +14 -0
  281. data/lib/active_record/type/type_map.rb +17 -21
  282. data/lib/active_record/type/unsigned_integer.rb +0 -1
  283. data/lib/active_record/type.rb +7 -2
  284. data/lib/active_record/type_caster/connection.rb +4 -5
  285. data/lib/active_record/type_caster/map.rb +8 -5
  286. data/lib/active_record/validations/absence.rb +1 -1
  287. data/lib/active_record/validations/associated.rb +13 -8
  288. data/lib/active_record/validations/numericality.rb +36 -0
  289. data/lib/active_record/validations/presence.rb +5 -28
  290. data/lib/active_record/validations/uniqueness.rb +88 -18
  291. data/lib/active_record/validations.rb +15 -8
  292. data/lib/active_record/version.rb +1 -1
  293. data/lib/active_record.rb +446 -40
  294. data/lib/arel/alias_predication.rb +1 -1
  295. data/lib/arel/attributes/attribute.rb +4 -8
  296. data/lib/arel/collectors/bind.rb +8 -1
  297. data/lib/arel/collectors/composite.rb +15 -0
  298. data/lib/arel/collectors/sql_string.rb +7 -0
  299. data/lib/arel/collectors/substitute_binds.rb +7 -0
  300. data/lib/arel/crud.rb +30 -22
  301. data/lib/arel/delete_manager.rb +23 -4
  302. data/lib/arel/errors.rb +10 -0
  303. data/lib/arel/factory_methods.rb +4 -0
  304. data/lib/arel/filter_predications.rb +9 -0
  305. data/lib/arel/insert_manager.rb +2 -3
  306. data/lib/arel/nodes/binary.rb +82 -9
  307. data/lib/arel/nodes/bind_param.rb +8 -0
  308. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  309. data/lib/arel/nodes/casted.rb +22 -10
  310. data/lib/arel/nodes/cte.rb +36 -0
  311. data/lib/arel/nodes/delete_statement.rb +14 -13
  312. data/lib/arel/nodes/equality.rb +6 -9
  313. data/lib/arel/nodes/filter.rb +10 -0
  314. data/lib/arel/nodes/fragments.rb +35 -0
  315. data/lib/arel/nodes/function.rb +1 -0
  316. data/lib/arel/nodes/grouping.rb +3 -0
  317. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  318. data/lib/arel/nodes/in.rb +8 -1
  319. data/lib/arel/nodes/infix_operation.rb +13 -1
  320. data/lib/arel/nodes/insert_statement.rb +2 -2
  321. data/lib/arel/nodes/join_source.rb +1 -1
  322. data/lib/arel/nodes/leading_join.rb +8 -0
  323. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  324. data/lib/arel/nodes/node.rb +122 -11
  325. data/lib/arel/nodes/ordering.rb +27 -0
  326. data/lib/arel/nodes/select_core.rb +2 -2
  327. data/lib/arel/nodes/select_statement.rb +2 -2
  328. data/lib/arel/nodes/sql_literal.rb +16 -0
  329. data/lib/arel/nodes/table_alias.rb +11 -3
  330. data/lib/arel/nodes/unary.rb +0 -1
  331. data/lib/arel/nodes/update_statement.rb +11 -4
  332. data/lib/arel/nodes.rb +10 -3
  333. data/lib/arel/predications.rb +31 -28
  334. data/lib/arel/select_manager.rb +18 -9
  335. data/lib/arel/table.rb +21 -10
  336. data/lib/arel/tree_manager.rb +8 -15
  337. data/lib/arel/update_manager.rb +25 -5
  338. data/lib/arel/visitors/dot.rb +94 -90
  339. data/lib/arel/visitors/mysql.rb +34 -6
  340. data/lib/arel/visitors/postgresql.rb +5 -16
  341. data/lib/arel/visitors/sqlite.rb +25 -1
  342. data/lib/arel/visitors/to_sql.rb +227 -81
  343. data/lib/arel/visitors/visitor.rb +2 -3
  344. data/lib/arel/visitors.rb +0 -7
  345. data/lib/arel.rb +37 -15
  346. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  347. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  348. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  349. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  350. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
  351. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  352. data/lib/rails/generators/active_record/migration.rb +9 -3
  353. data/lib/rails/generators/active_record/model/USAGE +113 -0
  354. data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
  355. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  356. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  357. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  358. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  359. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  360. metadata +117 -30
  361. data/lib/active_record/attribute_decorators.rb +0 -90
  362. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  363. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  364. data/lib/active_record/define_callbacks.rb +0 -22
  365. data/lib/active_record/null_relation.rb +0 -68
  366. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  367. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  368. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  369. data/lib/arel/attributes.rb +0 -22
  370. data/lib/arel/visitors/depth_first.rb +0 -204
  371. data/lib/arel/visitors/ibm_db.rb +0 -34
  372. data/lib/arel/visitors/informix.rb +0 -62
  373. data/lib/arel/visitors/mssql.rb +0 -157
  374. data/lib/arel/visitors/oracle.rb +0 -159
  375. data/lib/arel/visitors/oracle12.rb +0 -66
  376. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -9,7 +9,14 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  def queries
12
- [associated_table.association_join_foreign_key.to_s => ids]
12
+ if associated_table.join_foreign_key.is_a?(Array)
13
+ id_list = ids
14
+ id_list = id_list.pluck(primary_key) if id_list.is_a?(Relation)
15
+
16
+ id_list.map { |ids_set| associated_table.join_foreign_key.zip(ids_set).to_h }
17
+ else
18
+ [ associated_table.join_foreign_key => ids ]
19
+ end
13
20
  end
14
21
 
15
22
  private
@@ -18,22 +25,50 @@ module ActiveRecord
18
25
  def ids
19
26
  case value
20
27
  when Relation
21
- value.select_values.empty? ? value.select(primary_key) : value
28
+ relation = value
29
+ relation = relation.select(primary_key) if select_clause?
30
+ relation = relation.where(primary_type => polymorphic_name) if polymorphic_clause?
31
+ relation
22
32
  when Array
23
33
  value.map { |v| convert_to_id(v) }
24
34
  else
25
- convert_to_id(value)
35
+ [convert_to_id(value)]
26
36
  end
27
37
  end
28
38
 
29
39
  def primary_key
30
- associated_table.association_join_primary_key
40
+ associated_table.join_primary_key
41
+ end
42
+
43
+ def primary_type
44
+ associated_table.join_primary_type
45
+ end
46
+
47
+ def polymorphic_name
48
+ associated_table.polymorphic_name_association
49
+ end
50
+
51
+ def select_clause?
52
+ value.select_values.empty?
53
+ end
54
+
55
+ def polymorphic_clause?
56
+ primary_type && !value.where_values_hash.has_key?(primary_type)
31
57
  end
32
58
 
33
59
  def convert_to_id(value)
34
- case value
35
- when Base
36
- value._read_attribute(primary_key)
60
+ if primary_key.is_a?(Array)
61
+ primary_key.map do |attribute|
62
+ next nil if value.nil?
63
+
64
+ if attribute == "id"
65
+ value.id_value
66
+ else
67
+ value.public_send(attribute)
68
+ end
69
+ end
70
+ elsif value.respond_to?(primary_key)
71
+ value.public_send(primary_key)
37
72
  else
38
73
  value
39
74
  end
@@ -9,11 +9,13 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  def queries
12
+ return [ associated_table.join_foreign_key => values ] if values.empty?
13
+
12
14
  type_to_ids_mapping.map do |type, ids|
13
- {
14
- associated_table.association_foreign_type.to_s => type,
15
- associated_table.association_foreign_key.to_s => ids
16
- }
15
+ query = {}
16
+ query[associated_table.join_foreign_type] = type if type
17
+ query[associated_table.join_foreign_key] = ids
18
+ query
17
19
  end
18
20
  end
19
21
 
@@ -23,29 +25,34 @@ module ActiveRecord
23
25
  def type_to_ids_mapping
24
26
  default_hash = Hash.new { |hsh, key| hsh[key] = [] }
25
27
  values.each_with_object(default_hash) do |value, hash|
26
- hash[klass(value).polymorphic_name] << convert_to_id(value)
28
+ hash[klass(value)&.polymorphic_name] << convert_to_id(value)
27
29
  end
28
30
  end
29
31
 
30
32
  def primary_key(value)
31
- associated_table.association_join_primary_key(klass(value))
33
+ associated_table.join_primary_key(klass(value))
32
34
  end
33
35
 
34
36
  def klass(value)
35
- case value
36
- when Base
37
+ if value.is_a?(Base)
37
38
  value.class
38
- when Relation
39
+ elsif value.is_a?(Relation)
39
40
  value.klass
40
41
  end
41
42
  end
42
43
 
43
44
  def convert_to_id(value)
44
- case value
45
- when Base
46
- value._read_attribute(primary_key(value))
47
- when Relation
45
+ if value.is_a?(Base)
46
+ primary_key = primary_key(value)
47
+ if primary_key.is_a?(Array)
48
+ primary_key.map { |column| value._read_attribute(column) }
49
+ else
50
+ value._read_attribute(primary_key)
51
+ end
52
+ elsif value.is_a?(Relation)
48
53
  value.select(primary_key(value))
54
+ else
55
+ value
49
56
  end
50
57
  end
51
58
  end
@@ -9,7 +9,11 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  if value.select_values.empty?
12
- value = value.select(value.arel_attribute(value.klass.primary_key))
12
+ if value.klass.composite_primary_key?
13
+ raise ArgumentError, "Cannot map composite primary key #{value.klass.primary_key} to #{attribute.name}"
14
+ else
15
+ value = value.select(value.table[value.klass.primary_key])
16
+ end
13
17
  end
14
18
 
15
19
  attribute.in(value.arel)
@@ -2,34 +2,37 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class PredicateBuilder # :nodoc:
5
- delegate :resolve_column_aliases, to: :table
5
+ require "active_record/relation/predicate_builder/array_handler"
6
+ require "active_record/relation/predicate_builder/basic_object_handler"
7
+ require "active_record/relation/predicate_builder/range_handler"
8
+ require "active_record/relation/predicate_builder/relation_handler"
9
+ require "active_record/relation/predicate_builder/association_query_value"
10
+ require "active_record/relation/predicate_builder/polymorphic_array_value"
6
11
 
7
12
  def initialize(table)
8
13
  @table = table
9
14
  @handlers = []
10
15
 
11
16
  register_handler(BasicObject, BasicObjectHandler.new(self))
12
- register_handler(Base, BaseHandler.new(self))
13
17
  register_handler(Range, RangeHandler.new(self))
14
18
  register_handler(Relation, RelationHandler.new)
15
19
  register_handler(Array, ArrayHandler.new(self))
16
20
  register_handler(Set, ArrayHandler.new(self))
17
21
  end
18
22
 
19
- def build_from_hash(attributes)
23
+ def build_from_hash(attributes, &block)
20
24
  attributes = convert_dot_notation_to_hash(attributes)
21
- expand_from_hash(attributes)
25
+ expand_from_hash(attributes, &block)
22
26
  end
23
27
 
24
28
  def self.references(attributes)
25
- attributes.map do |key, value|
29
+ attributes.each_with_object([]) do |(key, value), result|
26
30
  if value.is_a?(Hash)
27
- key
28
- else
29
- key = key.to_s
30
- key.split(".").first if key.include?(".")
31
+ result << Arel.sql(key, retryable: true)
32
+ elsif (idx = key.rindex("."))
33
+ result << Arel.sql(key[0, idx], retryable: true)
31
34
  end
32
- end.compact
35
+ end
33
36
  end
34
37
 
35
38
  # Define how a class is converted to Arel nodes when passed to +where+.
@@ -47,27 +50,42 @@ module ActiveRecord
47
50
  @handlers.unshift([klass, handler])
48
51
  end
49
52
 
50
- def build(attribute, value)
51
- if table.type(attribute.name).force_equality?(value)
53
+ def [](attr_name, value, operator = nil)
54
+ build(table.arel_table[attr_name], value, operator)
55
+ end
56
+
57
+ def build(attribute, value, operator = nil)
58
+ value = value.id if value.respond_to?(:id)
59
+ if operator ||= table.type(attribute.name).force_equality?(value) && :eq
52
60
  bind = build_bind_attribute(attribute.name, value)
53
- attribute.eq(bind)
61
+ attribute.public_send(operator, bind)
54
62
  else
55
63
  handler_for(value).call(attribute, value)
56
64
  end
57
65
  end
58
66
 
59
67
  def build_bind_attribute(column_name, value)
60
- attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
61
- Arel::Nodes::BindParam.new(attr)
68
+ Relation::QueryAttribute.new(column_name, value, table.type(column_name))
69
+ end
70
+
71
+ def resolve_arel_attribute(table_name, column_name, &block)
72
+ table.associated_table(table_name, &block).arel_table[column_name]
62
73
  end
63
74
 
64
75
  protected
65
- def expand_from_hash(attributes)
76
+ def expand_from_hash(attributes, &block)
66
77
  return ["1=0"] if attributes.empty?
67
78
 
68
79
  attributes.flat_map do |key, value|
69
- if value.is_a?(Hash) && !table.has_column?(key)
70
- associated_predicate_builder(key).expand_from_hash(value)
80
+ if key.is_a?(Array)
81
+ queries = Array(value).map do |ids_set|
82
+ raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
83
+ expand_from_hash(key.zip(ids_set).to_h)
84
+ end
85
+ grouping_queries(queries)
86
+ elsif value.is_a?(Hash) && !table.has_column?(key)
87
+ table.associated_table(key, &block)
88
+ .predicate_builder.expand_from_hash(value.stringify_keys)
71
89
  elsif table.associated_with?(key)
72
90
  # Find the foreign key when using queries such as:
73
91
  # Post.where(author: author)
@@ -76,18 +94,22 @@ module ActiveRecord
76
94
  # PriceEstimate.where(estimate_of: treasure)
77
95
  associated_table = table.associated_table(key)
78
96
  if associated_table.polymorphic_association?
79
- case value.is_a?(Array) ? value.first : value
80
- when Base, Relation
81
- value = [value] unless value.is_a?(Array)
82
- klass = PolymorphicArrayValue
83
- end
97
+ value = [value] unless value.is_a?(Array)
98
+ klass = PolymorphicArrayValue
99
+ elsif associated_table.through_association?
100
+ next associated_table.predicate_builder.expand_from_hash(
101
+ associated_table.primary_key => value
102
+ )
84
103
  end
85
104
 
86
105
  klass ||= AssociationQueryValue
87
- queries = klass.new(associated_table, value).queries.map do |query|
88
- expand_from_hash(query).reduce(&:and)
106
+ queries = klass.new(associated_table, value).queries.map! do |query|
107
+ # If the query produced is identical to attributes don't go any deeper.
108
+ # Prevents stack level too deep errors when association and foreign_key are identical.
109
+ query == attributes ? self[key, value] : expand_from_hash(query)
89
110
  end
90
- queries.reduce(&:or)
111
+
112
+ grouping_queries(queries)
91
113
  elsif table.aggregated_with?(key)
92
114
  mapping = table.reflect_on_aggregation(key).mapping
93
115
  values = value.nil? ? [nil] : Array.wrap(value)
@@ -96,17 +118,18 @@ module ActiveRecord
96
118
  values = values.map do |object|
97
119
  object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
98
120
  end
99
- build(table.arel_attribute(column_name), values)
121
+ self[column_name, values]
100
122
  else
101
123
  queries = values.map do |object|
102
124
  mapping.map do |field_attr, aggregate_attr|
103
- build(table.arel_attribute(field_attr), object.try!(aggregate_attr))
104
- end.reduce(&:and)
125
+ self[field_attr, object.try!(aggregate_attr)]
126
+ end
105
127
  end
106
- queries.reduce(&:or)
128
+
129
+ grouping_queries(queries)
107
130
  end
108
131
  else
109
- build(table.arel_attribute(key), value)
132
+ self[key, value]
110
133
  end
111
134
  end
112
135
  end
@@ -114,24 +137,36 @@ module ActiveRecord
114
137
  private
115
138
  attr_reader :table
116
139
 
117
- def associated_predicate_builder(association_name)
118
- self.class.new(table.associated_table(association_name))
140
+ def grouping_queries(queries)
141
+ if queries.one?
142
+ queries.first
143
+ else
144
+ queries.map! { |query| query.reduce(&:and) }
145
+ queries = Arel::Nodes::Or.new(queries)
146
+ Arel::Nodes::Grouping.new(queries)
147
+ end
119
148
  end
120
149
 
121
150
  def convert_dot_notation_to_hash(attributes)
122
- dot_notation = attributes.select do |k, v|
123
- k.include?(".") && !v.is_a?(Hash)
124
- end
125
-
126
- dot_notation.each_key do |key|
127
- table_name, column_name = key.split(".")
128
- value = attributes.delete(key)
129
- attributes[table_name] ||= {}
151
+ attributes.each_with_object({}) do |(key, value), converted|
152
+ if value.is_a?(Hash)
153
+ if (existing = converted[key])
154
+ existing.merge!(value)
155
+ else
156
+ converted[key] = value.dup
157
+ end
158
+ elsif (idx = key.rindex("."))
159
+ table_name, column_name = key[0, idx], key[idx + 1, key.length]
130
160
 
131
- attributes[table_name] = attributes[table_name].merge(column_name => value)
161
+ if (existing = converted[table_name])
162
+ existing[column_name] = value
163
+ else
164
+ converted[table_name] = { column_name => value }
165
+ end
166
+ else
167
+ converted[key] = value
168
+ end
132
169
  end
133
-
134
- attributes
135
170
  end
136
171
 
137
172
  def handler_for(object)
@@ -139,12 +174,3 @@ module ActiveRecord
139
174
  end
140
175
  end
141
176
  end
142
-
143
- require "active_record/relation/predicate_builder/array_handler"
144
- require "active_record/relation/predicate_builder/base_handler"
145
- require "active_record/relation/predicate_builder/basic_object_handler"
146
- require "active_record/relation/predicate_builder/range_handler"
147
- require "active_record/relation/predicate_builder/relation_handler"
148
-
149
- require "active_record/relation/predicate_builder/association_query_value"
150
- require "active_record/relation/predicate_builder/polymorphic_array_value"
@@ -5,12 +5,27 @@ require "active_model/attribute"
5
5
  module ActiveRecord
6
6
  class Relation
7
7
  class QueryAttribute < ActiveModel::Attribute # :nodoc:
8
+ def initialize(...)
9
+ super
10
+
11
+ # The query attribute value may be mutated before we actually "compile" the query.
12
+ # To avoid that if the type uses a serializer we eagerly compute the value for database
13
+ if value_before_type_cast.is_a?(StatementCache::Substitute)
14
+ # we don't need to serialize StatementCache::Substitute
15
+ elsif @type.serialized?
16
+ value_for_database
17
+ elsif @type.mutable? # If the type is simply mutable, we deep_dup it.
18
+ @value_before_type_cast = @value_before_type_cast.deep_dup
19
+ end
20
+ end
21
+
8
22
  def type_cast(value)
9
23
  value
10
24
  end
11
25
 
12
26
  def value_for_database
13
- @value_for_database ||= super
27
+ @value_for_database = _value_for_database unless defined?(@value_for_database)
28
+ @value_for_database
14
29
  end
15
30
 
16
31
  def with_cast_value(value)
@@ -20,25 +35,28 @@ module ActiveRecord
20
35
  def nil?
21
36
  unless value_before_type_cast.is_a?(StatementCache::Substitute)
22
37
  value_before_type_cast.nil? ||
23
- type.respond_to?(:subtype, true) && value_for_database.nil?
38
+ (type.respond_to?(:subtype) || type.respond_to?(:normalizer)) && serializable? && value_for_database.nil?
24
39
  end
25
- rescue ::RangeError
26
40
  end
27
41
 
28
42
  def infinite?
29
- infinity?(value_before_type_cast) || infinity?(value_for_database)
30
- rescue ::RangeError
43
+ infinity?(value_before_type_cast) || serializable? && infinity?(value_for_database)
31
44
  end
32
45
 
33
46
  def unboundable?
34
- if defined?(@_unboundable)
35
- @_unboundable
36
- else
37
- value_for_database unless value_before_type_cast.is_a?(StatementCache::Substitute)
38
- @_unboundable = nil
47
+ unless defined?(@_unboundable)
48
+ serializable? { |value| @_unboundable = value <=> 0 } && @_unboundable = nil
39
49
  end
40
- rescue ::RangeError
41
- @_unboundable = type.cast(value_before_type_cast) <=> 0
50
+ @_unboundable
51
+ end
52
+
53
+ def ==(other)
54
+ super && value_for_database == other.value_for_database
55
+ end
56
+ alias eql? ==
57
+
58
+ def hash
59
+ [self.class, name, value_for_database, type].hash
42
60
  end
43
61
 
44
62
  private