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
@@ -3,11 +3,14 @@
3
3
  require "benchmark"
4
4
  require "set"
5
5
  require "zlib"
6
+ require "active_support/core_ext/array/access"
7
+ require "active_support/core_ext/enumerable"
6
8
  require "active_support/core_ext/module/attribute_accessors"
7
9
  require "active_support/actionable_error"
10
+ require "active_record/migration/pending_migration_connection"
8
11
 
9
12
  module ActiveRecord
10
- class MigrationError < ActiveRecordError #:nodoc:
13
+ class MigrationError < ActiveRecordError # :nodoc:
11
14
  def initialize(message = nil)
12
15
  message = "\n\n#{message}\n\n" if message
13
16
  super
@@ -18,7 +21,7 @@ module ActiveRecord
18
21
  # For example the following migration is not reversible.
19
22
  # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
20
23
  #
21
- # class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
24
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[7.2]
22
25
  # def change
23
26
  # create_table :distributors do |t|
24
27
  # t.string :zipcode
@@ -36,7 +39,7 @@ module ActiveRecord
36
39
  #
37
40
  # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
38
41
  #
39
- # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
42
+ # class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
40
43
  # def up
41
44
  # create_table :distributors do |t|
42
45
  # t.string :zipcode
@@ -61,7 +64,7 @@ module ActiveRecord
61
64
  #
62
65
  # 2. Use the #reversible method in <tt>#change</tt> method:
63
66
  #
64
- # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
67
+ # class ReversibleMigrationExample < ActiveRecord::Migration[7.2]
65
68
  # def change
66
69
  # create_table :distributors do |t|
67
70
  # t.string :zipcode
@@ -88,7 +91,7 @@ module ActiveRecord
88
91
  class IrreversibleMigration < MigrationError
89
92
  end
90
93
 
91
- class DuplicateMigrationVersionError < MigrationError #:nodoc:
94
+ class DuplicateMigrationVersionError < MigrationError # :nodoc:
92
95
  def initialize(version = nil)
93
96
  if version
94
97
  super("Multiple migrations have the version number #{version}.")
@@ -98,7 +101,7 @@ module ActiveRecord
98
101
  end
99
102
  end
100
103
 
101
- class DuplicateMigrationNameError < MigrationError #:nodoc:
104
+ class DuplicateMigrationNameError < MigrationError # :nodoc:
102
105
  def initialize(name = nil)
103
106
  if name
104
107
  super("Multiple migrations have the name #{name}.")
@@ -108,7 +111,7 @@ module ActiveRecord
108
111
  end
109
112
  end
110
113
 
111
- class UnknownMigrationVersionError < MigrationError #:nodoc:
114
+ class UnknownMigrationVersionError < MigrationError # :nodoc:
112
115
  def initialize(version = nil)
113
116
  if version
114
117
  super("No migration with version number #{version}.")
@@ -118,7 +121,7 @@ module ActiveRecord
118
121
  end
119
122
  end
120
123
 
121
- class IllegalMigrationNameError < MigrationError #:nodoc:
124
+ class IllegalMigrationNameError < MigrationError # :nodoc:
122
125
  def initialize(name = nil)
123
126
  if name
124
127
  super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
@@ -128,25 +131,63 @@ module ActiveRecord
128
131
  end
129
132
  end
130
133
 
131
- class PendingMigrationError < MigrationError #:nodoc:
134
+ class InvalidMigrationTimestampError < MigrationError # :nodoc:
135
+ def initialize(version = nil, name = nil)
136
+ if version && name
137
+ super(<<~MSG)
138
+ Invalid timestamp #{version} for migration file: #{name}.
139
+ Timestamp must be in form YYYYMMDDHHMMSS, and less than #{(Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S")}.
140
+ MSG
141
+ else
142
+ super(<<~MSG)
143
+ Invalid timestamp for migration.
144
+ Timestamp must be in form YYYYMMDDHHMMSS, and less than #{(Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S")}.
145
+ MSG
146
+ end
147
+ end
148
+ end
149
+
150
+ class PendingMigrationError < MigrationError # :nodoc:
132
151
  include ActiveSupport::ActionableError
133
152
 
134
153
  action "Run pending migrations" do
135
154
  ActiveRecord::Tasks::DatabaseTasks.migrate
155
+
156
+ if ActiveRecord.dump_schema_after_migration
157
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
158
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
159
+ end
136
160
  end
137
161
 
138
- def initialize(message = nil)
139
- if !message && defined?(Rails.env)
140
- super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate RAILS_ENV=#{::Rails.env}")
141
- elsif !message
142
- super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate")
143
- else
144
- super
162
+ def initialize(message = nil, pending_migrations: nil)
163
+ if pending_migrations.nil?
164
+ pending_migrations = connection_pool.migration_context.open.pending_migrations
145
165
  end
166
+
167
+ super(message || detailed_migration_message(pending_migrations))
146
168
  end
169
+
170
+ private
171
+ def detailed_migration_message(pending_migrations)
172
+ message = "Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate"
173
+ message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env) && !Rails.env.local?
174
+ message += "\n\n"
175
+
176
+ message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
177
+
178
+ pending_migrations.each do |pending_migration|
179
+ message += "#{pending_migration.filename}\n"
180
+ end
181
+
182
+ message
183
+ end
184
+
185
+ def connection_pool
186
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
187
+ end
147
188
  end
148
189
 
149
- class ConcurrentMigrationError < MigrationError #:nodoc:
190
+ class ConcurrentMigrationError < MigrationError # :nodoc:
150
191
  DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
151
192
  RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
152
193
 
@@ -155,9 +196,9 @@ module ActiveRecord
155
196
  end
156
197
  end
157
198
 
158
- class NoEnvironmentInSchemaError < MigrationError #:nodoc:
199
+ class NoEnvironmentInSchemaError < MigrationError # :nodoc:
159
200
  def initialize
160
- msg = "Environment data not found in the schema. To resolve this issue, run: \n\n rails db:environment:set"
201
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
161
202
  if defined?(Rails.env)
162
203
  super("#{msg} RAILS_ENV=#{::Rails.env}")
163
204
  else
