activerecord 4.2.11.3 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1281 -1204
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record/aggregations.rb +35 -24
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +11 -9
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +49 -41
- data/lib/active_record/associations/collection_proxy.rb +67 -27
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency.rb +29 -19
- data/lib/active_record/associations/preloader/association.rb +46 -52
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/associations.rb +317 -209
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +68 -18
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_methods.rb +76 -47
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +49 -16
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +89 -107
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +113 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +363 -133
- data/lib/active_record/model_schema.rb +129 -41
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +121 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +69 -46
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +282 -115
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +79 -108
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +163 -81
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +176 -116
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping/default.rb +23 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +57 -43
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +30 -29
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +8 -4
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +59 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -14,15 +14,24 @@ module ActiveRecord
|
|
14
14
|
{}
|
15
15
|
end
|
16
16
|
|
17
|
+
def table_options(table_name)
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the table comment that's stored in database metadata.
|
22
|
+
def table_comment(table_name)
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
17
26
|
# Truncates a table alias according to the limits of the current adapter.
|
18
27
|
def table_alias_for(table_name)
|
19
28
|
table_name[0...table_alias_length].tr('.', '_')
|
20
29
|
end
|
21
30
|
|
22
31
|
# Returns the relation names useable to back Active Record models.
|
23
|
-
# For most adapters this means all tables and views.
|
32
|
+
# For most adapters this means all #tables and #views.
|
24
33
|
def data_sources
|
25
|
-
tables
|
34
|
+
tables | views
|
26
35
|
end
|
27
36
|
|
28
37
|
# Checks to see if the data source +name+ exists on the database.
|
@@ -33,6 +42,11 @@ module ActiveRecord
|
|
33
42
|
data_sources.include?(name.to_s)
|
34
43
|
end
|
35
44
|
|
45
|
+
# Returns an array of table names defined in the database.
|
46
|
+
def tables(name = nil)
|
47
|
+
raise NotImplementedError, "#tables is not implemented"
|
48
|
+
end
|
49
|
+
|
36
50
|
# Checks to see if the table +table_name+ exists on the database.
|
37
51
|
#
|
38
52
|
# table_exists?(:developers)
|
@@ -41,6 +55,19 @@ module ActiveRecord
|
|
41
55
|
tables.include?(table_name.to_s)
|
42
56
|
end
|
43
57
|
|
58
|
+
# Returns an array of view names defined in the database.
|
59
|
+
def views
|
60
|
+
raise NotImplementedError, "#views is not implemented"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Checks to see if the view +view_name+ exists on the database.
|
64
|
+
#
|
65
|
+
# view_exists?(:ebooks)
|
66
|
+
#
|
67
|
+
def view_exists?(view_name)
|
68
|
+
views.include?(view_name.to_s)
|
69
|
+
end
|
70
|
+
|
44
71
|
# Returns an array of indexes for the given table.
|
45
72
|
# def indexes(table_name, name = nil) end
|
46
73
|
|
@@ -60,18 +87,19 @@ module ActiveRecord
|
|
60
87
|
#
|
61
88
|
def index_exists?(table_name, column_name, options = {})
|
62
89
|
column_names = Array(column_name).map(&:to_s)
|
63
|
-
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, column: column_names)
|
64
90
|
checks = []
|
65
|
-
checks << lambda { |i| i.name == index_name }
|
66
91
|
checks << lambda { |i| i.columns == column_names }
|
67
92
|
checks << lambda { |i| i.unique } if options[:unique]
|
93
|
+
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
|
68
94
|
|
69
95
|
indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
|
70
96
|
end
|
71
97
|
|
72
98
|
# Returns an array of Column objects for the table specified by +table_name+.
|
73
99
|
# See the concrete implementation for details on the expected parameter values.
|
74
|
-
def columns(table_name)
|
100
|
+
def columns(table_name)
|
101
|
+
raise NotImplementedError, "#columns is not implemented"
|
102
|
+
end
|
75
103
|
|
76
104
|
# Checks to see if a column exists in a given table.
|
77
105
|
#
|
@@ -89,19 +117,32 @@ module ActiveRecord
|
|
89
117
|
#
|
90
118
|
def column_exists?(table_name, column_name, type = nil, options = {})
|
91
119
|
column_name = column_name.to_s
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
120
|
+
checks = []
|
121
|
+
checks << lambda { |c| c.name == column_name }
|
122
|
+
checks << lambda { |c| c.type == type } if type
|
123
|
+
(migration_keys - [:name]).each do |attr|
|
124
|
+
checks << lambda { |c| c.send(attr) == options[attr] } if options.key?(attr)
|
125
|
+
end
|
126
|
+
|
127
|
+
columns(table_name).any? { |c| checks.all? { |check| check[c] } }
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns just a table's primary key
|
131
|
+
def primary_key(table_name)
|
132
|
+
pks = primary_keys(table_name)
|
133
|
+
warn <<-WARNING.strip_heredoc if pks.count > 1
|
134
|
+
WARNING: Rails does not support composite primary key.
|
135
|
+
|
136
|
+
#{table_name} has composite primary key. Composite primary key is ignored.
|
137
|
+
WARNING
|
138
|
+
|
139
|
+
pks.first if pks.one?
|
99
140
|
end
|
100
141
|
|
101
142
|
# Creates a new table with the name +table_name+. +table_name+ may either
|
102
143
|
# be a String or a Symbol.
|
103
144
|
#
|
104
|
-
# There are two ways to work with
|
145
|
+
# There are two ways to work with #create_table. You can use the block
|
105
146
|
# form or the regular form, like this:
|
106
147
|
#
|
107
148
|
# === Block form
|
@@ -133,13 +174,16 @@ module ActiveRecord
|
|
133
174
|
# The +options+ hash can include the following keys:
|
134
175
|
# [<tt>:id</tt>]
|
135
176
|
# Whether to automatically add a primary key column. Defaults to true.
|
136
|
-
# Join tables for
|
177
|
+
# Join tables for {ActiveRecord::Base.has_and_belongs_to_many}[rdoc-ref:Associations::ClassMethods#has_and_belongs_to_many] should set it to false.
|
178
|
+
#
|
179
|
+
# A Symbol can be used to specify the type of the generated primary key column.
|
137
180
|
# [<tt>:primary_key</tt>]
|
138
181
|
# The name of the primary key, if one is to be added automatically.
|
139
182
|
# Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
|
140
183
|
#
|
141
184
|
# Note that Active Record models will automatically detect their
|
142
|
-
# primary key. This can be avoided by using
|
185
|
+
# primary key. This can be avoided by using
|
186
|
+
# {self.primary_key=}[rdoc-ref:AttributeMethods::PrimaryKey::ClassMethods#primary_key=] on the model
|
143
187
|
# to define the key explicitly.
|
144
188
|
#
|
145
189
|
# [<tt>:options</tt>]
|
@@ -161,7 +205,7 @@ module ActiveRecord
|
|
161
205
|
# generates:
|
162
206
|
#
|
163
207
|
# CREATE TABLE suppliers (
|
164
|
-
# id int
|
208
|
+
# id int auto_increment PRIMARY KEY
|
165
209
|
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
166
210
|
#
|
167
211
|
# ====== Rename the primary key column
|
@@ -173,10 +217,23 @@ module ActiveRecord
|
|
173
217
|
# generates:
|
174
218
|
#
|
175
219
|
# CREATE TABLE objects (
|
176
|
-
# guid int
|
220
|
+
# guid int auto_increment PRIMARY KEY,
|
177
221
|
# name varchar(80)
|
178
222
|
# )
|
179
223
|
#
|
224
|
+
# ====== Change the primary key column type
|
225
|
+
#
|
226
|
+
# create_table(:tags, id: :string) do |t|
|
227
|
+
# t.column :label, :string
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
# generates:
|
231
|
+
#
|
232
|
+
# CREATE TABLE tags (
|
233
|
+
# id varchar PRIMARY KEY,
|
234
|
+
# label varchar
|
235
|
+
# )
|
236
|
+
#
|
180
237
|
# ====== Do not add a primary key column
|
181
238
|
#
|
182
239
|
# create_table(:categories_suppliers, id: false) do |t|
|
@@ -202,20 +259,24 @@ module ActiveRecord
|
|
202
259
|
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
|
203
260
|
#
|
204
261
|
# See also TableDefinition#column for details on how to create columns.
|
205
|
-
def create_table(table_name,
|
206
|
-
td = create_table_definition table_name, options[:temporary], options[:options], options[:as]
|
262
|
+
def create_table(table_name, comment: nil, **options)
|
263
|
+
td = create_table_definition table_name, options[:temporary], options[:options], options[:as], comment: comment
|
207
264
|
|
208
265
|
if options[:id] != false && !options[:as]
|
209
266
|
pk = options.fetch(:primary_key) do
|
210
267
|
Base.get_primary_key table_name.to_s.singularize
|
211
268
|
end
|
212
269
|
|
213
|
-
|
270
|
+
if pk.is_a?(Array)
|
271
|
+
td.primary_keys pk
|
272
|
+
else
|
273
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options
|
274
|
+
end
|
214
275
|
end
|
215
276
|
|
216
277
|
yield td if block_given?
|
217
278
|
|
218
|
-
if options[:force] &&
|
279
|
+
if options[:force] && data_source_exists?(table_name)
|
219
280
|
drop_table(table_name, options)
|
220
281
|
end
|
221
282
|
|
@@ -227,8 +288,12 @@ module ActiveRecord
|
|
227
288
|
end
|
228
289
|
end
|
229
290
|
|
230
|
-
|
231
|
-
|
291
|
+
if supports_comments? && !supports_comments_in_create?
|
292
|
+
change_table_comment(table_name, comment) if comment
|
293
|
+
|
294
|
+
td.columns.each do |column|
|
295
|
+
change_column_comment(table_name, column.name, column.comment) if column.comment
|
296
|
+
end
|
232
297
|
end
|
233
298
|
|
234
299
|
result
|
@@ -253,7 +318,7 @@ module ActiveRecord
|
|
253
318
|
# Set to true to drop the table before creating it.
|
254
319
|
# Defaults to false.
|
255
320
|
#
|
256
|
-
# Note that
|
321
|
+
# Note that #create_join_table does not create any indices by default; you can use
|
257
322
|
# its block form to do so yourself:
|
258
323
|
#
|
259
324
|
# create_join_table :products, :categories do |t|
|
@@ -277,22 +342,23 @@ module ActiveRecord
|
|
277
342
|
|
278
343
|
column_options = options.delete(:column_options) || {}
|
279
344
|
column_options.reverse_merge!(null: false)
|
345
|
+
type = column_options.delete(:type) || :integer
|
280
346
|
|
281
347
|
t1_column, t2_column = [table_1, table_2].map{ |t| t.to_s.singularize.foreign_key }
|
282
348
|
|
283
349
|
create_table(join_table_name, options.merge!(id: false)) do |td|
|
284
|
-
td.
|
285
|
-
td.
|
350
|
+
td.send type, t1_column, column_options
|
351
|
+
td.send type, t2_column, column_options
|
286
352
|
yield td if block_given?
|
287
353
|
end
|
288
354
|
end
|
289
355
|
|
290
356
|
# Drops the join table specified by the given arguments.
|
291
|
-
# See
|
357
|
+
# See #create_join_table for details.
|
292
358
|
#
|
293
359
|
# Although this command ignores the block if one is given, it can be helpful
|
294
360
|
# to provide one in a migration's +change+ method so it can be reverted.
|
295
|
-
# In that case, the block will be used by create_join_table.
|
361
|
+
# In that case, the block will be used by #create_join_table.
|
296
362
|
def drop_join_table(table_1, table_2, options = {})
|
297
363
|
join_table_name = find_join_table_name(table_1, table_2, options)
|
298
364
|
drop_table(join_table_name)
|
@@ -310,7 +376,7 @@ module ActiveRecord
|
|
310
376
|
# [<tt>:bulk</tt>]
|
311
377
|
# Set this to true to make this a bulk alter query, such as
|
312
378
|
#
|
313
|
-
# ALTER TABLE `users` ADD COLUMN age INT
|
379
|
+
# ALTER TABLE `users` ADD COLUMN age INT, ADD COLUMN birthdate DATETIME ...
|
314
380
|
#
|
315
381
|
# Defaults to false.
|
316
382
|
#
|
@@ -391,16 +457,90 @@ module ActiveRecord
|
|
391
457
|
# [<tt>:force</tt>]
|
392
458
|
# Set to +:cascade+ to drop dependent objects as well.
|
393
459
|
# Defaults to false.
|
460
|
+
# [<tt>:if_exists</tt>]
|
461
|
+
# Set to +true+ to only drop the table if it exists.
|
462
|
+
# Defaults to false.
|
394
463
|
#
|
395
464
|
# Although this command ignores most +options+ and the block if one is given,
|
396
465
|
# it can be helpful to provide these in a migration's +change+ method so it can be reverted.
|
397
|
-
# In that case, +options+ and the block will be used by create_table.
|
466
|
+
# In that case, +options+ and the block will be used by #create_table.
|
398
467
|
def drop_table(table_name, options = {})
|
399
|
-
execute "DROP TABLE #{quote_table_name(table_name)}"
|
468
|
+
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
|
400
469
|
end
|
401
470
|
|
402
|
-
#
|
403
|
-
#
|
471
|
+
# Add a new +type+ column named +column_name+ to +table_name+.
|
472
|
+
#
|
473
|
+
# The +type+ parameter is normally one of the migrations native types,
|
474
|
+
# which is one of the following:
|
475
|
+
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
476
|
+
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:numeric</tt>,
|
477
|
+
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
478
|
+
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
479
|
+
#
|
480
|
+
# You may use a type not in this list as long as it is supported by your
|
481
|
+
# database (for example, "polygon" in MySQL), but this will not be database
|
482
|
+
# agnostic and should usually be avoided.
|
483
|
+
#
|
484
|
+
# Available options are (none of these exists by default):
|
485
|
+
# * <tt>:limit</tt> -
|
486
|
+
# Requests a maximum column length. This is number of characters for a <tt>:string</tt> column
|
487
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt> and <tt>:integer</tt> columns.
|
488
|
+
# * <tt>:default</tt> -
|
489
|
+
# The column's default value. Use nil for NULL.
|
490
|
+
# * <tt>:null</tt> -
|
491
|
+
# Allows or disallows +NULL+ values in the column. This option could
|
492
|
+
# have been named <tt>:null_allowed</tt>.
|
493
|
+
# * <tt>:precision</tt> -
|
494
|
+
# Specifies the precision for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
|
495
|
+
# * <tt>:scale</tt> -
|
496
|
+
# Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
|
497
|
+
#
|
498
|
+
# Note: The precision is the total number of significant digits
|
499
|
+
# and the scale is the number of digits that can be stored following
|
500
|
+
# the decimal point. For example, the number 123.45 has a precision of 5
|
501
|
+
# and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
|
502
|
+
# range from -999.99 to 999.99.
|
503
|
+
#
|
504
|
+
# Please be aware of different RDBMS implementations behavior with
|
505
|
+
# <tt>:decimal</tt> columns:
|
506
|
+
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
|
507
|
+
# <tt>:precision</tt>, and makes no comments about the requirements of
|
508
|
+
# <tt>:precision</tt>.
|
509
|
+
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
|
510
|
+
# Default is (10,0).
|
511
|
+
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
512
|
+
# <tt>:scale</tt> [0..infinity]. No default.
|
513
|
+
# * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
|
514
|
+
# but the maximum supported <tt>:precision</tt> is 16. No default.
|
515
|
+
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
516
|
+
# Default is (38,0).
|
517
|
+
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
518
|
+
# Default unknown.
|
519
|
+
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
520
|
+
# Default (38,0).
|
521
|
+
#
|
522
|
+
# == Examples
|
523
|
+
#
|
524
|
+
# add_column(:users, :picture, :binary, limit: 2.megabytes)
|
525
|
+
# # ALTER TABLE "users" ADD "picture" blob(2097152)
|
526
|
+
#
|
527
|
+
# add_column(:articles, :status, :string, limit: 20, default: 'draft', null: false)
|
528
|
+
# # ALTER TABLE "articles" ADD "status" varchar(20) DEFAULT 'draft' NOT NULL
|
529
|
+
#
|
530
|
+
# add_column(:answers, :bill_gates_money, :decimal, precision: 15, scale: 2)
|
531
|
+
# # ALTER TABLE "answers" ADD "bill_gates_money" decimal(15,2)
|
532
|
+
#
|
533
|
+
# add_column(:measurements, :sensor_reading, :decimal, precision: 30, scale: 20)
|
534
|
+
# # ALTER TABLE "measurements" ADD "sensor_reading" decimal(30,20)
|
535
|
+
#
|
536
|
+
# # While :scale defaults to zero on most databases, it
|
537
|
+
# # probably wouldn't hurt to include it.
|
538
|
+
# add_column(:measurements, :huge_integer, :decimal, precision: 30)
|
539
|
+
# # ALTER TABLE "measurements" ADD "huge_integer" decimal(30)
|
540
|
+
#
|
541
|
+
# # Defines a column with a database-specific type.
|
542
|
+
# add_column(:shapes, :triangle, 'polygon')
|
543
|
+
# # ALTER TABLE "shapes" ADD "triangle" polygon
|
404
544
|
def add_column(table_name, column_name, type, options = {})
|
405
545
|
at = create_alter_table table_name
|
406
546
|
at.add_column(column_name, type, options)
|
@@ -448,11 +588,16 @@ module ActiveRecord
|
|
448
588
|
#
|
449
589
|
# change_column_default(:users, :email, nil)
|
450
590
|
#
|
451
|
-
|
591
|
+
# Passing a hash containing +:from+ and +:to+ will make this change
|
592
|
+
# reversible in migration:
|
593
|
+
#
|
594
|
+
# change_column_default(:posts, :state, from: nil, to: "draft")
|
595
|
+
#
|
596
|
+
def change_column_default(table_name, column_name, default_or_changes)
|
452
597
|
raise NotImplementedError, "change_column_default is not implemented"
|
453
598
|
end
|
454
599
|
|
455
|
-
# Sets or removes a
|
600
|
+
# Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag
|
456
601
|
# indicates whether the value can be +NULL+. For example
|
457
602
|
#
|
458
603
|
# change_column_null(:users, :nickname, false)
|
@@ -464,7 +609,7 @@ module ActiveRecord
|
|
464
609
|
# allows them to be +NULL+ (drops the constraint).
|
465
610
|
#
|
466
611
|
# The method accepts an optional fourth argument to replace existing
|
467
|
-
#
|
612
|
+
# <tt>NULL</tt>s with some other value. Use that one when enabling the
|
468
613
|
# constraint if needed, since otherwise those rows would not be valid.
|
469
614
|
#
|
470
615
|
# Please note the fourth argument does not set a column's default.
|
@@ -518,6 +663,8 @@ module ActiveRecord
|
|
518
663
|
#
|
519
664
|
# CREATE INDEX by_name ON accounts(name(10))
|
520
665
|
#
|
666
|
+
# ====== Creating an index with specific key lengths for multiple keys
|
667
|
+
#
|
521
668
|
# add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
|
522
669
|
#
|
523
670
|
# generates:
|
@@ -565,7 +712,7 @@ module ActiveRecord
|
|
565
712
|
#
|
566
713
|
# CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
|
567
714
|
#
|
568
|
-
# Note: only supported by MySQL.
|
715
|
+
# Note: only supported by MySQL.
|
569
716
|
def add_index(table_name, column_name, options = {})
|
570
717
|
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
|
571
718
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
|
@@ -573,15 +720,15 @@ module ActiveRecord
|
|
573
720
|
|
574
721
|
# Removes the given index from the table.
|
575
722
|
#
|
576
|
-
# Removes the +
|
723
|
+
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
577
724
|
#
|
578
|
-
# remove_index :accounts, :
|
725
|
+
# remove_index :accounts, :branch_id
|
579
726
|
#
|
580
|
-
# Removes the index
|
727
|
+
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
581
728
|
#
|
582
729
|
# remove_index :accounts, column: :branch_id
|
583
730
|
#
|
584
|
-
# Removes the index
|
731
|
+
# Removes the index on +branch_id+ and +party_id+ in the +accounts+ table if exactly one such index exists.
|
585
732
|
#
|
586
733
|
# remove_index :accounts, column: [:branch_id, :party_id]
|
587
734
|
#
|
@@ -590,10 +737,7 @@ module ActiveRecord
|
|
590
737
|
# remove_index :accounts, name: :by_branch_party
|
591
738
|
#
|
592
739
|
def remove_index(table_name, options = {})
|
593
|
-
|
594
|
-
end
|
595
|
-
|
596
|
-
def remove_index!(table_name, index_name) #:nodoc:
|
740
|
+
index_name = index_name_for_remove(table_name, options)
|
597
741
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
598
742
|
end
|
599
743
|
|
@@ -640,17 +784,20 @@ module ActiveRecord
|
|
640
784
|
# Adds a reference. The reference column is an integer by default,
|
641
785
|
# the <tt>:type</tt> option can be used to specify a different type.
|
642
786
|
# Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
|
643
|
-
#
|
787
|
+
# #add_reference and #add_belongs_to are acceptable.
|
644
788
|
#
|
645
789
|
# The +options+ hash can include the following keys:
|
646
790
|
# [<tt>:type</tt>]
|
647
791
|
# The reference column type. Defaults to +:integer+.
|
648
792
|
# [<tt>:index</tt>]
|
649
|
-
# Add an appropriate index. Defaults to false.
|
793
|
+
# Add an appropriate index. Defaults to false.
|
794
|
+
# See #add_index for usage of this option.
|
650
795
|
# [<tt>:foreign_key</tt>]
|
651
|
-
# Add an appropriate foreign key. Defaults to false.
|
796
|
+
# Add an appropriate foreign key constraint. Defaults to false.
|
652
797
|
# [<tt>:polymorphic</tt>]
|
653
|
-
#
|
798
|
+
# Whether an additional +_type+ column should be added. Defaults to false.
|
799
|
+
# [<tt>:null</tt>]
|
800
|
+
# Whether the column allows nulls. Defaults to true.
|
654
801
|
#
|
655
802
|
# ====== Create a user_id integer column
|
656
803
|
#
|
@@ -664,28 +811,29 @@ module ActiveRecord
|
|
664
811
|
#
|
665
812
|
# add_reference(:products, :supplier, polymorphic: true, index: true)
|
666
813
|
#
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
814
|
+
# ====== Create a supplier_id column with a unique index
|
815
|
+
#
|
816
|
+
# add_reference(:products, :supplier, index: { unique: true })
|
817
|
+
#
|
818
|
+
# ====== Create a supplier_id column with a named index
|
819
|
+
#
|
820
|
+
# add_reference(:products, :supplier, index: { name: "my_supplier_index" })
|
821
|
+
#
|
822
|
+
# ====== Create a supplier_id column and appropriate foreign key
|
823
|
+
#
|
824
|
+
# add_reference(:products, :supplier, foreign_key: true)
|
825
|
+
#
|
826
|
+
# ====== Create a supplier_id column and a foreign key to the firms table
|
827
|
+
#
|
828
|
+
# add_reference(:products, :supplier, foreign_key: {to_table: :firms})
|
829
|
+
#
|
830
|
+
def add_reference(table_name, *args)
|
831
|
+
ReferenceDefinition.new(*args).add_to(update_table_definition(table_name, self))
|
684
832
|
end
|
685
833
|
alias :add_belongs_to :add_reference
|
686
834
|
|
687
835
|
# Removes the reference(s). Also removes a +type+ column if one exists.
|
688
|
-
#
|
836
|
+
# #remove_reference and #remove_belongs_to are acceptable.
|
689
837
|
#
|
690
838
|
# ====== Remove the reference
|
691
839
|
#
|
@@ -701,8 +849,8 @@ module ActiveRecord
|
|
701
849
|
#
|
702
850
|
def remove_reference(table_name, ref_name, options = {})
|
703
851
|
if options[:foreign_key]
|
704
|
-
|
705
|
-
remove_foreign_key(table_name,
|
852
|
+
reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
853
|
+
remove_foreign_key(table_name, reference_name)
|
706
854
|
end
|
707
855
|
|
708
856
|
remove_column(table_name, "#{ref_name}_id")
|
@@ -711,7 +859,7 @@ module ActiveRecord
|
|
711
859
|
alias :remove_belongs_to :remove_reference
|
712
860
|
|
713
861
|
# Returns an array of foreign keys for the given table.
|
714
|
-
# The foreign keys are represented as
|
862
|
+
# The foreign keys are represented as ForeignKeyDefinition objects.
|
715
863
|
def foreign_keys(table_name)
|
716
864
|
raise NotImplementedError, "foreign_keys is not implemented"
|
717
865
|
end
|
@@ -729,11 +877,11 @@ module ActiveRecord
|
|
729
877
|
#
|
730
878
|
# generates:
|
731
879
|
#
|
732
|
-
# ALTER TABLE "articles" ADD CONSTRAINT
|
880
|
+
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
733
881
|
#
|
734
882
|
# ====== Creating a foreign key on a specific column
|
735
883
|
#
|
736
|
-
# add_foreign_key :articles, :users, column: :author_id, primary_key:
|
884
|
+
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
737
885
|
#
|
738
886
|
# generates:
|
739
887
|
#
|
@@ -745,7 +893,7 @@ module ActiveRecord
|
|
745
893
|
#
|
746
894
|
# generates:
|
747
895
|
#
|
748
|
-
# ALTER TABLE "articles" ADD CONSTRAINT
|
896
|
+
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
|
749
897
|
#
|
750
898
|
# The +options+ hash can include the following keys:
|
751
899
|
# [<tt>:column</tt>]
|
@@ -755,28 +903,23 @@ module ActiveRecord
|
|
755
903
|
# [<tt>:name</tt>]
|
756
904
|
# The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
|
757
905
|
# [<tt>:on_delete</tt>]
|
758
|
-
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade
|
906
|
+
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
759
907
|
# [<tt>:on_update</tt>]
|
760
|
-
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade
|
908
|
+
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
761
909
|
def add_foreign_key(from_table, to_table, options = {})
|
762
910
|
return unless supports_foreign_keys?
|
763
911
|
|
764
|
-
options
|
765
|
-
|
766
|
-
options = {
|
767
|
-
column: options[:column],
|
768
|
-
primary_key: options[:primary_key],
|
769
|
-
name: foreign_key_name(from_table, options),
|
770
|
-
on_delete: options[:on_delete],
|
771
|
-
on_update: options[:on_update]
|
772
|
-
}
|
912
|
+
options = foreign_key_options(from_table, to_table, options)
|
773
913
|
at = create_alter_table from_table
|
774
914
|
at.add_foreign_key to_table, options
|
775
915
|
|
776
916
|
execute schema_creation.accept(at)
|
777
917
|
end
|
778
918
|
|
779
|
-
# Removes the given foreign key from the table.
|
919
|
+
# Removes the given foreign key from the table. Any option parameters provided
|
920
|
+
# will be used to re-add the foreign key in case of a migration rollback.
|
921
|
+
# It is recommended that you provide any options used when creating the foreign
|
922
|
+
# key so that the migration can be reverted properly.
|
780
923
|
#
|
781
924
|
# Removes the foreign key on +accounts.branch_id+.
|
782
925
|
#
|
@@ -790,24 +933,11 @@ module ActiveRecord
|
|
790
933
|
#
|
791
934
|
# remove_foreign_key :accounts, name: :special_fk_name
|
792
935
|
#
|
936
|
+
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key.
|
793
937
|
def remove_foreign_key(from_table, options_or_to_table = {})
|
794
938
|
return unless supports_foreign_keys?
|
795
939
|
|
796
|
-
|
797
|
-
options = options_or_to_table
|
798
|
-
else
|
799
|
-
options = { column: foreign_key_column_for(options_or_to_table) }
|
800
|
-
end
|
801
|
-
|
802
|
-
fk_name_to_delete = options.fetch(:name) do
|
803
|
-
fk_to_delete = foreign_keys(from_table).detect {|fk| fk.column == options[:column].to_s }
|
804
|
-
|
805
|
-
if fk_to_delete
|
806
|
-
fk_to_delete.name
|
807
|
-
else
|
808
|
-
raise ArgumentError, "Table '#{from_table}' has no foreign key on column '#{options[:column]}'"
|
809
|
-
end
|
810
|
-
end
|
940
|
+
fk_name_to_delete = foreign_key_for!(from_table, options_or_to_table).name
|
811
941
|
|
812
942
|
at = create_alter_table from_table
|
813
943
|
at.drop_foreign_key fk_name_to_delete
|
@@ -815,6 +945,31 @@ module ActiveRecord
|
|
815
945
|
execute schema_creation.accept(at)
|
816
946
|
end
|
817
947
|
|
948
|
+
# Checks to see if a foreign key exists on a table for a given foreign key definition.
|
949
|
+
#
|
950
|
+
# # Check a foreign key exists
|
951
|
+
# foreign_key_exists?(:accounts, :branches)
|
952
|
+
#
|
953
|
+
# # Check a foreign key on a specified column exists
|
954
|
+
# foreign_key_exists?(:accounts, column: :owner_id)
|
955
|
+
#
|
956
|
+
# # Check a foreign key with a custom name exists
|
957
|
+
# foreign_key_exists?(:accounts, name: "special_fk_name")
|
958
|
+
#
|
959
|
+
def foreign_key_exists?(from_table, options_or_to_table = {})
|
960
|
+
foreign_key_for(from_table, options_or_to_table).present?
|
961
|
+
end
|
962
|
+
|
963
|
+
def foreign_key_for(from_table, options_or_to_table = {}) # :nodoc:
|
964
|
+
return unless supports_foreign_keys?
|
965
|
+
foreign_keys(from_table).detect {|fk| fk.defined_for? options_or_to_table }
|
966
|
+
end
|
967
|
+
|
968
|
+
def foreign_key_for!(from_table, options_or_to_table = {}) # :nodoc:
|
969
|
+
foreign_key_for(from_table, options_or_to_table) or \
|
970
|
+
raise ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}"
|
971
|
+
end
|
972
|
+
|
818
973
|
def foreign_key_column_for(table_name) # :nodoc:
|
819
974
|
prefix = Base.table_name_prefix
|
820
975
|
suffix = Base.table_name_suffix
|
@@ -822,12 +977,31 @@ module ActiveRecord
|
|
822
977
|
"#{name.singularize}_id"
|
823
978
|
end
|
824
979
|
|
980
|
+
def foreign_key_options(from_table, to_table, options) # :nodoc:
|
981
|
+
options = options.dup
|
982
|
+
options[:column] ||= foreign_key_column_for(to_table)
|
983
|
+
options[:name] ||= foreign_key_name(from_table, options)
|
984
|
+
options
|
985
|
+
end
|
986
|
+
|
825
987
|
def dump_schema_information #:nodoc:
|
988
|
+
versions = ActiveRecord::SchemaMigration.order('version').pluck(:version)
|
989
|
+
insert_versions_sql(versions)
|
990
|
+
end
|
991
|
+
|
992
|
+
def insert_versions_sql(versions) # :nodoc:
|
826
993
|
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
827
994
|
|
828
|
-
|
829
|
-
"INSERT INTO #{sm_table} (version) VALUES
|
830
|
-
|
995
|
+
if supports_multi_insert?
|
996
|
+
sql = "INSERT INTO #{sm_table} (version) VALUES "
|
997
|
+
sql << versions.map {|v| "('#{v}')" }.join(', ')
|
998
|
+
sql << ";\n\n"
|
999
|
+
sql
|
1000
|
+
else
|
1001
|
+
versions.map { |version|
|
1002
|
+
"INSERT INTO #{sm_table} (version) VALUES ('#{version}');"
|
1003
|
+
}.join "\n\n"
|
1004
|
+
end
|
831
1005
|
end
|
832
1006
|
|
833
1007
|
# Should not be called normally, but this operation is non-destructive.
|
@@ -836,28 +1010,35 @@ module ActiveRecord
|
|
836
1010
|
ActiveRecord::SchemaMigration.create_table
|
837
1011
|
end
|
838
1012
|
|
839
|
-
def
|
1013
|
+
def initialize_internal_metadata_table
|
1014
|
+
ActiveRecord::InternalMetadata.create_table
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def internal_string_options_for_primary_key # :nodoc:
|
1018
|
+
{ primary_key: true }
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def assume_migrated_upto_version(version, migrations_paths)
|
840
1022
|
migrations_paths = Array(migrations_paths)
|
841
1023
|
version = version.to_i
|
842
1024
|
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
843
1025
|
|
844
1026
|
migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
|
845
|
-
|
846
|
-
|
1027
|
+
paths = migrations_paths.map {|p| "#{p}/[0-9]*_*.rb" }
|
1028
|
+
versions = Dir[*paths].map do |filename|
|
1029
|
+
filename.split('/').last.split('_').first.to_i
|
847
1030
|
end
|
848
1031
|
|
849
1032
|
unless migrated.include?(version)
|
850
1033
|
execute "INSERT INTO #{sm_table} (version) VALUES ('#{version}')"
|
851
1034
|
end
|
852
1035
|
|
853
|
-
|
854
|
-
|
855
|
-
if
|
856
|
-
raise "Duplicate migration #{
|
857
|
-
elsif v < version
|
858
|
-
execute "INSERT INTO #{sm_table} (version) VALUES ('#{v}')"
|
859
|
-
inserted << v
|
1036
|
+
inserting = (versions - migrated).select {|v| v < version}
|
1037
|
+
if inserting.any?
|
1038
|
+
if (duplicate = inserting.detect {|v| inserting.count(v) > 1})
|
1039
|
+
raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
|
860
1040
|
end
|
1041
|
+
execute insert_versions_sql(inserting)
|
861
1042
|
end
|
862
1043
|
end
|
863
1044
|
|
@@ -878,6 +1059,12 @@ module ActiveRecord
|
|
878
1059
|
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
|
879
1060
|
end
|
880
1061
|
|
1062
|
+
elsif [:datetime, :time].include?(type) && precision ||= native[:precision]
|
1063
|
+
if (0..6) === precision
|
1064
|
+
column_type_sql << "(#{precision})"
|
1065
|
+
else
|
1066
|
+
raise(ActiveRecordError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6")
|
1067
|
+
end
|
881
1068
|
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
882
1069
|
column_type_sql << "(#{limit})"
|
883
1070
|
end
|
@@ -898,14 +1085,14 @@ module ActiveRecord
|
|
898
1085
|
columns
|
899
1086
|
end
|
900
1087
|
|
901
|
-
include TimestampDefaultDeprecation
|
902
1088
|
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
903
|
-
# Additional options (like
|
1089
|
+
# Additional options (like +:null+) are forwarded to #add_column.
|
904
1090
|
#
|
905
|
-
# add_timestamps(:suppliers, null:
|
1091
|
+
# add_timestamps(:suppliers, null: true)
|
906
1092
|
#
|
907
1093
|
def add_timestamps(table_name, options = {})
|
908
|
-
|
1094
|
+
options[:null] = false if options[:null].nil?
|
1095
|
+
|
909
1096
|
add_column table_name, :created_at, :datetime, options
|
910
1097
|
add_column table_name, :updated_at, :datetime, options
|
911
1098
|
end
|
@@ -923,15 +1110,19 @@ module ActiveRecord
|
|
923
1110
|
Table.new(table_name, base)
|
924
1111
|
end
|
925
1112
|
|
926
|
-
def add_index_options(table_name, column_name,
|
927
|
-
|
928
|
-
|
1113
|
+
def add_index_options(table_name, column_name, comment: nil, **options) # :nodoc:
|
1114
|
+
if column_name.is_a?(String) && /\W/ === column_name
|
1115
|
+
column_names = column_name
|
1116
|
+
else
|
1117
|
+
column_names = Array(column_name)
|
1118
|
+
end
|
929
1119
|
|
930
1120
|
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
931
1121
|
|
932
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
933
1122
|
index_type = options[:type].to_s if options.key?(:type)
|
1123
|
+
index_type ||= options[:unique] ? "UNIQUE" : ""
|
934
1124
|
index_name = options[:name].to_s if options.key?(:name)
|
1125
|
+
index_name ||= index_name(table_name, index_name_options(column_names))
|
935
1126
|
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
936
1127
|
|
937
1128
|
if options.key?(:algorithm)
|
@@ -949,12 +1140,26 @@ module ActiveRecord
|
|
949
1140
|
if index_name.length > max_index_length
|
950
1141
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
951
1142
|
end
|
952
|
-
if
|
1143
|
+
if data_source_exists?(table_name) && index_name_exists?(table_name, index_name, false)
|
953
1144
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
954
1145
|
end
|
955
1146
|
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
956
1147
|
|
957
|
-
[index_name, index_type, index_columns, index_options, algorithm, using]
|
1148
|
+
[index_name, index_type, index_columns, index_options, algorithm, using, comment]
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
def options_include_default?(options)
|
1152
|
+
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
# Changes the comment for a table or removes it if +nil+.
|
1156
|
+
def change_table_comment(table_name, comment)
|
1157
|
+
raise NotImplementedError, "#{self.class} does not support changing table comments"
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
# Changes the comment for a column or removes it if +nil+.
|
1161
|
+
def change_column_comment(table_name, column_name, comment) #:nodoc:
|
1162
|
+
raise NotImplementedError, "#{self.class} does not support changing column comments"
|
958
1163
|
end
|
959
1164
|
|
960
1165
|
protected
|
@@ -973,6 +1178,8 @@ module ActiveRecord
|
|
973
1178
|
|
974
1179
|
# Overridden by the MySQL adapter for supporting index lengths
|
975
1180
|
def quoted_columns_for_index(column_names, options = {})
|
1181
|
+
return [column_names] if column_names.is_a?(String)
|
1182
|
+
|
976
1183
|
option_strings = Hash[column_names.map {|name| [name, '']}]
|
977
1184
|
|
978
1185
|
# add index sort order if supported
|
@@ -983,26 +1190,38 @@ module ActiveRecord
|
|
983
1190
|
column_names.map {|name| quote_column_name(name) + option_strings[name]}
|
984
1191
|
end
|
985
1192
|
|
986
|
-
def options_include_default?(options)
|
987
|
-
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
988
|
-
end
|
989
|
-
|
990
1193
|
def index_name_for_remove(table_name, options = {})
|
991
|
-
|
1194
|
+
return options[:name] if can_remove_index_by_name?(options)
|
992
1195
|
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
options_without_column.delete :column
|
997
|
-
index_name_without_column = index_name(table_name, options_without_column)
|
1196
|
+
# if the adapter doesn't support the indexes call the best we can do
|
1197
|
+
# is return the default index name for the options provided
|
1198
|
+
return index_name(table_name, options) unless respond_to?(:indexes)
|
998
1199
|
|
999
|
-
|
1000
|
-
|
1200
|
+
checks = []
|
1201
|
+
|
1202
|
+
if options.is_a?(Hash)
|
1203
|
+
checks << lambda { |i| i.name == options[:name].to_s } if options.key?(:name)
|
1204
|
+
column_names = Array(options[:column]).map(&:to_s)
|
1205
|
+
else
|
1206
|
+
column_names = Array(options).map(&:to_s)
|
1207
|
+
end
|
1001
1208
|
|
1002
|
-
|
1209
|
+
if column_names.any?
|
1210
|
+
checks << lambda { |i| i.columns.join('_and_') == column_names.join('_and_') }
|
1003
1211
|
end
|
1004
1212
|
|
1005
|
-
|
1213
|
+
raise ArgumentError "No name or columns specified" if checks.none?
|
1214
|
+
|
1215
|
+
matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }
|
1216
|
+
|
1217
|
+
if matching_indexes.count > 1
|
1218
|
+
raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. " \
|
1219
|
+
"Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
|
1220
|
+
elsif matching_indexes.none?
|
1221
|
+
raise ArgumentError, "No indexes found on #{table_name} with the options provided."
|
1222
|
+
else
|
1223
|
+
matching_indexes.first.name
|
1224
|
+
end
|
1006
1225
|
end
|
1007
1226
|
|
1008
1227
|
def rename_table_indexes(table_name, new_name)
|
@@ -1028,12 +1247,20 @@ module ActiveRecord
|
|
1028
1247
|
end
|
1029
1248
|
|
1030
1249
|
private
|
1031
|
-
def create_table_definition(
|
1032
|
-
TableDefinition.new
|
1250
|
+
def create_table_definition(*args)
|
1251
|
+
TableDefinition.new(*args)
|
1033
1252
|
end
|
1034
1253
|
|
1035
1254
|
def create_alter_table(name)
|
1036
|
-
AlterTable.new create_table_definition(name
|
1255
|
+
AlterTable.new create_table_definition(name)
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
def index_name_options(column_names) # :nodoc:
|
1259
|
+
if column_names.is_a?(String)
|
1260
|
+
column_names = column_names.scan(/\w+/).join('_')
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
{ column: column_names }
|
1037
1264
|
end
|
1038
1265
|
|
1039
1266
|
def foreign_key_name(table_name, options) # :nodoc:
|
@@ -1044,11 +1271,23 @@ module ActiveRecord
|
|
1044
1271
|
end
|
1045
1272
|
end
|
1046
1273
|
|
1047
|
-
def validate_index_length!(table_name, new_name)
|
1274
|
+
def validate_index_length!(table_name, new_name) # :nodoc:
|
1048
1275
|
if new_name.length > allowed_index_name_length
|
1049
1276
|
raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters"
|
1050
1277
|
end
|
1051
1278
|
end
|
1279
|
+
|
1280
|
+
def extract_new_default_value(default_or_changes)
|
1281
|
+
if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
|
1282
|
+
default_or_changes[:to]
|
1283
|
+
else
|
1284
|
+
default_or_changes
|
1285
|
+
end
|
1286
|
+
end
|
1287
|
+
|
1288
|
+
def can_remove_index_by_name?(options)
|
1289
|
+
options.is_a?(Hash) && options.key?(:name) && options.except(:name, :algorithm).empty?
|
1290
|
+
end
|
1052
1291
|
end
|
1053
1292
|
end
|
1054
1293
|
end
|