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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mutex_m"
3
+ require "active_support/core_ext/enumerable"
4
4
 
5
5
  module ActiveRecord
6
6
  # = Active Record Attribute Methods
@@ -18,49 +18,133 @@ module ActiveRecord
18
18
  include TimeZoneConversion
19
19
  include Dirty
20
20
  include Serialization
21
-
22
- delegate :column_for_attribute, to: :class
23
21
  end
24
22
 
25
- RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
23
+ RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name superclass)
26
24
 
27
- class GeneratedAttributeMethods < Module #:nodoc:
28
- include Mutex_m
25
+ class GeneratedAttributeMethods < Module # :nodoc:
26
+ LOCK = Monitor.new
29
27
  end
30
28
 
31
- module ClassMethods
32
- def inherited(child_class) #:nodoc:
33
- child_class.initialize_generated_modules
34
- super
29
+ class << self
30
+ def dangerous_attribute_methods # :nodoc:
31
+ @dangerous_attribute_methods ||= (
32
+ Base.instance_methods +
33
+ Base.private_instance_methods -
34
+ Base.superclass.instance_methods -
35
+ Base.superclass.private_instance_methods +
36
+ %i[__id__ dup freeze frozen? hash class clone]
37
+ ).map { |m| -m.to_s }.to_set.freeze
35
38
  end
39
+ end
36
40
 
41
+ module ClassMethods
37
42
  def initialize_generated_modules # :nodoc:
38
43
  @generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
39
44
  private_constant :GeneratedAttributeMethods
40
45
  @attribute_methods_generated = false
46
+ @alias_attributes_mass_generated = false
41
47
  include @generated_attribute_methods
42
48
 
43
49
  super
44
50
  end
45
51
 
52
+ # Allows you to make aliases for attributes.
53
+ #
54
+ # class Person < ActiveRecord::Base
55
+ # alias_attribute :nickname, :name
56
+ # end
57
+ #
58
+ # person = Person.create(name: 'Bob')
59
+ # person.name # => "Bob"
60
+ # person.nickname # => "Bob"
61
+ #
62
+ # The alias can also be used for querying:
63
+ #
64
+ # Person.where(nickname: "Bob")
65
+ # # SELECT "people".* FROM "people" WHERE "people"."name" = "Bob"
66
+ def alias_attribute(new_name, old_name)
67
+ super
68
+
69
+ if @alias_attributes_mass_generated
70
+ ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
71
+ generate_alias_attribute_methods(code_generator, new_name, old_name)
72
+ end
73
+ end
74
+ end
75
+
76
+ def eagerly_generate_alias_attribute_methods(_new_name, _old_name) # :nodoc:
77
+ # alias attributes in Active Record are lazily generated
78
+ end
79
+
80
+ def generate_alias_attribute_methods(code_generator, new_name, old_name) # :nodoc:
81
+ attribute_method_patterns.each do |pattern|
82
+ alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
83
+ end
84
+ attribute_method_patterns_cache.clear
85
+ end
86
+
87
+ def alias_attribute_method_definition(code_generator, pattern, new_name, old_name) # :nodoc:
88
+ old_name = old_name.to_s
89
+
90
+ if !abstract_class? && !has_attribute?(old_name)
91
+ raise ArgumentError, "#{self.name} model aliases `#{old_name}`, but `#{old_name}` is not an attribute. " \
92
+ "Use `alias_method :#{new_name}, :#{old_name}` or define the method manually."
93
+ else
94
+ define_attribute_method_pattern(pattern, old_name, owner: code_generator, as: new_name, override: true)
95
+ end
96
+ end
97
+
98
+ def attribute_methods_generated? # :nodoc:
99
+ @attribute_methods_generated
100
+ end
101
+
46
102
  # Generates all the attribute related methods for columns in the database
47
103
  # accessors, mutators and query methods.
48
104
  def define_attribute_methods # :nodoc:
49
105
  return false if @attribute_methods_generated
50
106
  # Use a mutex; we don't want two threads simultaneously trying to define
51
107
  # attribute methods.
52
- generated_attribute_methods.synchronize do
108
+ GeneratedAttributeMethods::LOCK.synchronize do
53
109
  return false if @attribute_methods_generated