@@ -166,7 +207,7 @@ module ActiveRecord
166
207
  end
167
208
  end
168
209
 
169
- class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
210
+ class ProtectedEnvironmentError < ActiveRecordError # :nodoc:
170
211
  def initialize(env = "production")
171
212
  msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
172
213
  msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
@@ -180,7 +221,7 @@ module ActiveRecord
180
221
  msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
181
222
  msg << "You are running in `#{ current }` environment. "
182
223
  msg << "If you are sure you want to continue, first set the environment using:\n\n"
183
- msg << " rails db:environment:set"
224
+ msg << " bin/rails db:environment:set"
184
225
  if defined?(Rails.env)
185
226
  super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
186
227
  else
@@ -189,6 +230,14 @@ module ActiveRecord
189
230
  end
190
231
  end
191
232
 
233
+ class EnvironmentStorageError < ActiveRecordError # :nodoc:
234
+ def initialize
235
+ msg = +"You are attempting to store the environment in a database where metadata is disabled.\n"
236
+ msg << "Check your database configuration to see if this is intended."
237
+ super(msg)
238
+ end
239
+ end
240
+
192
241
  # = Active Record Migrations
193
242
  #
194
243
  # Migrations can manage the evolution of a schema used by several physical
@@ -201,7 +250,7 @@ module ActiveRecord
201
250
  #
202
251
  # Example of a simple migration:
203
252
  #
204
- # class AddSsl < ActiveRecord::Migration[5.0]
253
+ # class AddSsl < ActiveRecord::Migration[7.2]
205
254
  # def up
206
255
  # add_column :accounts, :ssl_enabled, :boolean, default: true
207
256
  # end
@@ -221,7 +270,7 @@ module ActiveRecord
221
270
  #
222
271
  # Example of a more complex migration that also needs to initialize data:
223
272
  #
224
- # class AddSystemSettings < ActiveRecord::Migration[5.0]
273
+ # class AddSystemSettings < ActiveRecord::Migration[7.2]
225
274
  # def up
226
275
  # create_table :system_settings do |t|
227
276
  # t.string :name
@@ -293,13 +342,13 @@ module ActiveRecord
293
342
  # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
294
343
  # as +default_or_changes+ will make this change reversible in the migration.
295
344
  # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
296
- # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
345
+ # Sets or removes a <tt>NOT NULL</tt> constraint on +column_name+. The +null+ flag
297
346
  # indicates whether the value can be +NULL+. See
298
347
  # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
299
348
  # details.
300
349
  # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
301
350
  # the table called +name+. It makes the table object available to a block that
302
- # can then add/remove columns, indexes or foreign keys to it.
351
+ # can then add/remove columns, indexes, or foreign keys to it.
303
352
  # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
304
353
  # a column but keeps the type and content.
305
354
  # * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
@@ -329,15 +378,16 @@ module ActiveRecord
329
378
  # == Irreversible transformations
330
379
  #
331
380
  # Some transformations are destructive in a manner that cannot be reversed.
332
- # Migrations of that kind should raise an <tt>ActiveRecord::IrreversibleMigration</tt>
381
+ # Migrations of that kind should raise an ActiveRecord::IrreversibleMigration
333
382
  # exception in their +down+ method.
334
383
  #
335
- # == Running migrations from within Rails
384
+ # == Running migrations from within \Rails
336
385
  #
337
- # The Rails package has several tools to help create and apply migrations.
386
+ # The \Rails package has several tools to help create and apply migrations.
338
387
  #
339
388
  # To generate a new migration, you can use
340
- # rails generate migration MyNewMigration
389
+ #
390
+ # $ bin/rails generate migration MyNewMigration
341
391
  #
342
392
  # where MyNewMigration is the name of your migration. The generator will
343
393
  # create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
@@ -346,41 +396,36 @@ module ActiveRecord
346
396
  #
347
397
  # There is a special syntactic shortcut to generate migrations that add fields to a table.
348
398
  #
349
- # rails generate migration add_fieldname_to_tablename fieldname:string
399
+ # $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
350
400
  #
351
401
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
352
- # class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
402
+ # class AddFieldnameToTablename < ActiveRecord::Migration[7.2]
353
403
  # def change
354
404
  # add_column :tablenames, :fieldname, :string
355
405
  # end
356
406
  # end
357
407
  #
358
408
  # To run migrations against the currently configured database, use
359
- # <tt>rails db:migrate</tt>. This will update the database by running all of the
409
+ # <tt>bin/rails db:migrate</tt>. This will update the database by running all of the
360
410
  # pending migrations, creating the <tt>schema_migrations</tt> table
361
411
  # (see "About the schema_migrations table" section below) if missing. It will also
362
412
  # invoke the db:schema:dump command, which will update your db/schema.rb file
363
413
  # to match the structure of your database.
364
414
  #
365
415
  # To roll the database back to a previous migration version, use
366
- # <tt>rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
416
+ # <tt>bin/rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
367
417
  # you wish to downgrade. Alternatively, you can also use the STEP option if you
368
- # wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
418
+ # wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
369
419
  # the latest two migrations.
370
420
  #
371
- # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
421
+ # If any of the migrations throw an ActiveRecord::IrreversibleMigration exception,
372
422
  # that step will fail and you'll have some manual work to do.
373
423
  #
374
- # == Database support
375
- #
376
- # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
377
- # SQL Server, and Oracle (all supported databases except DB2).
378
- #
379
424
  # == More examples
380
425
  #
381
426
  # Not all migrations change the schema. Some just fix the data:
382
427
  #
383
- # class RemoveEmptyTags < ActiveRecord::Migration[5.0]
428
+ # class RemoveEmptyTags < ActiveRecord::Migration[7.2]
384
429
  # def up
385
430
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
386
431
  # end
@@ -393,7 +438,7 @@ module ActiveRecord
393
438
  #
394
439
  # Others remove columns when they migrate up instead of down:
395
440
  #
396
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
441
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[7.2]
397
442
  # def up
398
443
  # remove_column :items, :incomplete_items_count
399
444
  # remove_column :items, :completed_items_count
@@ -407,7 +452,7 @@ module ActiveRecord
407
452
  #
408
453
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
409
454
  #
