activerecord 5.2.4.2 → 6.0.2.2
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 +4 -4
- data/CHANGELOG.md +715 -566
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +61 -20
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +12 -23
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +28 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +39 -31
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +2 -2
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +104 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +99 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +187 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +138 -195
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +129 -141
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +103 -59
- data/lib/active_record/counter_cache.rb +4 -29
- 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/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- 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 +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/model_schema.rb +33 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +23 -27
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +213 -64
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +4 -5
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -65
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +58 -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/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +109 -24
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/string/strip"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
module ConnectionAdapters
|
7
5
|
class AbstractAdapter
|
@@ -17,14 +15,13 @@ module ActiveRecord
|
|
17
15
|
end
|
18
16
|
|
19
17
|
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
20
|
-
:options_include_default?, :supports_indexes_in_create?, :
|
21
|
-
|
22
|
-
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options
|
18
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
|
19
|
+
to: :@conn, private: true
|
23
20
|
|
24
21
|
private
|
25
22
|
|
26
23
|
def visit_AlterTable(o)
|
27
|
-
sql = "ALTER TABLE #{quote_table_name(o.name)} "
|
24
|
+
sql = +"ALTER TABLE #{quote_table_name(o.name)} "
|
28
25
|
sql << o.adds.map { |col| accept col }.join(" ")
|
29
26
|
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
|
30
27
|
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
|
@@ -32,17 +29,19 @@ module ActiveRecord
|
|
32
29
|
|
33
30
|
def visit_ColumnDefinition(o)
|
34
31
|
o.sql_type = type_to_sql(o.type, o.options)
|
35
|
-
column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
|
32
|
+
column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
|
36
33
|
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
37
34
|
column_sql
|
38
35
|
end
|
39
36
|
|
40
37
|
def visit_AddColumnDefinition(o)
|
41
|
-
"ADD #{accept(o.column)}"
|
38
|
+
+"ADD #{accept(o.column)}"
|
42
39
|
end
|
43
40
|
|
44
41
|
def visit_TableDefinition(o)
|
45
|
-
create_sql = "CREATE#{
|
42
|
+
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
43
|
+
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
44
|
+
create_sql << "#{quote_table_name(o.name)} "
|
46
45
|
|
47
46
|
statements = o.columns.map { |c| accept c }
|
48
47
|
statements << accept(o.primary_keys) if o.primary_keys
|
@@ -51,7 +50,7 @@ module ActiveRecord
|
|
51
50
|
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
52
51
|
end
|
53
52
|
|
54
|
-
if
|
53
|
+
if supports_foreign_keys?
|
55
54
|
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
56
55
|
end
|
57
56
|
|
@@ -66,7 +65,7 @@ module ActiveRecord
|
|
66
65
|
end
|
67
66
|
|
68
67
|
def visit_ForeignKeyDefinition(o)
|
69
|
-
sql =
|
68
|
+
sql = +<<~SQL
|
70
69
|
CONSTRAINT #{quote_column_name(o.name)}
|
71
70
|
FOREIGN KEY (#{quote_column_name(o.column)})
|
72
71
|
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
|
@@ -122,7 +121,15 @@ module ActiveRecord
|
|
122
121
|
sql
|
123
122
|
end
|
124
123
|
|
124
|
+
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
125
|
+
def table_modifier_in_create(o)
|
126
|
+
" TEMPORARY" if o.temporary
|
127
|
+
end
|
128
|
+
|
125
129
|
def foreign_key_in_create(from_table, to_table, options)
|
130
|
+
prefix = ActiveRecord::Base.table_name_prefix
|
131
|
+
suffix = ActiveRecord::Base.table_name_suffix
|
132
|
+
to_table = "#{prefix}#{to_table}#{suffix}"
|
126
133
|
options = foreign_key_options(from_table, to_table, options)
|
127
134
|
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
128
135
|
end
|
@@ -133,7 +140,7 @@ module ActiveRecord
|
|
133
140
|
when :cascade then "ON #{action} CASCADE"
|
134
141
|
when :restrict then "ON #{action} RESTRICT"
|
135
142
|
else
|
136
|
-
raise ArgumentError,
|
143
|
+
raise ArgumentError, <<~MSG
|
137
144
|
'#{dependency}' is not supported for :on_update or :on_delete.
|
138
145
|
Supported values are: :nullify, :cascade, :restrict
|
139
146
|
MSG
|
@@ -101,13 +101,13 @@ module ActiveRecord
|
|
101
101
|
end
|
102
102
|
alias validated? validate?
|
103
103
|
|
104
|
-
def
|
105
|
-
if
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
def export_name_on_schema_dump?
|
105
|
+
!ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
|
106
|
+
end
|
107
|
+
|
108
|
+
def defined_for?(to_table: nil, **options)
|
109
|
+
(to_table.nil? || to_table.to_s == self.to_table) &&
|
110
|
+
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
111
111
|
end
|
112
112
|
|
113
113
|
private
|
@@ -151,13 +151,8 @@ module ActiveRecord
|
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
155
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
156
|
-
protected
|
157
|
-
|
158
|
-
attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
|
159
|
-
|
160
154
|
private
|
155
|
+
attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
|
161
156
|
|
162
157
|
def as_options(value)
|
163
158
|
value.is_a?(Hash) ? value : {}
|
@@ -199,41 +194,44 @@ module ActiveRecord
|
|
199
194
|
end
|
200
195
|
|
201
196
|
module ColumnMethods
|
197
|
+
extend ActiveSupport::Concern
|
198
|
+
|
202
199
|
# Appends a primary key definition to the table definition.
|
203
200
|
# Can be called multiple times, but this is probably not a good idea.
|
204
201
|
def primary_key(name, type = :primary_key, **options)
|
205
202
|
column(name, type, options.merge(primary_key: true))
|
206
203
|
end
|
207
204
|
|
205
|
+
##
|
206
|
+
# :method: column
|
207
|
+
# :call-seq: column(name, type, **options)
|
208
|
+
#
|
208
209
|
# Appends a column or columns of a specified type.
|
209
210
|
#
|
210
211
|
# t.string(:goat)
|
211
212
|
# t.string(:goat, :sheep)
|
212
213
|
#
|
213
214
|
# See TableDefinition#column
|
214
|
-
|
215
|
-
|
216
|
-
:binary,
|
217
|
-
|
218
|
-
|
219
|
-
:
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
:
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
def #{column_type}(*args, **options)
|
232
|
-
args.each { |name| column(name, :#{column_type}, options) }
|
215
|
+
|
216
|
+
included do
|
217
|
+
define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
|
218
|
+
:float, :integer, :json, :string, :text, :time, :timestamp, :virtual
|
219
|
+
|
220
|
+
alias :numeric :decimal
|
221
|
+
end
|
222
|
+
|
223
|
+
class_methods do
|
224
|
+
private def define_column_methods(*column_types) # :nodoc:
|
225
|
+
column_types.each do |column_type|
|
226
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
227
|
+
def #{column_type}(*names, **options)
|
228
|
+
raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
|
229
|
+
names.each { |name| column(name, :#{column_type}, options) }
|
230
|
+
end
|
231
|
+
RUBY
|
233
232
|
end
|
234
|
-
|
233
|
+
end
|
235
234
|
end
|
236
|
-
alias_method :numeric, :decimal
|
237
235
|
end
|
238
236
|
|
239
237
|
# Represents the schema of an SQL table in an abstract way. This class
|
@@ -257,15 +255,25 @@ module ActiveRecord
|
|
257
255
|
class TableDefinition
|
258
256
|
include ColumnMethods
|
259
257
|
|
260
|
-
|
261
|
-
attr_reader :name, :temporary, :options, :as, :foreign_keys, :comment
|
258
|
+
attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys
|
262
259
|
|
263
|
-
def initialize(
|
260
|
+
def initialize(
|
261
|
+
conn,
|
262
|
+
name,
|
263
|
+
temporary: false,
|
264
|
+
if_not_exists: false,
|
265
|
+
options: nil,
|
266
|
+
as: nil,
|
267
|
+
comment: nil,
|
268
|
+
**
|
269
|
+
)
|
270
|
+
@conn = conn
|
264
271
|
@columns_hash = {}
|
265
272
|
@indexes = []
|
266
273
|
@foreign_keys = []
|
267
274
|
@primary_keys = nil
|
268
275
|
@temporary = temporary
|
276
|
+
@if_not_exists = if_not_exists
|
269
277
|
@options = options
|
270
278
|
@as = as
|
271
279
|
@name = name
|
@@ -349,16 +357,20 @@ module ActiveRecord
|
|
349
357
|
#
|
350
358
|
# create_table :taggings do |t|
|
351
359
|
# t.references :tag, index: { name: 'index_taggings_on_tag_id' }
|
352
|
-
# t.references :tagger, polymorphic: true
|
353
|
-
# t.references :taggable, polymorphic: { default: 'Photo' }
|
360
|
+
# t.references :tagger, polymorphic: true
|
361
|
+
# t.references :taggable, polymorphic: { default: 'Photo' }, index: false
|
354
362
|
# end
|
355
|
-
def column(name, type, options
|
363
|
+
def column(name, type, **options)
|
356
364
|
name = name.to_s
|
357
365
|
type = type.to_sym if type
|
358
366
|
options = options.dup
|
359
367
|
|
360
|
-
if @columns_hash[name]
|
361
|
-
|
368
|
+
if @columns_hash[name]
|
369
|
+
if @columns_hash[name].primary_key?
|
370
|
+
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
371
|
+
else
|
372
|
+
raise ArgumentError, "you can't define an already defined column '#{name}'."
|
373
|
+
end
|
362
374
|
end
|
363
375
|
|
364
376
|
index_options = options.delete(:index)
|
@@ -382,10 +394,7 @@ module ActiveRecord
|
|
382
394
|
end
|
383
395
|
|
384
396
|
def foreign_key(table_name, options = {}) # :nodoc:
|
385
|
-
|
386
|
-
table_name_suffix = ActiveRecord::Base.table_name_suffix
|
387
|
-
table_name = "#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
388
|
-
foreign_keys.push([table_name, options])
|
397
|
+
foreign_keys << [table_name, options]
|
389
398
|
end
|
390
399
|
|
391
400
|
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
@@ -395,6 +404,10 @@ module ActiveRecord
|
|
395
404
|
def timestamps(**options)
|
396
405
|
options[:null] = false if options[:null].nil?
|
397
406
|
|
407
|
+
if !options.key?(:precision) && @conn.supports_datetime_with_precision?
|
408
|
+
options[:precision] = 6
|
409
|
+
end
|
410
|
+
|
398
411
|
column(:created_at, :datetime, options)
|
399
412
|
column(:updated_at, :datetime, options)
|
400
413
|
end
|
@@ -403,6 +416,7 @@ module ActiveRecord
|
|
403
416
|
#
|
404
417
|
# t.references(:user)
|
405
418
|
# t.belongs_to(:supplier, foreign_key: true)
|
419
|
+
# t.belongs_to(:supplier, foreign_key: true, type: :integer)
|
406
420
|
#
|
407
421
|
# See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
|
408
422
|
def references(*args, **options)
|
@@ -502,6 +516,7 @@ module ActiveRecord
|
|
502
516
|
# t.json
|
503
517
|
# t.virtual
|
504
518
|
# t.remove
|
519
|
+
# t.remove_foreign_key
|
505
520
|
# t.remove_references
|
506
521
|
# t.remove_belongs_to
|
507
522
|
# t.remove_index
|
@@ -523,8 +538,10 @@ module ActiveRecord
|
|
523
538
|
# t.column(:name, :string)
|
524
539
|
#
|
525
540
|
# See TableDefinition#column for details of the options you can use.
|
526
|
-
def column(column_name, type, options
|
541
|
+
def column(column_name, type, **options)
|
542
|
+
index_options = options.delete(:index)
|
527
543
|
@base.add_column(name, column_name, type, options)
|
544
|
+
index(column_name, index_options.is_a?(Hash) ? index_options : {}) if index_options
|
528
545
|
end
|
529
546
|
|
530
547
|
# Checks to see if a column exists.
|
@@ -663,15 +680,26 @@ module ActiveRecord
|
|
663
680
|
end
|
664
681
|
alias :remove_belongs_to :remove_references
|
665
682
|
|
666
|
-
# Adds a foreign key.
|
683
|
+
# Adds a foreign key to the table using a supplied table name.
|
667
684
|
#
|
668
685
|
# t.foreign_key(:authors)
|
686
|
+
# t.foreign_key(:authors, column: :author_id, primary_key: "id")
|
669
687
|
#
|
670
688
|
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
671
689
|
def foreign_key(*args)
|
672
690
|
@base.add_foreign_key(name, *args)
|
673
691
|
end
|
674
692
|
|
693
|
+
# Removes the given foreign key from the table.
|
694
|
+
#
|
695
|
+
# t.remove_foreign_key(:authors)
|
696
|
+
# t.remove_foreign_key(column: :author_id)
|
697
|
+
#
|
698
|
+
# See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
|
699
|
+
def remove_foreign_key(*args)
|
700
|
+
@base.remove_foreign_key(name, *args)
|
701
|
+
end
|
702
|
+
|
675
703
|
# Checks to see if a foreign key exists.
|
676
704
|
#
|
677
705
|
# t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/hash/compact"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
module ConnectionAdapters # :nodoc:
|
7
5
|
class SchemaDumper < SchemaDumper # :nodoc:
|
@@ -17,7 +15,7 @@ module ActiveRecord
|
|
17
15
|
def column_spec_for_primary_key(column)
|
18
16
|
return {} if default_primary_key?(column)
|
19
17
|
spec = { id: schema_type(column).inspect }
|
20
|
-
spec.merge!(prepare_column_options(column).except!(:null))
|
18
|
+
spec.merge!(prepare_column_options(column).except!(:null, :comment))
|
21
19
|
spec[:default] ||= "nil" if explicit_primary_key_default?(column)
|
22
20
|
spec
|
23
21
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "active_record/migration/join_table"
|
4
4
|
require "active_support/core_ext/string/access"
|
5
|
+
require "active_support/deprecation"
|
5
6
|
require "digest/sha2"
|
6
7
|
|
7
8
|
module ActiveRecord
|
@@ -129,11 +130,11 @@ module ActiveRecord
|
|
129
130
|
# column_exists?(:suppliers, :name, :string, null: false)
|
130
131
|
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
|
131
132
|
#
|
132
|
-
def column_exists?(table_name, column_name, type = nil, options
|
133
|
+
def column_exists?(table_name, column_name, type = nil, **options)
|
133
134
|
column_name = column_name.to_s
|
134
135
|
checks = []
|
135
136
|
checks << lambda { |c| c.name == column_name }
|
136
|
-
checks << lambda { |c| c.type == type } if type
|
137
|
+
checks << lambda { |c| c.type == type.to_sym rescue nil } if type
|
137
138
|
column_options_keys.each do |attr|
|
138
139
|
checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
|
139
140
|
end
|
@@ -205,19 +206,22 @@ module ActiveRecord
|
|
205
206
|
# Set to true to drop the table before creating it.
|
206
207
|
# Set to +:cascade+ to drop dependent objects as well.
|
207
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.
|
208
212
|
# [<tt>:as</tt>]
|
209
213
|
# SQL to use to generate the table. When this option is used, the block is
|
210
214
|
# ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options.
|
211
215
|
#
|
212
216
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
213
217
|
#
|
214
|
-
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=
|
218
|
+
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4')
|
215
219
|
#
|
216
220
|
# generates:
|
217
221
|
#
|
218
222
|
# CREATE TABLE suppliers (
|
219
223
|
# id bigint auto_increment PRIMARY KEY
|
220
|
-
# ) ENGINE=InnoDB DEFAULT CHARSET=
|
224
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
221
225
|
#
|
222
226
|
# ====== Rename the primary key column
|
223
227
|
#
|
@@ -287,8 +291,8 @@ module ActiveRecord
|
|
287
291
|
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
|
288
292
|
#
|
289
293
|
# See also TableDefinition#column for details on how to create columns.
|
290
|
-
def create_table(table_name,
|
291
|
-
td = create_table_definition
|
294
|
+
def create_table(table_name, **options)
|
295
|
+
td = create_table_definition(table_name, options)
|
292
296
|
|
293
297
|
if options[:id] != false && !options[:as]
|
294
298
|
pk = options.fetch(:primary_key) do
|
@@ -298,7 +302,7 @@ module ActiveRecord
|
|
298
302
|
if pk.is_a?(Array)
|
299
303
|
td.primary_keys pk
|
300
304
|
else
|
301
|
-
td.primary_key pk, options.fetch(:id, :primary_key), options
|
305
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options.except(:comment)
|
302
306
|
end
|
303
307
|
end
|
304
308
|
|
@@ -317,7 +321,9 @@ module ActiveRecord
|
|
317
321
|
end
|
318
322
|
|
319
323
|
if supports_comments? && !supports_comments_in_create?
|
320
|
-
|
324
|
+
if table_comment = options[:comment].presence
|
325
|
+
change_table_comment(table_name, table_comment)
|
326
|
+
end
|
321
327
|
|
322
328
|
td.columns.each do |column|
|
323
329
|
change_column_comment(table_name, column.name, column.comment) if column.comment.present?
|
@@ -512,16 +518,20 @@ module ActiveRecord
|
|
512
518
|
# Available options are (none of these exists by default):
|
513
519
|
# * <tt>:limit</tt> -
|
514
520
|
# Requests a maximum column length. This is the number of characters for a <tt>:string</tt> column
|
515
|
-
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt
|
521
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt>, and <tt>:integer</tt> columns.
|
516
522
|
# This option is ignored by some backends.
|
517
523
|
# * <tt>:default</tt> -
|
518
524
|
# The column's default value. Use +nil+ for +NULL+.
|
519
525
|
# * <tt>:null</tt> -
|
520
526
|
# Allows or disallows +NULL+ values in the column.
|
521
527
|
# * <tt>:precision</tt> -
|
522
|
-
# Specifies the precision for the <tt>:decimal</tt
|
528
|
+
# Specifies the precision for the <tt>:decimal</tt>, <tt>:numeric</tt>,
|
529
|
+
# <tt>:datetime</tt>, and <tt>:time</tt> columns.
|
523
530
|
# * <tt>:scale</tt> -
|
524
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.
|
525
535
|
# * <tt>:comment</tt> -
|
526
536
|
# Specifies the comment for the column. This option is ignored by some backends.
|
527
537
|
#
|
@@ -575,7 +585,7 @@ module ActiveRecord
|
|
575
585
|
# # Defines a column with a database-specific type.
|
576
586
|
# add_column(:shapes, :triangle, 'polygon')
|
577
587
|
# # ALTER TABLE "shapes" ADD "triangle" polygon
|
578
|
-
def add_column(table_name, column_name, type, options
|
588
|
+
def add_column(table_name, column_name, type, **options)
|
579
589
|
at = create_alter_table table_name
|
580
590
|
at.add_column(column_name, type, options)
|
581
591
|
execute schema_creation.accept at
|
@@ -599,6 +609,7 @@ module ActiveRecord
|
|
599
609
|
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
600
610
|
# to provide these in a migration's +change+ method so it can be reverted.
|
601
611
|
# In that case, +type+ and +options+ will be used by #add_column.
|
612
|
+
# Indexes on the column are automatically removed.
|
602
613
|
def remove_column(table_name, column_name, type = nil, options = {})
|
603
614
|
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_for_alter(table_name, column_name, type, options)}"
|
604
615
|
end
|
@@ -760,6 +771,17 @@ module ActiveRecord
|
|
760
771
|
# CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
|
761
772
|
#
|
762
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].
|
763
785
|
def add_index(table_name, column_name, options = {})
|
764
786
|
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
|
765
787
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
|
@@ -783,6 +805,15 @@ module ActiveRecord
|
|
783
805
|
#
|
784
806
|
# remove_index :accounts, name: :by_branch_party
|
785
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].
|
786
817
|
def remove_index(table_name, options = {})
|
787
818
|
index_name = index_name_for_remove(table_name, options)
|
788
819
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
@@ -842,17 +873,17 @@ module ActiveRecord
|
|
842
873
|
# [<tt>:null</tt>]
|
843
874
|
# Whether the column allows nulls. Defaults to true.
|
844
875
|
#
|
845
|
-
# ====== Create a user_id bigint column
|
876
|
+
# ====== Create a user_id bigint column without an index
|
846
877
|
#
|
847
|
-
# add_reference(:products, :user)
|
878
|
+
# add_reference(:products, :user, index: false)
|
848
879
|
#
|
849
880
|
# ====== Create a user_id string column
|
850
881
|
#
|
851
882
|
# add_reference(:products, :user, type: :string)
|
852
883
|
#
|
853
|
-
# ====== Create supplier_id, supplier_type columns
|
884
|
+
# ====== Create supplier_id, supplier_type columns
|
854
885
|
#
|
855
|
-
# add_reference(:products, :supplier, polymorphic: true
|
886
|
+
# add_reference(:products, :supplier, polymorphic: true)
|
856
887
|
#
|
857
888
|
# ====== Create a supplier_id column with a unique index
|
858
889
|
#
|
@@ -880,7 +911,7 @@ module ActiveRecord
|
|
880
911
|
#
|
881
912
|
# ====== Remove the reference
|
882
913
|
#
|
883
|
-
# remove_reference(:products, :user, index:
|
914
|
+
# remove_reference(:products, :user, index: false)
|
884
915
|
#
|
885
916
|
# ====== Remove polymorphic reference
|
886
917
|
#
|
@@ -888,7 +919,7 @@ module ActiveRecord
|
|
888
919
|
#
|
889
920
|
# ====== Remove the reference with a foreign key
|
890
921
|
#
|
891
|
-
# remove_reference(:products, :user,
|
922
|
+
# remove_reference(:products, :user, foreign_key: true)
|
892
923
|
#
|
893
924
|
def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
|
894
925
|
if foreign_key
|
@@ -956,7 +987,7 @@ module ActiveRecord
|
|
956
987
|
# [<tt>:on_update</tt>]
|
957
988
|
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
958
989
|
# [<tt>:validate</tt>]
|
959
|
-
# (
|
990
|
+
# (PostgreSQL only) Specify whether or not the constraint should be validated. Defaults to +true+.
|
960
991
|
def add_foreign_key(from_table, to_table, options = {})
|
961
992
|
return unless supports_foreign_keys?
|
962
993
|
|
@@ -980,15 +1011,22 @@ module ActiveRecord
|
|
980
1011
|
#
|
981
1012
|
# remove_foreign_key :accounts, column: :owner_id
|
982
1013
|
#
|
1014
|
+
# Removes the foreign key on +accounts.owner_id+.
|
1015
|
+
#
|
1016
|
+
# remove_foreign_key :accounts, to_table: :owners
|
1017
|
+
#
|
983
1018
|
# Removes the foreign key named +special_fk_name+ on the +accounts+ table.
|
984
1019
|
#
|
985
1020
|
# remove_foreign_key :accounts, name: :special_fk_name
|
986
1021
|
#
|
987
|
-
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key
|
988
|
-
|
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)
|
989
1027
|
return unless supports_foreign_keys?
|
990
1028
|
|
991
|
-
fk_name_to_delete = foreign_key_for!(from_table,
|
1029
|
+
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
|
992
1030
|
|
993
1031
|
at = create_alter_table from_table
|
994
1032
|
at.drop_foreign_key fk_name_to_delete
|
@@ -1007,14 +1045,12 @@ module ActiveRecord
|
|
1007
1045
|
# # Checks to see if a foreign key with a custom name exists.
|
1008
1046
|
# foreign_key_exists?(:accounts, name: "special_fk_name")
|
1009
1047
|
#
|
1010
|
-
def foreign_key_exists?(from_table,
|
1011
|
-
foreign_key_for(from_table,
|
1048
|
+
def foreign_key_exists?(from_table, to_table = nil, **options)
|
1049
|
+
foreign_key_for(from_table, to_table: to_table, **options).present?
|
1012
1050
|
end
|
1013
1051
|
|
1014
1052
|
def foreign_key_column_for(table_name) # :nodoc:
|
1015
|
-
|
1016
|
-
suffix = Base.table_name_suffix
|
1017
|
-
name = table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
|
1053
|
+
name = strip_table_name_prefix_and_suffix(table_name)
|
1018
1054
|
"#{name.singularize}_id"
|
1019
1055
|
end
|
1020
1056
|
|
@@ -1025,8 +1061,8 @@ module ActiveRecord
|
|
1025
1061
|
options
|
1026
1062
|
end
|
1027
1063
|
|
1028
|
-
def dump_schema_information
|
1029
|
-
versions =
|
1064
|
+
def dump_schema_information # :nodoc:
|
1065
|
+
versions = schema_migration.all_versions
|
1030
1066
|
insert_versions_sql(versions) if versions.any?
|
1031
1067
|
end
|
1032
1068
|
|
@@ -1034,15 +1070,18 @@ module ActiveRecord
|
|
1034
1070
|
{ primary_key: true }
|
1035
1071
|
end
|
1036
1072
|
|
1037
|
-
def assume_migrated_upto_version(version, migrations_paths)
|
1038
|
-
|
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
|
+
|
1039
1080
|
version = version.to_i
|
1040
|
-
sm_table = quote_table_name(
|
1081
|
+
sm_table = quote_table_name(schema_migration.table_name)
|
1041
1082
|
|
1042
|
-
migrated =
|
1043
|
-
versions = migration_context.
|
1044
|
-
migration_context.parse_migration_filename(file).first.to_i
|
1045
|
-
end
|
1083
|
+
migrated = migration_context.get_all_versions
|
1084
|
+
versions = migration_context.migrations.map(&:version)
|
1046
1085
|
|
1047
1086
|
unless migrated.include?(version)
|
1048
1087
|
execute "INSERT INTO #{sm_table} (version) VALUES (#{quote(version)})"
|
@@ -1053,13 +1092,7 @@ module ActiveRecord
|
|
1053
1092
|
if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
|
1054
1093
|
raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
|
1055
1094
|
end
|
1056
|
-
|
1057
|
-
execute insert_versions_sql(inserting)
|
1058
|
-
else
|
1059
|
-
inserting.each do |v|
|
1060
|
-
execute insert_versions_sql(v)
|
1061
|
-
end
|
1062
|
-
end
|
1095
|
+
execute insert_versions_sql(inserting)
|
1063
1096
|
end
|
1064
1097
|
end
|
1065
1098
|
|
@@ -1085,7 +1118,7 @@ module ActiveRecord
|
|
1085
1118
|
if (0..6) === precision
|
1086
1119
|
column_type_sql << "(#{precision})"
|
1087
1120
|
else
|
1088
|
-
raise
|
1121
|
+
raise ArgumentError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6"
|
1089
1122
|
end
|
1090
1123
|
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
1091
1124
|
column_type_sql << "(#{limit})"
|
@@ -1115,6 +1148,10 @@ module ActiveRecord
|
|
1115
1148
|
def add_timestamps(table_name, options = {})
|
1116
1149
|
options[:null] = false if options[:null].nil?
|
1117
1150
|
|
1151
|
+
if !options.key?(:precision) && supports_datetime_with_precision?
|
1152
|
+
options[:precision] = 6
|
1153
|
+
end
|
1154
|
+
|
1118
1155
|
add_column table_name, :created_at, :datetime, options
|
1119
1156
|
add_column table_name, :updated_at, :datetime, options
|
1120
1157
|
end
|
@@ -1169,12 +1206,22 @@ module ActiveRecord
|
|
1169
1206
|
end
|
1170
1207
|
|
1171
1208
|
# Changes the comment for a table or removes it if +nil+.
|
1172
|
-
|
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)
|
1173
1215
|
raise NotImplementedError, "#{self.class} does not support changing table comments"
|
1174
1216
|
end
|
1175
1217
|
|
1176
1218
|
# Changes the comment for a column or removes it if +nil+.
|
1177
|
-
|
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)
|
1178
1225
|
raise NotImplementedError, "#{self.class} does not support changing column comments"
|
1179
1226
|
end
|
1180
1227
|
|
@@ -1276,7 +1323,7 @@ module ActiveRecord
|
|
1276
1323
|
end
|
1277
1324
|
|
1278
1325
|
def create_table_definition(*args)
|
1279
|
-
TableDefinition.new(*args)
|
1326
|
+
TableDefinition.new(self, *args)
|
1280
1327
|
end
|
1281
1328
|
|
1282
1329
|
def create_alter_table(name)
|
@@ -1310,6 +1357,12 @@ module ActiveRecord
|
|
1310
1357
|
{ column: column_names }
|
1311
1358
|
end
|
1312
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
|
+
|
1313
1366
|
def foreign_key_name(table_name, options)
|
1314
1367
|
options.fetch(:name) do
|
1315
1368
|
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
|
@@ -1319,14 +1372,14 @@ module ActiveRecord
|
|
1319
1372
|
end
|
1320
1373
|
end
|
1321
1374
|
|
1322
|
-
def foreign_key_for(from_table,
|
1375
|
+
def foreign_key_for(from_table, **options)
|
1323
1376
|
return unless supports_foreign_keys?
|
1324
|
-
foreign_keys(from_table).detect { |fk| fk.defined_for?
|
1377
|
+
foreign_keys(from_table).detect { |fk| fk.defined_for?(options) }
|
1325
1378
|
end
|
1326
1379
|
|
1327
|
-
def foreign_key_for!(from_table,
|
1328
|
-
foreign_key_for(from_table,
|
1329
|
-
raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{
|
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}")
|
1330
1383
|
end
|
1331
1384
|
|
1332
1385
|
def extract_foreign_key_action(specifier)
|
@@ -1352,11 +1405,37 @@ module ActiveRecord
|
|
1352
1405
|
default_or_changes
|
1353
1406
|
end
|
1354
1407
|
end
|
1408
|
+
alias :extract_new_comment_value :extract_new_default_value
|
1355
1409
|
|
1356
1410
|
def can_remove_index_by_name?(options)
|
1357
1411
|
options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
|
1358
1412
|
end
|
1359
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
|
+
|
1360
1439
|
def add_column_for_alter(table_name, column_name, type, options = {})
|
1361
1440
|
td = create_table_definition(table_name)
|
1362
1441
|
cd = td.new_column_definition(column_name, type, options)
|
@@ -1372,10 +1451,10 @@ module ActiveRecord
|
|
1372
1451
|
end
|
1373
1452
|
|
1374
1453
|
def insert_versions_sql(versions)
|
1375
|
-
sm_table = quote_table_name(
|
1454
|
+
sm_table = quote_table_name(schema_migration.table_name)
|
1376
1455
|
|
1377
1456
|
if versions.is_a?(Array)
|
1378
|
-
sql = "INSERT INTO #{sm_table} (version) VALUES\n"
|
1457
|
+
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
|
1379
1458
|
sql << versions.map { |v| "(#{quote(v)})" }.join(",\n")
|
1380
1459
|
sql << ";\n\n"
|
1381
1460
|
sql
|