110
+
54
111
  superclass.define_attribute_methods unless base_class?
55
- super(attribute_names)
112
+
113
+ unless abstract_class?
114
+ load_schema
115
+ super(attribute_names)
116
+ alias_attribute :id_value, :id if _has_attribute?("id") && !_has_attribute?("id_value")
117
+ end
118
+
119
+ generate_alias_attributes
120
+
56
121
  @attribute_methods_generated = true
57
122
  end
123
+
124
+ true
125
+ end
126
+
127
+ def generate_alias_attributes # :nodoc:
128
+ superclass.generate_alias_attributes unless superclass == Base
129
+
130
+ return if @alias_attributes_mass_generated
131
+
132
+ ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
133
+ aliases_by_attribute_name.each do |old_name, new_names|
134
+ new_names.each do |new_name|
135
+ generate_alias_attribute_methods(code_generator, new_name, old_name)
136
+ end
137
+ end
138
+ end
139
+
140
+ @alias_attributes_mass_generated = true
58
141
  end
59
142
 
60
143
  def undefine_attribute_methods # :nodoc:
61
- generated_attribute_methods.synchronize do
62
- super if defined?(@attribute_methods_generated) && @attribute_methods_generated
144
+ GeneratedAttributeMethods::LOCK.synchronize do
145
+ super if @attribute_methods_generated
63
146
  @attribute_methods_generated = false
147
+ @alias_attributes_mass_generated = false
64
148
  end
65
149
  end
66
150
 
@@ -87,7 +171,7 @@ module ActiveRecord
87
171
  super
88
172
  else
89
173
  # If ThisClass < ... < SomeSuperClass < ... < Base and SomeSuperClass
90
- # defines its own attribute method, then we don't want to overwrite that.
174
+ # defines its own attribute method, then we don't want to override that.
91
175
  defined = method_defined_within?(method_name, superclass, Base) &&
92
176
  ! superclass.instance_method(method_name).owner.is_a?(GeneratedAttributeMethods)
93
177
  defined || super
@@ -97,7 +181,7 @@ module ActiveRecord
97
181
  # A method name is 'dangerous' if it is already (re)defined by Active Record, but
98
182
  # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
99
183
  def dangerous_attribute_method?(name) # :nodoc:
100
- method_defined_within?(name, Base)
184
+ ::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(name.to_s)
101
185
  end
102
186
 
103
187
  def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
@@ -115,13 +199,11 @@ module ActiveRecord
115
199
  # A class method is 'dangerous' if it is already (re)defined by Active Record, but
116
200
  # not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
117
201
  def dangerous_class_method?(method_name)
118
- RESTRICTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base)
119
- end
202
+ return true if RESTRICTED_CLASS_METHODS.include?(method_name.to_s)
120
203
 
121
- def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
122
- if klass.respond_to?(name, true)
123
- if superklass.respond_to?(name, true)
124
- klass.method(name).owner != superklass.method(name).owner
204
+ if Base.respond_to?(method_name, true)
205
+ if Object.respond_to?(method_name, true)
206
+ Base.method(method_name).owner != Object.method(method_name).owner
125
207
  else
126
208
  true
127
209
  end
@@ -140,7 +222,7 @@ module ActiveRecord
140
222
  # Person.attribute_method?(:age=) # => true
141
223
  # Person.attribute_method?(:nothing) # => false
142
224
  def attribute_method?(attribute)
143
- super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, "")))
225
+ super || (table_exists? && column_names.include?(attribute.to_s.delete_suffix("=")))
144
226
  end
145
227
 
146
228
  # Returns an array of column names as strings if it's not an abstract class and
@@ -156,40 +238,38 @@ module ActiveRecord
156
238
  attribute_types.keys
157
239
  else
158
240
  []
159
- end
241
+ end.freeze
160
242
  end
161
243
 
162
244
  # Returns true if the given attribute exists, otherwise false.
163
245
  #
164
246
  # class Person < ActiveRecord::Base
247
+ # alias_attribute :new_name, :name
165
248
  # end
166
249
  #