410
- # class MakeJoinUnique < ActiveRecord::Migration[5.0]
455
+ # class MakeJoinUnique < ActiveRecord::Migration[7.2]
411
456
  # def up
412
457
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
413
458
  # end
@@ -424,7 +469,7 @@ module ActiveRecord
424
469
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
425
470
  # latest column data from after the new column was added. Example:
426
471
  #
427
- # class AddPeopleSalary < ActiveRecord::Migration[5.0]
472
+ # class AddPeopleSalary < ActiveRecord::Migration[7.2]
428
473
  # def up
429
474
  # add_column :people, :salary, :integer
430
475
  # Person.reset_column_information
@@ -440,7 +485,7 @@ module ActiveRecord
440
485
  # them to the console as they happen, along with benchmarks describing how
441
486
  # long each step took.
442
487
  #
443
- # You can quiet them down by setting ActiveRecord::Migration.verbose = false.
488
+ # You can quiet them down by setting <tt>ActiveRecord::Migration.verbose = false</tt>.
444
489
  #
445
490
  # You can also insert your own messages and benchmarks by using the +say_with_time+
446
491
  # method:
@@ -460,11 +505,15 @@ module ActiveRecord
460
505
  #
461
506
  # == Timestamped Migrations
462
507
  #
463
- # By default, Rails generates migrations that look like:
508
+ # By default, \Rails generates migrations that look like:
464
509
  #
465
510
  # 20080717013526_your_migration_name.rb
466
511
  #
467
- # The prefix is a generation timestamp (in UTC).
512
+ # The prefix is a generation timestamp (in UTC). Timestamps should not be
513
+ # modified manually. To validate that migration timestamps adhere to the
514
+ # format Active Record expects, you can use the following configuration option:
515
+ #
516
+ # config.active_record.validate_migration_timestamps = true
468
517
  #
469
518
  # If you'd prefer to use numeric prefixes, you can turn timestamped migrations
470
519
  # off by setting:
@@ -482,7 +531,7 @@ module ActiveRecord
482
531
  # To define a reversible migration, define the +change+ method in your
483
532
  # migration like this:
484
533
  #
485
- # class TenderloveMigration < ActiveRecord::Migration[5.0]
534
+ # class TenderloveMigration < ActiveRecord::Migration[7.2]
486
535
  # def change
487
536
  # create_table(:horses) do |t|
488
537
  # t.column :content, :text
@@ -499,11 +548,11 @@ module ActiveRecord
499
548
  # as before.
500
549
  #
501
550
  # If a command cannot be reversed, an
502
- # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
551
+ # ActiveRecord::IrreversibleMigration exception will be raised when
503
552
  # the migration is moving down.
504
553
  #
505
554
  # For a list of commands that are reversible, please see
506
- # <tt>ActiveRecord::Migration::CommandRecorder</tt>.
555
+ # +ActiveRecord::Migration::CommandRecorder+.
507
556
  #
508
557
  # == Transactional Migrations
509
558
  #
@@ -512,7 +561,7 @@ module ActiveRecord
512
561
  # can't execute inside a transaction though, and for these situations
513
562
  # you can turn the automatic transactions off.
514
563
  #
515
- # class ChangeEnum < ActiveRecord::Migration[5.0]
564
+ # class ChangeEnum < ActiveRecord::Migration[7.2]
516
565
  # disable_ddl_transaction!
517
566
  #
518
567
  # def up
@@ -525,18 +574,58 @@ module ActiveRecord
525
574
  class Migration
526
575
  autoload :CommandRecorder, "active_record/migration/command_recorder"
527
576
  autoload :Compatibility, "active_record/migration/compatibility"
577
+ autoload :JoinTable, "active_record/migration/join_table"
578
+ autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
579
+ autoload :DefaultStrategy, "active_record/migration/default_strategy"
528
580
 
529
581
  # This must be defined before the inherited hook, below
530
- class Current < Migration #:nodoc:
582
+ class Current < Migration # :nodoc:
583
+ def create_table(table_name, **options)
584
+ if block_given?
585
+ super { |t| yield compatible_table_definition(t) }
586
+ else
587
+ super
588
+ end
589
+ end
590
+
591
+ def change_table(table_name, **options)
592
+ if block_given?
593
+ super { |t| yield compatible_table_definition(t) }
594
+ else
595
+ super
596
+ end
597
+ end
598
+
599
+ def create_join_table(table_1, table_2, **options)
600
+ if block_given?
601
+ super { |t| yield compatible_table_definition(t) }
602
+ else
603
+ super
604
+ end
605
+ end
606
+
607
+ def drop_table(table_name, **options)
608
+ if block_given?
609
+ super { |t| yield compatible_table_definition(t) }
610
+ else
611
+ super
612
+ end
613
+ end
614
+
615
+ def compatible_table_definition(t)
616
+ t
617
+ end
531
618
  end
532
619
 
533
- def self.inherited(subclass) #:nodoc:
620
+ def self.inherited(subclass) # :nodoc:
534
621
  super
535
622
  if subclass.superclass == Migration
623
+ major = ActiveRecord::VERSION::MAJOR
624
+ minor = ActiveRecord::VERSION::MINOR
536
625
  raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
537
- "Please specify the Rails release the migration was written for:\n" \
626
+ "Please specify the Active Record release the migration was written for:\n" \
538
627
  "\n" \
539
- " class #{subclass} < ActiveRecord::Migration[4.2]"
628
+ " class #{subclass} < ActiveRecord::Migration[#{major}.#{minor}]"
540
629
  end
541
630
  end
542
631
 
@@ -548,76 +637,104 @@ module ActiveRecord
548
637
  ActiveRecord::VERSION::STRING.to_f
549
638
  end
550
639
 
551
- MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
640
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
641
+
642
+ def self.valid_version_format?(version_string) # :nodoc:
643
+ [
644
+ MigrationFilenameRegexp,
645
+ /\A\d(_?\d)*\z/ # integer with optional underscores
646
+ ].any? { |pattern| pattern.match?(version_string) }
647
+ end
552
648
 
553
649
  # This class is used to verify that all migrations have been run before
