omg-activerecord 8.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (412) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +355 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +219 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record/aggregations.rb +287 -0
  8. data/lib/active_record/association_relation.rb +50 -0
  9. data/lib/active_record/associations/alias_tracker.rb +90 -0
  10. data/lib/active_record/associations/association.rb +417 -0
  11. data/lib/active_record/associations/association_scope.rb +175 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +163 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  14. data/lib/active_record/associations/builder/association.rb +170 -0
  15. data/lib/active_record/associations/builder/belongs_to.rb +160 -0
  16. data/lib/active_record/associations/builder/collection_association.rb +80 -0
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -0
  18. data/lib/active_record/associations/builder/has_many.rb +23 -0
  19. data/lib/active_record/associations/builder/has_one.rb +61 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +48 -0
  21. data/lib/active_record/associations/collection_association.rb +535 -0
  22. data/lib/active_record/associations/collection_proxy.rb +1163 -0
  23. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  24. data/lib/active_record/associations/errors.rb +265 -0
  25. data/lib/active_record/associations/foreign_association.rb +40 -0
  26. data/lib/active_record/associations/has_many_association.rb +167 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +232 -0
  28. data/lib/active_record/associations/has_one_association.rb +142 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +106 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  33. data/lib/active_record/associations/join_dependency.rb +301 -0
  34. data/lib/active_record/associations/nested_error.rb +47 -0
  35. data/lib/active_record/associations/preloader/association.rb +316 -0
  36. data/lib/active_record/associations/preloader/batch.rb +48 -0
  37. data/lib/active_record/associations/preloader/branch.rb +153 -0
  38. data/lib/active_record/associations/preloader/through_association.rb +150 -0
  39. data/lib/active_record/associations/preloader.rb +135 -0
  40. data/lib/active_record/associations/singular_association.rb +76 -0
  41. data/lib/active_record/associations/through_association.rb +132 -0
  42. data/lib/active_record/associations.rb +1897 -0
  43. data/lib/active_record/asynchronous_queries_tracker.rb +64 -0
  44. data/lib/active_record/attribute_assignment.rb +82 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +106 -0
  46. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  47. data/lib/active_record/attribute_methods/dirty.rb +262 -0
  48. data/lib/active_record/attribute_methods/primary_key.rb +158 -0
  49. data/lib/active_record/attribute_methods/query.rb +50 -0
  50. data/lib/active_record/attribute_methods/read.rb +46 -0
  51. data/lib/active_record/attribute_methods/serialization.rb +232 -0
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +94 -0
  53. data/lib/active_record/attribute_methods/write.rb +49 -0
  54. data/lib/active_record/attribute_methods.rb +542 -0
  55. data/lib/active_record/attributes.rb +307 -0
  56. data/lib/active_record/autosave_association.rb +586 -0
  57. data/lib/active_record/base.rb +338 -0
  58. data/lib/active_record/callbacks.rb +452 -0
  59. data/lib/active_record/coders/column_serializer.rb +61 -0
  60. data/lib/active_record/coders/json.rb +15 -0
  61. data/lib/active_record/coders/yaml_column.rb +95 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +290 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +210 -0
  64. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +923 -0
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +31 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +747 -0
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +319 -0
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +239 -0
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +24 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +190 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +961 -0
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +106 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1883 -0
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +676 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +1218 -0
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1016 -0
  78. data/lib/active_record/connection_adapters/column.rb +122 -0
  79. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  80. data/lib/active_record/connection_adapters/mysql/column.rb +28 -0
  81. data/lib/active_record/connection_adapters/mysql/database_statements.rb +95 -0
  82. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  83. data/lib/active_record/connection_adapters/mysql/quoting.rb +114 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +106 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +106 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +97 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +300 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  89. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +96 -0
  90. data/lib/active_record/connection_adapters/mysql2_adapter.rb +196 -0
  91. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  92. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  93. data/lib/active_record/connection_adapters/postgresql/column.rb +82 -0
  94. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +231 -0
  95. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +91 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +54 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +31 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +20 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +109 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +42 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +74 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +124 -0
  115. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  116. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  117. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  118. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +125 -0
  119. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +45 -0
  120. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  121. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  122. data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -0
  123. data/lib/active_record/connection_adapters/postgresql/quoting.rb +238 -0
  124. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +71 -0
  125. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +169 -0
  126. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +392 -0
  127. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +127 -0
  128. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1162 -0
  129. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  130. data/lib/active_record/connection_adapters/postgresql/utils.rb +79 -0
  131. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1182 -0
  132. data/lib/active_record/connection_adapters/schema_cache.rb +478 -0
  133. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  134. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  135. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +145 -0
  136. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  137. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +116 -0
  138. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +37 -0
  139. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +39 -0
  140. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +47 -0
  141. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +221 -0
  142. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +843 -0
  143. data/lib/active_record/connection_adapters/statement_pool.rb +67 -0
  144. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +69 -0
  145. data/lib/active_record/connection_adapters/trilogy_adapter.rb +212 -0
  146. data/lib/active_record/connection_adapters.rb +176 -0
  147. data/lib/active_record/connection_handling.rb +413 -0
  148. data/lib/active_record/core.rb +836 -0
  149. data/lib/active_record/counter_cache.rb +230 -0
  150. data/lib/active_record/database_configurations/connection_url_resolver.rb +105 -0
  151. data/lib/active_record/database_configurations/database_config.rb +104 -0
  152. data/lib/active_record/database_configurations/hash_config.rb +172 -0
  153. data/lib/active_record/database_configurations/url_config.rb +78 -0
  154. data/lib/active_record/database_configurations.rb +309 -0
  155. data/lib/active_record/delegated_type.rb +289 -0
  156. data/lib/active_record/deprecator.rb +7 -0
  157. data/lib/active_record/destroy_association_async_job.rb +38 -0
  158. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  159. data/lib/active_record/dynamic_matchers.rb +121 -0
  160. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  161. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  162. data/lib/active_record/encryption/cipher.rb +53 -0
  163. data/lib/active_record/encryption/config.rb +70 -0
  164. data/lib/active_record/encryption/configurable.rb +60 -0
  165. data/lib/active_record/encryption/context.rb +42 -0
  166. data/lib/active_record/encryption/contexts.rb +76 -0
  167. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  168. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  169. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  170. data/lib/active_record/encryption/encrypted_attribute_type.rb +184 -0
  171. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  172. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  173. data/lib/active_record/encryption/encryptor.rb +177 -0
  174. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  175. data/lib/active_record/encryption/errors.rb +15 -0
  176. data/lib/active_record/encryption/extended_deterministic_queries.rb +159 -0
  177. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  178. data/lib/active_record/encryption/key.rb +28 -0
  179. data/lib/active_record/encryption/key_generator.rb +53 -0
  180. data/lib/active_record/encryption/key_provider.rb +46 -0
  181. data/lib/active_record/encryption/message.rb +33 -0
  182. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  183. data/lib/active_record/encryption/message_serializer.rb +96 -0
  184. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  185. data/lib/active_record/encryption/properties.rb +76 -0
  186. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  187. data/lib/active_record/encryption/scheme.rb +107 -0
  188. data/lib/active_record/encryption.rb +58 -0
  189. data/lib/active_record/enum.rb +424 -0
  190. data/lib/active_record/errors.rb +614 -0
  191. data/lib/active_record/explain.rb +63 -0
  192. data/lib/active_record/explain_registry.rb +37 -0
  193. data/lib/active_record/explain_subscriber.rb +34 -0
  194. data/lib/active_record/fixture_set/file.rb +89 -0
  195. data/lib/active_record/fixture_set/model_metadata.rb +42 -0
  196. data/lib/active_record/fixture_set/render_context.rb +19 -0
  197. data/lib/active_record/fixture_set/table_row.rb +208 -0
  198. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  199. data/lib/active_record/fixtures.rb +850 -0
  200. data/lib/active_record/future_result.rb +182 -0
  201. data/lib/active_record/gem_version.rb +17 -0
  202. data/lib/active_record/inheritance.rb +366 -0
  203. data/lib/active_record/insert_all.rb +328 -0
  204. data/lib/active_record/integration.rb +209 -0
  205. data/lib/active_record/internal_metadata.rb +164 -0
  206. data/lib/active_record/legacy_yaml_adapter.rb +15 -0
  207. data/lib/active_record/locale/en.yml +48 -0
  208. data/lib/active_record/locking/optimistic.rb +228 -0
  209. data/lib/active_record/locking/pessimistic.rb +102 -0
  210. data/lib/active_record/log_subscriber.rb +149 -0
  211. data/lib/active_record/marshalling.rb +56 -0
  212. data/lib/active_record/message_pack.rb +124 -0
  213. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  214. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  215. data/lib/active_record/middleware/database_selector.rb +87 -0
  216. data/lib/active_record/middleware/shard_selector.rb +62 -0
  217. data/lib/active_record/migration/command_recorder.rb +406 -0
  218. data/lib/active_record/migration/compatibility.rb +490 -0
  219. data/lib/active_record/migration/default_strategy.rb +22 -0
  220. data/lib/active_record/migration/execution_strategy.rb +19 -0
  221. data/lib/active_record/migration/join_table.rb +16 -0
  222. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  223. data/lib/active_record/migration.rb +1626 -0
  224. data/lib/active_record/model_schema.rb +635 -0
  225. data/lib/active_record/nested_attributes.rb +633 -0
  226. data/lib/active_record/no_touching.rb +65 -0
  227. data/lib/active_record/normalization.rb +163 -0
  228. data/lib/active_record/persistence.rb +968 -0
  229. data/lib/active_record/promise.rb +84 -0
  230. data/lib/active_record/query_cache.rb +56 -0
  231. data/lib/active_record/query_logs.rb +247 -0
  232. data/lib/active_record/query_logs_formatter.rb +30 -0
  233. data/lib/active_record/querying.rb +122 -0
  234. data/lib/active_record/railtie.rb +440 -0
  235. data/lib/active_record/railties/console_sandbox.rb +5 -0
  236. data/lib/active_record/railties/controller_runtime.rb +65 -0
  237. data/lib/active_record/railties/databases.rake +641 -0
  238. data/lib/active_record/railties/job_runtime.rb +23 -0
  239. data/lib/active_record/readonly_attributes.rb +66 -0
  240. data/lib/active_record/reflection.rb +1287 -0
  241. data/lib/active_record/relation/batches/batch_enumerator.rb +115 -0
  242. data/lib/active_record/relation/batches.rb +491 -0
  243. data/lib/active_record/relation/calculations.rb +679 -0
  244. data/lib/active_record/relation/delegation.rb +154 -0
  245. data/lib/active_record/relation/finder_methods.rb +661 -0
  246. data/lib/active_record/relation/from_clause.rb +30 -0
  247. data/lib/active_record/relation/merger.rb +192 -0
  248. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  249. data/lib/active_record/relation/predicate_builder/association_query_value.rb +76 -0
  250. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  251. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +60 -0
  252. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  253. data/lib/active_record/relation/predicate_builder/relation_handler.rb +24 -0
  254. data/lib/active_record/relation/predicate_builder.rb +181 -0
  255. data/lib/active_record/relation/query_attribute.rb +68 -0
  256. data/lib/active_record/relation/query_methods.rb +2235 -0
  257. data/lib/active_record/relation/record_fetch_warning.rb +52 -0
  258. data/lib/active_record/relation/spawn_methods.rb +78 -0
  259. data/lib/active_record/relation/where_clause.rb +218 -0
  260. data/lib/active_record/relation.rb +1495 -0
  261. data/lib/active_record/result.rb +249 -0
  262. data/lib/active_record/runtime_registry.rb +82 -0
  263. data/lib/active_record/sanitization.rb +254 -0
  264. data/lib/active_record/schema.rb +77 -0
  265. data/lib/active_record/schema_dumper.rb +364 -0
  266. data/lib/active_record/schema_migration.rb +106 -0
  267. data/lib/active_record/scoping/default.rb +205 -0
  268. data/lib/active_record/scoping/named.rb +202 -0
  269. data/lib/active_record/scoping.rb +136 -0
  270. data/lib/active_record/secure_password.rb +60 -0
  271. data/lib/active_record/secure_token.rb +66 -0
  272. data/lib/active_record/serialization.rb +29 -0
  273. data/lib/active_record/signed_id.rb +137 -0
  274. data/lib/active_record/statement_cache.rb +164 -0
  275. data/lib/active_record/store.rb +299 -0
  276. data/lib/active_record/suppressor.rb +59 -0
  277. data/lib/active_record/table_metadata.rb +85 -0
  278. data/lib/active_record/tasks/database_tasks.rb +681 -0
  279. data/lib/active_record/tasks/mysql_database_tasks.rb +120 -0
  280. data/lib/active_record/tasks/postgresql_database_tasks.rb +147 -0
  281. data/lib/active_record/tasks/sqlite_database_tasks.rb +89 -0
  282. data/lib/active_record/test_databases.rb +24 -0
  283. data/lib/active_record/test_fixtures.rb +321 -0
  284. data/lib/active_record/testing/query_assertions.rb +121 -0
  285. data/lib/active_record/timestamp.rb +177 -0
  286. data/lib/active_record/token_for.rb +123 -0
  287. data/lib/active_record/touch_later.rb +70 -0
  288. data/lib/active_record/transaction.rb +132 -0
  289. data/lib/active_record/transactions.rb +523 -0
  290. data/lib/active_record/translation.rb +22 -0
  291. data/lib/active_record/type/adapter_specific_registry.rb +144 -0
  292. data/lib/active_record/type/date.rb +9 -0
  293. data/lib/active_record/type/date_time.rb +9 -0
  294. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  295. data/lib/active_record/type/hash_lookup_type_map.rb +57 -0
  296. data/lib/active_record/type/internal/timezone.rb +22 -0
  297. data/lib/active_record/type/json.rb +30 -0
  298. data/lib/active_record/type/serialized.rb +76 -0
  299. data/lib/active_record/type/text.rb +11 -0
  300. data/lib/active_record/type/time.rb +35 -0
  301. data/lib/active_record/type/type_map.rb +58 -0
  302. data/lib/active_record/type/unsigned_integer.rb +16 -0
  303. data/lib/active_record/type.rb +83 -0
  304. data/lib/active_record/type_caster/connection.rb +33 -0
  305. data/lib/active_record/type_caster/map.rb +23 -0
  306. data/lib/active_record/type_caster.rb +9 -0
  307. data/lib/active_record/validations/absence.rb +25 -0
  308. data/lib/active_record/validations/associated.rb +65 -0
  309. data/lib/active_record/validations/length.rb +26 -0
  310. data/lib/active_record/validations/numericality.rb +36 -0
  311. data/lib/active_record/validations/presence.rb +45 -0
  312. data/lib/active_record/validations/uniqueness.rb +295 -0
  313. data/lib/active_record/validations.rb +101 -0
  314. data/lib/active_record/version.rb +10 -0
  315. data/lib/active_record.rb +616 -0
  316. data/lib/arel/alias_predication.rb +9 -0
  317. data/lib/arel/attributes/attribute.rb +33 -0
  318. data/lib/arel/collectors/bind.rb +31 -0
  319. data/lib/arel/collectors/composite.rb +46 -0
  320. data/lib/arel/collectors/plain_string.rb +20 -0
  321. data/lib/arel/collectors/sql_string.rb +27 -0
  322. data/lib/arel/collectors/substitute_binds.rb +35 -0
  323. data/lib/arel/crud.rb +48 -0
  324. data/lib/arel/delete_manager.rb +32 -0
  325. data/lib/arel/errors.rb +19 -0
  326. data/lib/arel/expressions.rb +29 -0
  327. data/lib/arel/factory_methods.rb +53 -0
  328. data/lib/arel/filter_predications.rb +9 -0
  329. data/lib/arel/insert_manager.rb +48 -0
  330. data/lib/arel/math.rb +45 -0
  331. data/lib/arel/nodes/ascending.rb +23 -0
  332. data/lib/arel/nodes/binary.rb +125 -0
  333. data/lib/arel/nodes/bind_param.rb +44 -0
  334. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  335. data/lib/arel/nodes/case.rb +55 -0
  336. data/lib/arel/nodes/casted.rb +62 -0
  337. data/lib/arel/nodes/comment.rb +29 -0
  338. data/lib/arel/nodes/count.rb +12 -0
  339. data/lib/arel/nodes/cte.rb +36 -0
  340. data/lib/arel/nodes/delete_statement.rb +44 -0
  341. data/lib/arel/nodes/descending.rb +23 -0
  342. data/lib/arel/nodes/equality.rb +15 -0
  343. data/lib/arel/nodes/extract.rb +24 -0
  344. data/lib/arel/nodes/false.rb +16 -0
  345. data/lib/arel/nodes/filter.rb +10 -0
  346. data/lib/arel/nodes/fragments.rb +35 -0
  347. data/lib/arel/nodes/full_outer_join.rb +8 -0
  348. data/lib/arel/nodes/function.rb +45 -0
  349. data/lib/arel/nodes/grouping.rb +11 -0
  350. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  351. data/lib/arel/nodes/in.rb +15 -0
  352. data/lib/arel/nodes/infix_operation.rb +92 -0
  353. data/lib/arel/nodes/inner_join.rb +8 -0
  354. data/lib/arel/nodes/insert_statement.rb +37 -0
  355. data/lib/arel/nodes/join_source.rb +20 -0
  356. data/lib/arel/nodes/leading_join.rb +8 -0
  357. data/lib/arel/nodes/matches.rb +18 -0
  358. data/lib/arel/nodes/named_function.rb +23 -0
  359. data/lib/arel/nodes/nary.rb +39 -0
  360. data/lib/arel/nodes/node.rb +161 -0
  361. data/lib/arel/nodes/node_expression.rb +13 -0
  362. data/lib/arel/nodes/ordering.rb +27 -0
  363. data/lib/arel/nodes/outer_join.rb +8 -0
  364. data/lib/arel/nodes/over.rb +15 -0
  365. data/lib/arel/nodes/regexp.rb +16 -0
  366. data/lib/arel/nodes/right_outer_join.rb +8 -0
  367. data/lib/arel/nodes/select_core.rb +67 -0
  368. data/lib/arel/nodes/select_statement.rb +41 -0
  369. data/lib/arel/nodes/sql_literal.rb +32 -0
  370. data/lib/arel/nodes/string_join.rb +11 -0
  371. data/lib/arel/nodes/table_alias.rb +35 -0
  372. data/lib/arel/nodes/terminal.rb +16 -0
  373. data/lib/arel/nodes/true.rb +16 -0
  374. data/lib/arel/nodes/unary.rb +44 -0
  375. data/lib/arel/nodes/unary_operation.rb +20 -0
  376. data/lib/arel/nodes/unqualified_column.rb +22 -0
  377. data/lib/arel/nodes/update_statement.rb +46 -0
  378. data/lib/arel/nodes/values_list.rb +9 -0
  379. data/lib/arel/nodes/window.rb +126 -0
  380. data/lib/arel/nodes/with.rb +11 -0
  381. data/lib/arel/nodes.rb +75 -0
  382. data/lib/arel/order_predications.rb +13 -0
  383. data/lib/arel/predications.rb +260 -0
  384. data/lib/arel/select_manager.rb +276 -0
  385. data/lib/arel/table.rb +121 -0
  386. data/lib/arel/tree_manager.rb +65 -0
  387. data/lib/arel/update_manager.rb +49 -0
  388. data/lib/arel/visitors/dot.rb +299 -0
  389. data/lib/arel/visitors/mysql.rb +111 -0
  390. data/lib/arel/visitors/postgresql.rb +99 -0
  391. data/lib/arel/visitors/sqlite.rb +38 -0
  392. data/lib/arel/visitors/to_sql.rb +1033 -0
  393. data/lib/arel/visitors/visitor.rb +45 -0
  394. data/lib/arel/visitors.rb +13 -0
  395. data/lib/arel/window_predications.rb +9 -0
  396. data/lib/arel.rb +73 -0
  397. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  398. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  399. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  400. data/lib/rails/generators/active_record/migration/migration_generator.rb +76 -0
  401. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +29 -0
  402. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  403. data/lib/rails/generators/active_record/migration.rb +54 -0
  404. data/lib/rails/generators/active_record/model/USAGE +113 -0
  405. data/lib/rails/generators/active_record/model/model_generator.rb +94 -0
  406. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  407. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  408. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  409. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  410. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  411. data/lib/rails/generators/active_record.rb +19 -0
  412. metadata +505 -0