167
- # Person.has_attribute?('name') # => true
168
- # Person.has_attribute?(:age) # => true
169
- # Person.has_attribute?(:nothing) # => false
250
+ # Person.has_attribute?('name') # => true
251
+ # Person.has_attribute?('new_name') # => true
252
+ # Person.has_attribute?(:age) # => true
253
+ # Person.has_attribute?(:nothing) # => false
170
254
  def has_attribute?(attr_name)
171
- attribute_types.key?(attr_name.to_s)
255
+ attr_name = attr_name.to_s
256
+ attr_name = attribute_aliases[attr_name] || attr_name
257
+ attribute_types.key?(attr_name)
172
258
  end
173
259
 
174
- # Returns the column object for the named attribute.
175
- # Returns a +ActiveRecord::ConnectionAdapters::NullColumn+ if the
176
- # named attribute does not exist.
177
- #
178
- # class Person < ActiveRecord::Base
179
- # end
180
- #
181
- # person = Person.new
182
- # person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
183
- # # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
184
- #
185
- # person.column_for_attribute(:nothing)
186
- # # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
187
- def column_for_attribute(name)
188
- name = name.to_s
189
- columns_hash.fetch(name) do
190
- ConnectionAdapters::NullColumn.new(name)
191
- end
260
+ def _has_attribute?(attr_name) # :nodoc:
261
+ attribute_types.key?(attr_name)
192
262
  end
263
+
264
+ private
265
+ def inherited(child_class)
266
+ super
267
+ child_class.initialize_generated_modules
268
+ child_class.class_eval do
269
+ @alias_attributes_mass_generated = false
270
+ @attribute_names = nil
271
+ end
272
+ end
193
273
  end
194
274
 
195
275
  # A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
@@ -213,11 +293,9 @@ module ActiveRecord
213
293
 
214
294
  # If the result is true then check for the select case.
215
295
  # For queries selecting a subset of columns, return false for unselected columns.
216
- # We check defined?(@attributes) not to issue warnings if called on objects that
217
- # have been allocated but not yet initialized.
218
- if defined?(@attributes)
296
+ if @attributes
219
297
  if name = self.class.symbol_column_to_string(name.to_sym)
220
- return has_attribute?(name)
298
+ return _has_attribute?(name)
221
299
  end
222
300
  end
223
301
 
@@ -227,14 +305,22 @@ module ActiveRecord
227
305
  # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
228
306
  #
229
307
  # class Person < ActiveRecord::Base
308
+ # alias_attribute :new_name, :name
230
309
  # end
231
310
  #
232
311
  # person = Person.new
233
- # person.has_attribute?(:name) # => true
234
- # person.has_attribute?('age') # => true
235
- # person.has_attribute?(:nothing) # => false
312
+ # person.has_attribute?(:name) # => true
313
+ # person.has_attribute?(:new_name) # => true
314
+ # person.has_attribute?('age') # => true
315
+ # person.has_attribute?(:nothing) # => false
236
316
  def has_attribute?(attr_name)
237
- @attributes.key?(attr_name.to_s)
317
+ attr_name = attr_name.to_s
318
+ attr_name = self.class.attribute_aliases[attr_name] || attr_name
319
+ @attributes.key?(attr_name)
320
+ end
321
+
322
+ def _has_attribute?(attr_name) # :nodoc:
323
+ @attributes.key?(attr_name)
238
324
  end
239
325
 
240
326
  # Returns an array of names for the attributes available on this object.
@@ -263,9 +349,8 @@ module ActiveRecord
263
349
 
264
350
  # Returns an <tt>#inspect</tt>-like string for the value of the
265
351
  # attribute +attr_name+. String attributes are truncated up to 50
266
- # characters, Date and Time attributes are returned in the
267
- # <tt>:db</tt> format. Other attributes return the value of
268
- # <tt>#inspect</tt> without modification.
352
+ # characters. Other attributes return the value of <tt>#inspect</tt>
353
+ # without modification.
269
354
  #
270
355
  # person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
271
356
  #
@@ -273,13 +358,15 @@ module ActiveRecord
273
358
  # # => "\"David Heinemeier Hansson David Heinemeier Hansson ...\""
274
359
  #
275
360
  # person.attribute_for_inspect(:created_at)
