activerecord 5.0.6 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +638 -2023
- data/MIT-LICENSE +3 -1
- data/README.rdoc +8 -6
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record/aggregations.rb +249 -246
- data/lib/active_record/association_relation.rb +24 -13
- data/lib/active_record/associations/alias_tracker.rb +24 -33
- data/lib/active_record/associations/association.rb +119 -56
- data/lib/active_record/associations/association_scope.rb +94 -94
- data/lib/active_record/associations/belongs_to_association.rb +58 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +18 -25
- data/lib/active_record/associations/builder/belongs_to.rb +43 -54
- data/lib/active_record/associations/builder/collection_association.rb +7 -18
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
- data/lib/active_record/associations/builder/has_many.rb +4 -0
- data/lib/active_record/associations/builder/has_one.rb +37 -1
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +80 -252
- data/lib/active_record/associations/collection_proxy.rb +158 -121
- data/lib/active_record/associations/foreign_association.rb +9 -0
- data/lib/active_record/associations/has_many_association.rb +23 -29
- data/lib/active_record/associations/has_many_through_association.rb +58 -44
- data/lib/active_record/associations/has_one_association.rb +59 -54
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -176
- data/lib/active_record/associations/preloader/association.rb +84 -125
- data/lib/active_record/associations/preloader/through_association.rb +82 -75
- data/lib/active_record/associations/preloader.rb +90 -102
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +26 -14
- data/lib/active_record/associations.rb +1603 -1592
- data/lib/active_record/attribute_assignment.rb +54 -60
- data/lib/active_record/attribute_decorators.rb +38 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
- data/lib/active_record/attribute_methods/dirty.rb +179 -109
- data/lib/active_record/attribute_methods/primary_key.rb +86 -91
- data/lib/active_record/attribute_methods/query.rb +4 -3
- data/lib/active_record/attribute_methods/read.rb +21 -49
- data/lib/active_record/attribute_methods/serialization.rb +30 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
- data/lib/active_record/attribute_methods/write.rb +35 -33
- data/lib/active_record/attribute_methods.rb +66 -106
- data/lib/active_record/attributes.rb +38 -24
- data/lib/active_record/autosave_association.rb +53 -32
- data/lib/active_record/base.rb +27 -24
- data/lib/active_record/callbacks.rb +63 -33
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -11
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
- data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
- data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
- data/lib/active_record/connection_adapters/column.rb +41 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
- data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
- data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
- data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
- data/lib/active_record/connection_handling.rb +159 -40
- data/lib/active_record/core.rb +202 -162
- data/lib/active_record/counter_cache.rb +57 -28
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -86
- data/lib/active_record/enum.rb +60 -23
- data/lib/active_record/errors.rb +114 -18
- data/lib/active_record/explain.rb +4 -3
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +13 -8
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +195 -502
- data/lib/active_record/gem_version.rb +4 -2
- data/lib/active_record/inheritance.rb +151 -97
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +116 -25
- data/lib/active_record/internal_metadata.rb +15 -18
- data/lib/active_record/legacy_yaml_adapter.rb +4 -2
- data/lib/active_record/locking/optimistic.rb +78 -87
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +48 -29
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +143 -97
- data/lib/active_record/migration/compatibility.rb +174 -56
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +367 -300
- data/lib/active_record/model_schema.rb +145 -139
- data/lib/active_record/nested_attributes.rb +214 -201
- data/lib/active_record/no_touching.rb +10 -1
- data/lib/active_record/null_relation.rb +13 -34
- data/lib/active_record/persistence.rb +442 -72
- data/lib/active_record/query_cache.rb +15 -14
- data/lib/active_record/querying.rb +36 -23
- data/lib/active_record/railtie.rb +128 -36
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +309 -177
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +211 -249
- data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
- data/lib/active_record/relation/batches.rb +99 -52
- data/lib/active_record/relation/calculations.rb +211 -172
- data/lib/active_record/relation/delegation.rb +67 -65
- data/lib/active_record/relation/finder_methods.rb +208 -247
- data/lib/active_record/relation/from_clause.rb +2 -8
- data/lib/active_record/relation/merger.rb +78 -61
- data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
- data/lib/active_record/relation/predicate_builder.rb +86 -104
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +458 -329
- data/lib/active_record/relation/record_fetch_warning.rb +5 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -7
- data/lib/active_record/relation/where_clause.rb +111 -95
- data/lib/active_record/relation/where_clause_factory.rb +6 -11
- data/lib/active_record/relation.rb +429 -318
- data/lib/active_record/result.rb +69 -39
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +83 -99
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +71 -69
- data/lib/active_record/schema_migration.rb +15 -5
- data/lib/active_record/scoping/default.rb +93 -95
- data/lib/active_record/scoping/named.rb +45 -25
- data/lib/active_record/scoping.rb +20 -19
- data/lib/active_record/secure_token.rb +4 -2
- data/lib/active_record/serialization.rb +2 -0
- data/lib/active_record/statement_cache.rb +63 -28
- data/lib/active_record/store.rb +121 -41
- data/lib/active_record/suppressor.rb +4 -1
- data/lib/active_record/table_metadata.rb +26 -20
- data/lib/active_record/tasks/database_tasks.rb +276 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
- data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +70 -35
- data/lib/active_record/touch_later.rb +7 -4
- data/lib/active_record/transactions.rb +133 -149
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type/adapter_specific_registry.rb +44 -45
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +16 -8
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +2 -1
- data/lib/active_record/type/type_map.rb +13 -15
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +23 -17
- data/lib/active_record/type_caster/connection.rb +17 -12
- data/lib/active_record/type_caster/map.rb +5 -4
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +3 -1
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +29 -42
- data/lib/active_record/validations.rb +7 -4
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -22
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +58 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
- data/lib/rails/generators/active_record/migration.rb +17 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +133 -50
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -20
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set/builder.rb +0 -130
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,9 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "benchmark"
|
1
4
|
require "set"
|
2
5
|
require "zlib"
|
3
6
|
require "active_support/core_ext/module/attribute_accessors"
|
7
|
+
require "active_support/actionable_error"
|
4
8
|
|
5
9
|
module ActiveRecord
|
6
|
-
class MigrationError < ActiveRecordError#:nodoc:
|
10
|
+
class MigrationError < ActiveRecordError #:nodoc:
|
7
11
|
def initialize(message = nil)
|
8
12
|
message = "\n\n#{message}\n\n" if message
|
9
13
|
super
|
@@ -20,7 +24,7 @@ module ActiveRecord
|
|
20
24
|
# t.string :zipcode
|
21
25
|
# end
|
22
26
|
#
|
23
|
-
# execute
|
27
|
+
# execute <<~SQL
|
24
28
|
# ALTER TABLE distributors
|
25
29
|
# ADD CONSTRAINT zipchk
|
26
30
|
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
@@ -38,7 +42,7 @@ module ActiveRecord
|
|
38
42
|
# t.string :zipcode
|
39
43
|
# end
|
40
44
|
#
|
41
|
-
# execute
|
45
|
+
# execute <<~SQL
|
42
46
|
# ALTER TABLE distributors
|
43
47
|
# ADD CONSTRAINT zipchk
|
44
48
|
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
@@ -46,7 +50,7 @@ module ActiveRecord
|
|
46
50
|
# end
|
47
51
|
#
|
48
52
|
# def down
|
49
|
-
# execute
|
53
|
+
# execute <<~SQL
|
50
54
|
# ALTER TABLE distributors
|
51
55
|
# DROP CONSTRAINT zipchk
|
52
56
|
# SQL
|
@@ -65,7 +69,7 @@ module ActiveRecord
|
|
65
69
|
#
|
66
70
|
# reversible do |dir|
|
67
71
|
# dir.up do
|
68
|
-
# execute
|
72
|
+
# execute <<~SQL
|
69
73
|
# ALTER TABLE distributors
|
70
74
|
# ADD CONSTRAINT zipchk
|
71
75
|
# CHECK (char_length(zipcode) = 5) NO INHERIT;
|
@@ -73,7 +77,7 @@ module ActiveRecord
|
|
73
77
|
# end
|
74
78
|
#
|
75
79
|
# dir.down do
|
76
|
-
# execute
|
80
|
+
# execute <<~SQL
|
77
81
|
# ALTER TABLE distributors
|
78
82
|
# DROP CONSTRAINT zipchk
|
79
83
|
# SQL
|
@@ -84,7 +88,7 @@ module ActiveRecord
|
|
84
88
|
class IrreversibleMigration < MigrationError
|
85
89
|
end
|
86
90
|
|
87
|
-
class DuplicateMigrationVersionError < MigrationError#:nodoc:
|
91
|
+
class DuplicateMigrationVersionError < MigrationError #:nodoc:
|
88
92
|
def initialize(version = nil)
|
89
93
|
if version
|
90
94
|
super("Multiple migrations have the version number #{version}.")
|
@@ -94,7 +98,7 @@ module ActiveRecord
|
|
94
98
|
end
|
95
99
|
end
|
96
100
|
|
97
|
-
class DuplicateMigrationNameError < MigrationError#:nodoc:
|
101
|
+
class DuplicateMigrationNameError < MigrationError #:nodoc:
|
98
102
|
def initialize(name = nil)
|
99
103
|
if name
|
100
104
|
super("Multiple migrations have the name #{name}.")
|
@@ -114,7 +118,7 @@ module ActiveRecord
|
|
114
118
|
end
|
115
119
|
end
|
116
120
|
|
117
|
-
class IllegalMigrationNameError < MigrationError#:nodoc:
|
121
|
+
class IllegalMigrationNameError < MigrationError #:nodoc:
|
118
122
|
def initialize(name = nil)
|
119
123
|
if name
|
120
124
|
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
|
@@ -124,12 +128,18 @@ module ActiveRecord
|
|
124
128
|
end
|
125
129
|
end
|
126
130
|
|
127
|
-
class PendingMigrationError < MigrationError#:nodoc:
|
131
|
+
class PendingMigrationError < MigrationError #:nodoc:
|
132
|
+
include ActiveSupport::ActionableError
|
133
|
+
|
134
|
+
action "Run pending migrations" do
|
135
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate
|
136
|
+
end
|
137
|
+
|
128
138
|
def initialize(message = nil)
|
129
139
|
if !message && defined?(Rails.env)
|
130
|
-
super("Migrations are pending. To resolve this issue, run:\n\n
|
140
|
+
super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate RAILS_ENV=#{::Rails.env}")
|
131
141
|
elsif !message
|
132
|
-
super("Migrations are pending. To resolve this issue, run:\n\n
|
142
|
+
super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate")
|
133
143
|
else
|
134
144
|
super
|
135
145
|
end
|
@@ -137,7 +147,8 @@ module ActiveRecord
|
|
137
147
|
end
|
138
148
|
|
139
149
|
class ConcurrentMigrationError < MigrationError #:nodoc:
|
140
|
-
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
|
150
|
+
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
|
151
|
+
RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
|
141
152
|
|
142
153
|
def initialize(message = DEFAULT_MESSAGE)
|
143
154
|
super
|
@@ -146,7 +157,7 @@ module ActiveRecord
|
|
146
157
|
|
147
158
|
class NoEnvironmentInSchemaError < MigrationError #:nodoc:
|
148
159
|
def initialize
|
149
|
-
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n
|
160
|
+
msg = "Environment data not found in the schema. To resolve this issue, run: \n\n rails db:environment:set"
|
150
161
|
if defined?(Rails.env)
|
151
162
|
super("#{msg} RAILS_ENV=#{::Rails.env}")
|
152
163
|
else
|
@@ -157,7 +168,7 @@ module ActiveRecord
|
|
157
168
|
|
158
169
|
class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
|
159
170
|
def initialize(env = "production")
|
160
|
-
msg = "You are attempting to run a destructive action against your '#{env}' database.\n"
|
171
|
+
msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
|
161
172
|
msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
|
162
173
|
msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
163
174
|
super(msg)
|
@@ -166,10 +177,10 @@ module ActiveRecord
|
|
166
177
|
|
167
178
|
class EnvironmentMismatchError < ActiveRecordError
|
168
179
|
def initialize(current: nil, stored: nil)
|
169
|
-
msg =
|
180
|
+
msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
|
170
181
|
msg << "You are running in `#{ current }` environment. "
|
171
182
|
msg << "If you are sure you want to continue, first set the environment using:\n\n"
|
172
|
-
msg << "
|
183
|
+
msg << " rails db:environment:set"
|
173
184
|
if defined?(Rails.env)
|
174
185
|
super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
|
175
186
|
else
|
@@ -277,8 +288,10 @@ module ActiveRecord
|
|
277
288
|
#
|
278
289
|
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
|
279
290
|
# the column to a different type using the same parameters as add_column.
|
280
|
-
# * <tt>change_column_default(table_name, column_name,
|
281
|
-
# default value for +column_name+ defined by +
|
291
|
+
# * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>:
|
292
|
+
# Sets a default value for +column_name+ defined by +default_or_changes+ on
|
293
|
+
# +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
|
294
|
+
# as +default_or_changes+ will make this change reversible in the migration.
|
282
295
|
# * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
|
283
296
|
# Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
|
284
297
|
# indicates whether the value can be +NULL+. See
|
@@ -302,7 +315,7 @@ module ActiveRecord
|
|
302
315
|
# named +column_name+ from the table called +table_name+.
|
303
316
|
# * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
|
304
317
|
# columns from the table definition.
|
305
|
-
# * <tt>remove_foreign_key(from_table,
|
318
|
+
# * <tt>remove_foreign_key(from_table, to_table = nil, **options)</tt>: Removes the
|
306
319
|
# given foreign key from the table called +table_name+.
|
307
320
|
# * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
|
308
321
|
# specified by +column_names+.
|
@@ -346,13 +359,13 @@ module ActiveRecord
|
|
346
359
|
# <tt>rails db:migrate</tt>. This will update the database by running all of the
|
347
360
|
# pending migrations, creating the <tt>schema_migrations</tt> table
|
348
361
|
# (see "About the schema_migrations table" section below) if missing. It will also
|
349
|
-
# invoke the db:schema:dump
|
362
|
+
# invoke the db:schema:dump command, which will update your db/schema.rb file
|
350
363
|
# to match the structure of your database.
|
351
364
|
#
|
352
365
|
# To roll the database back to a previous migration version, use
|
353
|
-
# <tt>rails db:
|
366
|
+
# <tt>rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
|
354
367
|
# you wish to downgrade. Alternatively, you can also use the STEP option if you
|
355
|
-
# wish to rollback last few migrations. <tt>rails db:
|
368
|
+
# wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
|
356
369
|
# the latest two migrations.
|
357
370
|
#
|
358
371
|
# If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
|
@@ -481,9 +494,9 @@ module ActiveRecord
|
|
481
494
|
# This migration will create the horses table for you on the way up, and
|
482
495
|
# automatically figure out how to drop the table on the way down.
|
483
496
|
#
|
484
|
-
# Some commands
|
485
|
-
#
|
486
|
-
#
|
497
|
+
# Some commands cannot be reversed. If you care to define how to move up
|
498
|
+
# and down in these cases, you should define the +up+ and +down+ methods
|
499
|
+
# as before.
|
487
500
|
#
|
488
501
|
# If a command cannot be reversed, an
|
489
502
|
# <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
|
@@ -510,17 +523,20 @@ module ActiveRecord
|
|
510
523
|
# Remember that you can still open your own transactions, even if you
|
511
524
|
# are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
|
512
525
|
class Migration
|
513
|
-
autoload :CommandRecorder,
|
514
|
-
autoload :Compatibility,
|
526
|
+
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
527
|
+
autoload :Compatibility, "active_record/migration/compatibility"
|
515
528
|
|
516
529
|
# This must be defined before the inherited hook, below
|
517
|
-
class Current < Migration
|
530
|
+
class Current < Migration #:nodoc:
|
518
531
|
end
|
519
532
|
|
520
|
-
def self.inherited(subclass)
|
533
|
+
def self.inherited(subclass) #:nodoc:
|
521
534
|
super
|
522
535
|
if subclass.superclass == Migration
|
523
|
-
|
536
|
+
raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
|
537
|
+
"Please specify the Rails release the migration was written for:\n" \
|
538
|
+
"\n" \
|
539
|
+
" class #{subclass} < ActiveRecord::Migration[4.2]"
|
524
540
|
end
|
525
541
|
end
|
526
542
|
|
@@ -532,7 +548,7 @@ module ActiveRecord
|
|
532
548
|
ActiveRecord::VERSION::STRING.to_f
|
533
549
|
end
|
534
550
|
|
535
|
-
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/
|
551
|
+
MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
|
536
552
|
|
537
553
|
# This class is used to verify that all migrations have been run before
|
538
554
|
# loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
|
@@ -543,57 +559,64 @@ module ActiveRecord
|
|
543
559
|
end
|
544
560
|
|
545
561
|
def call(env)
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
@last_check = mtime
|
551
|
-
end
|
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
|
552
566
|
end
|
553
567
|
@app.call(env)
|
554
568
|
end
|
555
569
|
|
556
570
|
private
|
557
571
|
|
558
|
-
|
559
|
-
|
560
|
-
|
572
|
+
def connection
|
573
|
+
ActiveRecord::Base.connection
|
574
|
+
end
|
561
575
|
end
|
562
576
|
|
563
577
|
class << self
|
564
|
-
attr_accessor :delegate
|
565
|
-
attr_accessor :disable_ddl_transaction
|
578
|
+
attr_accessor :delegate #:nodoc:
|
579
|
+
attr_accessor :disable_ddl_transaction #:nodoc:
|
566
580
|
|
567
|
-
def nearest_delegate
|
581
|
+
def nearest_delegate #:nodoc:
|
568
582
|
delegate || superclass.nearest_delegate
|
569
583
|
end
|
570
584
|
|
571
585
|
# Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
|
572
586
|
def check_pending!(connection = Base.connection)
|
573
|
-
raise ActiveRecord::PendingMigrationError if
|
587
|
+
raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
|
574
588
|
end
|
575
589
|
|
576
590
|
def load_schema_if_pending!
|
577
|
-
|
591
|
+
current_config = Base.connection_config
|
592
|
+
all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
|
593
|
+
|
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)
|
596
|
+
end
|
597
|
+
|
598
|
+
if needs_update
|
578
599
|
# Roundtrip to Rake to allow plugins to hook into database initialization.
|
579
|
-
|
580
|
-
|
600
|
+
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
|
601
|
+
FileUtils.cd(root) do
|
581
602
|
Base.clear_all_connections!
|
582
603
|
system("bin/rails db:test:prepare")
|
583
|
-
# Establish a new connection, the old database may be gone (db:test:prepare uses purge)
|
584
|
-
Base.establish_connection(current_config)
|
585
604
|
end
|
586
|
-
check_pending!
|
587
605
|
end
|
606
|
+
|
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!
|
588
611
|
end
|
589
612
|
|
590
|
-
def maintain_test_schema!
|
613
|
+
def maintain_test_schema! #:nodoc:
|
591
614
|
if ActiveRecord::Base.maintain_test_schema
|
592
615
|
suppress_messages { load_schema_if_pending! }
|
593
616
|
end
|
594
617
|
end
|
595
618
|
|
596
|
-
def method_missing(name, *args, &block)
|
619
|
+
def method_missing(name, *args, &block) #:nodoc:
|
597
620
|
nearest_delegate.send(name, *args, &block)
|
598
621
|
end
|
599
622
|
|
@@ -610,7 +633,7 @@ module ActiveRecord
|
|
610
633
|
end
|
611
634
|
end
|
612
635
|
|
613
|
-
def disable_ddl_transaction
|
636
|
+
def disable_ddl_transaction #:nodoc:
|
614
637
|
self.class.disable_ddl_transaction
|
615
638
|
end
|
616
639
|
|
@@ -670,15 +693,13 @@ module ActiveRecord
|
|
670
693
|
if connection.respond_to? :revert
|
671
694
|
connection.revert { yield }
|
672
695
|
else
|
673
|
-
recorder =
|
696
|
+
recorder = command_recorder
|
674
697
|
@connection = recorder
|
675
698
|
suppress_messages do
|
676
699
|
connection.revert { yield }
|
677
700
|
end
|
678
701
|
@connection = recorder.delegate
|
679
|
-
recorder.
|
680
|
-
send(cmd, *args, &block)
|
681
|
-
end
|
702
|
+
recorder.replay(self)
|
682
703
|
end
|
683
704
|
end
|
684
705
|
end
|
@@ -687,7 +708,7 @@ module ActiveRecord
|
|
687
708
|
connection.respond_to?(:reverting) && connection.reverting
|
688
709
|
end
|
689
710
|
|
690
|
-
|
711
|
+
ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
|
691
712
|
def up
|
692
713
|
yield unless reverting
|
693
714
|
end
|
@@ -725,7 +746,25 @@ module ActiveRecord
|
|
725
746
|
# end
|
726
747
|
def reversible
|
727
748
|
helper = ReversibleBlockHelper.new(reverting?)
|
728
|
-
execute_block{ yield helper }
|
749
|
+
execute_block { yield helper }
|
750
|
+
end
|
751
|
+
|
752
|
+
# Used to specify an operation that is only run when migrating up
|
753
|
+
# (for example, populating a new column with its initial values).
|
754
|
+
#
|
755
|
+
# In the following example, the new column +published+ will be given
|
756
|
+
# the value +true+ for all existing records.
|
757
|
+
#
|
758
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[5.2]
|
759
|
+
# def change
|
760
|
+
# add_column :posts, :published, :boolean, default: false
|
761
|
+
# up_only do
|
762
|
+
# execute "update posts set published = 'true'"
|
763
|
+
# end
|
764
|
+
# end
|
765
|
+
# end
|
766
|
+
def up_only
|
767
|
+
execute_block { yield } unless reverting?
|
729
768
|
end
|
730
769
|
|
731
770
|
# Runs the given migration classes.
|
@@ -767,7 +806,7 @@ module ActiveRecord
|
|
767
806
|
when :down then announce "reverting"
|
768
807
|
end
|
769
808
|
|
770
|
-
time
|
809
|
+
time = nil
|
771
810
|
ActiveRecord::Base.connection_pool.with_connection do |conn|
|
772
811
|
time = Benchmark.measure do
|
773
812
|
exec_migration(conn, direction)
|
@@ -795,7 +834,7 @@ module ActiveRecord
|
|
795
834
|
@connection = nil
|
796
835
|
end
|
797
836
|
|
798
|
-
def write(text="")
|
837
|
+
def write(text = "")
|
799
838
|
puts(text) if verbose
|
800
839
|
end
|
801
840
|
|
@@ -805,10 +844,14 @@ module ActiveRecord
|
|
805
844
|
write "== %s %s" % [text, "=" * length]
|
806
845
|
end
|
807
846
|
|
808
|
-
|
847
|
+
# Takes a message argument and outputs it as is.
|
848
|
+
# A second boolean argument can be passed to specify whether to indent or not.
|
849
|
+
def say(message, subitem = false)
|
809
850
|
write "#{subitem ? " ->" : "--"} #{message}"
|
810
851
|
end
|
811
852
|
|
853
|
+
# Outputs text along with how long it took to run its block.
|
854
|
+
# If the block returns an integer it assumes it is the number of rows affected.
|
812
855
|
def say_with_time(message)
|
813
856
|
say(message)
|
814
857
|
result = nil
|
@@ -818,6 +861,7 @@ module ActiveRecord
|
|
818
861
|
result
|
819
862
|
end
|
820
863
|
|
864
|
+
# Takes a block as an argument and suppresses any output generated by the block.
|
821
865
|
def suppress_messages
|
822
866
|
save, self.verbose = verbose, false
|
823
867
|
yield
|
@@ -830,7 +874,7 @@ module ActiveRecord
|
|
830
874
|
end
|
831
875
|
|
832
876
|
def method_missing(method, *arguments, &block)
|
833
|
-
arg_list = arguments.map(&:inspect) *
|
877
|
+
arg_list = arguments.map(&:inspect) * ", "
|
834
878
|
|
835
879
|
say_with_time "#{method}(#{arg_list})" do
|
836
880
|
unless connection.respond_to? :revert
|
@@ -849,26 +893,29 @@ module ActiveRecord
|
|
849
893
|
|
850
894
|
def copy(destination, sources, options = {})
|
851
895
|
copied = []
|
896
|
+
schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
|
852
897
|
|
853
898
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
854
899
|
|
855
|
-
destination_migrations = ActiveRecord::
|
900
|
+
destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
|
856
901
|
last = destination_migrations.last
|
857
902
|
sources.each do |scope, path|
|
858
|
-
source_migrations = ActiveRecord::
|
903
|
+
source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
|
859
904
|
|
860
905
|
source_migrations.each do |migration|
|
861
906
|
source = File.binread(migration.filename)
|
862
907
|
inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
|
863
|
-
|
908
|
+
magic_comments = +""
|
909
|
+
loop do
|
864
910
|
# If we have a magic comment in the original migration,
|
865
911
|
# insert our comment after the first newline(end of the magic comment line)
|
866
912
|
# so the magic keep working.
|
867
913
|
# Note that magic comments must be at the first line(except sh-bang).
|
868
|
-
source
|
869
|
-
|
870
|
-
|
914
|
+
source.sub!(/\A(?:#.*\b(?:en)?coding:\s*\S+|#\s*frozen_string_literal:\s*(?:true|false)).*\n/) do |magic_comment|
|
915
|
+
magic_comments << magic_comment; ""
|
916
|
+
end || break
|
871
917
|
end
|
918
|
+
source = "#{magic_comments}#{inserted_comment}#{source}"
|
872
919
|
|
873
920
|
if duplicate = destination_migrations.detect { |m| m.name == migration.name }
|
874
921
|
if options[:on_skip] && duplicate.scope != scope.to_s
|
@@ -922,19 +969,22 @@ module ActiveRecord
|
|
922
969
|
end
|
923
970
|
|
924
971
|
private
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
972
|
+
def execute_block
|
973
|
+
if connection.respond_to? :execute_block
|
974
|
+
super # use normal delegation to record the block
|
975
|
+
else
|
976
|
+
yield
|
977
|
+
end
|
978
|
+
end
|
979
|
+
|
980
|
+
def command_recorder
|
981
|
+
CommandRecorder.new(connection)
|
930
982
|
end
|
931
|
-
end
|
932
983
|
end
|
933
984
|
|
934
985
|
# MigrationProxy is used to defer loading of the actual migration classes
|
935
986
|
# until they are needed
|
936
|
-
|
937
|
-
|
987
|
+
MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
|
938
988
|
def initialize(name, version, filename, scope)
|
939
989
|
super
|
940
990
|
@migration = nil
|
@@ -960,7 +1010,6 @@ module ActiveRecord
|
|
960
1010
|
require(File.expand_path(filename))
|
961
1011
|
name.constantize.new(name, version)
|
962
1012
|
end
|
963
|
-
|
964
1013
|
end
|
965
1014
|
|
966
1015
|
class NullMigration < MigrationProxy #:nodoc:
|
@@ -973,159 +1022,189 @@ module ActiveRecord
|
|
973
1022
|
end
|
974
1023
|
end
|
975
1024
|
|
976
|
-
class
|
977
|
-
|
978
|
-
attr_writer :migrations_paths
|
979
|
-
alias :migrations_path= :migrations_paths=
|
980
|
-
|
981
|
-
def migrate(migrations_paths, target_version = nil, &block)
|
982
|
-
case
|
983
|
-
when target_version.nil?
|
984
|
-
up(migrations_paths, target_version, &block)
|
985
|
-
when current_version == 0 && target_version == 0
|
986
|
-
[]
|
987
|
-
when current_version > target_version
|
988
|
-
down(migrations_paths, target_version, &block)
|
989
|
-
else
|
990
|
-
up(migrations_paths, target_version, &block)
|
991
|
-
end
|
992
|
-
end
|
1025
|
+
class MigrationContext #:nodoc:
|
1026
|
+
attr_reader :migrations_paths, :schema_migration
|
993
1027
|
|
994
|
-
|
995
|
-
|
996
|
-
|
1028
|
+
def initialize(migrations_paths, schema_migration)
|
1029
|
+
@migrations_paths = migrations_paths
|
1030
|
+
@schema_migration = schema_migration
|
1031
|
+
end
|
997
1032
|
|
998
|
-
|
999
|
-
|
1033
|
+
def migrate(target_version = nil, &block)
|
1034
|
+
case
|
1035
|
+
when target_version.nil?
|
1036
|
+
up(target_version, &block)
|
1037
|
+
when current_version == 0 && target_version == 0
|
1038
|
+
[]
|
1039
|
+
when current_version > target_version
|
1040
|
+
down(target_version, &block)
|
1041
|
+
else
|
1042
|
+
up(target_version, &block)
|
1000
1043
|
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
def rollback(steps = 1)
|
1047
|
+
move(:down, steps)
|
1048
|
+
end
|
1001
1049
|
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1050
|
+
def forward(steps = 1)
|
1051
|
+
move(:up, steps)
|
1052
|
+
end
|
1005
1053
|
|
1006
|
-
|
1054
|
+
def up(target_version = nil)
|
1055
|
+
selected_migrations = if block_given?
|
1056
|
+
migrations.select { |m| yield m }
|
1057
|
+
else
|
1058
|
+
migrations
|
1007
1059
|
end
|
1008
1060
|
|
1009
|
-
|
1010
|
-
|
1011
|
-
migrations.select! { |m| yield m } if block_given?
|
1061
|
+
Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
|
1062
|
+
end
|
1012
1063
|
|
1013
|
-
|
1064
|
+
def down(target_version = nil)
|
1065
|
+
selected_migrations = if block_given?
|
1066
|
+
migrations.select { |m| yield m }
|
1067
|
+
else
|
1068
|
+
migrations
|
1014
1069
|
end
|
1015
1070
|
|
1016
|
-
|
1017
|
-
|
1018
|
-
end
|
1071
|
+
Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
|
1072
|
+
end
|
1019
1073
|
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1074
|
+
def run(direction, target_version)
|
1075
|
+
Migrator.new(direction, migrations, schema_migration, target_version).run
|
1076
|
+
end
|
1023
1077
|
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1078
|
+
def open
|
1079
|
+
Migrator.new(:up, migrations, schema_migration)
|
1080
|
+
end
|
1027
1081
|
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
[]
|
1034
|
-
end
|
1035
|
-
end
|
1082
|
+
def get_all_versions
|
1083
|
+
if schema_migration.table_exists?
|
1084
|
+
schema_migration.all_versions.map(&:to_i)
|
1085
|
+
else
|
1086
|
+
[]
|
1036
1087
|
end
|
1088
|
+
end
|
1037
1089
|
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1090
|
+
def current_version
|
1091
|
+
get_all_versions.max || 0
|
1092
|
+
rescue ActiveRecord::NoDatabaseError
|
1093
|
+
end
|
1041
1094
|
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1095
|
+
def needs_migration?
|
1096
|
+
(migrations.collect(&:version) - get_all_versions).size > 0
|
1097
|
+
end
|
1045
1098
|
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1099
|
+
def any_migrations?
|
1100
|
+
migrations.any?
|
1101
|
+
end
|
1049
1102
|
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1103
|
+
def last_migration #:nodoc:
|
1104
|
+
migrations.last || NullMigration.new
|
1105
|
+
end
|
1053
1106
|
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1107
|
+
def migrations
|
1108
|
+
migrations = migration_files.map do |file|
|
1109
|
+
version, name, scope = parse_migration_filename(file)
|
1110
|
+
raise IllegalMigrationNameError.new(file) unless version
|
1111
|
+
version = version.to_i
|
1112
|
+
name = name.camelize
|
1059
1113
|
|
1060
|
-
|
1061
|
-
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1114
|
+
MigrationProxy.new(name, version, file, scope)
|
1062
1115
|
end
|
1063
1116
|
|
1064
|
-
|
1065
|
-
|
1117
|
+
migrations.sort_by(&:version)
|
1118
|
+
end
|
1066
1119
|
|
1067
|
-
|
1068
|
-
|
1069
|
-
raise IllegalMigrationNameError.new(file) unless version
|
1070
|
-
version = version.to_i
|
1071
|
-
name = name.camelize
|
1120
|
+
def migrations_status
|
1121
|
+
db_list = schema_migration.normalized_versions
|
1072
1122
|
|
1073
|
-
|
1074
|
-
|
1123
|
+
file_list = migration_files.map do |file|
|
1124
|
+
version, name, scope = parse_migration_filename(file)
|
1125
|
+
raise IllegalMigrationNameError.new(file) unless version
|
1126
|
+
version = schema_migration.normalize_migration_number(version)
|
1127
|
+
status = db_list.delete(version) ? "up" : "down"
|
1128
|
+
[status, version, (name + scope).humanize]
|
1129
|
+
end.compact
|
1075
1130
|
|
1076
|
-
|
1131
|
+
db_list.map! do |version|
|
1132
|
+
["up", version, "********** NO FILE **********"]
|
1077
1133
|
end
|
1078
1134
|
|
1079
|
-
|
1080
|
-
|
1135
|
+
(db_list + file_list).sort_by { |_, version, _| version }
|
1136
|
+
end
|
1081
1137
|
|
1082
|
-
|
1138
|
+
def current_environment
|
1139
|
+
ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
1140
|
+
end
|
1083
1141
|
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
|
1088
|
-
status = db_list.delete(version) ? "up" : "down"
|
1089
|
-
[status, version, (name + scope).humanize]
|
1090
|
-
end.compact
|
1142
|
+
def protected_environment?
|
1143
|
+
ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
|
1144
|
+
end
|
1091
1145
|
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1146
|
+
def last_stored_environment
|
1147
|
+
return nil if current_version == 0
|
1148
|
+
raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
|
1095
1149
|
|
1096
|
-
|
1097
|
-
|
1150
|
+
environment = ActiveRecord::InternalMetadata[:environment]
|
1151
|
+
raise NoEnvironmentInSchemaError unless environment
|
1152
|
+
environment
|
1153
|
+
end
|
1098
1154
|
|
1099
|
-
|
1155
|
+
private
|
1156
|
+
def migration_files
|
1157
|
+
paths = Array(migrations_paths)
|
1100
1158
|
Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
|
1101
1159
|
end
|
1102
1160
|
|
1103
|
-
|
1161
|
+
def parse_migration_filename(filename)
|
1162
|
+
File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
|
1163
|
+
end
|
1104
1164
|
|
1105
|
-
def move(direction,
|
1106
|
-
migrator = new(direction, migrations
|
1107
|
-
start_index = migrator.migrations.index(migrator.current_migration)
|
1165
|
+
def move(direction, steps)
|
1166
|
+
migrator = Migrator.new(direction, migrations, schema_migration)
|
1108
1167
|
|
1109
|
-
if
|
1110
|
-
|
1111
|
-
version = finish ? finish.version : 0
|
1112
|
-
send(direction, migrations_paths, version)
|
1168
|
+
if current_version != 0 && !migrator.current_migration
|
1169
|
+
raise UnknownMigrationVersionError.new(current_version)
|
1113
1170
|
end
|
1171
|
+
|
1172
|
+
start_index =
|
1173
|
+
if current_version == 0
|
1174
|
+
0
|
1175
|
+
else
|
1176
|
+
migrator.migrations.index(migrator.current_migration)
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
finish = migrator.migrations[start_index + steps]
|
1180
|
+
version = finish ? finish.version : 0
|
1181
|
+
send(direction, version)
|
1182
|
+
end
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
class Migrator # :nodoc:
|
1186
|
+
class << self
|
1187
|
+
attr_accessor :migrations_paths
|
1188
|
+
|
1189
|
+
# For cases where a table doesn't exist like loading from schema cache
|
1190
|
+
def current_version
|
1191
|
+
MigrationContext.new(migrations_paths, SchemaMigration).current_version
|
1114
1192
|
end
|
1115
1193
|
end
|
1116
1194
|
|
1117
|
-
|
1118
|
-
raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
|
1195
|
+
self.migrations_paths = ["db/migrate"]
|
1119
1196
|
|
1197
|
+
def initialize(direction, migrations, schema_migration, target_version = nil)
|
1120
1198
|
@direction = direction
|
1121
1199
|
@target_version = target_version
|
1122
1200
|
@migrated_versions = nil
|
1123
1201
|
@migrations = migrations
|
1202
|
+
@schema_migration = schema_migration
|
1124
1203
|
|
1125
1204
|
validate(@migrations)
|
1126
1205
|
|
1127
|
-
|
1128
|
-
|
1206
|
+
@schema_migration.create_table
|
1207
|
+
ActiveRecord::InternalMetadata.create_table
|
1129
1208
|
end
|
1130
1209
|
|
1131
1210
|
def current_version
|
@@ -1178,153 +1257,141 @@ module ActiveRecord
|
|
1178
1257
|
end
|
1179
1258
|
|
1180
1259
|
def load_migrated
|
1181
|
-
@migrated_versions = Set.new(
|
1260
|
+
@migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
|
1182
1261
|
end
|
1183
1262
|
|
1184
1263
|
private
|
1185
1264
|
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
record_environment
|
1193
|
-
result
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
# Used for running multiple migrations up to or down to a certain value.
|
1197
|
-
def migrate_without_lock
|
1198
|
-
if invalid_target?
|
1199
|
-
raise UnknownMigrationVersionError.new(@target_version)
|
1200
|
-
end
|
1265
|
+
# Used for running a specific migration.
|
1266
|
+
def run_without_lock
|
1267
|
+
migration = migrations.detect { |m| m.version == @target_version }
|
1268
|
+
raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
|
1269
|
+
result = execute_migration_in_transaction(migration, @direction)
|
1201
1270
|
|
1202
|
-
|
1203
|
-
|
1271
|
+
record_environment
|
1272
|
+
result
|
1204
1273
|
end
|
1205
1274
|
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
def record_environment
|
1212
|
-
return if down?
|
1213
|
-
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
|
1214
|
-
end
|
1215
|
-
|
1216
|
-
def ran?(migration)
|
1217
|
-
migrated.include?(migration.version.to_i)
|
1218
|
-
end
|
1275
|
+
# Used for running multiple migrations up to or down to a certain value.
|
1276
|
+
def migrate_without_lock
|
1277
|
+
if invalid_target?
|
1278
|
+
raise UnknownMigrationVersionError.new(@target_version)
|
1279
|
+
end
|
1219
1280
|
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
end
|
1281
|
+
result = runnable.each do |migration|
|
1282
|
+
execute_migration_in_transaction(migration, @direction)
|
1283
|
+
end
|
1224
1284
|
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1285
|
+
record_environment
|
1286
|
+
result
|
1287
|
+
end
|
1228
1288
|
|
1229
|
-
|
1289
|
+
# Stores the current environment in the database.
|
1290
|
+
def record_environment
|
1291
|
+
return if down?
|
1292
|
+
ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
|
1293
|
+
end
|
1230
1294
|
|
1231
|
-
|
1232
|
-
migration.
|
1233
|
-
record_version_state_after_migrating(migration.version)
|
1295
|
+
def ran?(migration)
|
1296
|
+
migrated.include?(migration.version.to_i)
|
1234
1297
|
end
|
1235
|
-
rescue => e
|
1236
|
-
msg = "An error has occurred, "
|
1237
|
-
msg << "this and " if use_transaction?(migration)
|
1238
|
-
msg << "all later migrations canceled:\n\n#{e}"
|
1239
|
-
raise StandardError, msg, e.backtrace
|
1240
|
-
end
|
1241
1298
|
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1299
|
+
# Return true if a valid version is not provided.
|
1300
|
+
def invalid_target?
|
1301
|
+
@target_version && @target_version != 0 && !target
|
1302
|
+
end
|
1245
1303
|
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1304
|
+
def execute_migration_in_transaction(migration, direction)
|
1305
|
+
return if down? && !migrated.include?(migration.version.to_i)
|
1306
|
+
return if up? && migrated.include?(migration.version.to_i)
|
1249
1307
|
|
1250
|
-
|
1251
|
-
up? ? 0 : (migrations.index(current) || 0)
|
1252
|
-
end
|
1308
|
+
Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
|
1253
1309
|
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1310
|
+
ddl_transaction(migration) do
|
1311
|
+
migration.migrate(direction)
|
1312
|
+
record_version_state_after_migrating(migration.version)
|
1313
|
+
end
|
1314
|
+
rescue => e
|
1315
|
+
msg = +"An error has occurred, "
|
1316
|
+
msg << "this and " if use_transaction?(migration)
|
1317
|
+
msg << "all later migrations canceled:\n\n#{e}"
|
1318
|
+
raise StandardError, msg, e.backtrace
|
1319
|
+
end
|
1257
1320
|
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1321
|
+
def target
|
1322
|
+
migrations.detect { |m| m.version == @target_version }
|
1323
|
+
end
|
1261
1324
|
|
1262
|
-
|
1263
|
-
|
1264
|
-
migrated.delete(version)
|
1265
|
-
ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
|
1266
|
-
else
|
1267
|
-
migrated << version
|
1268
|
-
ActiveRecord::SchemaMigration.create!(version: version.to_s)
|
1325
|
+
def finish
|
1326
|
+
migrations.index(target) || migrations.size - 1
|
1269
1327
|
end
|
1270
|
-
end
|
1271
1328
|
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1329
|
+
def start
|
1330
|
+
up? ? 0 : (migrations.index(current) || 0)
|
1331
|
+
end
|
1275
1332
|
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
end
|
1333
|
+
def validate(migrations)
|
1334
|
+
name, = migrations.group_by(&:name).find { |_, v| v.length > 1 }
|
1335
|
+
raise DuplicateMigrationNameError.new(name) if name
|
1280
1336
|
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1337
|
+
version, = migrations.group_by(&:version).find { |_, v| v.length > 1 }
|
1338
|
+
raise DuplicateMigrationVersionError.new(version) if version
|
1339
|
+
end
|
1284
1340
|
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1341
|
+
def record_version_state_after_migrating(version)
|
1342
|
+
if down?
|
1343
|
+
migrated.delete(version)
|
1344
|
+
@schema_migration.delete_by(version: version.to_s)
|
1345
|
+
else
|
1346
|
+
migrated << version
|
1347
|
+
@schema_migration.create!(version: version.to_s)
|
1348
|
+
end
|
1349
|
+
end
|
1288
1350
|
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1351
|
+
def up?
|
1352
|
+
@direction == :up
|
1353
|
+
end
|
1292
1354
|
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1355
|
+
def down?
|
1356
|
+
@direction == :down
|
1357
|
+
end
|
1296
1358
|
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1359
|
+
# Wrap the migration in a transaction only if supported by the adapter.
|
1360
|
+
def ddl_transaction(migration)
|
1361
|
+
if use_transaction?(migration)
|
1362
|
+
Base.transaction { yield }
|
1363
|
+
else
|
1364
|
+
yield
|
1365
|
+
end
|
1303
1366
|
end
|
1304
|
-
end
|
1305
1367
|
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1368
|
+
def use_transaction?(migration)
|
1369
|
+
!migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
|
1370
|
+
end
|
1309
1371
|
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1372
|
+
def use_advisory_lock?
|
1373
|
+
Base.connection.advisory_locks_enabled?
|
1374
|
+
end
|
1313
1375
|
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1376
|
+
def with_advisory_lock
|
1377
|
+
lock_id = generate_migrator_advisory_lock_id
|
1378
|
+
connection = Base.connection
|
1379
|
+
got_lock = connection.get_advisory_lock(lock_id)
|
1380
|
+
raise ConcurrentMigrationError unless got_lock
|
1381
|
+
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1382
|
+
yield
|
1383
|
+
ensure
|
1384
|
+
if got_lock && !connection.release_advisory_lock(lock_id)
|
1385
|
+
raise ConcurrentMigrationError.new(
|
1386
|
+
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1387
|
+
)
|
1388
|
+
end
|
1389
|
+
end
|
1323
1390
|
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1391
|
+
MIGRATOR_SALT = 2053462845
|
1392
|
+
def generate_migrator_advisory_lock_id
|
1393
|
+
db_name_hash = Zlib.crc32(Base.connection.current_database)
|
1394
|
+
MIGRATOR_SALT * db_name_hash
|
1395
|
+
end
|
1329
1396
|
end
|
1330
1397
|
end
|