activerecord 4.2.8 → 6.0.0
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 +612 -1583
- data/MIT-LICENSE +4 -2
- data/README.rdoc +13 -12
- data/examples/performance.rb +33 -32
- data/examples/simple.rb +5 -4
- data/lib/active_record.rb +41 -22
- data/lib/active_record/aggregations.rb +267 -251
- data/lib/active_record/association_relation.rb +11 -6
- data/lib/active_record/associations.rb +1737 -1597
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +125 -58
- data/lib/active_record/associations/association_scope.rb +103 -132
- data/lib/active_record/associations/belongs_to_association.rb +65 -60
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
- data/lib/active_record/associations/builder/association.rb +27 -40
- data/lib/active_record/associations/builder/belongs_to.rb +69 -55
- data/lib/active_record/associations/builder/collection_association.rb +10 -33
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
- data/lib/active_record/associations/builder/has_many.rb +8 -4
- data/lib/active_record/associations/builder/has_one.rb +46 -5
- data/lib/active_record/associations/builder/singular_association.rb +16 -10
- data/lib/active_record/associations/collection_association.rb +134 -286
- data/lib/active_record/associations/collection_proxy.rb +241 -146
- data/lib/active_record/associations/foreign_association.rb +10 -1
- data/lib/active_record/associations/has_many_association.rb +34 -97
- data/lib/active_record/associations/has_many_through_association.rb +60 -87
- data/lib/active_record/associations/has_one_association.rb +61 -49
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency.rb +137 -167
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -88
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/preloader.rb +90 -92
- data/lib/active_record/associations/preloader/association.rb +90 -123
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/attribute_assignment.rb +56 -183
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods.rb +120 -135
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
- data/lib/active_record/attribute_methods/dirty.rb +174 -144
- data/lib/active_record/attribute_methods/primary_key.rb +91 -83
- data/lib/active_record/attribute_methods/query.rb +6 -5
- data/lib/active_record/attribute_methods/read.rb +20 -76
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +58 -36
- data/lib/active_record/attribute_methods/write.rb +32 -54
- data/lib/active_record/attributes.rb +214 -82
- data/lib/active_record/autosave_association.rb +91 -37
- data/lib/active_record/base.rb +57 -45
- data/lib/active_record/callbacks.rb +100 -74
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +796 -296
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -115
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -244
- data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
- data/lib/active_record/connection_adapters/abstract_adapter.rb +460 -204
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -627
- data/lib/active_record/connection_adapters/column.rb +56 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +174 -152
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +58 -188
- data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +4 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -22
- 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 +31 -19
- 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 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +10 -5
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +144 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +470 -290
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +551 -356
- data/lib/active_record/connection_adapters/schema_cache.rb +72 -25
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- 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 +290 -345
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +176 -41
- data/lib/active_record/core.rb +251 -231
- data/lib/active_record/counter_cache.rb +67 -49
- data/lib/active_record/database_configurations.rb +233 -0
- 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/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +163 -86
- data/lib/active_record/errors.rb +188 -53
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +35 -9
- 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 +228 -499
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +158 -112
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +123 -29
- data/lib/active_record/internal_metadata.rb +53 -0
- data/lib/active_record/legacy_yaml_adapter.rb +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +87 -96
- data/lib/active_record/locking/pessimistic.rb +18 -6
- data/lib/active_record/log_subscriber.rb +76 -33
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +626 -283
- data/lib/active_record/migration/command_recorder.rb +177 -90
- data/lib/active_record/migration/compatibility.rb +244 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/model_schema.rb +314 -112
- data/lib/active_record/nested_attributes.rb +264 -222
- data/lib/active_record/no_touching.rb +14 -1
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +557 -125
- data/lib/active_record/query_cache.rb +19 -23
- data/lib/active_record/querying.rb +43 -29
- data/lib/active_record/railtie.rb +147 -46
- 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 +330 -197
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +428 -279
- data/lib/active_record/relation.rb +518 -341
- data/lib/active_record/relation/batches.rb +207 -55
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/calculations.rb +267 -253
- data/lib/active_record/relation/delegation.rb +70 -80
- data/lib/active_record/relation/finder_methods.rb +277 -241
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +78 -87
- data/lib/active_record/relation/predicate_builder.rb +114 -119
- data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +575 -394
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -13
- data/lib/active_record/relation/where_clause.rb +190 -0
- data/lib/active_record/relation/where_clause_factory.rb +33 -0
- data/lib/active_record/result.rb +79 -42
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +144 -121
- data/lib/active_record/schema.rb +21 -24
- data/lib/active_record/schema_dumper.rb +112 -93
- data/lib/active_record/schema_migration.rb +24 -17
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/scoping/default.rb +101 -85
- data/lib/active_record/scoping/named.rb +86 -33
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +73 -36
- data/lib/active_record/store.rb +127 -42
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +75 -0
- data/lib/active_record/tasks/database_tasks.rb +308 -99
- data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
- data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +38 -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 +86 -40
- data/lib/active_record/touch_later.rb +66 -0
- data/lib/active_record/transactions.rb +216 -150
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type.rb +78 -23
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +24 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -0
- data/lib/active_record/validations.rb +39 -35
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +42 -55
- data/lib/active_record/version.rb +3 -1
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -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.rb +68 -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/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.rb +20 -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/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +7 -5
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration.rb +31 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +42 -37
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +11 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +19 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +164 -60
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- 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 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -163
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -58
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,50 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
# We can then redefine how certain data types may be handled in the schema dumper on the
|
7
|
-
# Adapter level by over-writing this code inside the database specific adapters
|
8
|
-
module ColumnDumper
|
9
|
-
def column_spec(column, types)
|
10
|
-
spec = prepare_column_options(column, types)
|
11
|
-
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k}: ")}
|
12
|
-
spec
|
5
|
+
class SchemaDumper < SchemaDumper # :nodoc:
|
6
|
+
def self.create(connection, options)
|
7
|
+
new(connection, options)
|
13
8
|
end
|
14
9
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
spec = {}
|
20
|
-
spec[:name] = column.name.inspect
|
21
|
-
spec[:type] = column.type.to_s
|
22
|
-
spec[:null] = 'false' unless column.null
|
10
|
+
private
|
11
|
+
def column_spec(column)
|
12
|
+
[schema_type_with_virtual(column), prepare_column_options(column)]
|
13
|
+
end
|
23
14
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
15
|
+
def column_spec_for_primary_key(column)
|
16
|
+
return {} if default_primary_key?(column)
|
17
|
+
spec = { id: schema_type(column).inspect }
|
18
|
+
spec.merge!(prepare_column_options(column).except!(:null, :comment))
|
19
|
+
spec[:default] ||= "nil" if explicit_primary_key_default?(column)
|
20
|
+
spec
|
21
|
+
end
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
def prepare_column_options(column)
|
24
|
+
spec = {}
|
25
|
+
spec[:limit] = schema_limit(column)
|
26
|
+
spec[:precision] = schema_precision(column)
|
27
|
+
spec[:scale] = schema_scale(column)
|
28
|
+
spec[:default] = schema_default(column)
|
29
|
+
spec[:null] = "false" unless column.null
|
30
|
+
spec[:collation] = schema_collation(column)
|
31
|
+
spec[:comment] = column.comment.inspect if column.comment.present?
|
32
|
+
spec.compact!
|
33
|
+
spec
|
34
|
+
end
|
31
35
|
|
32
|
-
|
33
|
-
|
36
|
+
def default_primary_key?(column)
|
37
|
+
schema_type(column) == :bigint
|
38
|
+
end
|
34
39
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
40
|
+
def explicit_primary_key_default?(column)
|
41
|
+
false
|
42
|
+
end
|
39
43
|
|
40
|
-
|
44
|
+
def schema_type_with_virtual(column)
|
45
|
+
if @connection.supports_virtual_columns? && column.virtual?
|
46
|
+
:virtual
|
47
|
+
else
|
48
|
+
schema_type(column)
|
49
|
+
end
|
50
|
+
end
|
41
51
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
52
|
+
def schema_type(column)
|
53
|
+
if column.bigint?
|
54
|
+
:bigint
|
55
|
+
else
|
56
|
+
column.type
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def schema_limit(column)
|
61
|
+
limit = column.limit unless column.bigint?
|
62
|
+
limit.inspect if limit && limit != @connection.native_database_types[column.type][:limit]
|
63
|
+
end
|
64
|
+
|
65
|
+
def schema_precision(column)
|
66
|
+
column.precision.inspect if column.precision
|
67
|
+
end
|
68
|
+
|
69
|
+
def schema_scale(column)
|
70
|
+
column.scale.inspect if column.scale
|
71
|
+
end
|
72
|
+
|
73
|
+
def schema_default(column)
|
74
|
+
return unless column.has_default?
|
75
|
+
type = @connection.lookup_cast_type_from_column(column)
|
76
|
+
default = type.deserialize(column.default)
|
77
|
+
if default.nil?
|
78
|
+
schema_expression(column)
|
79
|
+
else
|
80
|
+
type.type_cast_for_schema(default)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def schema_expression(column)
|
85
|
+
"-> { #{column.default_function.inspect} }" if column.default_function
|
86
|
+
end
|
87
|
+
|
88
|
+
def schema_collation(column)
|
89
|
+
column.collation.inspect if column.collation
|
46
90
|
end
|
47
|
-
end
|
48
91
|
end
|
49
92
|
end
|
50
93
|
end
|
@@ -1,6 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/migration/join_table"
|
4
|
+
require "active_support/core_ext/string/access"
|
5
|
+
require "active_support/deprecation"
|
6
|
+
require "digest/sha2"
|
4
7
|
|
5
8
|
module ActiveRecord
|
6
9
|
module ConnectionAdapters # :nodoc:
|
@@ -14,15 +17,26 @@ module ActiveRecord
|
|
14
17
|
{}
|
15
18
|
end
|
16
19
|
|
20
|
+
def table_options(table_name)
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the table comment that's stored in database metadata.
|
25
|
+
def table_comment(table_name)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
17
29
|
# Truncates a table alias according to the limits of the current adapter.
|
18
30
|
def table_alias_for(table_name)
|
19
|
-
table_name[0...table_alias_length].tr(
|
31
|
+
table_name[0...table_alias_length].tr(".", "_")
|
20
32
|
end
|
21
33
|
|
22
34
|
# Returns the relation names useable to back Active Record models.
|
23
|
-
# For most adapters this means all tables and views.
|
35
|
+
# For most adapters this means all #tables and #views.
|
24
36
|
def data_sources
|
25
|
-
|
37
|
+
query_values(data_source_sql, "SCHEMA")
|
38
|
+
rescue NotImplementedError
|
39
|
+
tables | views
|
26
40
|
end
|
27
41
|
|
28
42
|
# Checks to see if the data source +name+ exists on the database.
|
@@ -30,19 +44,45 @@ module ActiveRecord
|
|
30
44
|
# data_source_exists?(:ebooks)
|
31
45
|
#
|
32
46
|
def data_source_exists?(name)
|
47
|
+
query_values(data_source_sql(name), "SCHEMA").any? if name.present?
|
48
|
+
rescue NotImplementedError
|
33
49
|
data_sources.include?(name.to_s)
|
34
50
|
end
|
35
51
|
|
52
|
+
# Returns an array of table names defined in the database.
|
53
|
+
def tables
|
54
|
+
query_values(data_source_sql(type: "BASE TABLE"), "SCHEMA")
|
55
|
+
end
|
56
|
+
|
36
57
|
# Checks to see if the table +table_name+ exists on the database.
|
37
58
|
#
|
38
59
|
# table_exists?(:developers)
|
39
60
|
#
|
40
61
|
def table_exists?(table_name)
|
62
|
+
query_values(data_source_sql(table_name, type: "BASE TABLE"), "SCHEMA").any? if table_name.present?
|
63
|
+
rescue NotImplementedError
|
41
64
|
tables.include?(table_name.to_s)
|
42
65
|
end
|
43
66
|
|
67
|
+
# Returns an array of view names defined in the database.
|
68
|
+
def views
|
69
|
+
query_values(data_source_sql(type: "VIEW"), "SCHEMA")
|
70
|
+
end
|
71
|
+
|
72
|
+
# Checks to see if the view +view_name+ exists on the database.
|
73
|
+
#
|
74
|
+
# view_exists?(:ebooks)
|
75
|
+
#
|
76
|
+
def view_exists?(view_name)
|
77
|
+
query_values(data_source_sql(view_name, type: "VIEW"), "SCHEMA").any? if view_name.present?
|
78
|
+
rescue NotImplementedError
|
79
|
+
views.include?(view_name.to_s)
|
80
|
+
end
|
81
|
+
|
44
82
|
# Returns an array of indexes for the given table.
|
45
|
-
|
83
|
+
def indexes(table_name)
|
84
|
+
raise NotImplementedError, "#indexes is not implemented"
|
85
|
+
end
|
46
86
|
|
47
87
|
# Checks to see if an index exists on a table for a given index definition.
|
48
88
|
#
|
@@ -60,18 +100,21 @@ module ActiveRecord
|
|
60
100
|
#
|
61
101
|
def index_exists?(table_name, column_name, options = {})
|
62
102
|
column_names = Array(column_name).map(&:to_s)
|
63
|
-
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, column: column_names)
|
64
103
|
checks = []
|
65
|
-
checks << lambda { |i| i.
|
66
|
-
checks << lambda { |i| i.columns == column_names }
|
104
|
+
checks << lambda { |i| Array(i.columns) == column_names }
|
67
105
|
checks << lambda { |i| i.unique } if options[:unique]
|
106
|
+
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
|
68
107
|
|
69
108
|
indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
|
70
109
|
end
|
71
110
|
|
72
|
-
# Returns an array of Column objects for the table specified by +table_name+.
|
73
|
-
|
74
|
-
|
111
|
+
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
112
|
+
def columns(table_name)
|
113
|
+
table_name = table_name.to_s
|
114
|
+
column_definitions(table_name).map do |field|
|
115
|
+
new_column_from_field(table_name, field)
|
116
|
+
end
|
117
|
+
end
|
75
118
|
|
76
119
|
# Checks to see if a column exists in a given table.
|
77
120
|
#
|
@@ -87,21 +130,29 @@ module ActiveRecord
|
|
87
130
|
# column_exists?(:suppliers, :name, :string, null: false)
|
88
131
|
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
|
89
132
|
#
|
90
|
-
def column_exists?(table_name, column_name, type = nil, options
|
133
|
+
def column_exists?(table_name, column_name, type = nil, **options)
|
91
134
|
column_name = column_name.to_s
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
135
|
+
checks = []
|
136
|
+
checks << lambda { |c| c.name == column_name }
|
137
|
+
checks << lambda { |c| c.type == type.to_sym rescue nil } if type
|
138
|
+
column_options_keys.each do |attr|
|
139
|
+
checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
|
140
|
+
end
|
141
|
+
|
142
|
+
columns(table_name).any? { |c| checks.all? { |check| check[c] } }
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns just a table's primary key
|
146
|
+
def primary_key(table_name)
|
147
|
+
pk = primary_keys(table_name)
|
148
|
+
pk = pk.first unless pk.size > 1
|
149
|
+
pk
|
99
150
|
end
|
100
151
|
|
101
152
|
# Creates a new table with the name +table_name+. +table_name+ may either
|
102
153
|
# be a String or a Symbol.
|
103
154
|
#
|
104
|
-
# There are two ways to work with
|
155
|
+
# There are two ways to work with #create_table. You can use the block
|
105
156
|
# form or the regular form, like this:
|
106
157
|
#
|
107
158
|
# === Block form
|
@@ -133,13 +184,18 @@ module ActiveRecord
|
|
133
184
|
# The +options+ hash can include the following keys:
|
134
185
|
# [<tt>:id</tt>]
|
135
186
|
# Whether to automatically add a primary key column. Defaults to true.
|
136
|
-
# Join tables for
|
187
|
+
# Join tables for {ActiveRecord::Base.has_and_belongs_to_many}[rdoc-ref:Associations::ClassMethods#has_and_belongs_to_many] should set it to false.
|
188
|
+
#
|
189
|
+
# A Symbol can be used to specify the type of the generated primary key column.
|
137
190
|
# [<tt>:primary_key</tt>]
|
138
191
|
# The name of the primary key, if one is to be added automatically.
|
139
|
-
# Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
|
192
|
+
# Defaults to +id+. If <tt>:id</tt> is false, then this option is ignored.
|
193
|
+
#
|
194
|
+
# If an array is passed, a composite primary key will be created.
|
140
195
|
#
|
141
196
|
# Note that Active Record models will automatically detect their
|
142
|
-
# primary key. This can be avoided by using
|
197
|
+
# primary key. This can be avoided by using
|
198
|
+
# {self.primary_key=}[rdoc-ref:AttributeMethods::PrimaryKey::ClassMethods#primary_key=] on the model
|
143
199
|
# to define the key explicitly.
|
144
200
|
#
|
145
201
|
# [<tt>:options</tt>]
|
@@ -150,19 +206,22 @@ module ActiveRecord
|
|
150
206
|
# Set to true to drop the table before creating it.
|
151
207
|
# Set to +:cascade+ to drop dependent objects as well.
|
152
208
|
# Defaults to false.
|
209
|
+
# [<tt>:if_not_exists</tt>]
|
210
|
+
# Set to true to avoid raising an error when the table already exists.
|
211
|
+
# Defaults to false.
|
153
212
|
# [<tt>:as</tt>]
|
154
213
|
# SQL to use to generate the table. When this option is used, the block is
|
155
214
|
# ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options.
|
156
215
|
#
|
157
216
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
158
217
|
#
|
159
|
-
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=
|
218
|
+
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4')
|
160
219
|
#
|
161
220
|
# generates:
|
162
221
|
#
|
163
222
|
# CREATE TABLE suppliers (
|
164
|
-
# id
|
165
|
-
# ) ENGINE=InnoDB DEFAULT CHARSET=
|
223
|
+
# id bigint auto_increment PRIMARY KEY
|
224
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
166
225
|
#
|
167
226
|
# ====== Rename the primary key column
|
168
227
|
#
|
@@ -173,22 +232,52 @@ module ActiveRecord
|
|
173
232
|
# generates:
|
174
233
|
#
|
175
234
|
# CREATE TABLE objects (
|
176
|
-
# guid
|
235
|
+
# guid bigint auto_increment PRIMARY KEY,
|
177
236
|
# name varchar(80)
|
178
237
|
# )
|
179
238
|
#
|
239
|
+
# ====== Change the primary key column type
|
240
|
+
#
|
241
|
+
# create_table(:tags, id: :string) do |t|
|
242
|
+
# t.column :label, :string
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# generates:
|
246
|
+
#
|
247
|
+
# CREATE TABLE tags (
|
248
|
+
# id varchar PRIMARY KEY,
|
249
|
+
# label varchar
|
250
|
+
# )
|
251
|
+
#
|
252
|
+
# ====== Create a composite primary key
|
253
|
+
#
|
254
|
+
# create_table(:orders, primary_key: [:product_id, :client_id]) do |t|
|
255
|
+
# t.belongs_to :product
|
256
|
+
# t.belongs_to :client
|
257
|
+
# end
|
258
|
+
#
|
259
|
+
# generates:
|
260
|
+
#
|
261
|
+
# CREATE TABLE order (
|
262
|
+
# product_id bigint NOT NULL,
|
263
|
+
# client_id bigint NOT NULL
|
264
|
+
# );
|
265
|
+
#
|
266
|
+
# ALTER TABLE ONLY "orders"
|
267
|
+
# ADD CONSTRAINT orders_pkey PRIMARY KEY (product_id, client_id);
|
268
|
+
#
|
180
269
|
# ====== Do not add a primary key column
|
181
270
|
#
|
182
271
|
# create_table(:categories_suppliers, id: false) do |t|
|
183
|
-
# t.column :category_id, :
|
184
|
-
# t.column :supplier_id, :
|
272
|
+
# t.column :category_id, :bigint
|
273
|
+
# t.column :supplier_id, :bigint
|
185
274
|
# end
|
186
275
|
#
|
187
276
|
# generates:
|
188
277
|
#
|
189
278
|
# CREATE TABLE categories_suppliers (
|
190
|
-
# category_id
|
191
|
-
# supplier_id
|
279
|
+
# category_id bigint,
|
280
|
+
# supplier_id bigint
|
192
281
|
# )
|
193
282
|
#
|
194
283
|
# ====== Create a temporary table based on a query
|
@@ -202,33 +291,43 @@ module ActiveRecord
|
|
202
291
|
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
|
203
292
|
#
|
204
293
|
# See also TableDefinition#column for details on how to create columns.
|
205
|
-
def create_table(table_name, options
|
206
|
-
td = create_table_definition
|
294
|
+
def create_table(table_name, **options)
|
295
|
+
td = create_table_definition(table_name, options)
|
207
296
|
|
208
297
|
if options[:id] != false && !options[:as]
|
209
298
|
pk = options.fetch(:primary_key) do
|
210
299
|
Base.get_primary_key table_name.to_s.singularize
|
211
300
|
end
|
212
301
|
|
213
|
-
|
302
|
+
if pk.is_a?(Array)
|
303
|
+
td.primary_keys pk
|
304
|
+
else
|
305
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options.except(:comment)
|
306
|
+
end
|
214
307
|
end
|
215
308
|
|
216
309
|
yield td if block_given?
|
217
310
|
|
218
|
-
if options[:force]
|
219
|
-
drop_table(table_name, options)
|
311
|
+
if options[:force]
|
312
|
+
drop_table(table_name, options.merge(if_exists: true))
|
220
313
|
end
|
221
314
|
|
222
315
|
result = execute schema_creation.accept td
|
223
316
|
|
224
317
|
unless supports_indexes_in_create?
|
225
|
-
td.indexes.
|
318
|
+
td.indexes.each do |column_name, index_options|
|
226
319
|
add_index(table_name, column_name, index_options)
|
227
320
|
end
|
228
321
|
end
|
229
322
|
|
230
|
-
|
231
|
-
|
323
|
+
if supports_comments? && !supports_comments_in_create?
|
324
|
+
if table_comment = options[:comment].presence
|
325
|
+
change_table_comment(table_name, table_comment)
|
326
|
+
end
|
327
|
+
|
328
|
+
td.columns.each do |column|
|
329
|
+
change_column_comment(table_name, column.name, column.comment) if column.comment.present?
|
330
|
+
end
|
232
331
|
end
|
233
332
|
|
234
333
|
result
|
@@ -240,9 +339,9 @@ module ActiveRecord
|
|
240
339
|
# # Creates a table called 'assemblies_parts' with no id.
|
241
340
|
# create_join_table(:assemblies, :parts)
|
242
341
|
#
|
243
|
-
# You can pass
|
342
|
+
# You can pass an +options+ hash which can include the following keys:
|
244
343
|
# [<tt>:table_name</tt>]
|
245
|
-
# Sets the table name overriding the default
|
344
|
+
# Sets the table name, overriding the default.
|
246
345
|
# [<tt>:column_options</tt>]
|
247
346
|
# Any extra options you want appended to the columns definition.
|
248
347
|
# [<tt>:options</tt>]
|
@@ -253,7 +352,7 @@ module ActiveRecord
|
|
253
352
|
# Set to true to drop the table before creating it.
|
254
353
|
# Defaults to false.
|
255
354
|
#
|
256
|
-
# Note that
|
355
|
+
# Note that #create_join_table does not create any indices by default; you can use
|
257
356
|
# its block form to do so yourself:
|
258
357
|
#
|
259
358
|
# create_join_table :products, :categories do |t|
|
@@ -268,31 +367,30 @@ module ActiveRecord
|
|
268
367
|
# generates:
|
269
368
|
#
|
270
369
|
# CREATE TABLE assemblies_parts (
|
271
|
-
# assembly_id
|
272
|
-
# part_id
|
370
|
+
# assembly_id bigint NOT NULL,
|
371
|
+
# part_id bigint NOT NULL,
|
273
372
|
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
274
373
|
#
|
275
|
-
def create_join_table(table_1, table_2,
|
374
|
+
def create_join_table(table_1, table_2, column_options: {}, **options)
|
276
375
|
join_table_name = find_join_table_name(table_1, table_2, options)
|
277
376
|
|
278
|
-
column_options
|
279
|
-
column_options.reverse_merge!(null: false)
|
377
|
+
column_options.reverse_merge!(null: false, index: false)
|
280
378
|
|
281
|
-
|
379
|
+
t1_ref, t2_ref = [table_1, table_2].map { |t| t.to_s.singularize }
|
282
380
|
|
283
381
|
create_table(join_table_name, options.merge!(id: false)) do |td|
|
284
|
-
td.
|
285
|
-
td.
|
382
|
+
td.references t1_ref, column_options
|
383
|
+
td.references t2_ref, column_options
|
286
384
|
yield td if block_given?
|
287
385
|
end
|
288
386
|
end
|
289
387
|
|
290
388
|
# Drops the join table specified by the given arguments.
|
291
|
-
# See
|
389
|
+
# See #create_join_table for details.
|
292
390
|
#
|
293
391
|
# Although this command ignores the block if one is given, it can be helpful
|
294
392
|
# to provide one in a migration's +change+ method so it can be reverted.
|
295
|
-
# In that case, the block will be used by create_join_table.
|
393
|
+
# In that case, the block will be used by #create_join_table.
|
296
394
|
def drop_join_table(table_1, table_2, options = {})
|
297
395
|
join_table_name = find_join_table_name(table_1, table_2, options)
|
298
396
|
drop_table(join_table_name)
|
@@ -310,10 +408,12 @@ module ActiveRecord
|
|
310
408
|
# [<tt>:bulk</tt>]
|
311
409
|
# Set this to true to make this a bulk alter query, such as
|
312
410
|
#
|
313
|
-
# ALTER TABLE `users` ADD COLUMN age INT
|
411
|
+
# ALTER TABLE `users` ADD COLUMN age INT, ADD COLUMN birthdate DATETIME ...
|
314
412
|
#
|
315
413
|
# Defaults to false.
|
316
414
|
#
|
415
|
+
# Only supported on the MySQL and PostgreSQL adapter, ignored elsewhere.
|
416
|
+
#
|
317
417
|
# ====== Add a column
|
318
418
|
#
|
319
419
|
# change_table(:suppliers) do |t|
|
@@ -338,7 +438,7 @@ module ActiveRecord
|
|
338
438
|
# t.references :company
|
339
439
|
# end
|
340
440
|
#
|
341
|
-
# Creates a <tt>company_id(
|
441
|
+
# Creates a <tt>company_id(bigint)</tt> column.
|
342
442
|
#
|
343
443
|
# ====== Add a polymorphic foreign key column
|
344
444
|
#
|
@@ -346,7 +446,7 @@ module ActiveRecord
|
|
346
446
|
# t.belongs_to :company, polymorphic: true
|
347
447
|
# end
|
348
448
|
#
|
349
|
-
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(
|
449
|
+
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(bigint)</tt> columns.
|
350
450
|
#
|
351
451
|
# ====== Remove a column
|
352
452
|
#
|
@@ -367,7 +467,7 @@ module ActiveRecord
|
|
367
467
|
# t.remove_index :company_id
|
368
468
|
# end
|
369
469
|
#
|
370
|
-
# See also Table for details on all of the various column
|
470
|
+
# See also Table for details on all of the various column transformations.
|
371
471
|
def change_table(table_name, options = {})
|
372
472
|
if supports_bulk_alter? && options[:bulk]
|
373
473
|
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
|
@@ -391,17 +491,101 @@ module ActiveRecord
|
|
391
491
|
# [<tt>:force</tt>]
|
392
492
|
# Set to +:cascade+ to drop dependent objects as well.
|
393
493
|
# Defaults to false.
|
494
|
+
# [<tt>:if_exists</tt>]
|
495
|
+
# Set to +true+ to only drop the table if it exists.
|
496
|
+
# Defaults to false.
|
394
497
|
#
|
395
498
|
# Although this command ignores most +options+ and the block if one is given,
|
396
499
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
397
|
-
# In that case, +options+ and the block will be used by create_table.
|
500
|
+
# In that case, +options+ and the block will be used by #create_table.
|
398
501
|
def drop_table(table_name, options = {})
|
399
|
-
execute "DROP TABLE #{quote_table_name(table_name)}"
|
502
|
+
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
|
400
503
|
end
|
401
504
|
|
402
|
-
#
|
403
|
-
#
|
404
|
-
|
505
|
+
# Add a new +type+ column named +column_name+ to +table_name+.
|
506
|
+
#
|
507
|
+
# The +type+ parameter is normally one of the migrations native types,
|
508
|
+
# which is one of the following:
|
509
|
+
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
510
|
+
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
511
|
+
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
512
|
+
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
513
|
+
#
|
514
|
+
# You may use a type not in this list as long as it is supported by your
|
515
|
+
# database (for example, "polygon" in MySQL), but this will not be database
|
516
|
+
# agnostic and should usually be avoided.
|
517
|
+
#
|
518
|
+
# Available options are (none of these exists by default):
|
519
|
+
# * <tt>:limit</tt> -
|
520
|
+
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
|
521
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
|
522
|
+
# This option is ignored by some backends.
|
523
|
+
# * <tt>:default</tt> -
|
524
|
+
# The column's default value. Use +nil+ for +NULL+.
|
525
|
+
# * <tt>:null</tt> -
|
526
|
+
# Allows or disallows +NULL+ values in the column.
|
527
|
+
# * <tt>:precision</tt> -
|
528
|
+
# Specifies the precision for the <tt>:decimal</tt>, <tt>:numeric</tt>,
|
529
|
+
# <tt>:datetime</tt>, and <tt>:time</tt> columns.
|
530
|
+
# * <tt>:scale</tt> -
|
531
|
+
# Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
|
532
|
+
# * <tt>:collation</tt> -
|
533
|
+
# Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column. If not specified, the
|
534
|
+
# column will have the same collation as the table.
|
535
|
+
# * <tt>:comment</tt> -
|
536
|
+
# Specifies the comment for the column. This option is ignored by some backends.
|
537
|
+
#
|
538
|
+
# Note: The precision is the total number of significant digits,
|
539
|
+
# and the scale is the number of digits that can be stored following
|
540
|
+
# the decimal point. For example, the number 123.45 has a precision of 5
|
541
|
+
# and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
|
542
|
+
# range from -999.99 to 999.99.
|
543
|
+
#
|
544
|
+
# Please be aware of different RDBMS implementations behavior with
|
545
|
+
# <tt>:decimal</tt> columns:
|
546
|
+
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
|
547
|
+
# <tt>:precision</tt>, and makes no comments about the requirements of
|
548
|
+
# <tt>:precision</tt>.
|
549
|
+
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
|
550
|
+
# Default is (10,0).
|
551
|
+
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
552
|
+
# <tt>:scale</tt> [0..infinity]. No default.
|
553
|
+
# * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
|
554
|
+
# but the maximum supported <tt>:precision</tt> is 16. No default.
|
555
|
+
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
556
|
+
# Default is (38,0).
|
557
|
+
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
558
|
+
# Default unknown.
|
559
|
+
# * SqlServer: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
560
|
+
# Default (38,0).
|
561
|
+
#
|
562
|
+
# == Examples
|
563
|
+
#
|
564
|
+
# add_column(:users, :picture, :binary, limit: 2.megabytes)
|
565
|
+
# # ALTER TABLE "users" ADD "picture" blob(2097152)
|
566
|
+
#
|
567
|
+
# add_column(:articles, :status, :string, limit: 20, default: 'draft', null: false)
|
568
|
+
# # ALTER TABLE "articles" ADD "status" varchar(20) DEFAULT 'draft' NOT NULL
|
569
|
+
#
|
570
|
+
# add_column(:answers, :bill_gates_money, :decimal, precision: 15, scale: 2)
|
571
|
+
# # ALTER TABLE "answers" ADD "bill_gates_money" decimal(15,2)
|
572
|
+
#
|
573
|
+
# add_column(:measurements, :sensor_reading, :decimal, precision: 30, scale: 20)
|
574
|
+
# # ALTER TABLE "measurements" ADD "sensor_reading" decimal(30,20)
|
575
|
+
#
|
576
|
+
# # While :scale defaults to zero on most databases, it
|
577
|
+
# # probably wouldn't hurt to include it.
|
578
|
+
# add_column(:measurements, :huge_integer, :decimal, precision: 30)
|
579
|
+
# # ALTER TABLE "measurements" ADD "huge_integer" decimal(30)
|
580
|
+
#
|
581
|
+
# # Defines a column that stores an array of a type.
|
582
|
+
# add_column(:users, :skills, :text, array: true)
|
583
|
+
# # ALTER TABLE "users" ADD "skills" text[]
|
584
|
+
#
|
585
|
+
# # Defines a column with a database-specific type.
|
586
|
+
# add_column(:shapes, :triangle, 'polygon')
|
587
|
+
# # ALTER TABLE "shapes" ADD "triangle" polygon
|
588
|
+
def add_column(table_name, column_name, type, **options)
|
405
589
|
at = create_alter_table table_name
|
406
590
|
at.add_column(column_name, type, options)
|
407
591
|
execute schema_creation.accept at
|
@@ -424,9 +608,10 @@ module ActiveRecord
|
|
424
608
|
#
|
425
609
|
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
426
610
|
# to provide these in a migration's +change+ method so it can be reverted.
|
427
|
-
# In that case, +type+ and +options+ will be used by add_column.
|
611
|
+
# In that case, +type+ and +options+ will be used by #add_column.
|
612
|
+
# Indexes on the column are automatically removed.
|
428
613
|
def remove_column(table_name, column_name, type = nil, options = {})
|
429
|
-
execute "ALTER TABLE #{quote_table_name(table_name)}
|
614
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_for_alter(table_name, column_name, type, options)}"
|
430
615
|
end
|
431
616
|
|
432
617
|
# Changes the column's definition according to the new options.
|
@@ -448,11 +633,16 @@ module ActiveRecord
|
|
448
633
|
#
|
449
634
|
# change_column_default(:users, :email, nil)
|
450
635
|
#
|
451
|
-
|
636
|
+
# Passing a hash containing +:from+ and +:to+ will make this change
|
637
|
+
# reversible in migration:
|
638
|
+
#
|
639
|
+
# change_column_default(:posts, :state, from: nil, to: "draft")
|
640
|
+
#
|
641
|
+
def change_column_default(table_name, column_name, default_or_changes)
|
452
642
|
raise NotImplementedError, "change_column_default is not implemented"
|
453
643
|
end
|
454
644
|
|
455
|
-
# Sets or removes a
|
645
|
+
# Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag
|
456
646
|
# indicates whether the value can be +NULL+. For example
|
457
647
|
#
|
458
648
|
# change_column_null(:users, :nickname, false)
|
@@ -464,7 +654,7 @@ module ActiveRecord
|
|
464
654
|
# allows them to be +NULL+ (drops the constraint).
|
465
655
|
#
|
466
656
|
# The method accepts an optional fourth argument to replace existing
|
467
|
-
#
|
657
|
+
# <tt>NULL</tt>s with some other value. Use that one when enabling the
|
468
658
|
# constraint if needed, since otherwise those rows would not be valid.
|
469
659
|
#
|
470
660
|
# Please note the fourth argument does not set a column's default.
|
@@ -518,6 +708,8 @@ module ActiveRecord
|
|
518
708
|
#
|
519
709
|
# CREATE INDEX by_name ON accounts(name(10))
|
520
710
|
#
|
711
|
+
# ====== Creating an index with specific key lengths for multiple keys
|
712
|
+
#
|
521
713
|
# add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
|
522
714
|
#
|
523
715
|
# generates:
|
@@ -534,7 +726,7 @@ module ActiveRecord
|
|
534
726
|
#
|
535
727
|
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
|
536
728
|
#
|
537
|
-
# Note: MySQL
|
729
|
+
# Note: MySQL only supports index order from 8.0.1 onwards (earlier versions accepted the syntax but ignored it).
|
538
730
|
#
|
539
731
|
# ====== Creating a partial index
|
540
732
|
#
|
@@ -557,6 +749,19 @@ module ActiveRecord
|
|
557
749
|
#
|
558
750
|
# Note: only supported by PostgreSQL and MySQL
|
559
751
|
#
|
752
|
+
# ====== Creating an index with a specific operator class
|
753
|
+
#
|
754
|
+
# add_index(:developers, :name, using: 'gist', opclass: :gist_trgm_ops)
|
755
|
+
# # CREATE INDEX developers_on_name ON developers USING gist (name gist_trgm_ops) -- PostgreSQL
|
756
|
+
#
|
757
|
+
# add_index(:developers, [:name, :city], using: 'gist', opclass: { city: :gist_trgm_ops })
|
758
|
+
# # CREATE INDEX developers_on_name_and_city ON developers USING gist (name, city gist_trgm_ops) -- PostgreSQL
|
759
|
+
#
|
760
|
+
# add_index(:developers, [:name, :city], using: 'gist', opclass: :gist_trgm_ops)
|
761
|
+
# # CREATE INDEX developers_on_name_and_city ON developers USING gist (name gist_trgm_ops, city gist_trgm_ops) -- PostgreSQL
|
762
|
+
#
|
763
|
+
# Note: only supported by PostgreSQL
|
764
|
+
#
|
560
765
|
# ====== Creating an index with a specific type
|
561
766
|
#
|
562
767
|
# add_index(:developers, :name, type: :fulltext)
|
@@ -565,7 +770,18 @@ module ActiveRecord
|
|
565
770
|
#
|
566
771
|
# CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
|
567
772
|
#
|
568
|
-
# Note: only supported by MySQL.
|
773
|
+
# Note: only supported by MySQL.
|
774
|
+
#
|
775
|
+
# ====== Creating an index with a specific algorithm
|
776
|
+
#
|
777
|
+
# add_index(:developers, :name, algorithm: :concurrently)
|
778
|
+
# # CREATE INDEX CONCURRENTLY developers_on_name on developers (name)
|
779
|
+
#
|
780
|
+
# Note: only supported by PostgreSQL.
|
781
|
+
#
|
782
|
+
# Concurrently adding an index is not supported in a transaction.
|
783
|
+
#
|
784
|
+
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
569
785
|
def add_index(table_name, column_name, options = {})
|
570
786
|
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
|
571
787
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
|
@@ -573,15 +789,15 @@ module ActiveRecord
|
|
573
789
|
|
574
790
|
# Removes the given index from the table.
|
575
791
|
#
|
576
|
-
# Removes the +
|
792
|
+
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
577
793
|
#
|
578
|
-
# remove_index :accounts, :
|
794
|
+
# remove_index :accounts, :branch_id
|
579
795
|
#
|
580
|
-
# Removes the index
|
796
|
+
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
581
797
|
#
|
582
798
|
# remove_index :accounts, column: :branch_id
|
583
799
|
#
|
584
|
-
# Removes the index
|
800
|
+
# Removes the index on +branch_id+ and +party_id+ in the +accounts+ table if exactly one such index exists.
|
585
801
|
#
|
586
802
|
# remove_index :accounts, column: [:branch_id, :party_id]
|
587
803
|
#
|
@@ -589,11 +805,17 @@ module ActiveRecord
|
|
589
805
|
#
|
590
806
|
# remove_index :accounts, name: :by_branch_party
|
591
807
|
#
|
808
|
+
# Removes the index named +by_branch_party+ in the +accounts+ table +concurrently+.
|
809
|
+
#
|
810
|
+
# remove_index :accounts, name: :by_branch_party, algorithm: :concurrently
|
811
|
+
#
|
812
|
+
# Note: only supported by PostgreSQL.
|
813
|
+
#
|
814
|
+
# Concurrently removing an index is not supported in a transaction.
|
815
|
+
#
|
816
|
+
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
592
817
|
def remove_index(table_name, options = {})
|
593
|
-
|
594
|
-
end
|
595
|
-
|
596
|
-
def remove_index!(table_name, index_name) #:nodoc:
|
818
|
+
index_name = index_name_for_remove(table_name, options)
|
597
819
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
598
820
|
end
|
599
821
|
|
@@ -606,7 +828,7 @@ module ActiveRecord
|
|
606
828
|
def rename_index(table_name, old_name, new_name)
|
607
829
|
validate_index_length!(table_name, new_name)
|
608
830
|
|
609
|
-
# this is a naive implementation; some DBs may support this more efficiently (
|
831
|
+
# this is a naive implementation; some DBs may support this more efficiently (PostgreSQL, for instance)
|
610
832
|
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
611
833
|
return unless old_index_def
|
612
834
|
add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
|
@@ -623,73 +845,73 @@ module ActiveRecord
|
|
623
845
|
raise ArgumentError, "You must specify the index name"
|
624
846
|
end
|
625
847
|
else
|
626
|
-
index_name(table_name,
|
848
|
+
index_name(table_name, index_name_options(options))
|
627
849
|
end
|
628
850
|
end
|
629
851
|
|
630
852
|
# Verifies the existence of an index with a given name.
|
631
|
-
|
632
|
-
# The default argument is returned if the underlying implementation does not define the indexes method,
|
633
|
-
# as there's no way to determine the correct answer in that case.
|
634
|
-
def index_name_exists?(table_name, index_name, default)
|
635
|
-
return default unless respond_to?(:indexes)
|
853
|
+
def index_name_exists?(table_name, index_name)
|
636
854
|
index_name = index_name.to_s
|
637
855
|
indexes(table_name).detect { |i| i.name == index_name }
|
638
856
|
end
|
639
857
|
|
640
|
-
# Adds a reference. The reference column is
|
858
|
+
# Adds a reference. The reference column is a bigint by default,
|
641
859
|
# the <tt>:type</tt> option can be used to specify a different type.
|
642
860
|
# Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
|
643
|
-
#
|
861
|
+
# #add_reference and #add_belongs_to are acceptable.
|
644
862
|
#
|
645
863
|
# The +options+ hash can include the following keys:
|
646
864
|
# [<tt>:type</tt>]
|
647
|
-
# The reference column type. Defaults to +:
|
865
|
+
# The reference column type. Defaults to +:bigint+.
|
648
866
|
# [<tt>:index</tt>]
|
649
|
-
# Add an appropriate index. Defaults to
|
867
|
+
# Add an appropriate index. Defaults to true.
|
868
|
+
# See #add_index for usage of this option.
|
650
869
|
# [<tt>:foreign_key</tt>]
|
651
|
-
# Add an appropriate foreign key. Defaults to false.
|
870
|
+
# Add an appropriate foreign key constraint. Defaults to false.
|
652
871
|
# [<tt>:polymorphic</tt>]
|
653
|
-
#
|
872
|
+
# Whether an additional +_type+ column should be added. Defaults to false.
|
873
|
+
# [<tt>:null</tt>]
|
874
|
+
# Whether the column allows nulls. Defaults to true.
|
654
875
|
#
|
655
|
-
# ====== Create a user_id
|
876
|
+
# ====== Create a user_id bigint column without an index
|
656
877
|
#
|
657
|
-
# add_reference(:products, :user)
|
878
|
+
# add_reference(:products, :user, index: false)
|
658
879
|
#
|
659
880
|
# ====== Create a user_id string column
|
660
881
|
#
|
661
882
|
# add_reference(:products, :user, type: :string)
|
662
883
|
#
|
663
|
-
# ====== Create supplier_id, supplier_type columns
|
884
|
+
# ====== Create supplier_id, supplier_type columns
|
664
885
|
#
|
665
|
-
# add_reference(:products, :supplier, polymorphic: true
|
886
|
+
# add_reference(:products, :supplier, polymorphic: true)
|
666
887
|
#
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
888
|
+
# ====== Create a supplier_id column with a unique index
|
889
|
+
#
|
890
|
+
# add_reference(:products, :supplier, index: { unique: true })
|
891
|
+
#
|
892
|
+
# ====== Create a supplier_id column with a named index
|
893
|
+
#
|
894
|
+
# add_reference(:products, :supplier, index: { name: "my_supplier_index" })
|
895
|
+
#
|
896
|
+
# ====== Create a supplier_id column and appropriate foreign key
|
897
|
+
#
|
898
|
+
# add_reference(:products, :supplier, foreign_key: true)
|
899
|
+
#
|
900
|
+
# ====== Create a supplier_id column and a foreign key to the firms table
|
901
|
+
#
|
902
|
+
# add_reference(:products, :supplier, foreign_key: {to_table: :firms})
|
903
|
+
#
|
904
|
+
def add_reference(table_name, ref_name, **options)
|
905
|
+
ReferenceDefinition.new(ref_name, options).add_to(update_table_definition(table_name, self))
|
684
906
|
end
|
685
907
|
alias :add_belongs_to :add_reference
|
686
908
|
|
687
909
|
# Removes the reference(s). Also removes a +type+ column if one exists.
|
688
|
-
#
|
910
|
+
# #remove_reference and #remove_belongs_to are acceptable.
|
689
911
|
#
|
690
912
|
# ====== Remove the reference
|
691
913
|
#
|
692
|
-
# remove_reference(:products, :user, index:
|
914
|
+
# remove_reference(:products, :user, index: false)
|
693
915
|
#
|
694
916
|
# ====== Remove polymorphic reference
|
695
917
|
#
|
@@ -697,21 +919,27 @@ module ActiveRecord
|
|
697
919
|
#
|
698
920
|
# ====== Remove the reference with a foreign key
|
699
921
|
#
|
700
|
-
# remove_reference(:products, :user,
|
922
|
+
# remove_reference(:products, :user, foreign_key: true)
|
701
923
|
#
|
702
|
-
def remove_reference(table_name, ref_name,
|
703
|
-
if
|
704
|
-
|
705
|
-
|
924
|
+
def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
|
925
|
+
if foreign_key
|
926
|
+
reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
927
|
+
if foreign_key.is_a?(Hash)
|
928
|
+
foreign_key_options = foreign_key
|
929
|
+
else
|
930
|
+
foreign_key_options = { to_table: reference_name }
|
931
|
+
end
|
932
|
+
foreign_key_options[:column] ||= "#{ref_name}_id"
|
933
|
+
remove_foreign_key(table_name, foreign_key_options)
|
706
934
|
end
|
707
935
|
|
708
936
|
remove_column(table_name, "#{ref_name}_id")
|
709
|
-
remove_column(table_name, "#{ref_name}_type") if
|
937
|
+
remove_column(table_name, "#{ref_name}_type") if polymorphic
|
710
938
|
end
|
711
939
|
alias :remove_belongs_to :remove_reference
|
712
940
|
|
713
941
|
# Returns an array of foreign keys for the given table.
|
714
|
-
# The foreign keys are represented as
|
942
|
+
# The foreign keys are represented as ForeignKeyDefinition objects.
|
715
943
|
def foreign_keys(table_name)
|
716
944
|
raise NotImplementedError, "foreign_keys is not implemented"
|
717
945
|
end
|
@@ -729,11 +957,11 @@ module ActiveRecord
|
|
729
957
|
#
|
730
958
|
# generates:
|
731
959
|
#
|
732
|
-
# ALTER TABLE "articles" ADD CONSTRAINT
|
960
|
+
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
733
961
|
#
|
734
962
|
# ====== Creating a foreign key on a specific column
|
735
963
|
#
|
736
|
-
# add_foreign_key :articles, :users, column: :author_id, primary_key:
|
964
|
+
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
737
965
|
#
|
738
966
|
# generates:
|
739
967
|
#
|
@@ -745,7 +973,7 @@ module ActiveRecord
|
|
745
973
|
#
|
746
974
|
# generates:
|
747
975
|
#
|
748
|
-
# ALTER TABLE "articles" ADD CONSTRAINT
|
976
|
+
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
|
749
977
|
#
|
750
978
|
# The +options+ hash can include the following keys:
|
751
979
|
# [<tt>:column</tt>]
|
@@ -755,28 +983,25 @@ module ActiveRecord
|
|
755
983
|
# [<tt>:name</tt>]
|
756
984
|
# The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
|
757
985
|
# [<tt>:on_delete</tt>]
|
758
|
-
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade
|
986
|
+
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
759
987
|
# [<tt>:on_update</tt>]
|
760
|
-
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade
|
988
|
+
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
989
|
+
# [<tt>:validate</tt>]
|
990
|
+
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
761
991
|
def add_foreign_key(from_table, to_table, options = {})
|
762
992
|
return unless supports_foreign_keys?
|
763
993
|
|
764
|
-
options
|
765
|
-
|
766
|
-
options = {
|
767
|
-
column: options[:column],
|
768
|
-
primary_key: options[:primary_key],
|
769
|
-
name: foreign_key_name(from_table, options),
|
770
|
-
on_delete: options[:on_delete],
|
771
|
-
on_update: options[:on_update]
|
772
|
-
}
|
994
|
+
options = foreign_key_options(from_table, to_table, options)
|
773
995
|
at = create_alter_table from_table
|
774
996
|
at.add_foreign_key to_table, options
|
775
997
|
|
776
998
|
execute schema_creation.accept(at)
|
777
999
|
end
|
778
1000
|
|
779
|
-
# Removes the given foreign key from the table.
|
1001
|
+
# Removes the given foreign key from the table. Any option parameters provided
|
1002
|
+
# will be used to re-add the foreign key in case of a migration rollback.
|
1003
|
+
# It is recommended that you provide any options used when creating the foreign
|
1004
|
+
# key so that the migration can be reverted properly.
|
780
1005
|
#
|
781
1006
|
# Removes the foreign key on +accounts.branch_id+.
|
782
1007
|
#
|
@@ -786,28 +1011,22 @@ module ActiveRecord
|
|
786
1011
|
#
|
787
1012
|
# remove_foreign_key :accounts, column: :owner_id
|
788
1013
|
#
|
1014
|
+
# Removes the foreign key on +accounts.owner_id+.
|
1015
|
+
#
|
1016
|
+
# remove_foreign_key :accounts, to_table: :owners
|
1017
|
+
#
|
789
1018
|
# Removes the foreign key named +special_fk_name+ on the +accounts+ table.
|
790
1019
|
#
|
791
1020
|
# remove_foreign_key :accounts, name: :special_fk_name
|
792
1021
|
#
|
793
|
-
|
1022
|
+
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
|
1023
|
+
# with an addition of
|
1024
|
+
# [<tt>:to_table</tt>]
|
1025
|
+
# The name of the table that contains the referenced primary key.
|
1026
|
+
def remove_foreign_key(from_table, to_table = nil, **options)
|
794
1027
|
return unless supports_foreign_keys?
|
795
1028
|
|
796
|
-
|
797
|
-
options = options_or_to_table
|
798
|
-
else
|
799
|
-
options = { column: foreign_key_column_for(options_or_to_table) }
|
800
|
-
end
|
801
|
-
|
802
|
-
fk_name_to_delete = options.fetch(:name) do
|
803
|
-
fk_to_delete = foreign_keys(from_table).detect {|fk| fk.column == options[:column].to_s }
|
804
|
-
|
805
|
-
if fk_to_delete
|
806
|
-
fk_to_delete.name
|
807
|
-
else
|
808
|
-
raise ArgumentError, "Table '#{from_table}' has no foreign key on column '#{options[:column]}'"
|
809
|
-
end
|
810
|
-
end
|
1029
|
+
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
811
1030
|
|
812
1031
|
at = create_alter_table from_table
|
813
1032
|
at.drop_foreign_key fk_name_to_delete
|
@@ -815,55 +1034,71 @@ module ActiveRecord
|
|
815
1034
|
execute schema_creation.accept(at)
|
816
1035
|
end
|
817
1036
|
|
1037
|
+
# Checks to see if a foreign key exists on a table for a given foreign key definition.
|
1038
|
+
#
|
1039
|
+
# # Checks to see if a foreign key exists.
|
1040
|
+
# foreign_key_exists?(:accounts, :branches)
|
1041
|
+
#
|
1042
|
+
# # Checks to see if a foreign key on a specified column exists.
|
1043
|
+
# foreign_key_exists?(:accounts, column: :owner_id)
|
1044
|
+
#
|
1045
|
+
# # Checks to see if a foreign key with a custom name exists.
|
1046
|
+
# foreign_key_exists?(:accounts, name: "special_fk_name")
|
1047
|
+
#
|
1048
|
+
def foreign_key_exists?(from_table, to_table = nil, **options)
|
1049
|
+
foreign_key_for(from_table, to_table: to_table, **options).present?
|
1050
|
+
end
|
1051
|
+
|
818
1052
|
def foreign_key_column_for(table_name) # :nodoc:
|
819
|
-
|
820
|
-
suffix = Base.table_name_suffix
|
821
|
-
name = table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
|
1053
|
+
name = strip_table_name_prefix_and_suffix(table_name)
|
822
1054
|
"#{name.singularize}_id"
|
823
1055
|
end
|
824
1056
|
|
825
|
-
def
|
826
|
-
|
1057
|
+
def foreign_key_options(from_table, to_table, options) # :nodoc:
|
1058
|
+
options = options.dup
|
1059
|
+
options[:column] ||= foreign_key_column_for(to_table)
|
1060
|
+
options[:name] ||= foreign_key_name(from_table, options)
|
1061
|
+
options
|
1062
|
+
end
|
827
1063
|
|
828
|
-
|
829
|
-
|
830
|
-
|
1064
|
+
def dump_schema_information # :nodoc:
|
1065
|
+
versions = schema_migration.all_versions
|
1066
|
+
insert_versions_sql(versions) if versions.any?
|
831
1067
|
end
|
832
1068
|
|
833
|
-
|
834
|
-
|
835
|
-
def initialize_schema_migrations_table
|
836
|
-
ActiveRecord::SchemaMigration.create_table
|
1069
|
+
def internal_string_options_for_primary_key # :nodoc:
|
1070
|
+
{ primary_key: true }
|
837
1071
|
end
|
838
1072
|
|
839
|
-
def assume_migrated_upto_version(version, migrations_paths =
|
840
|
-
|
1073
|
+
def assume_migrated_upto_version(version, migrations_paths = nil)
|
1074
|
+
unless migrations_paths.nil?
|
1075
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
1076
|
+
Passing migrations_paths to #assume_migrated_upto_version is deprecated and will be removed in Rails 6.1.
|
1077
|
+
MSG
|
1078
|
+
end
|
1079
|
+
|
841
1080
|
version = version.to_i
|
842
|
-
sm_table = quote_table_name(
|
1081
|
+
sm_table = quote_table_name(schema_migration.table_name)
|
843
1082
|
|
844
|
-
migrated =
|
845
|
-
|
846
|
-
versions = Dir[*paths].map do |filename|
|
847
|
-
filename.split('/').last.split('_').first.to_i
|
848
|
-
end
|
1083
|
+
migrated = migration_context.get_all_versions
|
1084
|
+
versions = migration_context.migrations.map(&:version)
|
849
1085
|
|
850
1086
|
unless migrated.include?(version)
|
851
|
-
execute "INSERT INTO #{sm_table} (version) VALUES (
|
1087
|
+
execute "INSERT INTO #{sm_table} (version) VALUES (#{quote(version)})"
|
852
1088
|
end
|
853
1089
|
|
854
|
-
|
855
|
-
|
856
|
-
if
|
857
|
-
raise "Duplicate migration #{
|
858
|
-
elsif v < version
|
859
|
-
execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
|
860
|
-
inserted << v
|
1090
|
+
inserting = (versions - migrated).select { |v| v < version }
|
1091
|
+
if inserting.any?
|
1092
|
+
if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
|
1093
|
+
raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
|
861
1094
|
end
|
1095
|
+
execute insert_versions_sql(inserting)
|
862
1096
|
end
|
863
1097
|
end
|
864
1098
|
|
865
|
-
def type_to_sql(type, limit
|
866
|
-
|
1099
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) # :nodoc:
|
1100
|
+
type = type.to_sym if type
|
1101
|
+
if native = native_database_types[type]
|
867
1102
|
column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
|
868
1103
|
|
869
1104
|
if type == :decimal # ignore limit, use precision and scale
|
@@ -879,6 +1114,12 @@ module ActiveRecord
|
|
879
1114
|
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
|
880
1115
|
end
|
881
1116
|
|
1117
|
+
elsif [:datetime, :timestamp, :time, :interval].include?(type) && precision ||= native[:precision]
|
1118
|
+
if (0..6) === precision
|
1119
|
+
column_type_sql << "(#{precision})"
|
1120
|
+
else
|
1121
|
+
raise ArgumentError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6"
|
1122
|
+
end
|
882
1123
|
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
883
1124
|
column_type_sql << "(#{limit})"
|
884
1125
|
end
|
@@ -890,7 +1131,7 @@ module ActiveRecord
|
|
890
1131
|
end
|
891
1132
|
|
892
1133
|
# Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT.
|
893
|
-
# PostgreSQL, MySQL, and Oracle
|
1134
|
+
# PostgreSQL, MySQL, and Oracle override this for custom DISTINCT syntax - they
|
894
1135
|
# require the order columns appear in the SELECT.
|
895
1136
|
#
|
896
1137
|
# columns_for_distinct("posts.id", ["posts.created_at desc"])
|
@@ -899,14 +1140,18 @@ module ActiveRecord
|
|
899
1140
|
columns
|
900
1141
|
end
|
901
1142
|
|
902
|
-
include TimestampDefaultDeprecation
|
903
1143
|
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
904
|
-
# Additional options (like
|
1144
|
+
# Additional options (like +:null+) are forwarded to #add_column.
|
905
1145
|
#
|
906
|
-
# add_timestamps(:suppliers, null:
|
1146
|
+
# add_timestamps(:suppliers, null: true)
|
907
1147
|
#
|
908
1148
|
def add_timestamps(table_name, options = {})
|
909
|
-
|
1149
|
+
options[:null] = false if options[:null].nil?
|
1150
|
+
|
1151
|
+
if !options.key?(:precision) && supports_datetime_with_precision?
|
1152
|
+
options[:precision] = 6
|
1153
|
+
end
|
1154
|
+
|
910
1155
|
add_column table_name, :created_at, :datetime, options
|
911
1156
|
add_column table_name, :updated_at, :datetime, options
|
912
1157
|
end
|
@@ -924,16 +1169,15 @@ module ActiveRecord
|
|
924
1169
|
Table.new(table_name, base)
|
925
1170
|
end
|
926
1171
|
|
927
|
-
def add_index_options(table_name, column_name,
|
928
|
-
column_names =
|
929
|
-
index_name = index_name(table_name, column: column_names)
|
1172
|
+
def add_index_options(table_name, column_name, comment: nil, **options) # :nodoc:
|
1173
|
+
column_names = index_column_names(column_name)
|
930
1174
|
|
931
|
-
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
1175
|
+
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type, :opclass)
|
932
1176
|
|
933
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
934
1177
|
index_type = options[:type].to_s if options.key?(:type)
|
1178
|
+
index_type ||= options[:unique] ? "UNIQUE" : ""
|
935
1179
|
index_name = options[:name].to_s if options.key?(:name)
|
936
|
-
|
1180
|
+
index_name ||= index_name(table_name, column_names)
|
937
1181
|
|
938
1182
|
if options.key?(:algorithm)
|
939
1183
|
algorithm = index_algorithms.fetch(options[:algorithm]) {
|
@@ -947,63 +1191,109 @@ module ActiveRecord
|
|
947
1191
|
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
|
948
1192
|
end
|
949
1193
|
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
if table_exists?(table_name) && index_name_exists?(table_name, index_name, false)
|
1194
|
+
validate_index_length!(table_name, index_name, options.fetch(:internal, false))
|
1195
|
+
|
1196
|
+
if data_source_exists?(table_name) && index_name_exists?(table_name, index_name)
|
954
1197
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
955
1198
|
end
|
956
1199
|
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
957
1200
|
|
958
|
-
[index_name, index_type, index_columns, index_options, algorithm, using]
|
1201
|
+
[index_name, index_type, index_columns, index_options, algorithm, using, comment]
|
959
1202
|
end
|
960
1203
|
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
1204
|
+
def options_include_default?(options)
|
1205
|
+
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
# Changes the comment for a table or removes it if +nil+.
|
1209
|
+
#
|
1210
|
+
# Passing a hash containing +:from+ and +:to+ will make this change
|
1211
|
+
# reversible in migration:
|
1212
|
+
#
|
1213
|
+
# change_table_comment(:posts, from: "old_comment", to: "new_comment")
|
1214
|
+
def change_table_comment(table_name, comment_or_changes)
|
1215
|
+
raise NotImplementedError, "#{self.class} does not support changing table comments"
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
# Changes the comment for a column or removes it if +nil+.
|
1219
|
+
#
|
1220
|
+
# Passing a hash containing +:from+ and +:to+ will make this change
|
1221
|
+
# reversible in migration:
|
1222
|
+
#
|
1223
|
+
# change_column_comment(:posts, :state, from: "old_comment", to: "new_comment")
|
1224
|
+
def change_column_comment(table_name, column_name, comment_or_changes)
|
1225
|
+
raise NotImplementedError, "#{self.class} does not support changing column comments"
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
def create_schema_dumper(options) # :nodoc:
|
1229
|
+
SchemaDumper.create(self, options)
|
1230
|
+
end
|
971
1231
|
|
972
|
-
|
1232
|
+
private
|
1233
|
+
def column_options_keys
|
1234
|
+
[:limit, :precision, :scale, :default, :null, :collation, :comment]
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
def add_index_sort_order(quoted_columns, **options)
|
1238
|
+
orders = options_for_index_columns(options[:order])
|
1239
|
+
quoted_columns.each do |name, column|
|
1240
|
+
column << " #{orders[name].upcase}" if orders[name].present?
|
1241
|
+
end
|
973
1242
|
end
|
974
1243
|
|
975
|
-
|
976
|
-
|
977
|
-
|
1244
|
+
def options_for_index_columns(options)
|
1245
|
+
if options.is_a?(Hash)
|
1246
|
+
options.symbolize_keys
|
1247
|
+
else
|
1248
|
+
Hash.new { |hash, column| hash[column] = options }
|
1249
|
+
end
|
1250
|
+
end
|
978
1251
|
|
979
|
-
|
1252
|
+
# Overridden by the MySQL adapter for supporting index lengths and by
|
1253
|
+
# the PostgreSQL adapter for supporting operator classes.
|
1254
|
+
def add_options_for_index_columns(quoted_columns, **options)
|
980
1255
|
if supports_index_sort_order?
|
981
|
-
|
1256
|
+
quoted_columns = add_index_sort_order(quoted_columns, options)
|
982
1257
|
end
|
983
1258
|
|
984
|
-
|
1259
|
+
quoted_columns
|
985
1260
|
end
|
986
1261
|
|
987
|
-
def
|
988
|
-
|
1262
|
+
def quoted_columns_for_index(column_names, **options)
|
1263
|
+
return [column_names] if column_names.is_a?(String)
|
1264
|
+
|
1265
|
+
quoted_columns = Hash[column_names.map { |name| [name.to_sym, quote_column_name(name).dup] }]
|
1266
|
+
add_options_for_index_columns(quoted_columns, options).values
|
989
1267
|
end
|
990
1268
|
|
991
1269
|
def index_name_for_remove(table_name, options = {})
|
992
|
-
|
1270
|
+
return options[:name] if can_remove_index_by_name?(options)
|
993
1271
|
|
994
|
-
|
995
|
-
if options.is_a?(Hash) && options.has_key?(:name)
|
996
|
-
options_without_column = options.dup
|
997
|
-
options_without_column.delete :column
|
998
|
-
index_name_without_column = index_name(table_name, options_without_column)
|
1272
|
+
checks = []
|
999
1273
|
|
1000
|
-
|
1001
|
-
|
1274
|
+
if options.is_a?(Hash)
|
1275
|
+
checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
|
1276
|
+
column_names = index_column_names(options[:column])
|
1277
|
+
else
|
1278
|
+
column_names = index_column_names(options)
|
1279
|
+
end
|
1002
1280
|
|
1003
|
-
|
1281
|
+
if column_names.present?
|
1282
|
+
checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
|
1004
1283
|
end
|
1005
1284
|
|
1006
|
-
|
1285
|
+
raise ArgumentError, "No name or columns specified" if checks.none?
|
1286
|
+
|
1287
|
+
matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }
|
1288
|
+
|
1289
|
+
if matching_indexes.count > 1
|
1290
|
+
raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. " \
|
1291
|
+
"Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
|
1292
|
+
elsif matching_indexes.none?
|
1293
|
+
raise ArgumentError, "No indexes found on #{table_name} with the options provided."
|
1294
|
+
else
|
1295
|
+
matching_indexes.first.name
|
1296
|
+
end
|
1007
1297
|
end
|
1008
1298
|
|
1009
1299
|
def rename_table_indexes(table_name, new_name)
|
@@ -1028,28 +1318,158 @@ module ActiveRecord
|
|
1028
1318
|
end
|
1029
1319
|
end
|
1030
1320
|
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
end
|
1321
|
+
def schema_creation
|
1322
|
+
SchemaCreation.new(self)
|
1323
|
+
end
|
1035
1324
|
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1325
|
+
def create_table_definition(*args)
|
1326
|
+
TableDefinition.new(self, *args)
|
1327
|
+
end
|
1039
1328
|
|
1040
|
-
|
1041
|
-
|
1042
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1043
|
-
options.fetch(:name) do
|
1044
|
-
"fk_rails_#{hashed_identifier}"
|
1329
|
+
def create_alter_table(name)
|
1330
|
+
AlterTable.new create_table_definition(name)
|
1045
1331
|
end
|
1046
|
-
end
|
1047
1332
|
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1333
|
+
def fetch_type_metadata(sql_type)
|
1334
|
+
cast_type = lookup_cast_type(sql_type)
|
1335
|
+
SqlTypeMetadata.new(
|
1336
|
+
sql_type: sql_type,
|
1337
|
+
type: cast_type.type,
|
1338
|
+
limit: cast_type.limit,
|
1339
|
+
precision: cast_type.precision,
|
1340
|
+
scale: cast_type.scale,
|
1341
|
+
)
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
def index_column_names(column_names)
|
1345
|
+
if column_names.is_a?(String) && /\W/.match?(column_names)
|
1346
|
+
column_names
|
1347
|
+
else
|
1348
|
+
Array(column_names)
|
1349
|
+
end
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
def index_name_options(column_names)
|
1353
|
+
if column_names.is_a?(String) && /\W/.match?(column_names)
|
1354
|
+
column_names = column_names.scan(/\w+/).join("_")
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
{ column: column_names }
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
def strip_table_name_prefix_and_suffix(table_name)
|
1361
|
+
prefix = Base.table_name_prefix
|
1362
|
+
suffix = Base.table_name_suffix
|
1363
|
+
table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
def foreign_key_name(table_name, options)
|
1367
|
+
options.fetch(:name) do
|
1368
|
+
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
|
1369
|
+
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1370
|
+
|
1371
|
+
"fk_rails_#{hashed_identifier}"
|
1372
|
+
end
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
def foreign_key_for(from_table, **options)
|
1376
|
+
return unless supports_foreign_keys?
|
1377
|
+
foreign_keys(from_table).detect { |fk| fk.defined_for?(options) }
|
1378
|
+
end
|
1379
|
+
|
1380
|
+
def foreign_key_for!(from_table, to_table: nil, **options)
|
1381
|
+
foreign_key_for(from_table, to_table: to_table, **options) ||
|
1382
|
+
raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
def extract_foreign_key_action(specifier)
|
1386
|
+
case specifier
|
1387
|
+
when "CASCADE"; :cascade
|
1388
|
+
when "SET NULL"; :nullify
|
1389
|
+
when "RESTRICT"; :restrict
|
1390
|
+
end
|
1391
|
+
end
|
1392
|
+
|
1393
|
+
def validate_index_length!(table_name, new_name, internal = false)
|
1394
|
+
max_index_length = internal ? index_name_length : allowed_index_name_length
|
1395
|
+
|
1396
|
+
if new_name.length > max_index_length
|
1397
|
+
raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters"
|
1398
|
+
end
|
1399
|
+
end
|
1400
|
+
|
1401
|
+
def extract_new_default_value(default_or_changes)
|
1402
|
+
if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
|
1403
|
+
default_or_changes[:to]
|
1404
|
+
else
|
1405
|
+
default_or_changes
|
1406
|
+
end
|
1407
|
+
end
|
1408
|
+
alias :extract_new_comment_value :extract_new_default_value
|
1409
|
+
|
1410
|
+
def can_remove_index_by_name?(options)
|
1411
|
+
options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
def bulk_change_table(table_name, operations)
|
1415
|
+
sql_fragments = []
|
1416
|
+
non_combinable_operations = []
|
1417
|
+
|
1418
|
+
operations.each do |command, args|
|
1419
|
+
table, arguments = args.shift, args
|
1420
|
+
method = :"#{command}_for_alter"
|
1421
|
+
|
1422
|
+
if respond_to?(method, true)
|
1423
|
+
sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
|
1424
|
+
sql_fragments << sqls
|
1425
|
+
non_combinable_operations.concat(procs)
|
1426
|
+
else
|
1427
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1428
|
+
non_combinable_operations.each(&:call)
|
1429
|
+
sql_fragments = []
|
1430
|
+
non_combinable_operations = []
|
1431
|
+
send(command, table, *arguments)
|
1432
|
+
end
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1436
|
+
non_combinable_operations.each(&:call)
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
def add_column_for_alter(table_name, column_name, type, options = {})
|
1440
|
+
td = create_table_definition(table_name)
|
1441
|
+
cd = td.new_column_definition(column_name, type, options)
|
1442
|
+
schema_creation.accept(AddColumnDefinition.new(cd))
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
def remove_column_for_alter(table_name, column_name, type = nil, options = {})
|
1446
|
+
"DROP COLUMN #{quote_column_name(column_name)}"
|
1447
|
+
end
|
1448
|
+
|
1449
|
+
def remove_columns_for_alter(table_name, *column_names)
|
1450
|
+
column_names.map { |column_name| remove_column_for_alter(table_name, column_name) }
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
def insert_versions_sql(versions)
|
1454
|
+
sm_table = quote_table_name(schema_migration.table_name)
|
1455
|
+
|
1456
|
+
if versions.is_a?(Array)
|
1457
|
+
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
|
1458
|
+
sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
|
1459
|
+
sql << ";\n\n"
|
1460
|
+
sql
|
1461
|
+
else
|
1462
|
+
"INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"
|
1463
|
+
end
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
def data_source_sql(name = nil, type: nil)
|
1467
|
+
raise NotImplementedError
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
def quoted_scope(name = nil, type: nil)
|
1471
|
+
raise NotImplementedError
|
1051
1472
|
end
|
1052
|
-
end
|
1053
1473
|
end
|
1054
1474
|
end
|
1055
1475
|
end
|