276
- # # => "\"2012-10-22 00:15:07\""
361
+ # # => "\"2012-10-22 00:15:07.000000000 +0000\""
277
362
  #
278
363
  # person.attribute_for_inspect(:tag_ids)
279
364
  # # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
280
365
  def attribute_for_inspect(attr_name)
366
+ attr_name = attr_name.to_s
367
+ attr_name = self.class.attribute_aliases[attr_name] || attr_name
281
368
  value = _read_attribute(attr_name)
282
- format_for_inspect(value)
369
+ format_for_inspect(attr_name, value)
283
370
  end
284
371
 
285
372
  # Returns +true+ if the specified +attribute+ has been set by the user or by a
@@ -297,42 +384,47 @@ module ActiveRecord
297
384
  # task.is_done = true
298
385
  # task.attribute_present?(:title) # => true
299
386
  # task.attribute_present?(:is_done) # => true
300
- def attribute_present?(attribute)
301
- value = _read_attribute(attribute)
387
+ def attribute_present?(attr_name)
388
+ attr_name = attr_name.to_s
389
+ attr_name = self.class.attribute_aliases[attr_name] || attr_name
390
+ value = _read_attribute(attr_name)
302
391
  !value.nil? && !(value.respond_to?(:empty?) && value.empty?)
303
392
  end
304
393
 
305
- # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
306
- # "2004-12-12" in a date column is cast to a date object, like Date.new(2004, 12, 12)). It raises
307
- # <tt>ActiveModel::MissingAttributeError</tt> if the identified attribute is missing.
308
- #
309
- # Note: +:id+ is always present.
394
+ # Returns the value of the attribute identified by +attr_name+ after it has
395
+ # been type cast. (For information about specific type casting behavior, see
396
+ # the types under ActiveModel::Type.)
310
397
  #
311
398
  # class Person < ActiveRecord::Base
312
399
  # belongs_to :organization
313
400
  # end
314
401
  #
315
- # person = Person.new(name: 'Francesco', age: '22')
316
- # person[:name] # => "Francesco"
317
- # person[:age] # => 22
402
+ # person = Person.new(name: "Francesco", date_of_birth: "2004-12-12")
403
+ # person[:name] # => "Francesco"
404
+ # person[:date_of_birth] # => Date.new(2004, 12, 12)
405
+ # person[:organization_id] # => nil
406
+ #
407
+ # Raises ActiveModel::MissingAttributeError if the attribute is missing.
408
+ # Note, however, that the +id+ attribute will never be considered missing.
318
409
  #
319
- # person = Person.select('id').first
320
- # person[:name] # => ActiveModel::MissingAttributeError: missing attribute: name
321
- # person[:organization_id] # => ActiveModel::MissingAttributeError: missing attribute: organization_id
410
+ # person = Person.select(:name).first
411
+ # person[:name] # => "Francesco"
412
+ # person[:date_of_birth] # => ActiveModel::MissingAttributeError: missing attribute 'date_of_birth' for Person
413
+ # person[:organization_id] # => ActiveModel::MissingAttributeError: missing attribute 'organization_id' for Person
414
+ # person[:id] # => nil
322
415
  def [](attr_name)
323
416
  read_attribute(attr_name) { |n| missing_attribute(n, caller) }
324
417
  end
325
418
 
326
- # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
327
- # (Alias for the protected #write_attribute method).
419
+ # Updates the attribute identified by +attr_name+ using the specified
420
+ # +value+. The attribute value will be type cast upon being read.
328
421
  #
329
422
  # class Person < ActiveRecord::Base
330
423
  # end
331
424
  #
332
425
  # person = Person.new
333
- # person[:age] = '22'
334
- # person[:age] # => 22
335
- # person[:age].class # => Integer
426
+ # person[:date_of_birth] = "2004-12-12"
427
+ # person[:date_of_birth] # => Date.new(2004, 12, 12)
336
428
  def []=(attr_name, value)
337
429
  write_attribute(attr_name, value)
338
430
  end
@@ -353,10 +445,9 @@ module ActiveRecord
353
445
  # end
354
446
  #
355
447
  # private