554
- # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
650
+ # loading a web page if <tt>config.active_record.migration_error</tt> is set to +:page_load+.
555
651
  class CheckPending
556
- def initialize(app)
652
+ def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
557
653
  @app = app
558
- @last_check = 0
654
+ @needs_check = true
655
+ @mutex = Mutex.new
656
+ @file_watcher = file_watcher
559
657
  end
560
658
 
561
659
  def call(env)
562
- mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
563
- if @last_check < mtime
564
- ActiveRecord::Migration.check_pending!(connection)
565
- @last_check = mtime
660
+ @mutex.synchronize do
661
+ @watcher ||= build_watcher do
662
+ @needs_check = true
663
+ ActiveRecord::Migration.check_pending_migrations
664
+ @needs_check = false
665
+ end
666
+
667
+ if @needs_check
668
+ @watcher.execute
669
+ else
670
+ @watcher.execute_if_updated
671
+ end
566
672
  end
673
+
567
674
  @app.call(env)
568
675
  end
569
676
 
570
677
  private
678
+ def build_watcher(&block)
679
+ current_environment = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
680
+ all_configs = ActiveRecord::Base.configurations.configs_for(env_name: current_environment)
681
+ paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
682
+ @file_watcher.new([], paths.index_with(["rb"]), &block)
683
+ end
571
684
 
572
685
  def connection
573
- ActiveRecord::Base.connection
686
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
574
687
  end
575
688
  end
576
689
 
577
690
  class << self
578
- attr_accessor :delegate #:nodoc:
579
- attr_accessor :disable_ddl_transaction #:nodoc:
691
+ attr_accessor :delegate # :nodoc:
692
+ attr_accessor :disable_ddl_transaction # :nodoc:
580
693
 
581
- def nearest_delegate #:nodoc:
694
+ def nearest_delegate # :nodoc:
582
695
  delegate || superclass.nearest_delegate
583
696
  end
584
697
 
585
- # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
586
- def check_pending!(connection = Base.connection)
587
- raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
588
- end
698
+ # Raises ActiveRecord::PendingMigrationError error if any migrations are pending
699
+ # for all database configurations in an environment.
700
+ def check_all_pending!
701
+ pending_migrations = []
589
702
 
590
- def load_schema_if_pending!
591
- current_config = Base.connection_config
592
- all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
703
+ ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: env) do |pool|
704
+ if pending = pool.migration_context.open.pending_migrations
705
+ pending_migrations << pending
706
+ end
707
+ end
593
708
 
594
- needs_update = !all_configs.all? do |db_config|
595
- Tasks::DatabaseTasks.schema_up_to_date?(db_config.config, ActiveRecord::Base.schema_format, nil, Rails.env, db_config.spec_name)
709
+ migrations = pending_migrations.flatten
710
+
711
+ if migrations.any?
712
+ raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
596
713
  end
714
+ end
597
715
 
598
- if needs_update
716
+ def load_schema_if_pending!
717
+ if any_schema_needs_update?
599
718
  # Roundtrip to Rake to allow plugins to hook into database initialization.
600
719
  root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
720
+
601
721
  FileUtils.cd(root) do
602
- Base.clear_all_connections!
722
+ Base.connection_handler.clear_all_connections!(:all)
603
723
  system("bin/rails db:test:prepare")
604
724
  end
605
725
  end
606
726
 
607
- # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
608
- Base.establish_connection(current_config)
609
-
610
- check_pending!
727
+ check_pending_migrations
611
728
  end
612
729
 
613
- def maintain_test_schema! #:nodoc:
614
- if ActiveRecord::Base.maintain_test_schema
730
+ def maintain_test_schema! # :nodoc:
731
+ if ActiveRecord.maintain_test_schema
615
732
  suppress_messages { load_schema_if_pending! }
616
733
  end
617
734
  end
618
735
 
619
- def method_missing(name, *args, &block) #:nodoc:
620
- nearest_delegate.send(name, *args, &block)
736
+ def method_missing(name, ...) # :nodoc:
737
+ nearest_delegate.send(name, ...)
621
738
  end
622
739
 
623
740
  def migrate(direction)
@@ -631,12 +748,55 @@ module ActiveRecord
631
748
  def disable_ddl_transaction!
632
749
  @disable_ddl_transaction = true
633
750
  end
751
+
752
+ def check_pending_migrations # :nodoc:
753
+ migrations = pending_migrations
754
+
755
+ if migrations.any?
756
+ raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
757
+ end
758
+ end
759
+
760
+ private
761
+ def any_schema_needs_update?
762
+ !db_configs_in_current_env.all? do |db_config|
763
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
764
+ end
765
+ end
766
+
767
+ def db_configs_in_current_env
768
+ ActiveRecord::Base.configurations.configs_for(env_name: env)
769
+ end
770
+
771
+ def pending_migrations
772
+ pending_migrations = []
773
+
774
+ ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
775
+ ActiveRecord::PendingMigrationConnection.with_temporary_pool(db_config) do |pool|
776
+ if pending = pool.migration_context.open.pending_migrations
777
+ pending_migrations << pending
778
+ end
779
+ end
780
+ end
781
+
782
+ pending_migrations.flatten
783
+ end
784
+
785
+ def env
786
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
787
+ end
634
788
  end
635
789
 
636
- def disable_ddl_transaction #:nodoc:
790
+ def disable_ddl_transaction # :nodoc:
637
791
  self.class.disable_ddl_transaction
638
792
  end
639
793
 
794
+ ##
795
+ # :singleton-method: verbose
796
+ #
797
+ # Specifies if migrations will write the actions they are taking to the console as they
798
+ # happen, along with benchmarks describing how long each step took. Defaults to
799
+ # true.
640
800
  cattr_accessor :verbose
641
801
  attr_accessor :name, :version
642
802
 
@@ -644,6 +804,11 @@ module ActiveRecord
644
804
  @name = name
645
805
  @version = version
646
806
  @connection = nil
807
+ @pool = nil
808
+ end
809
+
810
+ def execution_strategy
811
+ @execution_strategy ||= ActiveRecord.migration_strategy.new(self)
647
812
  end
648
813
 
649
814
  self.verbose = true
