activerecord 6.1.7 → 7.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/string/access"
|
4
|
-
require "
|
4
|
+
require "openssl"
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
module ConnectionAdapters # :nodoc:
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
table_name[0...table_alias_length].tr(".", "_")
|
30
30
|
end
|
31
31
|
|
32
|
-
# Returns the relation names
|
32
|
+
# Returns the relation names usable to back Active Record models.
|
33
33
|
# For most adapters this means all #tables and #views.
|
34
34
|
def data_sources
|
35
35
|
query_values(data_source_sql, "SCHEMA")
|
@@ -96,25 +96,19 @@ module ActiveRecord
|
|
96
96
|
# # Check an index with a custom name exists
|
97
97
|
# index_exists?(:suppliers, :company_id, name: "idx_company_id")
|
98
98
|
#
|
99
|
+
# # Check a valid index exists (PostgreSQL only)
|
100
|
+
# index_exists?(:suppliers, :company_id, valid: true)
|
101
|
+
#
|
99
102
|
def index_exists?(table_name, column_name, **options)
|
100
|
-
|
101
|
-
|
102
|
-
if column_name.present?
|
103
|
-
column_names = Array(column_name).map(&:to_s)
|
104
|
-
checks << lambda { |i| Array(i.columns) == column_names }
|
105
|
-
end
|
106
|
-
|
107
|
-
checks << lambda { |i| i.unique } if options[:unique]
|
108
|
-
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
|
109
|
-
|
110
|
-
indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
|
103
|
+
indexes(table_name).any? { |i| i.defined_for?(column_name, **options) }
|
111
104
|
end
|
112
105
|
|
113
106
|
# Returns an array of +Column+ objects for the table specified by +table_name+.
|
114
107
|
def columns(table_name)
|
115
108
|
table_name = table_name.to_s
|
116
|
-
column_definitions(table_name)
|
117
|
-
|
109
|
+
definitions = column_definitions(table_name)
|
110
|
+
definitions.map do |field|
|
111
|
+
new_column_from_field(table_name, field, definitions)
|
118
112
|
end
|
119
113
|
end
|
120
114
|
|
@@ -124,6 +118,9 @@ module ActiveRecord
|
|
124
118
|
# column_exists?(:suppliers, :name)
|
125
119
|
#
|
126
120
|
# # Check a column exists of a particular type
|
121
|
+
# #
|
122
|
+
# # This works for standard non-casted types (eg. string) but is unreliable
|
123
|
+
# # for types that may get cast to something else (eg. char, bigint).
|
127
124
|
# column_exists?(:suppliers, :name, :string)
|
128
125
|
#
|
129
126
|
# # Check a column exists with a specific definition
|
@@ -260,7 +257,7 @@ module ActiveRecord
|
|
260
257
|
#
|
261
258
|
# generates:
|
262
259
|
#
|
263
|
-
# CREATE TABLE
|
260
|
+
# CREATE TABLE orders (
|
264
261
|
# product_id bigint NOT NULL,
|
265
262
|
# client_id bigint NOT NULL
|
266
263
|
# );
|
@@ -293,25 +290,10 @@ module ActiveRecord
|
|
293
290
|
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
|
294
291
|
#
|
295
292
|
# See also TableDefinition#column for details on how to create columns.
|
296
|
-
def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
|
301
|
-
|
302
|
-
if id.is_a?(Hash)
|
303
|
-
options.merge!(id.except(:type))
|
304
|
-
id = id.fetch(:type, :primary_key)
|
305
|
-
end
|
306
|
-
|
307
|
-
if pk.is_a?(Array)
|
308
|
-
td.primary_keys pk
|
309
|
-
else
|
310
|
-
td.primary_key pk, id, **options
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
yield td if block_given?
|
293
|
+
def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options, &block)
|
294
|
+
validate_create_table_options!(options)
|
295
|
+
validate_table_length!(table_name) unless options[:_uses_legacy_table_name]
|
296
|
+
td = build_create_table_definition(table_name, id: id, primary_key: primary_key, force: force, **options, &block)
|
315
297
|
|
316
298
|
if force
|
317
299
|
drop_table(table_name, force: force, if_exists: true)
|
@@ -319,7 +301,7 @@ module ActiveRecord
|
|
319
301
|
schema_cache.clear_data_source_cache!(table_name.to_s)
|
320
302
|
end
|
321
303
|
|
322
|
-
result = execute schema_creation.accept
|
304
|
+
result = execute schema_creation.accept(td)
|
323
305
|
|
324
306
|
unless supports_indexes_in_create?
|
325
307
|
td.indexes.each do |column_name, index_options|
|
@@ -340,6 +322,18 @@ module ActiveRecord
|
|
340
322
|
result
|
341
323
|
end
|
342
324
|
|
325
|
+
# Returns a TableDefinition object containing information about the table that would be created
|
326
|
+
# if the same arguments were passed to #create_table. See #create_table for information about
|
327
|
+
# passing a +table_name+, and other additional options that can be passed.
|
328
|
+
def build_create_table_definition(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
|
329
|
+
table_definition = create_table_definition(table_name, **options.extract!(*valid_table_definition_options, :_skip_validate_options))
|
330
|
+
table_definition.set_primary_key(table_name, id, primary_key, **options.extract!(*valid_primary_key_options, :_skip_validate_options))
|
331
|
+
|
332
|
+
yield table_definition if block_given?
|
333
|
+
|
334
|
+
table_definition
|
335
|
+
end
|
336
|
+
|
343
337
|
# Creates a new join table with the name created using the lexical order of the first two
|
344
338
|
# arguments. These arguments can be a String or a Symbol.
|
345
339
|
#
|
@@ -383,7 +377,7 @@ module ActiveRecord
|
|
383
377
|
|
384
378
|
column_options.reverse_merge!(null: false, index: false)
|
385
379
|
|
386
|
-
t1_ref, t2_ref = [table_1, table_2].map { |t| t
|
380
|
+
t1_ref, t2_ref = [table_1, table_2].map { |t| reference_name_for_table(t) }
|
387
381
|
|
388
382
|
create_table(join_table_name, **options.merge!(id: false)) do |td|
|
389
383
|
td.references t1_ref, **column_options
|
@@ -392,15 +386,33 @@ module ActiveRecord
|
|
392
386
|
end
|
393
387
|
end
|
394
388
|
|
389
|
+
# Builds a TableDefinition object for a join table.
|
390
|
+
#
|
391
|
+
# This definition object contains information about the table that would be created
|
392
|
+
# if the same arguments were passed to #create_join_table. See #create_join_table for
|
393
|
+
# information about what arguments should be passed.
|
394
|
+
def build_create_join_table_definition(table_1, table_2, column_options: {}, **options) # :nodoc:
|
395
|
+
join_table_name = find_join_table_name(table_1, table_2, options)
|
396
|
+
column_options.reverse_merge!(null: false, index: false)
|
397
|
+
|
398
|
+
t1_ref, t2_ref = [table_1, table_2].map { |t| reference_name_for_table(t) }
|
399
|
+
|
400
|
+
build_create_table_definition(join_table_name, **options.merge!(id: false)) do |td|
|
401
|
+
td.references t1_ref, **column_options
|
402
|
+
td.references t2_ref, **column_options
|
403
|
+
yield td if block_given?
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
395
407
|
# Drops the join table specified by the given arguments.
|
396
|
-
# See #create_join_table for details.
|
408
|
+
# See #create_join_table and #drop_table for details.
|
397
409
|
#
|
398
410
|
# Although this command ignores the block if one is given, it can be helpful
|
399
411
|
# to provide one in a migration's +change+ method so it can be reverted.
|
400
412
|
# In that case, the block will be used by #create_join_table.
|
401
413
|
def drop_join_table(table_1, table_2, **options)
|
402
414
|
join_table_name = find_join_table_name(table_1, table_2, options)
|
403
|
-
drop_table(join_table_name)
|
415
|
+
drop_table(join_table_name, **options)
|
404
416
|
end
|
405
417
|
|
406
418
|
# A block for changing columns in +table+.
|
@@ -481,13 +493,13 @@ module ActiveRecord
|
|
481
493
|
# end
|
482
494
|
#
|
483
495
|
# See also Table for details on all of the various column transformations.
|
484
|
-
def change_table(table_name, **options)
|
496
|
+
def change_table(table_name, base = self, **options)
|
485
497
|
if supports_bulk_alter? && options[:bulk]
|
486
498
|
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
|
487
499
|
yield update_table_definition(table_name, recorder)
|
488
500
|
bulk_change_table(table_name, recorder.commands)
|
489
501
|
else
|
490
|
-
yield update_table_definition(table_name,
|
502
|
+
yield update_table_definition(table_name, base)
|
491
503
|
end
|
492
504
|
end
|
493
505
|
|
@@ -495,7 +507,7 @@ module ActiveRecord
|
|
495
507
|
#
|
496
508
|
# rename_table('octopuses', 'octopi')
|
497
509
|
#
|
498
|
-
def rename_table(table_name, new_name)
|
510
|
+
def rename_table(table_name, new_name, **)
|
499
511
|
raise NotImplementedError, "rename_table is not implemented"
|
500
512
|
end
|
501
513
|
|
@@ -518,24 +530,31 @@ module ActiveRecord
|
|
518
530
|
|
519
531
|
# Add a new +type+ column named +column_name+ to +table_name+.
|
520
532
|
#
|
533
|
+
# See {ActiveRecord::ConnectionAdapters::TableDefinition.column}[rdoc-ref:ActiveRecord::ConnectionAdapters::TableDefinition#column].
|
534
|
+
#
|
521
535
|
# The +type+ parameter is normally one of the migrations native types,
|
522
536
|
# which is one of the following:
|
523
537
|
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
524
538
|
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
525
539
|
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
526
|
-
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
540
|
+
# <tt>:binary</tt>, <tt>:blob</tt>, <tt>:boolean</tt>.
|
527
541
|
#
|
528
542
|
# You may use a type not in this list as long as it is supported by your
|
529
543
|
# database (for example, "polygon" in MySQL), but this will not be database
|
530
544
|
# agnostic and should usually be avoided.
|
531
545
|
#
|
532
546
|
# Available options are (none of these exists by default):
|
547
|
+
# * <tt>:comment</tt> -
|
548
|
+
# Specifies the comment for the column. This option is ignored by some backends.
|
549
|
+
# * <tt>:collation</tt> -
|
550
|
+
# Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column.
|
551
|
+
# If not specified, the column will have the same collation as the table.
|
552
|
+
# * <tt>:default</tt> -
|
553
|
+
# The column's default value. Use +nil+ for +NULL+.
|
533
554
|
# * <tt>:limit</tt> -
|
534
555
|
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
|
535
|
-
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
|
556
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, <tt>:blob</tt>, and <tt>:integer</tt> columns.
|
536
557
|
# This option is ignored by some backends.
|
537
|
-
# * <tt>:default</tt> -
|
538
|
-
# The column's default value. Use +nil+ for +NULL+.
|
539
558
|
# * <tt>:null</tt> -
|
540
559
|
# Allows or disallows +NULL+ values in the column.
|
541
560
|
# * <tt>:precision</tt> -
|
@@ -543,11 +562,6 @@ module ActiveRecord
|
|
543
562
|
# <tt>:datetime</tt>, and <tt>:time</tt> columns.
|
544
563
|
# * <tt>:scale</tt> -
|
545
564
|
# Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
|
546
|
-
# * <tt>:collation</tt> -
|
547
|
-
# Specifies the collation for a <tt>:string</tt> or <tt>:text</tt> column. If not specified, the
|
548
|
-
# column will have the same collation as the table.
|
549
|
-
# * <tt>:comment</tt> -
|
550
|
-
# Specifies the comment for the column. This option is ignored by some backends.
|
551
565
|
# * <tt>:if_not_exists</tt> -
|
552
566
|
# Specifies if the column already exists to not try to re-add it. This will avoid
|
553
567
|
# duplicate column errors.
|
@@ -563,7 +577,7 @@ module ActiveRecord
|
|
563
577
|
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
|
564
578
|
# <tt>:precision</tt>, and makes no comments about the requirements of
|
565
579
|
# <tt>:precision</tt>.
|
566
|
-
# * MySQL: <tt>:precision</tt> [1..
|
580
|
+
# * MySQL: <tt>:precision</tt> [1..65], <tt>:scale</tt> [0..30].
|
567
581
|
# Default is (10,0).
|
568
582
|
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
569
583
|
# <tt>:scale</tt> [0..infinity]. No default.
|
@@ -604,11 +618,10 @@ module ActiveRecord
|
|
604
618
|
# # Ignores the method call if the column exists
|
605
619
|
# add_column(:shapes, :triangle, 'polygon', if_not_exists: true)
|
606
620
|
def add_column(table_name, column_name, type, **options)
|
607
|
-
|
621
|
+
add_column_def = build_add_column_definition(table_name, column_name, type, **options)
|
622
|
+
return unless add_column_def
|
608
623
|
|
609
|
-
|
610
|
-
at.add_column(column_name, type, **options)
|
611
|
-
execute schema_creation.accept at
|
624
|
+
execute schema_creation.accept(add_column_def)
|
612
625
|
end
|
613
626
|
|
614
627
|
def add_columns(table_name, *column_names, type:, **options) # :nodoc:
|
@@ -617,6 +630,25 @@ module ActiveRecord
|
|
617
630
|
end
|
618
631
|
end
|
619
632
|
|
633
|
+
# Builds an AlterTable object for adding a column to a table.
|
634
|
+
#
|
635
|
+
# This definition object contains information about the column that would be created
|
636
|
+
# if the same arguments were passed to #add_column. See #add_column for information about
|
637
|
+
# passing a +table_name+, +column_name+, +type+ and other options that can be passed.
|
638
|
+
def build_add_column_definition(table_name, column_name, type, **options) # :nodoc:
|
639
|
+
return if options[:if_not_exists] == true && column_exists?(table_name, column_name)
|
640
|
+
|
641
|
+
if supports_datetime_with_precision?
|
642
|
+
if type == :datetime && !options.key?(:precision)
|
643
|
+
options[:precision] = 6
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
alter_table = create_alter_table(table_name)
|
648
|
+
alter_table.add_column(column_name, type, **options)
|
649
|
+
alter_table
|
650
|
+
end
|
651
|
+
|
620
652
|
# Removes the given columns from the table definition.
|
621
653
|
#
|
622
654
|
# remove_columns(:suppliers, :qualification, :experience)
|
@@ -629,9 +661,8 @@ module ActiveRecord
|
|
629
661
|
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
|
630
662
|
end
|
631
663
|
|
632
|
-
column_names
|
633
|
-
|
634
|
-
end
|
664
|
+
remove_column_fragments = remove_columns_for_alter(table_name, *column_names, type: type, **options)
|
665
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_fragments.join(', ')}"
|
635
666
|
end
|
636
667
|
|
637
668
|
# Removes the column from the table definition.
|
@@ -641,7 +672,8 @@ module ActiveRecord
|
|
641
672
|
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
642
673
|
# to provide these in a migration's +change+ method so it can be reverted.
|
643
674
|
# In that case, +type+ and +options+ will be used by #add_column.
|
644
|
-
#
|
675
|
+
# Depending on the database you're using, indexes using this column may be
|
676
|
+
# automatically removed or modified to remove this column from the index.
|
645
677
|
#
|
646
678
|
# If the options provided include an +if_exists+ key, it will be used to check if the
|
647
679
|
# column does not exist. This will silently ignore the migration rather than raising
|
@@ -682,6 +714,15 @@ module ActiveRecord
|
|
682
714
|
raise NotImplementedError, "change_column_default is not implemented"
|
683
715
|
end
|
684
716
|
|
717
|
+
# Builds a ChangeColumnDefaultDefinition object.
|
718
|
+
#
|
719
|
+
# This definition object contains information about the column change that would occur
|
720
|
+
# if the same arguments were passed to #change_column_default. See #change_column_default for
|
721
|
+
# information about passing a +table_name+, +column_name+, +type+ and other options that can be passed.
|
722
|
+
def build_change_column_default_definition(table_name, column_name, default_or_changes) # :nodoc:
|
723
|
+
raise NotImplementedError, "build_change_column_default_definition is not implemented"
|
724
|
+
end
|
725
|
+
|
685
726
|
# Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag
|
686
727
|
# indicates whether the value can be +NULL+. For example
|
687
728
|
#
|
@@ -766,7 +807,7 @@ module ActiveRecord
|
|
766
807
|
#
|
767
808
|
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
768
809
|
#
|
769
|
-
# Note:
|
810
|
+
# Note: only supported by MySQL
|
770
811
|
#
|
771
812
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
772
813
|
#
|
@@ -788,6 +829,16 @@ module ActiveRecord
|
|
788
829
|
#
|
789
830
|
# Note: Partial indexes are only supported for PostgreSQL and SQLite.
|
790
831
|
#
|
832
|
+
# ====== Creating an index that includes additional columns
|
833
|
+
#
|
834
|
+
# add_index(:accounts, :branch_id, include: :party_id)
|
835
|
+
#
|
836
|
+
# generates:
|
837
|
+
#
|
838
|
+
# CREATE INDEX index_accounts_on_branch_id ON accounts USING btree(branch_id) INCLUDE (party_id)
|
839
|
+
#
|
840
|
+
# Note: only supported by PostgreSQL.
|
841
|
+
#
|
791
842
|
# ====== Creating an index with a specific method
|
792
843
|
#
|
793
844
|
# add_index(:developers, :name, using: 'btree')
|
@@ -833,12 +884,20 @@ module ActiveRecord
|
|
833
884
|
#
|
834
885
|
# For more information see the {"Transactional Migrations" section}[rdoc-ref:Migration].
|
835
886
|
def add_index(table_name, column_name, **options)
|
836
|
-
|
837
|
-
|
838
|
-
create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
887
|
+
create_index = build_create_index_definition(table_name, column_name, **options)
|
839
888
|
execute schema_creation.accept(create_index)
|
840
889
|
end
|
841
890
|
|
891
|
+
# Builds a CreateIndexDefinition object.
|
892
|
+
#
|
893
|
+
# This definition object contains information about the index that would be created
|
894
|
+
# if the same arguments were passed to #add_index. See #add_index for information about
|
895
|
+
# passing a +table_name+, +column_name+, and other additional options that can be passed.
|
896
|
+
def build_create_index_definition(table_name, column_name, **options) # :nodoc:
|
897
|
+
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
898
|
+
CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
899
|
+
end
|
900
|
+
|
842
901
|
# Removes the given index from the table.
|
843
902
|
#
|
844
903
|
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
@@ -901,10 +960,14 @@ module ActiveRecord
|
|
901
960
|
remove_index(table_name, name: old_name)
|
902
961
|
end
|
903
962
|
|
904
|
-
def index_name(table_name, options)
|
963
|
+
def index_name(table_name, options) # :nodoc:
|
905
964
|
if Hash === options
|
906
965
|
if options[:column]
|
907
|
-
|
966
|
+
if options[:_uses_legacy_index_name]
|
967
|
+
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
968
|
+
else
|
969
|
+
generate_index_name(table_name, options[:column])
|
970
|
+
end
|
908
971
|
elsif options[:name]
|
909
972
|
options[:name]
|
910
973
|
else
|
@@ -924,7 +987,6 @@ module ActiveRecord
|
|
924
987
|
# Adds a reference. The reference column is a bigint by default,
|
925
988
|
# the <tt>:type</tt> option can be used to specify a different type.
|
926
989
|
# Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
|
927
|
-
# #add_reference and #add_belongs_to are acceptable.
|
928
990
|
#
|
929
991
|
# The +options+ hash can include the following keys:
|
930
992
|
# [<tt>:type</tt>]
|
@@ -970,12 +1032,11 @@ module ActiveRecord
|
|
970
1032
|
# add_reference(:products, :supplier, foreign_key: { to_table: :firms })
|
971
1033
|
#
|
972
1034
|
def add_reference(table_name, ref_name, **options)
|
973
|
-
ReferenceDefinition.new(ref_name, **options).
|
1035
|
+
ReferenceDefinition.new(ref_name, **options).add(table_name, self)
|
974
1036
|
end
|
975
1037
|
alias :add_belongs_to :add_reference
|
976
1038
|
|
977
1039
|
# Removes the reference(s). Also removes a +type+ column if one exists.
|
978
|
-
# #remove_reference and #remove_belongs_to are acceptable.
|
979
1040
|
#
|
980
1041
|
# ====== Remove the reference
|
981
1042
|
#
|
@@ -990,19 +1051,21 @@ module ActiveRecord
|
|
990
1051
|
# remove_reference(:products, :user, foreign_key: true)
|
991
1052
|
#
|
992
1053
|
def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
|
1054
|
+
conditional_options = options.slice(:if_exists, :if_not_exists)
|
1055
|
+
|
993
1056
|
if foreign_key
|
994
1057
|
reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
995
1058
|
if foreign_key.is_a?(Hash)
|
996
|
-
foreign_key_options = foreign_key
|
1059
|
+
foreign_key_options = foreign_key.merge(conditional_options)
|
997
1060
|
else
|
998
|
-
foreign_key_options = { to_table: reference_name }
|
1061
|
+
foreign_key_options = { to_table: reference_name, **conditional_options }
|
999
1062
|
end
|
1000
1063
|
foreign_key_options[:column] ||= "#{ref_name}_id"
|
1001
1064
|
remove_foreign_key(table_name, **foreign_key_options)
|
1002
1065
|
end
|
1003
1066
|
|
1004
|
-
remove_column(table_name, "#{ref_name}_id")
|
1005
|
-
remove_column(table_name, "#{ref_name}_type") if polymorphic
|
1067
|
+
remove_column(table_name, "#{ref_name}_id", **conditional_options)
|
1068
|
+
remove_column(table_name, "#{ref_name}_type", **conditional_options) if polymorphic
|
1006
1069
|
end
|
1007
1070
|
alias :remove_belongs_to :remove_reference
|
1008
1071
|
|
@@ -1027,6 +1090,10 @@ module ActiveRecord
|
|
1027
1090
|
#
|
1028
1091
|
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
1029
1092
|
#
|
1093
|
+
# ====== Creating a foreign key, ignoring method call if the foreign key exists
|
1094
|
+
#
|
1095
|
+
# add_foreign_key(:articles, :authors, if_not_exists: true)
|
1096
|
+
#
|
1030
1097
|
# ====== Creating a foreign key on a specific column
|
1031
1098
|
#
|
1032
1099
|
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
@@ -1035,6 +1102,16 @@ module ActiveRecord
|
|
1035
1102
|
#
|
1036
1103
|
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id")
|
1037
1104
|
#
|
1105
|
+
# ====== Creating a composite foreign key
|
1106
|
+
#
|
1107
|
+
# Assuming "carts" table has "(shop_id, user_id)" as a primary key.
|
1108
|
+
#
|
1109
|
+
# add_foreign_key :orders, :carts, primary_key: [:shop_id, :user_id]
|
1110
|
+
#
|
1111
|
+
# generates:
|
1112
|
+
#
|
1113
|
+
# ALTER TABLE "orders" ADD CONSTRAINT fk_rails_6f5e4cb3a4 FOREIGN KEY ("cart_shop_id", "cart_user_id") REFERENCES "carts" ("shop_id", "user_id")
|
1114
|
+
#
|
1038
1115
|
# ====== Creating a cascading foreign key
|
1039
1116
|
#
|
1040
1117
|
# add_foreign_key :articles, :authors, on_delete: :cascade
|
@@ -1045,19 +1122,28 @@ module ActiveRecord
|
|
1045
1122
|
#
|
1046
1123
|
# The +options+ hash can include the following keys:
|
1047
1124
|
# [<tt>:column</tt>]
|
1048
|
-
# The foreign key column name on +from_table+. Defaults to <tt>to_table.singularize + "_id"</tt
|
1125
|
+
# The foreign key column name on +from_table+. Defaults to <tt>to_table.singularize + "_id"</tt>.
|
1126
|
+
# Pass an array to create a composite foreign key.
|
1049
1127
|
# [<tt>:primary_key</tt>]
|
1050
1128
|
# The primary key column name on +to_table+. Defaults to +id+.
|
1129
|
+
# Pass an array to create a composite foreign key.
|
1051
1130
|
# [<tt>:name</tt>]
|
1052
1131
|
# The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
|
1053
1132
|
# [<tt>:on_delete</tt>]
|
1054
|
-
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade
|
1133
|
+
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
|
1055
1134
|
# [<tt>:on_update</tt>]
|
1056
|
-
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade
|
1135
|
+
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+, and +:restrict+
|
1136
|
+
# [<tt>:if_not_exists</tt>]
|
1137
|
+
# Specifies if the foreign key already exists to not try to re-add it. This will avoid
|
1138
|
+
# duplicate column errors.
|
1057
1139
|
# [<tt>:validate</tt>]
|
1058
1140
|
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
1141
|
+
# [<tt>:deferrable</tt>]
|
1142
|
+
# (PostgreSQL only) Specify whether or not the foreign key should be deferrable. Valid values are booleans or
|
1143
|
+
# +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
|
1059
1144
|
def add_foreign_key(from_table, to_table, **options)
|
1060
|
-
return unless
|
1145
|
+
return unless use_foreign_keys?
|
1146
|
+
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table, **options.slice(:column))
|
1061
1147
|
|
1062
1148
|
options = foreign_key_options(from_table, to_table, options)
|
1063
1149
|
at = create_alter_table from_table
|
@@ -1087,12 +1173,18 @@ module ActiveRecord
|
|
1087
1173
|
#
|
1088
1174
|
# remove_foreign_key :accounts, name: :special_fk_name
|
1089
1175
|
#
|
1176
|
+
# Checks if the foreign key exists before trying to remove it. Will silently ignore indexes that
|
1177
|
+
# don't exist.
|
1178
|
+
#
|
1179
|
+
# remove_foreign_key :accounts, :branches, if_exists: true
|
1180
|
+
#
|
1090
1181
|
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
|
1091
1182
|
# with an addition of
|
1092
1183
|
# [<tt>:to_table</tt>]
|
1093
1184
|
# The name of the table that contains the referenced primary key.
|
1094
1185
|
def remove_foreign_key(from_table, to_table = nil, **options)
|
1095
|
-
return unless
|
1186
|
+
return unless use_foreign_keys?
|
1187
|
+
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
|
1096
1188
|
|
1097
1189
|
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
1098
1190
|
|
@@ -1117,15 +1209,33 @@ module ActiveRecord
|
|
1117
1209
|
foreign_key_for(from_table, to_table: to_table, **options).present?
|
1118
1210
|
end
|
1119
1211
|
|
1120
|
-
def foreign_key_column_for(table_name) # :nodoc:
|
1212
|
+
def foreign_key_column_for(table_name, column_name) # :nodoc:
|
1121
1213
|
name = strip_table_name_prefix_and_suffix(table_name)
|
1122
|
-
"#{name.singularize}
|
1214
|
+
"#{name.singularize}_#{column_name}"
|
1123
1215
|
end
|
1124
1216
|
|
1125
1217
|
def foreign_key_options(from_table, to_table, options) # :nodoc:
|
1126
1218
|
options = options.dup
|
1127
|
-
|
1219
|
+
|
1220
|
+
if options[:primary_key].is_a?(Array)
|
1221
|
+
options[:column] ||= options[:primary_key].map do |pk_column|
|
1222
|
+
foreign_key_column_for(to_table, pk_column)
|
1223
|
+
end
|
1224
|
+
else
|
1225
|
+
options[:column] ||= foreign_key_column_for(to_table, "id")
|
1226
|
+
end
|
1227
|
+
|
1128
1228
|
options[:name] ||= foreign_key_name(from_table, options)
|
1229
|
+
|
1230
|
+
if options[:column].is_a?(Array) || options[:primary_key].is_a?(Array)
|
1231
|
+
if Array(options[:primary_key]).size != Array(options[:column]).size
|
1232
|
+
raise ArgumentError, <<~MSG.squish
|
1233
|
+
For composite primary keys, specify :column and :primary_key, where
|
1234
|
+
:column must reference all the :primary_key columns from #{to_table.inspect}
|
1235
|
+
MSG
|
1236
|
+
end
|
1237
|
+
end
|
1238
|
+
|
1129
1239
|
options
|
1130
1240
|
end
|
1131
1241
|
|
@@ -1147,12 +1257,16 @@ module ActiveRecord
|
|
1147
1257
|
# The +options+ hash can include the following keys:
|
1148
1258
|
# [<tt>:name</tt>]
|
1149
1259
|
# The constraint name. Defaults to <tt>chk_rails_<identifier></tt>.
|
1260
|
+
# [<tt>:if_not_exists</tt>]
|
1261
|
+
# Silently ignore if the constraint already exists, rather than raise an error.
|
1150
1262
|
# [<tt>:validate</tt>]
|
1151
1263
|
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
1152
|
-
def add_check_constraint(table_name, expression, **options)
|
1264
|
+
def add_check_constraint(table_name, expression, if_not_exists: false, **options)
|
1153
1265
|
return unless supports_check_constraints?
|
1154
1266
|
|
1155
1267
|
options = check_constraint_options(table_name, expression, options)
|
1268
|
+
return if if_not_exists && check_constraint_exists?(table_name, **options)
|
1269
|
+
|
1156
1270
|
at = create_alter_table(table_name)
|
1157
1271
|
at.add_check_constraint(expression, options)
|
1158
1272
|
|
@@ -1165,16 +1279,24 @@ module ActiveRecord
|
|
1165
1279
|
options
|
1166
1280
|
end
|
1167
1281
|
|
1168
|
-
# Removes the given check constraint from the table.
|
1282
|
+
# Removes the given check constraint from the table. Removing a check constraint
|
1283
|
+
# that does not exist will raise an error.
|
1169
1284
|
#
|
1170
1285
|
# remove_check_constraint :products, name: "price_check"
|
1171
1286
|
#
|
1287
|
+
# To silently ignore a non-existent check constraint rather than raise an error,
|
1288
|
+
# use the +if_exists+ option.
|
1289
|
+
#
|
1290
|
+
# remove_check_constraint :products, name: "price_check", if_exists: true
|
1291
|
+
#
|
1172
1292
|
# The +expression+ parameter will be ignored if present. It can be helpful
|
1173
1293
|
# to provide this in a migration's +change+ method so it can be reverted.
|
1174
1294
|
# In that case, +expression+ will be used by #add_check_constraint.
|
1175
|
-
def remove_check_constraint(table_name, expression = nil, **options)
|
1295
|
+
def remove_check_constraint(table_name, expression = nil, if_exists: false, **options)
|
1176
1296
|
return unless supports_check_constraints?
|
1177
1297
|
|
1298
|
+
return if if_exists && !check_constraint_exists?(table_name, **options)
|
1299
|
+
|
1178
1300
|
chk_name_to_delete = check_constraint_for!(table_name, expression: expression, **options).name
|
1179
1301
|
|
1180
1302
|
at = create_alter_table(table_name)
|
@@ -1183,8 +1305,20 @@ module ActiveRecord
|
|
1183
1305
|
execute schema_creation.accept(at)
|
1184
1306
|
end
|
1185
1307
|
|
1308
|
+
|
1309
|
+
# Checks to see if a check constraint exists on a table for a given check constraint definition.
|
1310
|
+
#
|
1311
|
+
# check_constraint_exists?(:products, name: "price_check")
|
1312
|
+
#
|
1313
|
+
def check_constraint_exists?(table_name, **options)
|
1314
|
+
if !options.key?(:name) && !options.key?(:expression)
|
1315
|
+
raise ArgumentError, "At least one of :name or :expression must be supplied"
|
1316
|
+
end
|
1317
|
+
check_constraint_for(table_name, **options).present?
|
1318
|
+
end
|
1319
|
+
|
1186
1320
|
def dump_schema_information # :nodoc:
|
1187
|
-
versions = schema_migration.
|
1321
|
+
versions = schema_migration.versions
|
1188
1322
|
insert_versions_sql(versions) if versions.any?
|
1189
1323
|
end
|
1190
1324
|
|
@@ -1256,20 +1390,39 @@ module ActiveRecord
|
|
1256
1390
|
columns
|
1257
1391
|
end
|
1258
1392
|
|
1393
|
+
def distinct_relation_for_primary_key(relation) # :nodoc:
|
1394
|
+
primary_key_columns = Array(relation.primary_key).map do |column|
|
1395
|
+
visitor.compile(relation.table[column])
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
values = columns_for_distinct(
|
1399
|
+
primary_key_columns,
|
1400
|
+
relation.order_values
|
1401
|
+
)
|
1402
|
+
|
1403
|
+
limited = relation.reselect(values).distinct!
|
1404
|
+
limited_ids = select_rows(limited.arel, "SQL").map do |results|
|
1405
|
+
results.last(Array(relation.primary_key).length) # ignores order values for MySQL and PostgreSQL
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
if limited_ids.empty?
|
1409
|
+
relation.none!
|
1410
|
+
else
|
1411
|
+
relation.where!(**Array(relation.primary_key).zip(limited_ids.transpose).to_h)
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
relation.limit_value = relation.offset_value = nil
|
1415
|
+
relation
|
1416
|
+
end
|
1417
|
+
|
1259
1418
|
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
1260
1419
|
# Additional options (like +:null+) are forwarded to #add_column.
|
1261
1420
|
#
|
1262
1421
|
# add_timestamps(:suppliers, null: true)
|
1263
1422
|
#
|
1264
1423
|
def add_timestamps(table_name, **options)
|
1265
|
-
|
1266
|
-
|
1267
|
-
if !options.key?(:precision) && supports_datetime_with_precision?
|
1268
|
-
options[:precision] = 6
|
1269
|
-
end
|
1270
|
-
|
1271
|
-
add_column table_name, :created_at, :datetime, **options
|
1272
|
-
add_column table_name, :updated_at, :datetime, **options
|
1424
|
+
fragments = add_timestamps_for_alter(table_name, **options)
|
1425
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{fragments.join(', ')}"
|
1273
1426
|
end
|
1274
1427
|
|
1275
1428
|
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
|
@@ -1277,16 +1430,15 @@ module ActiveRecord
|
|
1277
1430
|
# remove_timestamps(:suppliers)
|
1278
1431
|
#
|
1279
1432
|
def remove_timestamps(table_name, **options)
|
1280
|
-
|
1281
|
-
remove_column table_name, :created_at
|
1433
|
+
remove_columns table_name, :updated_at, :created_at
|
1282
1434
|
end
|
1283
1435
|
|
1284
|
-
def update_table_definition(table_name, base)
|
1436
|
+
def update_table_definition(table_name, base) # :nodoc:
|
1285
1437
|
Table.new(table_name, base)
|
1286
1438
|
end
|
1287
1439
|
|
1288
1440
|
def add_index_options(table_name, column_name, name: nil, if_not_exists: false, internal: false, **options) # :nodoc:
|
1289
|
-
options.assert_valid_keys(:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm)
|
1441
|
+
options.assert_valid_keys(:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm, :include, :nulls_not_distinct)
|
1290
1442
|
|
1291
1443
|
column_names = index_column_names(column_name)
|
1292
1444
|
|
@@ -1305,6 +1457,8 @@ module ActiveRecord
|
|
1305
1457
|
where: options[:where],
|
1306
1458
|
type: options[:type],
|
1307
1459
|
using: options[:using],
|
1460
|
+
include: options[:include],
|
1461
|
+
nulls_not_distinct: options[:nulls_not_distinct],
|
1308
1462
|
comment: options[:comment]
|
1309
1463
|
)
|
1310
1464
|
|
@@ -1352,7 +1506,79 @@ module ActiveRecord
|
|
1352
1506
|
SchemaDumper.create(self, options)
|
1353
1507
|
end
|
1354
1508
|
|
1509
|
+
def use_foreign_keys?
|
1510
|
+
supports_foreign_keys? && foreign_keys_enabled?
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
# Returns an instance of SchemaCreation, which can be used to visit a schema definition
|
1514
|
+
# object and return DDL.
|
1515
|
+
def schema_creation # :nodoc:
|
1516
|
+
SchemaCreation.new(self)
|
1517
|
+
end
|
1518
|
+
|
1519
|
+
def bulk_change_table(table_name, operations) # :nodoc:
|
1520
|
+
sql_fragments = []
|
1521
|
+
non_combinable_operations = []
|
1522
|
+
|
1523
|
+
operations.each do |command, args|
|
1524
|
+
table, arguments = args.shift, args
|
1525
|
+
method = :"#{command}_for_alter"
|
1526
|
+
|
1527
|
+
if respond_to?(method, true)
|
1528
|
+
sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
|
1529
|
+
sql_fragments.concat(sqls)
|
1530
|
+
non_combinable_operations.concat(procs)
|
1531
|
+
else
|
1532
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1533
|
+
non_combinable_operations.each(&:call)
|
1534
|
+
sql_fragments = []
|
1535
|
+
non_combinable_operations = []
|
1536
|
+
send(command, table, *arguments)
|
1537
|
+
end
|
1538
|
+
end
|
1539
|
+
|
1540
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1541
|
+
non_combinable_operations.each(&:call)
|
1542
|
+
end
|
1543
|
+
|
1544
|
+
def valid_table_definition_options # :nodoc:
|
1545
|
+
[:temporary, :if_not_exists, :options, :as, :comment, :charset, :collation]
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
def valid_column_definition_options # :nodoc:
|
1549
|
+
ColumnDefinition::OPTION_NAMES
|
1550
|
+
end
|
1551
|
+
|
1552
|
+
def valid_primary_key_options # :nodoc:
|
1553
|
+
[:limit, :default, :precision]
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
# Returns the maximum length of an index name in bytes.
|
1557
|
+
def max_index_name_size
|
1558
|
+
62
|
1559
|
+
end
|
1560
|
+
|
1355
1561
|
private
|
1562
|
+
def generate_index_name(table_name, column)
|
1563
|
+
name = "index_#{table_name}_on_#{Array(column) * '_and_'}"
|
1564
|
+
return name if name.bytesize <= max_index_name_size
|
1565
|
+
|
1566
|
+
# Fallback to short version, add hash to ensure uniqueness
|
1567
|
+
hashed_identifier = "_" + OpenSSL::Digest::SHA256.hexdigest(name).first(10)
|
1568
|
+
name = "idx_on_#{Array(column) * '_'}"
|
1569
|
+
|
1570
|
+
short_limit = max_index_name_size - hashed_identifier.bytesize
|
1571
|
+
short_name = name.mb_chars.limit(short_limit).to_s
|
1572
|
+
|
1573
|
+
"#{short_name}#{hashed_identifier}"
|
1574
|
+
end
|
1575
|
+
|
1576
|
+
def validate_change_column_null_argument!(value)
|
1577
|
+
unless value == true || value == false
|
1578
|
+
raise ArgumentError, "change_column_null expects a boolean value (true for NULL, false for NOT NULL). Got: #{value.inspect}"
|
1579
|
+
end
|
1580
|
+
end
|
1581
|
+
|
1356
1582
|
def column_options_keys
|
1357
1583
|
[:limit, :precision, :scale, :default, :null, :collation, :comment]
|
1358
1584
|
end
|
@@ -1387,7 +1613,7 @@ module ActiveRecord
|
|
1387
1613
|
|
1388
1614
|
checks = []
|
1389
1615
|
|
1390
|
-
if !options.key?(:name) &&
|
1616
|
+
if !options.key?(:name) && expression_column_name?(column_name)
|
1391
1617
|
options[:name] = index_name(table_name, column_name)
|
1392
1618
|
column_names = []
|
1393
1619
|
else
|
@@ -1396,7 +1622,7 @@ module ActiveRecord
|
|
1396
1622
|
|
1397
1623
|
checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
|
1398
1624
|
|
1399
|
-
if column_names.present?
|
1625
|
+
if column_names.present? && !(options.key?(:name) && expression_column_name?(column_names))
|
1400
1626
|
checks << lambda { |i| index_name(table_name, i.columns) == index_name(table_name, column_names) }
|
1401
1627
|
end
|
1402
1628
|
|
@@ -1406,7 +1632,7 @@ module ActiveRecord
|
|
1406
1632
|
|
1407
1633
|
if matching_indexes.count > 1
|
1408
1634
|
raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. " \
|
1409
|
-
|
1635
|
+
"Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
|
1410
1636
|
elsif matching_indexes.none?
|
1411
1637
|
raise ArgumentError, "No indexes found on #{table_name} with the options provided."
|
1412
1638
|
else
|
@@ -1414,11 +1640,11 @@ module ActiveRecord
|
|
1414
1640
|
end
|
1415
1641
|
end
|
1416
1642
|
|
1417
|
-
def rename_table_indexes(table_name, new_name)
|
1643
|
+
def rename_table_indexes(table_name, new_name, **options)
|
1418
1644
|
indexes(new_name).each do |index|
|
1419
|
-
generated_index_name = index_name(table_name, column: index.columns)
|
1645
|
+
generated_index_name = index_name(table_name, column: index.columns, **options)
|
1420
1646
|
if generated_index_name == index.name
|
1421
|
-
rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
|
1647
|
+
rename_index new_name, generated_index_name, index_name(new_name, column: index.columns, **options)
|
1422
1648
|
end
|
1423
1649
|
end
|
1424
1650
|
end
|
@@ -1436,10 +1662,6 @@ module ActiveRecord
|
|
1436
1662
|
end
|
1437
1663
|
end
|
1438
1664
|
|
1439
|
-
def schema_creation
|
1440
|
-
SchemaCreation.new(self)
|
1441
|
-
end
|
1442
|
-
|
1443
1665
|
def create_table_definition(name, **options)
|
1444
1666
|
TableDefinition.new(self, name, **options)
|
1445
1667
|
end
|
@@ -1448,8 +1670,12 @@ module ActiveRecord
|
|
1448
1670
|
AlterTable.new create_table_definition(name)
|
1449
1671
|
end
|
1450
1672
|
|
1451
|
-
def
|
1452
|
-
|
1673
|
+
def validate_create_table_options!(options)
|
1674
|
+
unless options[:_skip_validate_options]
|
1675
|
+
options
|
1676
|
+
.except(:_uses_legacy_table_name, :_skip_validate_options)
|
1677
|
+
.assert_valid_keys(valid_table_definition_options, valid_primary_key_options)
|
1678
|
+
end
|
1453
1679
|
end
|
1454
1680
|
|
1455
1681
|
def fetch_type_metadata(sql_type)
|
@@ -1464,7 +1690,7 @@ module ActiveRecord
|
|
1464
1690
|
end
|
1465
1691
|
|
1466
1692
|
def index_column_names(column_names)
|
1467
|
-
if
|
1693
|
+
if expression_column_name?(column_names)
|
1468
1694
|
column_names
|
1469
1695
|
else
|
1470
1696
|
Array(column_names)
|
@@ -1472,13 +1698,18 @@ module ActiveRecord
|
|
1472
1698
|
end
|
1473
1699
|
|
1474
1700
|
def index_name_options(column_names)
|
1475
|
-
if
|
1701
|
+
if expression_column_name?(column_names)
|
1476
1702
|
column_names = column_names.scan(/\w+/).join("_")
|
1477
1703
|
end
|
1478
1704
|
|
1479
1705
|
{ column: column_names }
|
1480
1706
|
end
|
1481
1707
|
|
1708
|
+
# Try to identify whether the given column name is an expression
|
1709
|
+
def expression_column_name?(column_name)
|
1710
|
+
column_name.is_a?(String) && /\W/.match?(column_name)
|
1711
|
+
end
|
1712
|
+
|
1482
1713
|
def strip_table_name_prefix_and_suffix(table_name)
|
1483
1714
|
prefix = Base.table_name_prefix
|
1484
1715
|
suffix = Base.table_name_suffix
|
@@ -1487,15 +1718,16 @@ module ActiveRecord
|
|
1487
1718
|
|
1488
1719
|
def foreign_key_name(table_name, options)
|
1489
1720
|
options.fetch(:name) do
|
1490
|
-
|
1491
|
-
|
1721
|
+
columns = Array(options.fetch(:column)).map(&:to_s)
|
1722
|
+
identifier = "#{table_name}_#{columns * '_and_'}_fk"
|
1723
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1492
1724
|
|
1493
1725
|
"fk_rails_#{hashed_identifier}"
|
1494
1726
|
end
|
1495
1727
|
end
|
1496
1728
|
|
1497
1729
|
def foreign_key_for(from_table, **options)
|
1498
|
-
return unless
|
1730
|
+
return unless use_foreign_keys?
|
1499
1731
|
foreign_keys(from_table).detect { |fk| fk.defined_for?(**options) }
|
1500
1732
|
end
|
1501
1733
|
|
@@ -1512,11 +1744,15 @@ module ActiveRecord
|
|
1512
1744
|
end
|
1513
1745
|
end
|
1514
1746
|
|
1747
|
+
def foreign_keys_enabled?
|
1748
|
+
@config.fetch(:foreign_keys, true)
|
1749
|
+
end
|
1750
|
+
|
1515
1751
|
def check_constraint_name(table_name, **options)
|
1516
1752
|
options.fetch(:name) do
|
1517
1753
|
expression = options.fetch(:expression)
|
1518
1754
|
identifier = "#{table_name}_#{expression}_chk"
|
1519
|
-
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1755
|
+
hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)
|
1520
1756
|
|
1521
1757
|
"chk_rails_#{hashed_identifier}"
|
1522
1758
|
end
|
@@ -1525,7 +1761,7 @@ module ActiveRecord
|
|
1525
1761
|
def check_constraint_for(table_name, **options)
|
1526
1762
|
return unless supports_check_constraints?
|
1527
1763
|
chk_name = check_constraint_name(table_name, **options)
|
1528
|
-
check_constraints(table_name).detect { |chk| chk.name
|
1764
|
+
check_constraints(table_name).detect { |chk| chk.defined_for?(name: chk_name, **options) }
|
1529
1765
|
end
|
1530
1766
|
|
1531
1767
|
def check_constraint_for!(table_name, expression: nil, **options)
|
@@ -1539,6 +1775,12 @@ module ActiveRecord
|
|
1539
1775
|
end
|
1540
1776
|
end
|
1541
1777
|
|
1778
|
+
def validate_table_length!(table_name)
|
1779
|
+
if table_name.length > table_name_length
|
1780
|
+
raise ArgumentError, "Table name '#{table_name}' is too long; the limit is #{table_name_length} characters"
|
1781
|
+
end
|
1782
|
+
end
|
1783
|
+
|
1542
1784
|
def extract_new_default_value(default_or_changes)
|
1543
1785
|
if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
|
1544
1786
|
default_or_changes[:to]
|
@@ -1552,29 +1794,8 @@ module ActiveRecord
|
|
1552
1794
|
column_name.nil? && options.key?(:name) && options.except(:name, :algorithm).empty?
|
1553
1795
|
end
|
1554
1796
|
|
1555
|
-
def
|
1556
|
-
|
1557
|
-
non_combinable_operations = []
|
1558
|
-
|
1559
|
-
operations.each do |command, args|
|
1560
|
-
table, arguments = args.shift, args
|
1561
|
-
method = :"#{command}_for_alter"
|
1562
|
-
|
1563
|
-
if respond_to?(method, true)
|
1564
|
-
sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
|
1565
|
-
sql_fragments << sqls
|
1566
|
-
non_combinable_operations.concat(procs)
|
1567
|
-
else
|
1568
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1569
|
-
non_combinable_operations.each(&:call)
|
1570
|
-
sql_fragments = []
|
1571
|
-
non_combinable_operations = []
|
1572
|
-
send(command, table, *arguments)
|
1573
|
-
end
|
1574
|
-
end
|
1575
|
-
|
1576
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
1577
|
-
non_combinable_operations.each(&:call)
|
1797
|
+
def reference_name_for_table(table_name)
|
1798
|
+
table_name.to_s.singularize
|
1578
1799
|
end
|
1579
1800
|
|
1580
1801
|
def add_column_for_alter(table_name, column_name, type, **options)
|
@@ -1583,6 +1804,11 @@ module ActiveRecord
|
|
1583
1804
|
schema_creation.accept(AddColumnDefinition.new(cd))
|
1584
1805
|
end
|
1585
1806
|
|
1807
|
+
def change_column_default_for_alter(table_name, column_name, default_or_changes)
|
1808
|
+
cd = build_change_column_default_definition(table_name, column_name, default_or_changes)
|
1809
|
+
schema_creation.accept(cd)
|
1810
|
+
end
|
1811
|
+
|
1586
1812
|
def rename_column_sql(table_name, column_name, new_column_name)
|
1587
1813
|
"RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
|
1588
1814
|
end
|
@@ -1617,8 +1843,8 @@ module ActiveRecord
|
|
1617
1843
|
|
1618
1844
|
if versions.is_a?(Array)
|
1619
1845
|
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
|
1620
|
-
sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
|
1621
|
-
sql << "
|
1846
|
+
sql << versions.reverse.map { |v| "(#{quote(v)})" }.join(",\n")
|
1847
|
+
sql << ";"
|
1622
1848
|
sql
|
1623
1849
|
else
|
1624
1850
|
"INSERT INTO #{sm_table} (version) VALUES (#{quote(versions)});"
|