356
- #
357
- # def print_accessed_fields
358
- # p @posts.first.accessed_fields
359
- # end
448
+ # def print_accessed_fields
449
+ # p @posts.first.accessed_fields
450
+ # end
360
451
  # end
361
452
  #
362
453
  # Which allows you to quickly change your code to:
@@ -371,46 +462,82 @@ module ActiveRecord
371
462
  end
372
463
 
373
464
  private
465
+ def respond_to_missing?(name, include_private = false)
466
+ if self.class.define_attribute_methods
467
+ # Some methods weren't defined yet.
468
+ return true if self.class.method_defined?(name)
469
+ return true if include_private && self.class.private_method_defined?(name)
470
+ end
471
+
472
+ super
473
+ end
474
+
475
+ def method_missing(name, ...)
476
+ # We can't know whether some method was defined or not because
477
+ # multiple thread might be concurrently be in this code path.
478
+ # So the first one would define the methods and the others would
479
+ # appear to already have them.
480
+ self.class.define_attribute_methods
481
+
482
+ # So in all cases we must behave as if the method was just defined.
483
+ method = begin
484
+ self.class.public_instance_method(name)
485
+ rescue NameError
486
+ nil
487
+ end
488
+
489
+ # The method might be explicitly defined in the model, but call a generated
490
+ # method with super. So we must resume the call chain at the right step.
491
+ method = method.super_method while method && !method.owner.is_a?(GeneratedAttributeMethods)
492
+ if method
493
+ method.bind_call(self, ...)
494
+ else
495
+ super
496
+ end
497
+ end
498
+
374
499
  def attribute_method?(attr_name)
375
- # We check defined? because Syck calls respond_to? before actually calling initialize.
376
- defined?(@attributes) && @attributes.key?(attr_name)
500
+ @attributes&.key?(attr_name)
377
501
  end
378
502
 
379
503
  def attributes_with_values(attribute_names)
380
- attribute_names.each_with_object({}) do |name, attrs|
381
- attrs[name] = _read_attribute(name)
382
- end
504
+ attribute_names.index_with { |name| @attributes[name] }
383
505
  end
384
506
 
385
- # Filters the primary keys and readonly attributes from the attribute names.
507
+ # Filters the primary keys, readonly attributes and virtual columns from the attribute names.
386
508
  def attributes_for_update(attribute_names)
387
509
  attribute_names &= self.class.column_names
388
510
  attribute_names.delete_if do |name|
389
- readonly_attribute?(name)
511
+ self.class.readonly_attribute?(name) ||
512
+ self.class.counter_cache_column?(name) ||
513
+ column_for_attribute(name).virtual?
390
514
  end
391
515
  end
392
516
 
393
- # Filters out the primary keys, from the attribute names, when the primary
517
+ # Filters out the virtual columns and also primary keys, from the attribute names, when the primary
394
518
  # key is to be generated (e.g. the id attribute has no value).
395
519
  def attributes_for_create(attribute_names)
396
520
  attribute_names &= self.class.column_names
397
521
  attribute_names.delete_if do |name|
398
- pk_attribute?(name) && id.nil?
522
+ (pk_attribute?(name) && id.nil?) ||
523
+ column_for_attribute(name).virtual?
399
524
  end
400
525
  end
401
526
 
402
- def format_for_inspect(value)
403
- if value.is_a?(String) && value.length > 50
404
- "#{value[0, 50]}...".inspect
405
- elsif value.is_a?(Date) || value.is_a?(Time)
406
- %("#{value.to_s(:db)}")
407
- else
527
+ def format_for_inspect(name, value)
528
+ if value.nil?
408
529
  value.inspect
409
- end
410
- end
530
+ else
531
+ inspected_value = if value.is_a?(String) && value.length > 50
532
+ "#{value[0, 50]}...".inspect
533
+ elsif value.is_a?(Date) || value.is_a?(Time)
534
+ %("#{value.to_fs(:inspect)}")
535
+ else
536
+ value.inspect
537
+ end
411
538
 
412
- def readonly_attribute?(name)
413
- self.class.readonly_attributes.include?(name)
539
+ inspection_filter.filter_param(name, inspected_value)
540
+ end
414
541
  end
415
542
 
416
543
  def pk_attribute?(name)