@@ -657,7 +822,7 @@ module ActiveRecord
657
822
  # and create the table 'apples' on the way up, and the reverse
658
823
  # on the way down.
659
824
  #
660
- # class FixTLMigration < ActiveRecord::Migration[5.0]
825
+ # class FixTLMigration < ActiveRecord::Migration[7.2]
661
826
  # def change
662
827
  # revert do
663
828
  # create_table(:horses) do |t|
@@ -674,9 +839,9 @@ module ActiveRecord
674
839
  # Or equivalently, if +TenderloveMigration+ is defined as in the
675
840
  # documentation for Migration:
676
841
  #
677
- # require_relative '20121212123456_tenderlove_migration'
842
+ # require_relative "20121212123456_tenderlove_migration"
678
843
  #
679
- # class FixupTLMigration < ActiveRecord::Migration[5.0]
844
+ # class FixupTLMigration < ActiveRecord::Migration[7.2]
680
845
  # def change
681
846
  # revert TenderloveMigration
682
847
  #
@@ -687,16 +852,16 @@ module ActiveRecord
687
852
  # end
688
853
  #
689
854
  # This command can be nested.
690
- def revert(*migration_classes)
855
+ def revert(*migration_classes, &block)
691
856
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
692
857
  if block_given?
693
858
  if connection.respond_to? :revert
694
- connection.revert { yield }
859
+ connection.revert(&block)
695
860
  else
696
861
  recorder = command_recorder
697
862
  @connection = recorder
698
863
  suppress_messages do
699
- connection.revert { yield }
864
+ connection.revert(&block)
700
865
  end
701
866
  @connection = recorder.delegate
702
867
  recorder.replay(self)
@@ -708,7 +873,7 @@ module ActiveRecord
708
873
  connection.respond_to?(:reverting) && connection.reverting
709
874
  end
710
875
 
711
- ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
876
+ ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
712
877
  def up
713
878
  yield unless reverting
714
879
  end
@@ -727,7 +892,7 @@ module ActiveRecord
727
892
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
728
893
  # even when migrating down:
729
894
  #
730
- # class SplitNameMigration < ActiveRecord::Migration[5.0]
895
+ # class SplitNameMigration < ActiveRecord::Migration[7.2]
731
896
  # def change
732
897
  # add_column :users, :first_name, :string
733
898
  # add_column :users, :last_name, :string
@@ -755,7 +920,7 @@ module ActiveRecord
755
920
  # In the following example, the new column +published+ will be given
756
921
  # the value +true+ for all existing records.
757
922
  #
758
- # class AddPublishedToPosts < ActiveRecord::Migration[5.2]
923
+ # class AddPublishedToPosts < ActiveRecord::Migration[7.2]
759
924
  # def change
760
925
  # add_column :posts, :published, :boolean, default: false
761
926
  # up_only do
@@ -763,14 +928,15 @@ module ActiveRecord
763
928
  # end
764
929
  # end
765
930
  # end
766
- def up_only
767
- execute_block { yield } unless reverting?
931
+ def up_only(&block)
932
+ execute_block(&block) unless reverting?
768
933
  end
769
934
 
770
935
  # Runs the given migration classes.
771
936
  # Last argument can specify options:
772
- # - :direction (default is :up)
773
- # - :revert (default is false)
937
+ #
938
+ # - +:direction+ - Default is +:up+.
939
+ # - +:revert+ - Default is +false+.
774
940
  def run(*migration_classes)
775
941
  opts = migration_classes.extract_options!
776
942
  dir = opts[:direction] || :up
@@ -807,7 +973,7 @@ module ActiveRecord
807
973
  end
808
974
 
809
975
  time = nil
810
- ActiveRecord::Base.connection_pool.with_connection do |conn|
976
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn|
811
977
  time = Benchmark.measure do
812
978
  exec_migration(conn, direction)
813
979
  end
@@ -828,10 +994,11 @@ module ActiveRecord
828
994
  change
829
995
  end
830
996
  else
831
- send(direction)
997
+ public_send(direction)
832
998
  end
833
999
  ensure
834
1000
  @connection = nil
1001
+ @execution_strategy = nil
835
1002
  end
836
1003
 
837
1004
  def write(text = "")
@@ -870,37 +1037,41 @@ module ActiveRecord
870
1037
  end
871
1038
 
872
1039
  def connection
873
- @connection || ActiveRecord::Base.connection
1040
+ @connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection
874
1041
  end
875
1042
 
876
- def method_missing(method, *arguments, &block)
877
- arg_list = arguments.map(&:inspect) * ", "
1043
+ def connection_pool
1044
+ @pool || ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
1045
+ end
878
1046
 
879
- say_with_time "#{method}(#{arg_list})" do
1047
+ def method_missing(method, *arguments, &block)
1048
+ say_with_time "#{method}(#{format_arguments(arguments)})" do
880
1049
  unless connection.respond_to? :revert
881
1050
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
882
1051
  arguments[0] = proper_table_name(arguments.first, table_name_options)
883
- if [:rename_table, :add_foreign_key].include?(method) ||
1052
+ if method == :rename_table ||
884
1053
  (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
885
1054
  arguments[1] = proper_table_name(arguments.second, table_name_options)
886
1055
  end
887
1056
  end
888
1057
  end
889
- return super unless connection.respond_to?(method)
890
- connection.send(method, *arguments, &block)
1058
+ return super unless execution_strategy.respond_to?(method)
1059
+ execution_strategy.send(method, *arguments, &block)
891
1060
  end
892
1061
  end
1062
+ ruby2_keywords(:method_missing)
893
1063
 
894
1064
  def copy(destination, sources, options = {})
895
1065
  copied = []
896
- schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
897
1066
 
898
1067
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
1068
+ schema_migration = SchemaMigration::NullSchemaMigration.new
1069
+ internal_metadata = InternalMetadata::NullInternalMetadata.new
899
1070
 
900
- destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
1071
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration, internal_metadata).migrations
901
1072
  last = destination_migrations.last
902
1073
  sources.each do |scope, path|
903
- source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
1074
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration, internal_metadata).migrations
904
1075
 
905
1076
  source_migrations.each do |migration|
906
1077
  source = File.binread(migration.filename)