@@ -0,0 +1,1626 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "active_support/core_ext/array/access"
5
+ require "active_support/core_ext/enumerable"
6
+ require "active_support/core_ext/module/attribute_accessors"
7
+ require "active_support/actionable_error"
8
+ require "active_record/migration/pending_migration_connection"
9
+
10
+ module ActiveRecord
11
+ class MigrationError < ActiveRecordError # :nodoc:
12
+ def initialize(message = nil)
13
+ message = "\n\n#{message}\n\n" if message
14
+ super
15
+ end
16
+ end
17
+
18
+ # Exception that can be raised to stop migrations from being rolled back.
19
+ # For example the following migration is not reversible.
20
+ # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
21
+ #
22
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[8.0]
23
+ # def change
24
+ # create_table :distributors do |t|
25
+ # t.string :zipcode
26
+ # end
27
+ #
28
+ # execute <<~SQL
29
+ # ALTER TABLE distributors
30
+ # ADD CONSTRAINT zipchk
31
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
32
+ # SQL
33
+ # end
34
+ # end
35
+ #
36
+ # There are two ways to mitigate this problem.
37
+ #
38
+ # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
39
+ #
40
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
41
+ # def up
42
+ # create_table :distributors do |t|
43
+ # t.string :zipcode
44
+ # end
45
+ #
46
+ # execute <<~SQL
47
+ # ALTER TABLE distributors
48
+ # ADD CONSTRAINT zipchk
49
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
50
+ # SQL
51
+ # end
52
+ #
53
+ # def down
54
+ # execute <<~SQL
55
+ # ALTER TABLE distributors
56
+ # DROP CONSTRAINT zipchk
57
+ # SQL
58
+ #
59
+ # drop_table :distributors
60
+ # end
61
+ # end
62
+ #
63
+ # 2. Use the #reversible method in <tt>#change</tt> method:
64
+ #
65
+ # class ReversibleMigrationExample < ActiveRecord::Migration[8.0]
66
+ # def change
67
+ # create_table :distributors do |t|
68
+ # t.string :zipcode
69
+ # end
70
+ #
71
+ # reversible do |dir|
72
+ # dir.up do
73
+ # execute <<~SQL
74
+ # ALTER TABLE distributors
75
+ # ADD CONSTRAINT zipchk
76
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
77
+ # SQL
78
+ # end
79
+ #
80
+ # dir.down do
81
+ # execute <<~SQL
82
+ # ALTER TABLE distributors
83
+ # DROP CONSTRAINT zipchk
84
+ # SQL
85
+ # end
86
+ # end
87
+ # end
88
+ # end
89
+ class IrreversibleMigration < MigrationError
90
+ end
91
+
92
+ class DuplicateMigrationVersionError < MigrationError # :nodoc:
93
+ def initialize(version = nil)
94
+ if version
95
+ super("Multiple migrations have the version number #{version}.")
96
+ else
97
+ super("Duplicate migration version error.")
98
+ end
99
+ end
100
+ end
101
+
102
+ class DuplicateMigrationNameError < MigrationError # :nodoc:
103
+ def initialize(name = nil)
104
+ if name
105
+ super("Multiple migrations have the name #{name}.")
106
+ else
107
+ super("Duplicate migration name.")
108
+ end
109
+ end
110
+ end
111
+
112
+ class UnknownMigrationVersionError < MigrationError # :nodoc:
113
+ def initialize(version = nil)
114
+ if version
115
+ super("No migration with version number #{version}.")
116
+ else
117
+ super("Unknown migration version.")
118
+ end
119
+ end
120
+ end
121
+
122
+ class IllegalMigrationNameError < MigrationError # :nodoc:
123
+ def initialize(name = nil)
124
+ if name
125
+ super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
126
+ else
127
+ super("Illegal name for migration.")
128
+ end
129
+ end
130
+ end
131
+
132
+ class InvalidMigrationTimestampError < MigrationError # :nodoc:
133
+ def initialize(version = nil, name = nil)
134
+ if version && name
135
+ super(<<~MSG)
136
+ Invalid timestamp #{version} for migration file: #{name}.
137
+ Timestamp must be in form YYYYMMDDHHMMSS, and less than #{(Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S")}.
138
+ MSG
139
+ else
140
+ super(<<~MSG)
141
+ Invalid timestamp for migration.
142
+ Timestamp must be in form YYYYMMDDHHMMSS, and less than #{(Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S")}.
143
+ MSG
144
+ end
145
+ end
146
+ end
147
+
148
+ class PendingMigrationError < MigrationError # :nodoc:
149
+ include ActiveSupport::ActionableError
150
+
151
+ action "Run pending migrations" do
152
+ ActiveRecord::Tasks::DatabaseTasks.migrate
153
+
154
+ if ActiveRecord.dump_schema_after_migration
155
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
156
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
157
+ end
158
+ end
159
+
160
+ def initialize(message = nil, pending_migrations: nil)
161
+ if pending_migrations.nil?
162
+ pending_migrations = connection_pool.migration_context.open.pending_migrations
163
+ end
164
+
165
+ super(message || detailed_migration_message(pending_migrations))
166
+ end
167
+
168
+ private
169
+ def detailed_migration_message(pending_migrations)
170
+ message = "Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate"
171
+ message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env) && !Rails.env.local?
172
+ message += "\n\n"
173
+
174
+ message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
175
+
176
+ pending_migrations.each do |pending_migration|
177
+ message += "#{pending_migration.filename}\n"
178
+ end
179
+
180
+ message
181
+ end
182
+
183
+ def connection_pool
184
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
185
+ end
186
+ end
187
+
188
+ class ConcurrentMigrationError < MigrationError # :nodoc:
189
+ DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
190
+ RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
191
+
192
+ def initialize(message = DEFAULT_MESSAGE)
193
+ super
194
+ end
195
+ end
196
+
197
+ class NoEnvironmentInSchemaError < MigrationError # :nodoc:
198
+ def initialize
199
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
200
+ if defined?(Rails.env)
201
+ super("#{msg} RAILS_ENV=#{::Rails.env}")
202
+ else
203
+ super(msg)
204
+ end
205
+ end
206
+ end
207
+
208
+ class ProtectedEnvironmentError < ActiveRecordError # :nodoc:
209
+ def initialize(env = "production")
210
+ msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
211
+ msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
212
+ msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
213
+ super(msg)
214
+ end
215
+ end
216
+
217
+ class EnvironmentMismatchError < ActiveRecordError
218
+ def initialize(current: nil, stored: nil)
219
+ msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
220
+ msg << "You are running in `#{ current }` environment. "
221
+ msg << "If you are sure you want to continue, first set the environment using:\n\n"
222
+ msg << " bin/rails db:environment:set"
223
+ if defined?(Rails.env)
224
+ super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
225
+ else
226
+ super("#{msg}\n\n")
227
+ end
228
+ end
229
+ end
230
+
231
+ class EnvironmentStorageError < ActiveRecordError # :nodoc:
232
+ def initialize
233
+ msg = +"You are attempting to store the environment in a database where metadata is disabled.\n"
234
+ msg << "Check your database configuration to see if this is intended."
235
+ super(msg)
236
+ end
237
+ end
238
+
239
+ # = Active Record Migrations
240
+ #
241
+ # Migrations can manage the evolution of a schema used by several physical
242
+ # databases. It's a solution to the common problem of adding a field to make
243
+ # a new feature work in your local database, but being unsure of how to
244
+ # push that change to other developers and to the production server. With
245
+ # migrations, you can describe the transformations in self-contained classes
246
+ # that can be checked into version control systems and executed against
247
+ # another database that might be one, two, or five versions behind.
248
+ #
249
+ # Example of a simple migration:
250
+ #
251
+ # class AddSsl < ActiveRecord::Migration[8.0]
252
+ # def up
253
+ # add_column :accounts, :ssl_enabled, :boolean, default: true
254
+ # end
255
+ #
256
+ # def down
257
+ # remove_column :accounts, :ssl_enabled
258
+ # end
259
+ # end
260
+ #
261
+ # This migration will add a boolean flag to the accounts table and remove it
262
+ # if you're backing out of the migration. It shows how all migrations have
263
+ # two methods +up+ and +down+ that describes the transformations
264
+ # required to implement or remove the migration. These methods can consist
265
+ # of both the migration specific methods like +add_column+ and +remove_column+,
266
+ # but may also contain regular Ruby code for generating data needed for the
267
+ # transformations.
268
+ #
269
+ # Example of a more complex migration that also needs to initialize data:
270
+ #
271
+ # class AddSystemSettings < ActiveRecord::Migration[8.0]
272
+ # def up
273
+ # create_table :system_settings do |t|
274
+ # t.string :name
275
+ # t.string :label
276
+ # t.text :value
277
+ # t.string :type
278
+ # t.integer :position
279
+ # end
280
+ #
281
+ # SystemSetting.create name: 'notice',
282
+ # label: 'Use notice?',
283
+ # value: 1
284
+ # end
285
+ #
286
+ # def down
287
+ # drop_table :system_settings
288
+ # end
289
+ # end
290
+ #
291
+ # This migration first adds the +system_settings+ table, then creates the very
292
+ # first row in it using the Active Record model that relies on the table. It
293
+ # also uses the more advanced +create_table+ syntax where you can specify a
294
+ # complete table schema in one block call.
295
+ #
296
+ # == Available transformations
297
+ #
298
+ # === Creation
299
+ #
300
+ # * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
301
+ # table having its name as the lexical order of the first two
302
+ # arguments. See
303
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
304
+ # details.
305
+ # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
306
+ # makes the table object available to a block that can then add columns to it,
307
+ # following the same format as +add_column+. See example above. The options hash
308
+ # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
309
+ # table definition.
310
+ # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
311
+ # to the table called +table_name+
312
+ # named +column_name+ specified to be one of the following types:
313
+ # <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
314
+ # <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
315
+ # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be
316
+ # specified by passing an +options+ hash like <tt>{ default: 11 }</tt>.
317
+ # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
318
+ # <tt>{ limit: 50, null: false }</tt>) -- see
319
+ # ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
320
+ # * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
321
+ # foreign key. +from_table+ is the table with the key column, +to_table+ contains
322
+ # the referenced primary key.
323
+ # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
324
+ # with the name of the column. Other options include
325
+ # <tt>:name</tt>, <tt>:unique</tt> (e.g.
326
+ # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
327
+ # (e.g. <tt>{ order: { name: :desc } }</tt>).
328
+ # * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
329
+ # +reference_name_id+ by default an integer. See
330
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
331
+ # * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
332
+ # and +updated_at+) columns to +table_name+.
333
+ #
334
+ # === Modification
335
+ #
336
+ # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
337
+ # the column to a different type using the same parameters as add_column.
338
+ # * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>:
339
+ # Sets a default value for +column_name+ defined by +default_or_changes+ on
340
+ # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
341
+ # as +default_or_changes+ will make this change reversible in the migration.
342
+ # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
343
+ # Sets or removes a <tt>NOT NULL</tt> constraint on +column_name+. The +null+ flag
344
+ # indicates whether the value can be +NULL+. See
345
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
346
+ # details.
347
+ # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
348
+ # the table called +name+. It makes the table object available to a block that
349
+ # can then add/remove columns, indexes, or foreign keys to it.
350
+ # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
351
+ # a column but keeps the type and content.
352
+ # * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
353
+ # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
354
+ # to +new_name+.
355
+ #
356
+ # === Deletion
357
+ #
358
+ # * <tt>drop_table(*names)</tt>: Drops the given tables.
359
+ # * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
360
+ # specified by the given arguments.
361
+ # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
362
+ # named +column_name+ from the table called +table_name+.
363
+ # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
364
+ # columns from the table definition.
365
+ # * <tt>remove_foreign_key(from_table, to_table = nil, **options)</tt>: Removes the
366
+ # given foreign key from the table called +table_name+.
367
+ # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
368
+ # specified by +column_names+.
369
+ # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
370
+ # specified by +index_name+.
371
+ # * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
372
+ # reference(s) on +table_name+ specified by +ref_name+.
373
+ # * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
374
+ # columns (+created_at+ and +updated_at+) from the table definition.
375
+ #
376
+ # == Irreversible transformations
377
+ #
378
+ # Some transformations are destructive in a manner that cannot be reversed.
379
+ # Migrations of that kind should raise an ActiveRecord::IrreversibleMigration
380
+ # exception in their +down+ method.
381
+ #
382
+ # == Running migrations from within \Rails
383
+ #
384
+ # The \Rails package has several tools to help create and apply migrations.
385
+ #
386
+ # To generate a new migration, you can use
387
+ #
388
+ # $ bin/rails generate migration MyNewMigration
389
+ #
390
+ # where MyNewMigration is the name of your migration. The generator will
391
+ # create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
392
+ # in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
393
+ # UTC formatted date and time that the migration was generated.
394
+ #
395
+ # There is a special syntactic shortcut to generate migrations that add fields to a table.
396
+ #
397
+ # $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
398
+ #
399
+ # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
400
+ # class AddFieldnameToTablename < ActiveRecord::Migration[8.0]
401
+ # def change
402
+ # add_column :tablenames, :fieldname, :string
403
+ # end
404
+ # end
405
+ #
406
+ # To run migrations against the currently configured database, use
407
+ # <tt>bin/rails db:migrate</tt>. This will update the database by running all of the
408
+ # pending migrations, creating the <tt>schema_migrations</tt> table
409
+ # (see "About the schema_migrations table" section below) if missing. It will also
410
+ # invoke the db:schema:dump command, which will update your db/schema.rb file
411
+ # to match the structure of your database.
412
+ #
413
+ # To roll the database back to a previous migration version, use
414
+ # <tt>bin/rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
415
+ # you wish to downgrade. Alternatively, you can also use the STEP option if you
416
+ # wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
417
+ # the latest two migrations.
418
+ #
419
+ # If any of the migrations throw an ActiveRecord::IrreversibleMigration exception,
420
+ # that step will fail and you'll have some manual work to do.
421
+ #
422
+ # == More examples
423
+ #
424
+ # Not all migrations change the schema. Some just fix the data:
425
+ #
426
+ # class RemoveEmptyTags < ActiveRecord::Migration[8.0]
427
+ # def up
428
+ # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
429
+ # end
430
+ #
431
+ # def down
432
+ # # not much we can do to restore deleted data
433
+ # raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
434
+ # end
435
+ # end
436
+ #
437
+ # Others remove columns when they migrate up instead of down:
438
+ #
439
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.0]
440
+ # def up
441
+ # remove_column :items, :incomplete_items_count
442
+ # remove_column :items, :completed_items_count
443
+ # end
444
+ #
445
+ # def down
446
+ # add_column :items, :incomplete_items_count
447
+ # add_column :items, :completed_items_count
448
+ # end
449
+ # end
450
+ #
451
+ # And sometimes you need to do something in SQL not abstracted directly by migrations:
452
+ #
453
+ # class MakeJoinUnique < ActiveRecord::Migration[8.0]
454
+ # def up
455
+ # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
456
+ # end
457
+ #
458
+ # def down
459
+ # execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
460
+ # end
461
+ # end
462
+ #
463
+ # == Using a model after changing its table
464
+ #
465
+ # Sometimes you'll want to add a column in a migration and populate it
466
+ # immediately after. In that case, you'll need to make a call to
467
+ # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
468
+ # latest column data from after the new column was added. Example:
469
+ #
470
+ # class AddPeopleSalary < ActiveRecord::Migration[8.0]
471
+ # def up
472
+ # add_column :people, :salary, :integer
473
+ # Person.reset_column_information
474
+ # Person.all.each do |p|
475
+ # p.update_attribute :salary, SalaryCalculator.compute(p)
476
+ # end
477
+ # end
478
+ # end
479
+ #
480
+ # == Controlling verbosity
481
+ #
482
+ # By default, migrations will describe the actions they are taking, writing
483
+ # them to the console as they happen, along with benchmarks describing how
484
+ # long each step took.
485
+ #
486
+ # You can quiet them down by setting <tt>ActiveRecord::Migration.verbose = false</tt>.
487
+ #
488
+ # You can also insert your own messages and benchmarks by using the +say_with_time+
489
+ # method:
490
+ #
491
+ # def up
492
+ # ...
493
+ # say_with_time "Updating salaries..." do
494
+ # Person.all.each do |p|
495
+ # p.update_attribute :salary, SalaryCalculator.compute(p)
496
+ # end
497
+ # end
498
+ # ...
499
+ # end
500
+ #
501
+ # The phrase "Updating salaries..." would then be printed, along with the
502
+ # benchmark for the block when the block completes.
503
+ #
504
+ # == Timestamped Migrations
505
+ #
506
+ # By default, \Rails generates migrations that look like:
507
+ #
508
+ # 20080717013526_your_migration_name.rb
509
+ #
510
+ # The prefix is a generation timestamp (in UTC). Timestamps should not be
511
+ # modified manually. To validate that migration timestamps adhere to the
512
+ # format Active Record expects, you can use the following configuration option:
513
+ #
514
+ # config.active_record.validate_migration_timestamps = true
515
+ #
516
+ # If you'd prefer to use numeric prefixes, you can turn timestamped migrations
517
+ # off by setting:
518
+ #
519
+ # config.active_record.timestamped_migrations = false
520
+ #
521
+ # In application.rb.
522
+ #
523
+ # == Reversible Migrations
524
+ #
525
+ # Reversible migrations are migrations that know how to go +down+ for you.
526
+ # You simply supply the +up+ logic, and the Migration system figures out
527
+ # how to execute the down commands for you.
528
+ #
529
+ # To define a reversible migration, define the +change+ method in your
530
+ # migration like this:
531
+ #
532
+ # class TenderloveMigration < ActiveRecord::Migration[8.0]
533
+ # def change
534
+ # create_table(:horses) do |t|
535
+ # t.column :content, :text
536
+ # t.column :remind_at, :datetime
537
+ # end
538
+ # end
539
+ # end
540
+ #
541
+ # This migration will create the horses table for you on the way up, and
542
+ # automatically figure out how to drop the table on the way down.
543
+ #
544
+ # Some commands cannot be reversed. If you care to define how to move up
545
+ # and down in these cases, you should define the +up+ and +down+ methods
546
+ # as before.
547
+ #
548
+ # If a command cannot be reversed, an
549
+ # ActiveRecord::IrreversibleMigration exception will be raised when
550
+ # the migration is moving down.
551
+ #
552
+ # For a list of commands that are reversible, please see
553
+ # +ActiveRecord::Migration::CommandRecorder+.
554
+ #
555
+ # == Transactional Migrations
556
+ #
557
+ # If the database adapter supports DDL transactions, all migrations will
558
+ # automatically be wrapped in a transaction. There are queries that you
559
+ # can't execute inside a transaction though, and for these situations
560
+ # you can turn the automatic transactions off.
561
+ #
562
+ # class ChangeEnum < ActiveRecord::Migration[8.0]
563
+ # disable_ddl_transaction!
564
+ #
565
+ # def up
566
+ # execute "ALTER TYPE model_size ADD VALUE 'new_value'"
567
+ # end
568
+ # end
569
+ #
570
+ # Remember that you can still open your own transactions, even if you
571
+ # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
572
+ class Migration
573
+ autoload :CommandRecorder, "active_record/migration/command_recorder"
574
+ autoload :Compatibility, "active_record/migration/compatibility"
575
+ autoload :JoinTable, "active_record/migration/join_table"
576
+ autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
577
+ autoload :DefaultStrategy, "active_record/migration/default_strategy"
578
+
579
+ # This must be defined before the inherited hook, below
580
+ class Current < Migration # :nodoc:
581
+ def create_table(table_name, **options)
582
+ if block_given?
583
+ super { |t| yield compatible_table_definition(t) }
584
+ else
585
+ super
586
+ end
587
+ end
588
+
589
+ def change_table(table_name, **options)
590
+ if block_given?
591
+ super { |t| yield compatible_table_definition(t) }
592
+ else
593
+ super
594
+ end
595
+ end
596
+
597
+ def create_join_table(table_1, table_2, **options)
598
+ if block_given?
599
+ super { |t| yield compatible_table_definition(t) }
600
+ else
601
+ super
602
+ end
603
+ end
604
+
605
+ def drop_table(*table_names, **options)
606
+ if block_given?
607
+ super { |t| yield compatible_table_definition(t) }
608
+ else
609
+ super
610
+ end
611
+ end
612
+
613
+ def compatible_table_definition(t)
614
+ t
615
+ end
616
+ end
617
+
618
+ def self.inherited(subclass) # :nodoc:
619
+ super
620
+ if subclass.superclass == Migration
621
+ major = ActiveRecord::VERSION::MAJOR
622
+ minor = ActiveRecord::VERSION::MINOR
623
+ raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
624
+ "Please specify the Active Record release the migration was written for:\n" \
625
+ "\n" \
626
+ " class #{subclass} < ActiveRecord::Migration[#{major}.#{minor}]"
627
+ end
628
+ end
629
+
630
+ def self.[](version)
631
+ Compatibility.find(version)
632
+ end
633
+
634
+ def self.current_version
635
+ ActiveRecord::VERSION::STRING.to_f
636
+ end
637
+
638
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
639
+
640
+ def self.valid_version_format?(version_string) # :nodoc:
641
+ [
642
+ MigrationFilenameRegexp,
643
+ /\A\d(_?\d)*\z/ # integer with optional underscores
644
+ ].any? { |pattern| pattern.match?(version_string) }
645
+ end
646
+
647
+ # This class is used to verify that all migrations have been run before
648
+ # loading a web page if <tt>config.active_record.migration_error</tt> is set to +:page_load+.
649
+ class CheckPending
650
+ def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
651
+ @app = app
652
+ @needs_check = true
653
+ @mutex = Mutex.new
654
+ @file_watcher = file_watcher
655
+ end
656
+
657
+ def call(env)
658
+ @mutex.synchronize do
659
+ @watcher ||= build_watcher do
660
+ @needs_check = true
661
+ ActiveRecord::Migration.check_pending_migrations
662
+ @needs_check = false
663
+ end
664
+
665
+ if @needs_check
666
+ @watcher.execute
667
+ else
668
+ @watcher.execute_if_updated
669
+ end
670
+ end
671
+
672
+ @app.call(env)
673
+ end
674
+
675
+ private
676
+ def build_watcher(&block)
677
+ current_environment = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
678
+ all_configs = ActiveRecord::Base.configurations.configs_for(env_name: current_environment)
679
+ paths = all_configs.flat_map { |config| config.migrations_paths || Migrator.migrations_paths }.uniq
680
+ @file_watcher.new([], paths.index_with(["rb"]), &block)
681
+ end
682
+
683
+ def connection
684
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
685
+ end
686
+ end
687
+
688
+ class << self
689
+ attr_accessor :delegate # :nodoc:
690
+ attr_accessor :disable_ddl_transaction # :nodoc:
691
+
692
+ def nearest_delegate # :nodoc:
693
+ delegate || superclass.nearest_delegate
694
+ end
695
+
696
+ # Raises ActiveRecord::PendingMigrationError error if any migrations are pending
697
+ # for all database configurations in an environment.
698
+ def check_all_pending!
699
+ pending_migrations = []
700
+
701
+ ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: env) do |pool|
702
+ if pending = pool.migration_context.open.pending_migrations
703
+ pending_migrations << pending
704
+ end
705
+ end
706
+
707
+ migrations = pending_migrations.flatten
708
+
709
+ if migrations.any?
710
+ raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
711
+ end
712
+ end
713
+
714
+ def load_schema_if_pending!
715
+ if any_schema_needs_update?
716
+ load_schema!
717
+ end
718
+
719
+ check_pending_migrations
720
+ end
721
+
722
+ def maintain_test_schema! # :nodoc:
723
+ if ActiveRecord.maintain_test_schema
724
+ suppress_messages { load_schema_if_pending! }
725
+ end
726
+ end
727
+
728
+ def method_missing(name, ...) # :nodoc:
729
+ nearest_delegate.send(name, ...)
730
+ end
731
+
732
+ def migrate(direction)
733
+ new.migrate direction
734
+ end
735
+
736
+ # Disable the transaction wrapping this migration.
737
+ # You can still create your own transactions even after calling #disable_ddl_transaction!
738
+ #
739
+ # For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
740
+ def disable_ddl_transaction!
741
+ @disable_ddl_transaction = true
742
+ end
743
+
744
+ def check_pending_migrations # :nodoc:
745
+ migrations = pending_migrations
746
+
747
+ if migrations.any?
748
+ raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations)
749
+ end
750
+ end
751
+
752
+ private
753
+ def any_schema_needs_update?
754
+ !db_configs_in_current_env.all? do |db_config|
755
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord.schema_format)
756
+ end
757
+ end
758
+
759
+ def db_configs_in_current_env
760
+ ActiveRecord::Base.configurations.configs_for(env_name: env)
761
+ end
762
+
763
+ def pending_migrations
764
+ pending_migrations = []
765
+
766
+ ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
767
+ ActiveRecord::PendingMigrationConnection.with_temporary_pool(db_config) do |pool|
768
+ if pending = pool.migration_context.open.pending_migrations
769
+ pending_migrations << pending
770
+ end
771
+ end
772
+ end
773
+
774
+ pending_migrations.flatten
775
+ end
776
+
777
+ def env
778
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
779
+ end
780
+
781
+ def load_schema!
782
+ # Roundtrip to Rake to allow plugins to hook into database initialization.
783
+ root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
784
+
785
+ FileUtils.cd(root) do
786
+ Base.connection_handler.clear_all_connections!(:all)
787
+ system("bin/rails db:test:prepare")
788
+ end
789
+ end
790
+ end
791
+
792
+ def disable_ddl_transaction # :nodoc:
793
+ self.class.disable_ddl_transaction
794
+ end
795
+
796
+ ##
797
+ # :singleton-method: verbose
798
+ #
799
+ # Specifies if migrations will write the actions they are taking to the console as they
800
+ # happen, along with benchmarks describing how long each step took. Defaults to
801
+ # true.
802
+ cattr_accessor :verbose
803
+ attr_accessor :name, :version
804
+
805
+ def initialize(name = self.class.name, version = nil)
806
+ @name = name
807
+ @version = version
808
+ @connection = nil
809
+ @pool = nil
810
+ end
811
+
812
+ def execution_strategy
813
+ @execution_strategy ||= ActiveRecord.migration_strategy.new(self)
814
+ end
815
+
816
+ self.verbose = true
817
+ # instantiate the delegate object after initialize is defined
818
+ self.delegate = new
819
+
820
+ # Reverses the migration commands for the given block and
821
+ # the given migrations.
822
+ #
823
+ # The following migration will remove the table 'horses'
824
+ # and create the table 'apples' on the way up, and the reverse
825
+ # on the way down.
826
+ #
827
+ # class FixTLMigration < ActiveRecord::Migration[8.0]
828
+ # def change
829
+ # revert do
830
+ # create_table(:horses) do |t|
831
+ # t.text :content
832
+ # t.datetime :remind_at
833
+ # end
834
+ # end
835
+ # create_table(:apples) do |t|
836
+ # t.string :variety
837
+ # end
838
+ # end
839
+ # end
840
+ #
841
+ # Or equivalently, if +TenderloveMigration+ is defined as in the
842
+ # documentation for Migration:
843
+ #
844
+ # require_relative "20121212123456_tenderlove_migration"
845
+ #
846
+ # class FixupTLMigration < ActiveRecord::Migration[8.0]
847
+ # def change
848
+ # revert TenderloveMigration
849
+ #
850
+ # create_table(:apples) do |t|
851
+ # t.string :variety
852
+ # end
853
+ # end
854
+ # end
855
+ #
856
+ # This command can be nested.
857
+ def revert(*migration_classes, &block)
858
+ run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
859
+ if block_given?
860
+ if connection.respond_to? :revert
861
+ connection.revert(&block)
862
+ else
863
+ recorder = command_recorder
864
+ @connection = recorder
865
+ suppress_messages do
866
+ connection.revert(&block)
867
+ end
868
+ @connection = recorder.delegate
869
+ recorder.replay(self)
870
+ end
871
+ end
872
+ end
873
+
874
+ def reverting?
875
+ connection.respond_to?(:reverting) && connection.reverting
876
+ end
877
+
878
+ ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
879
+ def up
880
+ yield unless reverting
881
+ end
882
+
883
+ def down
884
+ yield if reverting
885
+ end
886
+ end
887
+
888
+ # Used to specify an operation that can be run in one direction or another.
889
+ # Call the methods +up+ and +down+ of the yielded object to run a block
890
+ # only in one given direction.
891
+ # The whole block will be called in the right order within the migration.
892
+ #
893
+ # In the following example, the looping on users will always be done
894
+ # when the three columns 'first_name', 'last_name' and 'full_name' exist,
895
+ # even when migrating down:
896
+ #
897
+ # class SplitNameMigration < ActiveRecord::Migration[8.0]
898
+ # def change
899
+ # add_column :users, :first_name, :string
900
+ # add_column :users, :last_name, :string
901
+ #
902
+ # reversible do |dir|
903
+ # User.reset_column_information
904
+ # User.all.each do |u|
905
+ # dir.up { u.first_name, u.last_name = u.full_name.split(' ') }
906
+ # dir.down { u.full_name = "#{u.first_name} #{u.last_name}" }
907
+ # u.save
908
+ # end
909
+ # end
910
+ #
911
+ # revert { add_column :users, :full_name, :string }
912
+ # end
913
+ # end
914
+ def reversible
915
+ helper = ReversibleBlockHelper.new(reverting?)
916
+ execute_block { yield helper }
917
+ end
918
+
919
+ # Used to specify an operation that is only run when migrating up
920
+ # (for example, populating a new column with its initial values).
921
+ #
922
+ # In the following example, the new column +published+ will be given
923
+ # the value +true+ for all existing records.
924
+ #
925
+ # class AddPublishedToPosts < ActiveRecord::Migration[8.0]
926
+ # def change
927
+ # add_column :posts, :published, :boolean, default: false
928
+ # up_only do
929
+ # execute "update posts set published = 'true'"
930
+ # end
931
+ # end
932
+ # end
933
+ def up_only(&block)
934
+ execute_block(&block) unless reverting?
935
+ end
936
+
937
+ # Runs the given migration classes.
938
+ # Last argument can specify options:
939
+ #
940
+ # - +:direction+ - Default is +:up+.
941
+ # - +:revert+ - Default is +false+.
942
+ def run(*migration_classes)
943
+ opts = migration_classes.extract_options!
944
+ dir = opts[:direction] || :up
945
+ dir = (dir == :down ? :up : :down) if opts[:revert]
946
+ if reverting?
947
+ # If in revert and going :up, say, we want to execute :down without reverting, so
948
+ revert { run(*migration_classes, direction: dir, revert: true) }
949
+ else
950
+ migration_classes.each do |migration_class|
951
+ migration_class.new.exec_migration(connection, dir)
952
+ end
953
+ end
954
+ end
955
+
956
+ def up
957
+ self.class.delegate = self
958
+ return unless self.class.respond_to?(:up)
959
+ self.class.up
960
+ end
961
+
962
+ def down
963
+ self.class.delegate = self
964
+ return unless self.class.respond_to?(:down)
965
+ self.class.down
966
+ end
967
+
968
+ # Execute this migration in the named direction
969
+ def migrate(direction)
970
+ return unless respond_to?(direction)
971
+
972
+ case direction
973
+ when :up then announce "migrating"
974
+ when :down then announce "reverting"
975
+ end
976
+
977
+ time_elapsed = nil
978
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn|
979
+ time_elapsed = ActiveSupport::Benchmark.realtime do
980
+ exec_migration(conn, direction)
981
+ end
982
+ end
983
+
984
+ case direction
985
+ when :up then announce "migrated (%.4fs)" % time_elapsed; write
986
+ when :down then announce "reverted (%.4fs)" % time_elapsed; write
987
+ end
988
+ end
989
+
990
+ def exec_migration(conn, direction)
991
+ @connection = conn
992
+ if respond_to?(:change)
993
+ if direction == :down
994
+ revert { change }
995
+ else
996
+ change
997
+ end
998
+ else
999
+ public_send(direction)
1000
+ end
1001
+ ensure
1002
+ @connection = nil
1003
+ @execution_strategy = nil
1004
+ end
1005
+
1006
+ def write(text = "")
1007
+ puts(text) if verbose
1008
+ end
1009
+
1010
+ def announce(message)
1011
+ text = "#{version} #{name}: #{message}"
1012
+ length = [0, 75 - text.length].max
1013
+ write "== %s %s" % [text, "=" * length]
1014
+ end
1015
+
1016
+ # Takes a message argument and outputs it as is.
1017
+ # A second boolean argument can be passed to specify whether to indent or not.
1018
+ def say(message, subitem = false)
1019
+ write "#{subitem ? " ->" : "--"} #{message}"
1020
+ end
1021
+
1022
+ # Outputs text along with how long it took to run its block.
1023
+ # If the block returns an integer it assumes it is the number of rows affected.
1024
+ def say_with_time(message)
1025
+ say(message)
1026
+ result = nil
1027
+ time_elapsed = ActiveSupport::Benchmark.realtime { result = yield }
1028
+ say "%.4fs" % time_elapsed, :subitem
1029
+ say("#{result} rows", :subitem) if result.is_a?(Integer)
1030
+ result
1031
+ end
1032
+
1033
+ # Takes a block as an argument and suppresses any output generated by the block.
1034
+ def suppress_messages
1035
+ save, self.verbose = verbose, false
1036
+ yield
1037
+ ensure
1038
+ self.verbose = save
1039
+ end
1040
+
1041
+ def connection
1042
+ @connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection
1043
+ end
1044
+
1045
+ def connection_pool
1046
+ @pool || ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
1047
+ end
1048
+
1049
+ def method_missing(method, *arguments, &block)
1050
+ say_with_time "#{method}(#{format_arguments(arguments)})" do
1051
+ unless connection.respond_to? :revert
1052
+ unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
1053
+ arguments[0] = proper_table_name(arguments.first, table_name_options)
1054
+ if method == :rename_table ||
1055
+ (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
1056
+ arguments[1] = proper_table_name(arguments.second, table_name_options)
1057
+ end
1058
+ end
1059
+ end
1060
+ return super unless execution_strategy.respond_to?(method)
1061
+ execution_strategy.send(method, *arguments, &block)
1062
+ end
1063
+ end
1064
+ ruby2_keywords(:method_missing)
1065
+
1066
+ def copy(destination, sources, options = {})
1067
+ copied = []
1068
+
1069
+ FileUtils.mkdir_p(destination) unless File.exist?(destination)
1070
+ schema_migration = SchemaMigration::NullSchemaMigration.new
1071
+ internal_metadata = InternalMetadata::NullInternalMetadata.new
1072
+
1073
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration, internal_metadata).migrations
1074
+ last = destination_migrations.last
1075
+ sources.each do |scope, path|
1076
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration, internal_metadata).migrations
1077
+
1078
+ source_migrations.each do |migration|
1079
+ source = File.binread(migration.filename)
1080
+ inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
1081
+ magic_comments = +""
1082
+ loop do
1083
+ # If we have a magic comment in the original migration,
1084
+ # insert our comment after the first newline(end of the magic comment line)
1085
+ # so the magic keep working.
1086
+ # Note that magic comments must be at the first line(except sh-bang).
1087
+ source.sub!(/\A(?:#.*\b(?:en)?coding:\s*\S+|#\s*frozen_string_literal:\s*(?:true|false)).*\n/) do |magic_comment|
1088
+ magic_comments << magic_comment; ""
1089
+ end || break
1090
+ end
1091
+
1092
+ if !magic_comments.empty? && source.start_with?("\n")
1093
+ magic_comments << "\n"
1094
+ source = source[1..-1]
1095
+ end
1096
+
1097
+ source = "#{magic_comments}#{inserted_comment}#{source}"
1098
+
1099
+ if duplicate = destination_migrations.detect { |m| m.name == migration.name }
1100
+ if options[:on_skip] && duplicate.scope != scope.to_s
1101
+ options[:on_skip].call(scope, migration)
1102
+ end
1103
+ next
1104
+ end
1105
+
1106
+ migration.version = next_migration_number(last ? last.version + 1 : 0).to_i
1107
+ new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.#{scope}.rb")
1108
+ old_path, migration.filename = migration.filename, new_path
1109
+ last = migration
1110
+
1111
+ File.binwrite(migration.filename, source)
1112
+ copied << migration
1113
+ options[:on_copy].call(scope, migration, old_path) if options[:on_copy]
1114
+ destination_migrations << migration
1115
+ end
1116
+ end
1117
+
1118
+ copied
1119
+ end
1120
+
1121
+ # Finds the correct table name given an Active Record object.
1122
+ # Uses the Active Record object's own table_name, or pre/suffix from the
1123
+ # options passed in.
1124
+ def proper_table_name(name, options = {})
1125
+ if name.respond_to? :table_name
1126
+ name.table_name
1127
+ else
1128
+ "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}"
1129
+ end
1130
+ end
1131
+
1132
+ # Determines the version number of the next migration.
1133
+ def next_migration_number(number)
1134
+ if ActiveRecord.timestamped_migrations
1135
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
1136
+ else
1137
+ "%.3d" % number.to_i
1138
+ end
1139
+ end
1140
+
1141
+ # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
1142
+ # the Active Record object's table_name prefix and suffix
1143
+ def table_name_options(config = ActiveRecord::Base) # :nodoc:
1144
+ {
1145
+ table_name_prefix: config.table_name_prefix,
1146
+ table_name_suffix: config.table_name_suffix
1147
+ }
1148
+ end
1149
+
1150
+ private
1151
+ def execute_block
1152
+ if connection.respond_to? :execute_block
1153
+ super # use normal delegation to record the block
1154
+ else
1155
+ yield
1156
+ end
1157
+ end
1158
+
1159
+ def format_arguments(arguments)
1160
+ arg_list = arguments[0...-1].map(&:inspect)
1161
+ last_arg = arguments.last
1162
+ if last_arg.is_a?(Hash)
1163
+ last_arg = last_arg.reject { |k, _v| internal_option?(k) }
1164
+ arg_list << last_arg.inspect unless last_arg.empty?
1165
+ else
1166
+ arg_list << last_arg.inspect
1167
+ end
1168
+ arg_list.join(", ")
1169
+ end
1170
+
1171
+ def internal_option?(option_name)
1172
+ option_name.start_with?("_")
1173
+ end
1174
+
1175
+ def command_recorder
1176
+ CommandRecorder.new(connection)
1177
+ end
1178
+ end
1179
+
1180
+ # MigrationProxy is used to defer loading of the actual migration classes
1181
+ # until they are needed
1182
+ MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
1183
+ def initialize(name, version, filename, scope)
1184
+ super
1185
+ @migration = nil
1186
+ end
1187
+
1188
+ def basename
1189
+ File.basename(filename)
1190
+ end
1191
+
1192
+ delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
1193
+
1194
+ private
1195
+ def migration
1196
+ @migration ||= load_migration
1197
+ end
1198
+
1199
+ def load_migration
1200
+ Object.send(:remove_const, name) rescue nil
1201
+
1202
+ load(File.expand_path(filename))
1203
+ name.constantize.new(name, version)
1204
+ end
1205
+ end
1206
+
1207
+ # = \Migration \Context
1208
+ #
1209
+ # MigrationContext sets the context in which a migration is run.
1210
+ #
1211
+ # A migration context requires the path to the migrations is set
1212
+ # in the +migrations_paths+ parameter. Optionally a +schema_migration+
1213
+ # class can be provided. Multiple database applications will instantiate
1214
+ # a +SchemaMigration+ object per database. From the Rake tasks, \Rails will
1215
+ # handle this for you.
1216
+ class MigrationContext
1217
+ attr_reader :migrations_paths, :schema_migration, :internal_metadata
1218
+
1219
+ def initialize(migrations_paths, schema_migration = nil, internal_metadata = nil)
1220
+ @migrations_paths = migrations_paths
1221
+ @schema_migration = schema_migration || SchemaMigration.new(connection_pool)
1222
+ @internal_metadata = internal_metadata || InternalMetadata.new(connection_pool)
1223
+ end
1224
+
1225
+ # Runs the migrations in the +migrations_path+.
1226
+ #
1227
+ # If +target_version+ is +nil+, +migrate+ will run +up+.
1228
+ #
1229
+ # If the +current_version+ and +target_version+ are both
1230
+ # 0 then an empty array will be returned and no migrations
1231
+ # will be run.
1232
+ #
1233
+ # If the +current_version+ in the schema is greater than
1234
+ # the +target_version+, then +down+ will be run.
1235
+ #
1236
+ # If none of the conditions are met, +up+ will be run with
1237
+ # the +target_version+.
1238
+ def migrate(target_version = nil, &block)
1239
+ case
1240
+ when target_version.nil?
1241
+ up(target_version, &block)
1242
+ when current_version == 0 && target_version == 0
1243
+ []
1244
+ when current_version > target_version
1245
+ down(target_version, &block)
1246
+ else
1247
+ up(target_version, &block)
1248
+ end
1249
+ end
1250
+
1251
+ def rollback(steps = 1) # :nodoc:
1252
+ move(:down, steps)
1253
+ end
1254
+
1255
+ def forward(steps = 1) # :nodoc:
1256
+ move(:up, steps)
1257
+ end
1258
+
1259
+ def up(target_version = nil, &block) # :nodoc:
1260
+ selected_migrations = if block_given?
1261
+ migrations.select(&block)
1262
+ else
1263
+ migrations
1264
+ end
1265
+
1266
+ Migrator.new(:up, selected_migrations, schema_migration, internal_metadata, target_version).migrate
1267
+ end
1268
+
1269
+ def down(target_version = nil, &block) # :nodoc:
1270
+ selected_migrations = if block_given?
1271
+ migrations.select(&block)
1272
+ else
1273
+ migrations
1274
+ end
1275
+
1276
+ Migrator.new(:down, selected_migrations, schema_migration, internal_metadata, target_version).migrate
1277
+ end
1278
+
1279
+ def run(direction, target_version) # :nodoc:
1280
+ Migrator.new(direction, migrations, schema_migration, internal_metadata, target_version).run
1281
+ end
1282
+
1283
+ def open # :nodoc:
1284
+ Migrator.new(:up, migrations, schema_migration, internal_metadata)
1285
+ end
1286
+
1287
+ def get_all_versions # :nodoc:
1288
+ if schema_migration.table_exists?
1289
+ schema_migration.integer_versions
1290
+ else
1291
+ []
1292
+ end
1293
+ end
1294
+
1295
+ def current_version # :nodoc:
1296
+ get_all_versions.max || 0
1297
+ rescue ActiveRecord::NoDatabaseError
1298
+ end
1299
+
1300
+ def needs_migration? # :nodoc:
1301
+ pending_migration_versions.size > 0
1302
+ end
1303
+
1304
+ def pending_migration_versions # :nodoc:
1305
+ migrations.collect(&:version) - get_all_versions
1306
+ end
1307
+
1308
+ def migrations # :nodoc:
1309
+ migrations = migration_files.map do |file|
1310
+ version, name, scope = parse_migration_filename(file)
1311
+ raise IllegalMigrationNameError.new(file) unless version
1312
+ if validate_timestamp? && !valid_migration_timestamp?(version)
1313
+ raise InvalidMigrationTimestampError.new(version, name)
1314
+ end
1315
+ version = version.to_i
1316
+ name = name.camelize
1317
+
1318
+ MigrationProxy.new(name, version, file, scope)
1319
+ end
1320
+
1321
+ migrations.sort_by(&:version)
1322
+ end
1323
+
1324
+ def migrations_status # :nodoc:
1325
+ db_list = schema_migration.normalized_versions
1326
+
1327
+ file_list = migration_files.filter_map do |file|
1328
+ version, name, scope = parse_migration_filename(file)
1329
+ raise IllegalMigrationNameError.new(file) unless version
1330
+ if validate_timestamp? && !valid_migration_timestamp?(version)
1331
+ raise InvalidMigrationTimestampError.new(version, name)
1332
+ end
1333
+ version = schema_migration.normalize_migration_number(version)
1334
+ status = db_list.delete(version) ? "up" : "down"
1335
+ [status, version, (name + scope).humanize]
1336
+ end
1337
+
1338
+ db_list.map! do |version|
1339
+ ["up", version, "********** NO FILE **********"]
1340
+ end
1341
+
1342
+ (db_list + file_list).sort_by { |_, version, _| version.to_i }
1343
+ end
1344
+
1345
+ def current_environment # :nodoc:
1346
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1347
+ end
1348
+
1349
+ def protected_environment? # :nodoc:
1350
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1351
+ end
1352
+
1353
+ def last_stored_environment # :nodoc:
1354
+ internal_metadata = connection_pool.internal_metadata
1355
+ return nil unless internal_metadata.enabled?
1356
+ return nil if current_version == 0
1357
+ raise NoEnvironmentInSchemaError unless internal_metadata.table_exists?
1358
+
1359
+ environment = internal_metadata[:environment]
1360
+ raise NoEnvironmentInSchemaError unless environment
1361
+ environment
1362
+ end
1363
+
1364
+ private
1365
+ def connection
1366
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
1367
+ end
1368
+
1369
+ def connection_pool
1370
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
1371
+ end
1372
+
1373
+ def migration_files
1374
+ paths = Array(migrations_paths)
1375
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1376
+ end
1377
+
1378
+ def parse_migration_filename(filename)
1379
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1380
+ end
1381
+
1382
+ def validate_timestamp?
1383
+ ActiveRecord.timestamped_migrations && ActiveRecord.validate_migration_timestamps
1384
+ end
1385
+
1386
+ def valid_migration_timestamp?(version)
1387
+ version.to_i < (Time.now.utc + 1.day).strftime("%Y%m%d%H%M%S").to_i
1388
+ end
1389
+
1390
+ def move(direction, steps)
1391
+ migrator = Migrator.new(direction, migrations, schema_migration, internal_metadata)
1392
+
1393
+ if current_version != 0 && !migrator.current_migration
1394
+ raise UnknownMigrationVersionError.new(current_version)
1395
+ end
1396
+
1397
+ start_index =
1398
+ if current_version == 0
1399
+ 0
1400
+ else
1401
+ migrator.migrations.index(migrator.current_migration)
1402
+ end
1403
+
1404
+ finish = migrator.migrations[start_index + steps]
1405
+ version = finish ? finish.version : 0
1406
+ public_send(direction, version)
1407
+ end
1408
+ end
1409
+
1410
+ class Migrator # :nodoc:
1411
+ class << self
1412
+ attr_accessor :migrations_paths
1413
+
1414
+ # For cases where a table doesn't exist like loading from schema cache
1415
+ def current_version
1416
+ connection_pool = ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool
1417
+ schema_migration = SchemaMigration.new(connection_pool)
1418
+ internal_metadata = InternalMetadata.new(connection_pool)
1419
+
1420
+ MigrationContext.new(migrations_paths, schema_migration, internal_metadata).current_version
1421
+ end
1422
+ end
1423
+
1424
+ self.migrations_paths = ["db/migrate"]
1425
+
1426
+ def initialize(direction, migrations, schema_migration, internal_metadata, target_version = nil)
1427
+ @direction = direction
1428
+ @target_version = target_version
1429
+ @migrated_versions = nil
1430
+ @migrations = migrations
1431
+ @schema_migration = schema_migration
1432
+ @internal_metadata = internal_metadata
1433
+
1434
+ validate(@migrations)
1435
+
1436
+ @schema_migration.create_table
1437
+ @internal_metadata.create_table
1438
+ end
1439
+
1440
+ def current_version
1441
+ migrated.max || 0
1442
+ end
1443
+
1444
+ def current_migration
1445
+ migrations.detect { |m| m.version == current_version }
1446
+ end
1447
+ alias :current :current_migration
1448
+
1449
+ def run
1450
+ if use_advisory_lock?
1451
+ with_advisory_lock { run_without_lock }
1452
+ else
1453
+ run_without_lock
1454
+ end
1455
+ end
1456
+
1457
+ def migrate
1458
+ if use_advisory_lock?
1459
+ with_advisory_lock { migrate_without_lock }
1460
+ else
1461
+ migrate_without_lock
1462
+ end
1463
+ end
1464
+
1465
+ def runnable
1466
+ runnable = migrations[start..finish]
1467
+ if up?
1468
+ runnable.reject { |m| ran?(m) }
1469
+ else
1470
+ # skip the last migration if we're headed down, but not ALL the way down
1471
+ runnable.pop if target
1472
+ runnable.find_all { |m| ran?(m) }
1473
+ end
1474
+ end
1475
+
1476
+ def migrations
1477
+ down? ? @migrations.reverse : @migrations.sort_by(&:version)
1478
+ end
1479
+
1480
+ def pending_migrations
1481
+ already_migrated = migrated
1482
+ migrations.reject { |m| already_migrated.include?(m.version) }
1483
+ end
1484
+
1485
+ def migrated
1486
+ @migrated_versions || load_migrated
1487
+ end
1488
+
1489
+ def load_migrated
1490
+ @migrated_versions = Set.new(@schema_migration.integer_versions)
1491
+ end
1492
+
1493
+ private
1494
+ def connection
1495
+ ActiveRecord::Tasks::DatabaseTasks.migration_connection
1496
+ end
1497
+
1498
+ # Used for running a specific migration.
1499
+ def run_without_lock
1500
+ migration = migrations.detect { |m| m.version == @target_version }
1501
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1502
+
1503
+ record_environment
1504
+ execute_migration_in_transaction(migration)
1505
+ end
1506
+
1507
+ # Used for running multiple migrations up to or down to a certain value.
1508
+ def migrate_without_lock
1509
+ if invalid_target?
1510
+ raise UnknownMigrationVersionError.new(@target_version)
1511
+ end
1512
+
1513
+ record_environment
1514
+ runnable.each(&method(:execute_migration_in_transaction))
1515
+ end
1516
+
1517
+ # Stores the current environment in the database.
1518
+ def record_environment
1519
+ return if down?
1520
+
1521
+ @internal_metadata[:environment] = connection.pool.db_config.env_name
1522
+ end
1523
+
1524
+ def ran?(migration)
1525
+ migrated.include?(migration.version.to_i)
1526
+ end
1527
+
1528
+ # Return true if a valid version is not provided.
1529
+ def invalid_target?
1530
+ @target_version && @target_version != 0 && !target
1531
+ end
1532
+
1533
+ def execute_migration_in_transaction(migration)
1534
+ return if down? && !migrated.include?(migration.version.to_i)
1535
+ return if up? && migrated.include?(migration.version.to_i)
1536
+
1537
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1538
+
1539
+ ddl_transaction(migration) do
1540
+ migration.migrate(@direction)
1541
+ record_version_state_after_migrating(migration.version)
1542
+ end
1543
+ rescue => e
1544
+ msg = +"An error has occurred, "
1545
+ msg << "this and " if use_transaction?(migration)
1546
+ msg << "all later migrations canceled:\n\n#{e}"
1547
+ raise StandardError, msg, e.backtrace
1548
+ end
1549
+
1550
+ def target
1551
+ migrations.detect { |m| m.version == @target_version }
1552
+ end
1553
+
1554
+ def finish
1555
+ migrations.index(target) || migrations.size - 1
1556
+ end
1557
+
1558
+ def start
1559
+ up? ? 0 : (migrations.index(current) || 0)
1560
+ end
1561
+
1562
+ def validate(migrations)
1563
+ name, = migrations.group_by(&:name).find { |_, v| v.length > 1 }
1564
+ raise DuplicateMigrationNameError.new(name) if name
1565
+
1566
+ version, = migrations.group_by(&:version).find { |_, v| v.length > 1 }
1567
+ raise DuplicateMigrationVersionError.new(version) if version
1568
+ end
1569
+
1570
+ def record_version_state_after_migrating(version)
1571
+ if down?
1572
+ migrated.delete(version)
1573
+ @schema_migration.delete_version(version.to_s)
1574
+ else
1575
+ migrated << version
1576
+ @schema_migration.create_version(version.to_s)
1577
+ end
1578
+ end
1579
+
1580
+ def up?
1581
+ @direction == :up
1582
+ end
1583
+
1584
+ def down?
1585
+ @direction == :down
1586
+ end
1587
+
1588
+ # Wrap the migration in a transaction only if supported by the adapter.
1589
+ def ddl_transaction(migration, &block)
1590
+ if use_transaction?(migration)
1591
+ connection.transaction(&block)
1592
+ else
1593
+ yield
1594
+ end
1595
+ end
1596
+
1597
+ def use_transaction?(migration)
1598
+ !migration.disable_ddl_transaction && connection.supports_ddl_transactions?
1599
+ end
1600
+
1601
+ def use_advisory_lock?
1602
+ connection.advisory_locks_enabled?
1603
+ end
1604
+
1605
+ def with_advisory_lock
1606
+ lock_id = generate_migrator_advisory_lock_id
1607
+
1608
+ got_lock = connection.get_advisory_lock(lock_id)
1609
+ raise ConcurrentMigrationError unless got_lock
1610
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1611
+ yield
1612
+ ensure
1613
+ if got_lock && !connection.release_advisory_lock(lock_id)
1614
+ raise ConcurrentMigrationError.new(
1615
+ ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1616
+ )
1617
+ end
1618
+ end
1619
+
1620
+ MIGRATOR_SALT = 2053462845
1621
+ def generate_migrator_advisory_lock_id
1622
+ db_name_hash = Zlib.crc32(connection.current_database)
1623
+ MIGRATOR_SALT * db_name_hash
1624
+ end
1625
+ end
1626
+ end