@@ -915,6 +1086,12 @@ module ActiveRecord
915
1086
  magic_comments << magic_comment; ""
916
1087
  end || break
917
1088
  end
1089
+
1090
+ if !magic_comments.empty? && source.start_with?("\n")
1091
+ magic_comments << "\n"
1092
+ source = source[1..-1]
1093
+ end
1094
+
918
1095
  source = "#{magic_comments}#{inserted_comment}#{source}"
919
1096
 
920
1097
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
@@ -952,16 +1129,16 @@ module ActiveRecord
952
1129
 
953
1130
  # Determines the version number of the next migration.
954
1131
  def next_migration_number(number)
955
- if ActiveRecord::Base.timestamped_migrations
1132
+ if ActiveRecord.timestamped_migrations
956
1133
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
957
1134
  else
958
- SchemaMigration.normalize_migration_number(number)
1135
+ "%.3d" % number.to_i
959
1136
  end
960
1137
  end
961
1138
 
962
1139
  # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
963
1140
  # the Active Record object's table_name prefix and suffix
964
- def table_name_options(config = ActiveRecord::Base) #:nodoc:
1141
+ def table_name_options(config = ActiveRecord::Base) # :nodoc:
965
1142
  {
966
1143
  table_name_prefix: config.table_name_prefix,
967
1144
  table_name_suffix: config.table_name_suffix
@@ -977,6 +1154,22 @@ module ActiveRecord
977
1154
  end
978
1155
  end
979
1156
 
1157
+ def format_arguments(arguments)
1158
+ arg_list = arguments[0...-1].map(&:inspect)
1159
+ last_arg = arguments.last
1160
+ if last_arg.is_a?(Hash)
1161
+ last_arg = last_arg.reject { |k, _v| internal_option?(k) }
1162
+ arg_list << last_arg.inspect unless last_arg.empty?
1163
+ else
1164
+ arg_list << last_arg.inspect
1165
+ end
1166
+ arg_list.join(", ")
1167
+ end
1168
+
1169
+ def internal_option?(option_name)
1170
+ option_name.start_with?("_")
1171
+ end
1172
+
980
1173
  def command_recorder
981
1174
  CommandRecorder.new(connection)
982
1175
  end
@@ -994,42 +1187,52 @@ module ActiveRecord
994
1187
  File.basename(filename)
995
1188
  end
996
1189
 
997
- def mtime
998
- File.mtime filename
999
- end
1000
-
1001
1190
  delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
1002
1191
 
1003
1192
  private
1004
-
1005
1193
  def migration
1006
1194
  @migration ||= load_migration
1007
1195
  end
1008
1196
 
1009
1197
  def load_migration
1010
- require(File.expand_path(filename))
1198
+ Object.send(:remove_const, name) rescue nil
1199
+
1200
+ load(File.expand_path(filename))
1011
1201
  name.constantize.new(name, version)
1012
1202
  end
1013
1203
  end
1014
1204
 
1015
- class NullMigration < MigrationProxy #:nodoc:
1016
- def initialize
1017
- super(nil, 0, nil, nil)
1018
- end
1019
-
1020
- def mtime
1021
- 0
1022
- end
1023
- end
1024
-
1025
- class MigrationContext #:nodoc:
1026
- attr_reader :migrations_paths, :schema_migration
1205
+ # = \Migration \Context
1206
+ #
1207
+ # MigrationContext sets the context in which a migration is run.
1208
+ #
1209
+ # A migration context requires the path to the migrations is set
1210
+ # in the +migrations_paths+ parameter. Optionally a +schema_migration+
1211
+ # class can be provided. Multiple database applications will instantiate
1212
+ # a +SchemaMigration+ object per database. From the Rake tasks, \Rails will
1213
+ # handle this for you.
1214
+ class MigrationContext
1215
+ attr_reader :migrations_paths, :schema_migration, :internal_metadata
1027
1216
 
1028
- def initialize(migrations_paths, schema_migration)
1217
+ def initialize(migrations_paths, schema_migration = nil, internal_metadata = nil)
1029
1218
  @migrations_paths = migrations_paths
1030
- @schema_migration = schema_migration
1219
+ @schema_migration = schema_migration || SchemaMigration.new(connection_pool)
1220
+ @internal_metadata = internal_metadata || InternalMetadata.new(connection_pool)
1031
1221
  end
1032
1222
 
1223
+ # Runs the migrations in the +migrations_path+.
1224
+ #
1225
+ # If +target_version+ is +nil+, +migrate+ will run +up+.
1226
+ #
1227
+ # If the +current_version+ and +target_version+ are both
1228
+ # 0 then an empty array will be returned and no migrations
1229
+ # will be run.
1230
+ #
1231
+ # If the +current_version+ in the schema is greater than
1232
+ # the +target_version+, then +down+ will be run.
1233
+ #
1234
+ # If none of the conditions are met, +up+ will be run with
1235
+ # the +target_version+.
1033
1236
  def migrate(target_version = nil, &block)
1034
1237
  case
1035
1238
  when target_version.nil?
@@ -1043,71 +1246,70 @@ module ActiveRecord
1043
1246
  end
1044
1247
  end
1045
1248
 
1046
- def rollback(steps = 1)
1249
+ def rollback(steps = 1) # :nodoc:
1047
1250
  move(:down, steps)
1048
1251
  end
1049
1252
 
1050
- def forward(steps = 1)
1253
+ def forward(steps = 1) # :nodoc:
1051
1254
  move(:up, steps)
1052
1255
  end
1053
1256
 
1054
- def up(target_version = nil)
1257
+ def up(target_version = nil, &block) # :nodoc:
1055
1258
  selected_migrations = if block_given?
1056
- migrations.select { |m| yield m }
1259
+ migrations.select(&block)
1057
1260
  else
1058
1261
  migrations
1059
1262
  end
1060
1263
 
1061
- Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
1264
+ Migrator.new(:up, selected_migrations, schema_migration, internal_metadata, target_version).migrate
1062
1265
  end
1063
1266
 
1064
- def down(target_version = nil)
1267
+ def down(target_version = nil, &block) # :nodoc:
1065
1268
  selected_migrations = if block_given?
1066
- migrations.select { |m| yield m }
1269
+ migrations.select(&block)
1067
1270
  else
1068
1271
  migrations
1069
1272
  end
1070
1273
 
1071
- Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
1274
+ Migrator.new(:down, selected_migrations, schema_migration, internal_metadata, target_version).migrate
1072
1275
  end
1073
1276
 
1074
- def run(direction, target_version)
1075
- Migrator.new(direction, migrations, schema_migration, target_version).run
1277
+ def run(direction, target_version) # :nodoc:
1278
+ Migrator.new(direction, migrations, schema_migration, internal_metadata, target_version).run
1076
1279
  end
1077
1280
 
1078
- def open
1079
- Migrator.new(:up, migrations, schema_migration)
1281
+ def open # :nodoc:
1282
+ Migrator.new(:up, migrations, schema_migration, internal_metadata)
1080
1283
  end
1081
1284
 
1082
- def get_all_versions
1285
+ def get_all_versions # :nodoc:
1083
1286
  if schema_migration.table_exists?
1084
- schema_migration.all_versions.map(&:to_i)
1287
+ schema_migration.integer_versions
1085
1288
  else
1086
1289
  []
1087
1290
  end
1088
1291
  end
1089
1292
 
1090
- def current_version
1293
+ def current_version # :nodoc:
1091
1294
  get_all_versions.max || 0
1092
1295
  rescue ActiveRecord::NoDatabaseError
1093
1296
  end
1094
1297
 
1095
- def needs_migration?
1096
- (migrations.collect(&:version) - get_all_versions).size > 0
1298
+ def needs_migration? # :nodoc:
1299
+ pending_migration_versions.size > 0
1097
1300
  end
1098
1301
 
1099
- def any_migrations?
1100
- migrations.any?
1302
+ def pending_migration_versions # :nodoc:
1303
+ migrations.collect(&:version) - get_all_versions
1101
1304
  end
1102
1305
 
1103
- def last_migration #:nodoc:
1104
- migrations.last || NullMigration.new
1105
- end
1106
-
1107
- def migrations
1306
+ def migrations # :nodoc:
1108
1307
  migrations = migration_files.map do |file|
1109
1308
  version, name, scope = parse_migration_filename(file)
1110
1309
  raise IllegalMigrationNameError.new(file) unless version
1310
+ if validate_timestamp? && !valid_migration_timestamp?(version)
1311
+ raise InvalidMigrationTimestampError.new(version, name)
1312
+ end
1111
1313
  version = version.to_i
1112
1314
  name = name.camelize
1113
1315
 
@@ -1117,42 +1319,55 @@ module ActiveRecord
1117
1319
  migrations.sort_by(&:version)
1118
1320
  end
1119
1321
 
1120
- def migrations_status
1322
+ def migrations_status # :nodoc:
1121
1323
  db_list = schema_migration.normalized_versions
1122
1324
 
1123
- file_list = migration_files.map do |file|
1325
+ file_list = migration_files.filter_map do |file|
1124
1326
  version, name, scope = parse_migration_filename(file)
1125
1327
  raise IllegalMigrationNameError.new(file) unless version
1328
+ if validate_timestamp? && !valid_migration_timestamp?(version)
1329
+ raise InvalidMigrationTimestampError.new(version, name)
1330
+ end
1126
1331
  version = schema_migration.normalize_migration_number(version)
1127
1332
  status = db_list.delete(version) ? "up" : "down"
1128
1333
  [status, version, (name + scope).humanize]
1129
- end.compact
1334
+ end
1130
1335
 
1131
1336
  db_list.map! do |version|
1132
1337
  ["up", version, "********** NO FILE **********"]
1133
1338
  end
1134
1339
 
1135
- (db_list + file_list).sort_by { |_, version, _| version }
1340
+ (db_list + file_list).sort_by { |_, version, _| version.to_i }
1136
1341
  end
1137
1342
 
1138
- def current_environment
1343
+ def current_environment # :nodoc:
1139
1344
  ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1140
1345
  end
1141
1346
 
1142
- def protected_environment?
1347
+ def protected_environment? # :nodoc:
1143
1348
  ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1144
1349
  end
1145
1350
 
1146
- def last_stored_environment
1351
+ def last_stored_environment # :nodoc:
1352
+ internal_metadata = connection_pool.internal_metadata
1353
+ return nil unless internal_metadata.enabled?
1147
1354
  return nil if current_version == 0
1148
- raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1355
+ raise NoEnvironmentInSchemaError unless internal_metadata.table_exists?
1149
1356
 
1150
- environment = ActiveRecord::InternalMetadata[:environment]
1357
+ environment = internal_metadata[:environment]
1151
1358
  raise NoEnvironmentInSchemaError unless environment
1152
1359
  environment
1153
1360
  end
1154
1361
 
1155
1362
  private
1363
+ def connection
1364
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
1365
+ end
1366
+
1367
+ def connection_pool
1368
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
1369
+ end
1370
+
1156
1371
  def migration_files
1157
1372
  paths = Array(migrations_paths)
1158
1373
  Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
@@ -1162,8 +1377,16 @@ module ActiveRecord
1162
1377
  File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1163
1378
  end
1164
1379
 
1380
+ def validate_timestamp?
1381
+ ActiveRecord.timestamped_migrations && ActiveRecord.validate_migration_timestamps
1382
+ end
1383
+
1384
+ def valid_migration_timestamp?(version)
1385
+ version.to_i < (Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S").to_i
1386
+ end
1387
+
1165
1388
  def move(direction, steps)
1166
- migrator = Migrator.new(direction, migrations, schema_migration)
1389
+ migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
1167
1390
 
1168
1391
  if current_version != 0 && !migrator.current_migration
1169
1392
  raise UnknownMigrationVersionError.new(current_version)
@@ -1178,7 +1401,7 @@ module ActiveRecord
1178
1401
 
1179
1402
  finish = migrator.migrations[start_index + steps]
1180
1403
  version = finish ? finish.version : 0
1181
- send(direction, version)
1404
+ public_send(direction, version)
1182
1405
  end
1183
1406
  end
1184
1407
 
@@ -1188,23 +1411,28 @@ module ActiveRecord
1188
1411
 
1189
1412
  # For cases where a table doesn't exist like loading from schema cache
1190
1413
  def current_version
1191
- MigrationContext.new(migrations_paths, SchemaMigration).current_version
1414
+ connection_pool = ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
1415
+ schema_migration = SchemaMigration.new(connection_pool)
1416
+ internal_metadata = InternalMetadata.new(connection_pool)
1417
+
1418
+ MigrationContext.new(migrations_paths, schema_migration, internal_metadata).current_version
1192
1419
  end
1193
1420
  end
1194
1421
 
1195
1422
  self.migrations_paths = ["db/migrate"]
1196
1423
 
1197
- def initialize(direction, migrations, schema_migration, target_version = nil)
1424
+ def initialize(direction, migrations, schema_migration, internal_metadata, target_version = nil)
1198
1425
  @direction = direction
1199
1426
  @target_version = target_version
1200
1427
  @migrated_versions = nil
1201
1428
  @migrations = migrations
1202
1429
  @schema_migration = schema_migration
1430
+ @internal_metadata = internal_metadata
1203
1431
 
1204
1432
  validate(@migrations)
1205
1433
 
1206
1434
  @schema_migration.create_table
1207
- ActiveRecord::InternalMetadata.create_table
1435
+ @internal_metadata.create_table
1208
1436
  end
1209
1437
 
1210
1438
  def current_version
@@ -1257,19 +1485,21 @@ module ActiveRecord
1257
1485
  end
1258
1486
 
1259
1487
  def load_migrated
1260
- @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
1488
+ @migrated_versions = Set.new(@schema_migration.integer_versions)
1261
1489
  end
1262
1490
 
1263
1491
  private
1492
+ def connection
1493
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
1494
+ end
1264
1495
 
1265
1496
  # Used for running a specific migration.
1266
1497
  def run_without_lock
1267
1498
  migration = migrations.detect { |m| m.version == @target_version }
1268
1499
  raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1269
- result = execute_migration_in_transaction(migration, @direction)
1270
1500
 
1271
1501
  record_environment
1272
- result
1502
+ execute_migration_in_transaction(migration)
1273
1503
  end
1274
1504
 
1275
1505
  # Used for running multiple migrations up to or down to a certain value.
@@ -1278,18 +1508,15 @@ module ActiveRecord
1278
1508
  raise UnknownMigrationVersionError.new(@target_version)
1279
1509
  end
1280
1510
 
1281
- result = runnable.each do |migration|
1282
- execute_migration_in_transaction(migration, @direction)
1283
- end
1284
-
1285
1511
  record_environment
1286
- result
1512
+ runnable.each(&method(:execute_migration_in_transaction))
1287
1513
  end
1288
1514
 
1289
1515
  # Stores the current environment in the database.
1290
1516
  def record_environment
1291
1517
  return if down?
1292
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1518
+
1519
+ @internal_metadata[:environment] = connection.pool.db_config.env_name
1293
1520
  end
1294
1521
 
1295
1522
  def ran?(migration)
@@ -1301,14 +1528,15 @@ module ActiveRecord
1301
1528
  @target_version && @target_version != 0 && !target
1302
1529
  end
1303
1530
 
1304
- def execute_migration_in_transaction(migration, direction)
1531
+ def execute_migration_in_transaction(migration)
1305
1532
  return if down? && !migrated.include?(migration.version.to_i)
1306
1533
  return if up? && migrated.include?(migration.version.to_i)
1307
1534
 
1308
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1535
+ message = up? ? "Migrating to" : "Reverting"
1536
+ Base.logger.info "#{message} #{migration.name} (#{migration.version})" if Base.logger
1309
1537
 
1310
1538
  ddl_transaction(migration) do
1311
- migration.migrate(direction)
1539
+ migration.migrate(@direction)
1312
1540
  record_version_state_after_migrating(migration.version)
1313
1541
  end
1314
1542
  rescue => e
@@ -1341,10 +1569,10 @@ module ActiveRecord
1341
1569
  def record_version_state_after_migrating(version)
1342
1570
  if down?
1343
1571
  migrated.delete(version)
1344
- @schema_migration.delete_by(version: version.to_s)
1572
+ @schema_migration.delete_version(version.to_s)
1345
1573
  else
1346
1574
  migrated << version
1347
- @schema_migration.create!(version: version.to_s)
1575
+ @schema_migration.create_version(version.to_s)
1348
1576
  end
1349
1577
  end
1350
1578
 
@@ -1357,25 +1585,25 @@ module ActiveRecord
1357
1585
  end
1358
1586
 
1359
1587
  # Wrap the migration in a transaction only if supported by the adapter.
1360
- def ddl_transaction(migration)
1588
+ def ddl_transaction(migration, &block)
1361
1589
  if use_transaction?(migration)
1362
- Base.transaction { yield }
1590
+ connection.transaction(&block)
1363
1591
  else
1364
1592
  yield
1365
1593
  end
1366
1594
  end
1367
1595
 
1368
1596
  def use_transaction?(migration)
1369
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1597
+ !migration.disable_ddl_transaction && connection.supports_ddl_transactions?
1370
1598
  end
1371
1599
 
1372
1600
  def use_advisory_lock?
1373
- Base.connection.advisory_locks_enabled?
1601
+ connection.advisory_locks_enabled?
1374
1602
  end
1375
1603
 
1376
1604
  def with_advisory_lock
1377
1605
  lock_id = generate_migrator_advisory_lock_id
1378
- connection = Base.connection
1606
+
1379
1607
  got_lock = connection.get_advisory_lock(lock_id)
1380
1608
  raise ConcurrentMigrationError unless got_lock
1381
1609
  load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
@@ -1390,7 +1618,7 @@ module ActiveRecord
1390
1618
 
1391
1619
  MIGRATOR_SALT = 2053462845
1392
1620
  def generate_migrator_advisory_lock_id
1393
- db_name_hash = Zlib.crc32(Base.connection.current_database)
1621
+ db_name_hash = Zlib.crc32(connection.current_database)
1394
1622
  MIGRATOR_SALT * db_name_hash
1395
1623
  end
1396
1624
  end