activerecord 3.2.22.5 → 4.2.11.3
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 +1632 -609
- data/MIT-LICENSE +1 -1
- data/README.rdoc +37 -41
- data/examples/performance.rb +31 -19
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +56 -42
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -36
- data/lib/active_record/associations/association.rb +73 -55
- data/lib/active_record/associations/association_scope.rb +143 -82
- data/lib/active_record/associations/belongs_to_association.rb +65 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +125 -31
- data/lib/active_record/associations/builder/belongs_to.rb +89 -61
- data/lib/active_record/associations/builder/collection_association.rb +69 -49
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +12 -51
- data/lib/active_record/associations/builder/singular_association.rb +23 -17
- data/lib/active_record/associations/collection_association.rb +251 -177
- data/lib/active_record/associations/collection_proxy.rb +963 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +113 -22
- data/lib/active_record/associations/has_many_through_association.rb +99 -39
- data/lib/active_record/associations/has_one_association.rb +43 -20
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +76 -107
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +230 -156
- data/lib/active_record/associations/preloader/association.rb +96 -55
- data/lib/active_record/associations/preloader/collection_association.rb +3 -3
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +62 -33
- data/lib/active_record/associations/preloader.rb +101 -79
- data/lib/active_record/associations/singular_association.rb +29 -13
- data/lib/active_record/associations/through_association.rb +30 -16
- data/lib/active_record/associations.rb +463 -345
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +142 -151
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +137 -57
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +73 -106
- data/lib/active_record/attribute_methods/serialization.rb +44 -94
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
- data/lib/active_record/attribute_methods/write.rb +57 -44
- data/lib/active_record/attribute_methods.rb +301 -141
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +246 -217
- data/lib/active_record/base.rb +70 -474
- data/lib/active_record/callbacks.rb +66 -28
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +18 -21
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +396 -219
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +261 -169
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
- data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
- data/lib/active_record/connection_adapters/column.rb +31 -245
- data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
- data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +430 -999
- data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
- data/lib/active_record/connection_handling.rb +132 -0
- data/lib/active_record/core.rb +579 -0
- data/lib/active_record/counter_cache.rb +157 -105
- data/lib/active_record/dynamic_matchers.rb +119 -63
- data/lib/active_record/enum.rb +197 -0
- data/lib/active_record/errors.rb +94 -36
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +9 -5
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +302 -215
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +143 -70
- data/lib/active_record/integration.rb +65 -12
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +73 -52
- data/lib/active_record/locking/pessimistic.rb +5 -5
- data/lib/active_record/log_subscriber.rb +24 -21
- data/lib/active_record/migration/command_recorder.rb +124 -32
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +511 -213
- data/lib/active_record/model_schema.rb +91 -117
- data/lib/active_record/nested_attributes.rb +184 -130
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +81 -0
- data/lib/active_record/persistence.rb +276 -117
- data/lib/active_record/query_cache.rb +19 -37
- data/lib/active_record/querying.rb +28 -18
- data/lib/active_record/railtie.rb +73 -40
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +4 -3
- data/lib/active_record/railties/databases.rake +141 -416
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +1 -4
- data/lib/active_record/reflection.rb +513 -154
- data/lib/active_record/relation/batches.rb +91 -43
- data/lib/active_record/relation/calculations.rb +199 -161
- data/lib/active_record/relation/delegation.rb +116 -25
- data/lib/active_record/relation/finder_methods.rb +362 -248
- data/lib/active_record/relation/merger.rb +193 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +135 -43
- data/lib/active_record/relation/query_methods.rb +928 -167
- data/lib/active_record/relation/spawn_methods.rb +48 -149
- data/lib/active_record/relation.rb +352 -207
- data/lib/active_record/result.rb +101 -10
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +56 -59
- data/lib/active_record/schema.rb +19 -13
- data/lib/active_record/schema_dumper.rb +106 -63
- data/lib/active_record/schema_migration.rb +53 -0
- data/lib/active_record/scoping/default.rb +50 -57
- data/lib/active_record/scoping/named.rb +73 -109
- data/lib/active_record/scoping.rb +58 -123
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +12 -22
- data/lib/active_record/statement_cache.rb +111 -0
- data/lib/active_record/store.rb +168 -15
- data/lib/active_record/tasks/database_tasks.rb +299 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
- data/lib/active_record/timestamp.rb +23 -16
- data/lib/active_record/transactions.rb +125 -79
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +24 -16
- data/lib/active_record/validations/presence.rb +67 -0
- data/lib/active_record/validations/uniqueness.rb +123 -64
- data/lib/active_record/validations.rb +36 -29
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +66 -46
- data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/migration.rb +11 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +101 -45
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,10 +1,13 @@
|
|
1
|
-
require '
|
2
|
-
require 'active_support/
|
1
|
+
require 'active_record/migration/join_table'
|
2
|
+
require 'active_support/core_ext/string/access'
|
3
|
+
require 'digest'
|
3
4
|
|
4
5
|
module ActiveRecord
|
5
6
|
module ConnectionAdapters # :nodoc:
|
6
7
|
module SchemaStatements
|
7
|
-
|
8
|
+
include ActiveRecord::Migration::JoinTable
|
9
|
+
|
10
|
+
# Returns a hash of mappings from the abstract data types to the native
|
8
11
|
# database types. See TableDefinition#column for details on the recognized
|
9
12
|
# abstract data types.
|
10
13
|
def native_database_types
|
@@ -13,13 +16,27 @@ module ActiveRecord
|
|
13
16
|
|
14
17
|
# Truncates a table alias according to the limits of the current adapter.
|
15
18
|
def table_alias_for(table_name)
|
16
|
-
table_name[0...table_alias_length].
|
19
|
+
table_name[0...table_alias_length].tr('.', '_')
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the relation names useable to back Active Record models.
|
23
|
+
# For most adapters this means all tables and views.
|
24
|
+
def data_sources
|
25
|
+
tables
|
26
|
+
end
|
27
|
+
|
28
|
+
# Checks to see if the data source +name+ exists on the database.
|
29
|
+
#
|
30
|
+
# data_source_exists?(:ebooks)
|
31
|
+
#
|
32
|
+
def data_source_exists?(name)
|
33
|
+
data_sources.include?(name.to_s)
|
17
34
|
end
|
18
35
|
|
19
36
|
# Checks to see if the table +table_name+ exists on the database.
|
20
37
|
#
|
21
|
-
# === Example
|
22
38
|
# table_exists?(:developers)
|
39
|
+
#
|
23
40
|
def table_exists?(table_name)
|
24
41
|
tables.include?(table_name.to_s)
|
25
42
|
end
|
@@ -29,49 +46,56 @@ module ActiveRecord
|
|
29
46
|
|
30
47
|
# Checks to see if an index exists on a table for a given index definition.
|
31
48
|
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
# index_exists?(:suppliers, :company_id)
|
49
|
+
# # Check an index exists
|
50
|
+
# index_exists?(:suppliers, :company_id)
|
35
51
|
#
|
36
|
-
#
|
37
|
-
#
|
52
|
+
# # Check an index on multiple columns exists
|
53
|
+
# index_exists?(:suppliers, [:company_id, :company_type])
|
38
54
|
#
|
39
|
-
#
|
40
|
-
#
|
55
|
+
# # Check a unique index exists
|
56
|
+
# index_exists?(:suppliers, :company_id, unique: true)
|
57
|
+
#
|
58
|
+
# # Check an index with a custom name exists
|
59
|
+
# index_exists?(:suppliers, :company_id, name: "idx_company_id")
|
41
60
|
#
|
42
|
-
# # Check an index with a custom name exists
|
43
|
-
# index_exists?(:suppliers, :company_id, :name => "idx_company_id"
|
44
61
|
def index_exists?(table_name, column_name, options = {})
|
45
|
-
column_names = Array
|
46
|
-
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
62
|
+
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
|
+
checks = []
|
65
|
+
checks << lambda { |i| i.name == index_name }
|
66
|
+
checks << lambda { |i| i.columns == column_names }
|
67
|
+
checks << lambda { |i| i.unique } if options[:unique]
|
68
|
+
|
69
|
+
indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
|
52
70
|
end
|
53
71
|
|
54
72
|
# Returns an array of Column objects for the table specified by +table_name+.
|
55
73
|
# See the concrete implementation for details on the expected parameter values.
|
56
|
-
def columns(table_name
|
74
|
+
def columns(table_name) end
|
57
75
|
|
58
76
|
# Checks to see if a column exists in a given table.
|
59
77
|
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
78
|
+
# # Check a column exists
|
79
|
+
# column_exists?(:suppliers, :name)
|
80
|
+
#
|
81
|
+
# # Check a column exists of a particular type
|
82
|
+
# column_exists?(:suppliers, :name, :string)
|
63
83
|
#
|
64
|
-
#
|
65
|
-
#
|
84
|
+
# # Check a column exists with a specific definition
|
85
|
+
# column_exists?(:suppliers, :name, :string, limit: 100)
|
86
|
+
# column_exists?(:suppliers, :name, :string, default: 'default')
|
87
|
+
# column_exists?(:suppliers, :name, :string, null: false)
|
88
|
+
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
|
66
89
|
#
|
67
|
-
# # Check a column exists with a specific definition
|
68
|
-
# column_exists?(:suppliers, :name, :string, :limit => 100)
|
69
90
|
def column_exists?(table_name, column_name, type = nil, options = {})
|
70
|
-
|
71
|
-
|
72
|
-
(!
|
73
|
-
(!options
|
74
|
-
(!options
|
91
|
+
column_name = column_name.to_s
|
92
|
+
columns(table_name).any?{ |c| c.name == column_name &&
|
93
|
+
(!type || c.type == type) &&
|
94
|
+
(!options.key?(:limit) || c.limit == options[:limit]) &&
|
95
|
+
(!options.key?(:precision) || c.precision == options[:precision]) &&
|
96
|
+
(!options.key?(:scale) || c.scale == options[:scale]) &&
|
97
|
+
(!options.key?(:default) || c.default == options[:default]) &&
|
98
|
+
(!options.key?(:null) || c.null == options[:null]) }
|
75
99
|
end
|
76
100
|
|
77
101
|
# Creates a new table with the name +table_name+. +table_name+ may either
|
@@ -81,27 +105,30 @@ module ActiveRecord
|
|
81
105
|
# form or the regular form, like this:
|
82
106
|
#
|
83
107
|
# === Block form
|
84
|
-
# # create_table() passes a TableDefinition object to the block.
|
85
|
-
# # This form will not only create the table, but also columns for the
|
86
|
-
# # table.
|
87
108
|
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
109
|
+
# # create_table() passes a TableDefinition object to the block.
|
110
|
+
# # This form will not only create the table, but also columns for the
|
111
|
+
# # table.
|
112
|
+
#
|
113
|
+
# create_table(:suppliers) do |t|
|
114
|
+
# t.column :name, :string, limit: 60
|
115
|
+
# # Other fields here
|
116
|
+
# end
|
92
117
|
#
|
93
118
|
# === Block form, with shorthand
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
119
|
+
#
|
120
|
+
# # You can also use the column types as method calls, rather than calling the column method.
|
121
|
+
# create_table(:suppliers) do |t|
|
122
|
+
# t.string :name, limit: 60
|
123
|
+
# # Other fields here
|
124
|
+
# end
|
99
125
|
#
|
100
126
|
# === Regular form
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
127
|
+
#
|
128
|
+
# # Creates a table called 'suppliers' with no columns.
|
129
|
+
# create_table(:suppliers)
|
130
|
+
# # Add a column to 'suppliers'.
|
131
|
+
# add_column(:suppliers, :name, :string, {limit: 60})
|
105
132
|
#
|
106
133
|
# The +options+ hash can include the following keys:
|
107
134
|
# [<tt>:id</tt>]
|
@@ -111,9 +138,9 @@ module ActiveRecord
|
|
111
138
|
# The name of the primary key, if one is to be added automatically.
|
112
139
|
# Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
|
113
140
|
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
141
|
+
# Note that Active Record models will automatically detect their
|
142
|
+
# primary key. This can be avoided by using +self.primary_key=+ on the model
|
143
|
+
# to define the key explicitly.
|
117
144
|
#
|
118
145
|
# [<tt>:options</tt>]
|
119
146
|
# Any extra options you want appended to the table definition.
|
@@ -121,41 +148,70 @@ module ActiveRecord
|
|
121
148
|
# Make a temporary table.
|
122
149
|
# [<tt>:force</tt>]
|
123
150
|
# Set to true to drop the table before creating it.
|
151
|
+
# Set to +:cascade+ to drop dependent objects as well.
|
124
152
|
# Defaults to false.
|
153
|
+
# [<tt>:as</tt>]
|
154
|
+
# SQL to use to generate the table. When this option is used, the block is
|
155
|
+
# ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options.
|
125
156
|
#
|
126
|
-
# ===== Examples
|
127
157
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
128
|
-
#
|
158
|
+
#
|
159
|
+
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
160
|
+
#
|
129
161
|
# generates:
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
162
|
+
#
|
163
|
+
# CREATE TABLE suppliers (
|
164
|
+
# id int(11) DEFAULT NULL auto_increment PRIMARY KEY
|
165
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
133
166
|
#
|
134
167
|
# ====== Rename the primary key column
|
135
|
-
#
|
136
|
-
#
|
137
|
-
#
|
168
|
+
#
|
169
|
+
# create_table(:objects, primary_key: 'guid') do |t|
|
170
|
+
# t.column :name, :string, limit: 80
|
171
|
+
# end
|
172
|
+
#
|
138
173
|
# generates:
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
174
|
+
#
|
175
|
+
# CREATE TABLE objects (
|
176
|
+
# guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
|
177
|
+
# name varchar(80)
|
178
|
+
# )
|
143
179
|
#
|
144
180
|
# ====== Do not add a primary key column
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
148
|
-
#
|
181
|
+
#
|
182
|
+
# create_table(:categories_suppliers, id: false) do |t|
|
183
|
+
# t.column :category_id, :integer
|
184
|
+
# t.column :supplier_id, :integer
|
185
|
+
# end
|
186
|
+
#
|
149
187
|
# generates:
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
188
|
+
#
|
189
|
+
# CREATE TABLE categories_suppliers (
|
190
|
+
# category_id int,
|
191
|
+
# supplier_id int
|
192
|
+
# )
|
193
|
+
#
|
194
|
+
# ====== Create a temporary table based on a query
|
195
|
+
#
|
196
|
+
# create_table(:long_query, temporary: true,
|
197
|
+
# as: "SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id")
|
198
|
+
#
|
199
|
+
# generates:
|
200
|
+
#
|
201
|
+
# CREATE TEMPORARY TABLE long_query AS
|
202
|
+
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
|
154
203
|
#
|
155
204
|
# See also TableDefinition#column for details on how to create columns.
|
156
205
|
def create_table(table_name, options = {})
|
157
|
-
td =
|
158
|
-
|
206
|
+
td = create_table_definition table_name, options[:temporary], options[:options], options[:as]
|
207
|
+
|
208
|
+
if options[:id] != false && !options[:as]
|
209
|
+
pk = options.fetch(:primary_key) do
|
210
|
+
Base.get_primary_key table_name.to_s.singularize
|
211
|
+
end
|
212
|
+
|
213
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options
|
214
|
+
end
|
159
215
|
|
160
216
|
yield td if block_given?
|
161
217
|
|
@@ -163,95 +219,182 @@ module ActiveRecord
|
|
163
219
|
drop_table(table_name, options)
|
164
220
|
end
|
165
221
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
222
|
+
result = execute schema_creation.accept td
|
223
|
+
|
224
|
+
unless supports_indexes_in_create?
|
225
|
+
td.indexes.each_pair do |column_name, index_options|
|
226
|
+
add_index(table_name, column_name, index_options)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
td.foreign_keys.each do |other_table_name, foreign_key_options|
|
231
|
+
add_foreign_key(table_name, other_table_name, foreign_key_options)
|
232
|
+
end
|
233
|
+
|
234
|
+
result
|
235
|
+
end
|
236
|
+
|
237
|
+
# Creates a new join table with the name created using the lexical order of the first two
|
238
|
+
# arguments. These arguments can be a String or a Symbol.
|
239
|
+
#
|
240
|
+
# # Creates a table called 'assemblies_parts' with no id.
|
241
|
+
# create_join_table(:assemblies, :parts)
|
242
|
+
#
|
243
|
+
# You can pass a +options+ hash can include the following keys:
|
244
|
+
# [<tt>:table_name</tt>]
|
245
|
+
# Sets the table name overriding the default
|
246
|
+
# [<tt>:column_options</tt>]
|
247
|
+
# Any extra options you want appended to the columns definition.
|
248
|
+
# [<tt>:options</tt>]
|
249
|
+
# Any extra options you want appended to the table definition.
|
250
|
+
# [<tt>:temporary</tt>]
|
251
|
+
# Make a temporary table.
|
252
|
+
# [<tt>:force</tt>]
|
253
|
+
# Set to true to drop the table before creating it.
|
254
|
+
# Defaults to false.
|
255
|
+
#
|
256
|
+
# Note that +create_join_table+ does not create any indices by default; you can use
|
257
|
+
# its block form to do so yourself:
|
258
|
+
#
|
259
|
+
# create_join_table :products, :categories do |t|
|
260
|
+
# t.index :product_id
|
261
|
+
# t.index :category_id
|
262
|
+
# end
|
263
|
+
#
|
264
|
+
# ====== Add a backend specific option to the generated SQL (MySQL)
|
265
|
+
#
|
266
|
+
# create_join_table(:assemblies, :parts, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
267
|
+
#
|
268
|
+
# generates:
|
269
|
+
#
|
270
|
+
# CREATE TABLE assemblies_parts (
|
271
|
+
# assembly_id int NOT NULL,
|
272
|
+
# part_id int NOT NULL,
|
273
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
274
|
+
#
|
275
|
+
def create_join_table(table_1, table_2, options = {})
|
276
|
+
join_table_name = find_join_table_name(table_1, table_2, options)
|
277
|
+
|
278
|
+
column_options = options.delete(:column_options) || {}
|
279
|
+
column_options.reverse_merge!(null: false)
|
280
|
+
|
281
|
+
t1_column, t2_column = [table_1, table_2].map{ |t| t.to_s.singularize.foreign_key }
|
282
|
+
|
283
|
+
create_table(join_table_name, options.merge!(id: false)) do |td|
|
284
|
+
td.integer t1_column, column_options
|
285
|
+
td.integer t2_column, column_options
|
286
|
+
yield td if block_given?
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Drops the join table specified by the given arguments.
|
291
|
+
# See +create_join_table+ for details.
|
292
|
+
#
|
293
|
+
# Although this command ignores the block if one is given, it can be helpful
|
294
|
+
# 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.
|
296
|
+
def drop_join_table(table_1, table_2, options = {})
|
297
|
+
join_table_name = find_join_table_name(table_1, table_2, options)
|
298
|
+
drop_table(join_table_name)
|
171
299
|
end
|
172
300
|
|
173
301
|
# A block for changing columns in +table+.
|
174
302
|
#
|
175
|
-
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
# end
|
303
|
+
# # change_table() yields a Table instance
|
304
|
+
# change_table(:suppliers) do |t|
|
305
|
+
# t.column :name, :string, limit: 60
|
306
|
+
# # Other column alterations here
|
307
|
+
# end
|
181
308
|
#
|
182
309
|
# The +options+ hash can include the following keys:
|
183
310
|
# [<tt>:bulk</tt>]
|
184
311
|
# Set this to true to make this a bulk alter query, such as
|
185
|
-
#
|
312
|
+
#
|
313
|
+
# ALTER TABLE `users` ADD COLUMN age INT(11), ADD COLUMN birthdate DATETIME ...
|
186
314
|
#
|
187
315
|
# Defaults to false.
|
188
316
|
#
|
189
|
-
# ===== Examples
|
190
317
|
# ====== Add a column
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
318
|
+
#
|
319
|
+
# change_table(:suppliers) do |t|
|
320
|
+
# t.column :name, :string, limit: 60
|
321
|
+
# end
|
194
322
|
#
|
195
323
|
# ====== Add 2 integer columns
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
324
|
+
#
|
325
|
+
# change_table(:suppliers) do |t|
|
326
|
+
# t.integer :width, :height, null: false, default: 0
|
327
|
+
# end
|
199
328
|
#
|
200
329
|
# ====== Add created_at/updated_at columns
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
330
|
+
#
|
331
|
+
# change_table(:suppliers) do |t|
|
332
|
+
# t.timestamps
|
333
|
+
# end
|
204
334
|
#
|
205
335
|
# ====== Add a foreign key column
|
206
|
-
# change_table(:suppliers) do |t|
|
207
|
-
# t.references :company
|
208
|
-
# end
|
209
336
|
#
|
210
|
-
#
|
337
|
+
# change_table(:suppliers) do |t|
|
338
|
+
# t.references :company
|
339
|
+
# end
|
340
|
+
#
|
341
|
+
# Creates a <tt>company_id(integer)</tt> column.
|
211
342
|
#
|
212
343
|
# ====== Add a polymorphic foreign key column
|
344
|
+
#
|
213
345
|
# change_table(:suppliers) do |t|
|
214
|
-
# t.belongs_to :company, :
|
346
|
+
# t.belongs_to :company, polymorphic: true
|
215
347
|
# end
|
216
348
|
#
|
217
|
-
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns
|
349
|
+
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns.
|
218
350
|
#
|
219
351
|
# ====== Remove a column
|
352
|
+
#
|
220
353
|
# change_table(:suppliers) do |t|
|
221
354
|
# t.remove :company
|
222
355
|
# end
|
223
356
|
#
|
224
357
|
# ====== Remove several columns
|
358
|
+
#
|
225
359
|
# change_table(:suppliers) do |t|
|
226
360
|
# t.remove :company_id
|
227
361
|
# t.remove :width, :height
|
228
362
|
# end
|
229
363
|
#
|
230
364
|
# ====== Remove an index
|
365
|
+
#
|
231
366
|
# change_table(:suppliers) do |t|
|
232
367
|
# t.remove_index :company_id
|
233
368
|
# end
|
234
369
|
#
|
235
|
-
# See also Table for details on
|
236
|
-
# all of the various column transformation
|
370
|
+
# See also Table for details on all of the various column transformation.
|
237
371
|
def change_table(table_name, options = {})
|
238
372
|
if supports_bulk_alter? && options[:bulk]
|
239
373
|
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
|
240
|
-
yield
|
374
|
+
yield update_table_definition(table_name, recorder)
|
241
375
|
bulk_change_table(table_name, recorder.commands)
|
242
376
|
else
|
243
|
-
yield
|
377
|
+
yield update_table_definition(table_name, self)
|
244
378
|
end
|
245
379
|
end
|
246
380
|
|
247
381
|
# Renames a table.
|
248
|
-
#
|
249
|
-
#
|
382
|
+
#
|
383
|
+
# rename_table('octopuses', 'octopi')
|
384
|
+
#
|
250
385
|
def rename_table(table_name, new_name)
|
251
386
|
raise NotImplementedError, "rename_table is not implemented"
|
252
387
|
end
|
253
388
|
|
254
389
|
# Drops a table from the database.
|
390
|
+
#
|
391
|
+
# [<tt>:force</tt>]
|
392
|
+
# Set to +:cascade+ to drop dependent objects as well.
|
393
|
+
# Defaults to false.
|
394
|
+
#
|
395
|
+
# Although this command ignores most +options+ and the block if one is given,
|
396
|
+
# 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.
|
255
398
|
def drop_table(table_name, options = {})
|
256
399
|
execute "DROP TABLE #{quote_table_name(table_name)}"
|
257
400
|
end
|
@@ -259,49 +402,80 @@ module ActiveRecord
|
|
259
402
|
# Adds a new column to the named table.
|
260
403
|
# See TableDefinition#column for details of the options you can use.
|
261
404
|
def add_column(table_name, column_name, type, options = {})
|
262
|
-
|
263
|
-
|
264
|
-
execute
|
265
|
-
end
|
266
|
-
|
267
|
-
# Removes the column(s) from the table definition.
|
268
|
-
# ===== Examples
|
269
|
-
# remove_column(:suppliers, :qualification)
|
270
|
-
# remove_columns(:suppliers, :qualification, :experience)
|
271
|
-
def remove_column(table_name, *column_names)
|
272
|
-
if column_names.flatten!
|
273
|
-
message = 'Passing array to remove_columns is deprecated, please use ' +
|
274
|
-
'multiple arguments, like: `remove_columns(:posts, :foo, :bar)`'
|
275
|
-
ActiveSupport::Deprecation.warn message, caller
|
276
|
-
end
|
405
|
+
at = create_alter_table table_name
|
406
|
+
at.add_column(column_name, type, options)
|
407
|
+
execute schema_creation.accept at
|
408
|
+
end
|
277
409
|
|
278
|
-
|
279
|
-
|
410
|
+
# Removes the given columns from the table definition.
|
411
|
+
#
|
412
|
+
# remove_columns(:suppliers, :qualification, :experience)
|
413
|
+
#
|
414
|
+
def remove_columns(table_name, *column_names)
|
415
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)") if column_names.empty?
|
416
|
+
column_names.each do |column_name|
|
417
|
+
remove_column(table_name, column_name)
|
280
418
|
end
|
281
419
|
end
|
282
|
-
|
420
|
+
|
421
|
+
# Removes the column from the table definition.
|
422
|
+
#
|
423
|
+
# remove_column(:suppliers, :qualification)
|
424
|
+
#
|
425
|
+
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
426
|
+
# to provide these in a migration's +change+ method so it can be reverted.
|
427
|
+
# In that case, +type+ and +options+ will be used by add_column.
|
428
|
+
def remove_column(table_name, column_name, type = nil, options = {})
|
429
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
430
|
+
end
|
283
431
|
|
284
432
|
# Changes the column's definition according to the new options.
|
285
433
|
# See TableDefinition#column for details of the options you can use.
|
286
|
-
#
|
287
|
-
#
|
288
|
-
#
|
434
|
+
#
|
435
|
+
# change_column(:suppliers, :name, :string, limit: 80)
|
436
|
+
# change_column(:accounts, :description, :text)
|
437
|
+
#
|
289
438
|
def change_column(table_name, column_name, type, options = {})
|
290
439
|
raise NotImplementedError, "change_column is not implemented"
|
291
440
|
end
|
292
441
|
|
293
|
-
# Sets a new default value for a column
|
294
|
-
#
|
295
|
-
#
|
296
|
-
#
|
297
|
-
#
|
442
|
+
# Sets a new default value for a column:
|
443
|
+
#
|
444
|
+
# change_column_default(:suppliers, :qualification, 'new')
|
445
|
+
# change_column_default(:accounts, :authorized, 1)
|
446
|
+
#
|
447
|
+
# Setting the default to +nil+ effectively drops the default:
|
448
|
+
#
|
449
|
+
# change_column_default(:users, :email, nil)
|
450
|
+
#
|
298
451
|
def change_column_default(table_name, column_name, default)
|
299
452
|
raise NotImplementedError, "change_column_default is not implemented"
|
300
453
|
end
|
301
454
|
|
455
|
+
# Sets or removes a +NOT NULL+ constraint on a column. The +null+ flag
|
456
|
+
# indicates whether the value can be +NULL+. For example
|
457
|
+
#
|
458
|
+
# change_column_null(:users, :nickname, false)
|
459
|
+
#
|
460
|
+
# says nicknames cannot be +NULL+ (adds the constraint), whereas
|
461
|
+
#
|
462
|
+
# change_column_null(:users, :nickname, true)
|
463
|
+
#
|
464
|
+
# allows them to be +NULL+ (drops the constraint).
|
465
|
+
#
|
466
|
+
# The method accepts an optional fourth argument to replace existing
|
467
|
+
# +NULL+s with some other value. Use that one when enabling the
|
468
|
+
# constraint if needed, since otherwise those rows would not be valid.
|
469
|
+
#
|
470
|
+
# Please note the fourth argument does not set a column's default.
|
471
|
+
def change_column_null(table_name, column_name, null, default = nil)
|
472
|
+
raise NotImplementedError, "change_column_null is not implemented"
|
473
|
+
end
|
474
|
+
|
302
475
|
# Renames a column.
|
303
|
-
#
|
304
|
-
#
|
476
|
+
#
|
477
|
+
# rename_column(:suppliers, :description, :name)
|
478
|
+
#
|
305
479
|
def rename_column(table_name, column_name, new_column_name)
|
306
480
|
raise NotImplementedError, "rename_column is not implemented"
|
307
481
|
end
|
@@ -312,56 +486,109 @@ module ActiveRecord
|
|
312
486
|
# The index will be named after the table and the column name(s), unless
|
313
487
|
# you pass <tt>:name</tt> as an option.
|
314
488
|
#
|
315
|
-
# ===== Examples
|
316
|
-
#
|
317
489
|
# ====== Creating a simple index
|
318
|
-
#
|
319
|
-
#
|
320
|
-
#
|
490
|
+
#
|
491
|
+
# add_index(:suppliers, :name)
|
492
|
+
#
|
493
|
+
# generates:
|
494
|
+
#
|
495
|
+
# CREATE INDEX suppliers_name_index ON suppliers(name)
|
321
496
|
#
|
322
497
|
# ====== Creating a unique index
|
323
|
-
#
|
324
|
-
#
|
325
|
-
#
|
498
|
+
#
|
499
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true)
|
500
|
+
#
|
501
|
+
# generates:
|
502
|
+
#
|
503
|
+
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
|
326
504
|
#
|
327
505
|
# ====== Creating a named index
|
328
|
-
#
|
329
|
-
#
|
506
|
+
#
|
507
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')
|
508
|
+
#
|
509
|
+
# generates:
|
510
|
+
#
|
330
511
|
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
331
512
|
#
|
332
513
|
# ====== Creating an index with specific key length
|
333
|
-
# add_index(:accounts, :name, :name => 'by_name', :length => 10)
|
334
|
-
# generates
|
335
|
-
# CREATE INDEX by_name ON accounts(name(10))
|
336
514
|
#
|
337
|
-
#
|
338
|
-
#
|
339
|
-
#
|
515
|
+
# add_index(:accounts, :name, name: 'by_name', length: 10)
|
516
|
+
#
|
517
|
+
# generates:
|
518
|
+
#
|
519
|
+
# CREATE INDEX by_name ON accounts(name(10))
|
520
|
+
#
|
521
|
+
# add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
|
522
|
+
#
|
523
|
+
# generates:
|
524
|
+
#
|
525
|
+
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
340
526
|
#
|
341
|
-
# Note: SQLite doesn't support index length
|
527
|
+
# Note: SQLite doesn't support index length.
|
342
528
|
#
|
343
529
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
344
|
-
# add_index(:accounts, [:branch_id, :party_id, :surname], :order => {:branch_id => :desc, :part_id => :asc})
|
345
|
-
# generates
|
346
|
-
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
|
347
530
|
#
|
348
|
-
#
|
531
|
+
# add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
|
532
|
+
#
|
533
|
+
# generates:
|
534
|
+
#
|
535
|
+
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
|
536
|
+
#
|
537
|
+
# Note: MySQL doesn't yet support index order (it accepts the syntax but ignores it).
|
538
|
+
#
|
539
|
+
# ====== Creating a partial index
|
540
|
+
#
|
541
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true, where: "active")
|
542
|
+
#
|
543
|
+
# generates:
|
544
|
+
#
|
545
|
+
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
|
349
546
|
#
|
547
|
+
# Note: Partial indexes are only supported for PostgreSQL and SQLite 3.8.0+.
|
548
|
+
#
|
549
|
+
# ====== Creating an index with a specific method
|
550
|
+
#
|
551
|
+
# add_index(:developers, :name, using: 'btree')
|
552
|
+
#
|
553
|
+
# generates:
|
554
|
+
#
|
555
|
+
# CREATE INDEX index_developers_on_name ON developers USING btree (name) -- PostgreSQL
|
556
|
+
# CREATE INDEX index_developers_on_name USING btree ON developers (name) -- MySQL
|
557
|
+
#
|
558
|
+
# Note: only supported by PostgreSQL and MySQL
|
559
|
+
#
|
560
|
+
# ====== Creating an index with a specific type
|
561
|
+
#
|
562
|
+
# add_index(:developers, :name, type: :fulltext)
|
563
|
+
#
|
564
|
+
# generates:
|
565
|
+
#
|
566
|
+
# CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
|
567
|
+
#
|
568
|
+
# Note: only supported by MySQL. Supported: <tt>:fulltext</tt> and <tt>:spatial</tt> on MyISAM tables.
|
350
569
|
def add_index(table_name, column_name, options = {})
|
351
|
-
index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
|
352
|
-
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})"
|
570
|
+
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
|
571
|
+
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
|
353
572
|
end
|
354
573
|
|
355
|
-
#
|
574
|
+
# Removes the given index from the table.
|
575
|
+
#
|
576
|
+
# Removes the +index_accounts_on_column+ in the +accounts+ table.
|
356
577
|
#
|
357
|
-
# Remove the index_accounts_on_column in the accounts table.
|
358
578
|
# remove_index :accounts, :column
|
359
|
-
#
|
360
|
-
#
|
361
|
-
#
|
362
|
-
# remove_index :accounts, :
|
363
|
-
#
|
364
|
-
#
|
579
|
+
#
|
580
|
+
# Removes the index named +index_accounts_on_branch_id+ in the +accounts+ table.
|
581
|
+
#
|
582
|
+
# remove_index :accounts, column: :branch_id
|
583
|
+
#
|
584
|
+
# Removes the index named +index_accounts_on_branch_id_and_party_id+ in the +accounts+ table.
|
585
|
+
#
|
586
|
+
# remove_index :accounts, column: [:branch_id, :party_id]
|
587
|
+
#
|
588
|
+
# Removes the index named +by_branch_party+ in the +accounts+ table.
|
589
|
+
#
|
590
|
+
# remove_index :accounts, name: :by_branch_party
|
591
|
+
#
|
365
592
|
def remove_index(table_name, options = {})
|
366
593
|
remove_index!(table_name, index_name_for_remove(table_name, options))
|
367
594
|
end
|
@@ -370,22 +597,26 @@ module ActiveRecord
|
|
370
597
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
371
598
|
end
|
372
599
|
|
373
|
-
#
|
600
|
+
# Renames an index.
|
601
|
+
#
|
602
|
+
# Rename the +index_people_on_last_name+ index to +index_users_on_last_name+:
|
374
603
|
#
|
375
|
-
# Rename the index_people_on_last_name index to index_users_on_last_name
|
376
604
|
# rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
|
605
|
+
#
|
377
606
|
def rename_index(table_name, old_name, new_name)
|
607
|
+
validate_index_length!(table_name, new_name)
|
608
|
+
|
378
609
|
# this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
|
379
610
|
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
380
611
|
return unless old_index_def
|
381
|
-
|
382
|
-
|
612
|
+
add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
|
613
|
+
remove_index(table_name, name: old_name)
|
383
614
|
end
|
384
615
|
|
385
616
|
def index_name(table_name, options) #:nodoc:
|
386
|
-
if Hash === options
|
617
|
+
if Hash === options
|
387
618
|
if options[:column]
|
388
|
-
"index_#{table_name}_on_#{Array
|
619
|
+
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
389
620
|
elsif options[:name]
|
390
621
|
options[:name]
|
391
622
|
else
|
@@ -396,7 +627,7 @@ module ActiveRecord
|
|
396
627
|
end
|
397
628
|
end
|
398
629
|
|
399
|
-
#
|
630
|
+
# Verifies the existence of an index with a given name.
|
400
631
|
#
|
401
632
|
# The default argument is returned if the underlying implementation does not define the indexes method,
|
402
633
|
# as there's no way to determine the correct answer in that case.
|
@@ -406,52 +637,213 @@ module ActiveRecord
|
|
406
637
|
indexes(table_name).detect { |i| i.name == index_name }
|
407
638
|
end
|
408
639
|
|
409
|
-
#
|
410
|
-
#
|
411
|
-
|
640
|
+
# Adds a reference. The reference column is an integer by default,
|
641
|
+
# the <tt>:type</tt> option can be used to specify a different type.
|
642
|
+
# Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
|
643
|
+
# <tt>add_reference</tt> and <tt>add_belongs_to</tt> are acceptable.
|
644
|
+
#
|
645
|
+
# The +options+ hash can include the following keys:
|
646
|
+
# [<tt>:type</tt>]
|
647
|
+
# The reference column type. Defaults to +:integer+.
|
648
|
+
# [<tt>:index</tt>]
|
649
|
+
# Add an appropriate index. Defaults to false.
|
650
|
+
# [<tt>:foreign_key</tt>]
|
651
|
+
# Add an appropriate foreign key. Defaults to false.
|
652
|
+
# [<tt>:polymorphic</tt>]
|
653
|
+
# Wether an additional +_type+ column should be added. Defaults to false.
|
654
|
+
#
|
655
|
+
# ====== Create a user_id integer column
|
656
|
+
#
|
657
|
+
# add_reference(:products, :user)
|
658
|
+
#
|
659
|
+
# ====== Create a user_id string column
|
660
|
+
#
|
661
|
+
# add_reference(:products, :user, type: :string)
|
662
|
+
#
|
663
|
+
# ====== Create supplier_id, supplier_type columns and appropriate index
|
664
|
+
#
|
665
|
+
# add_reference(:products, :supplier, polymorphic: true, index: true)
|
666
|
+
#
|
667
|
+
def add_reference(table_name, ref_name, options = {})
|
668
|
+
polymorphic = options.delete(:polymorphic)
|
669
|
+
index_options = options.delete(:index)
|
670
|
+
type = options.delete(:type) || :integer
|
671
|
+
foreign_key_options = options.delete(:foreign_key)
|
672
|
+
|
673
|
+
if polymorphic && foreign_key_options
|
674
|
+
raise ArgumentError, "Cannot add a foreign key to a polymorphic relation"
|
675
|
+
end
|
676
|
+
|
677
|
+
add_column(table_name, "#{ref_name}_id", type, options)
|
678
|
+
add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
|
679
|
+
add_index(table_name, polymorphic ? %w[type id].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
|
680
|
+
if foreign_key_options
|
681
|
+
to_table = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
682
|
+
add_foreign_key(table_name, to_table, foreign_key_options.is_a?(Hash) ? foreign_key_options : {})
|
683
|
+
end
|
412
684
|
end
|
685
|
+
alias :add_belongs_to :add_reference
|
413
686
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
687
|
+
# Removes the reference(s). Also removes a +type+ column if one exists.
|
688
|
+
# <tt>remove_reference</tt>, <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
|
689
|
+
#
|
690
|
+
# ====== Remove the reference
|
691
|
+
#
|
692
|
+
# remove_reference(:products, :user, index: true)
|
693
|
+
#
|
694
|
+
# ====== Remove polymorphic reference
|
695
|
+
#
|
696
|
+
# remove_reference(:products, :supplier, polymorphic: true)
|
697
|
+
#
|
698
|
+
# ====== Remove the reference with a foreign key
|
699
|
+
#
|
700
|
+
# remove_reference(:products, :user, index: true, foreign_key: true)
|
701
|
+
#
|
702
|
+
def remove_reference(table_name, ref_name, options = {})
|
703
|
+
if options[:foreign_key]
|
704
|
+
to_table = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
705
|
+
remove_foreign_key(table_name, to_table)
|
706
|
+
end
|
707
|
+
|
708
|
+
remove_column(table_name, "#{ref_name}_id")
|
709
|
+
remove_column(table_name, "#{ref_name}_type") if options[:polymorphic]
|
418
710
|
end
|
711
|
+
alias :remove_belongs_to :remove_reference
|
419
712
|
|
420
|
-
#
|
421
|
-
# The
|
422
|
-
def
|
423
|
-
|
713
|
+
# Returns an array of foreign keys for the given table.
|
714
|
+
# The foreign keys are represented as +ForeignKeyDefinition+ objects.
|
715
|
+
def foreign_keys(table_name)
|
716
|
+
raise NotImplementedError, "foreign_keys is not implemented"
|
717
|
+
end
|
424
718
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
719
|
+
# Adds a new foreign key. +from_table+ is the table with the key column,
|
720
|
+
# +to_table+ contains the referenced primary key.
|
721
|
+
#
|
722
|
+
# The foreign key will be named after the following pattern: <tt>fk_rails_<identifier></tt>.
|
723
|
+
# +identifier+ is a 10 character long string which is deterministically generated from the
|
724
|
+
# +from_table+ and +column+. A custom name can be specified with the <tt>:name</tt> option.
|
725
|
+
#
|
726
|
+
# ====== Creating a simple foreign key
|
727
|
+
#
|
728
|
+
# add_foreign_key :articles, :authors
|
729
|
+
#
|
730
|
+
# generates:
|
731
|
+
#
|
732
|
+
# ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
733
|
+
#
|
734
|
+
# ====== Creating a foreign key on a specific column
|
735
|
+
#
|
736
|
+
# add_foreign_key :articles, :users, column: :author_id, primary_key: :lng_id
|
737
|
+
#
|
738
|
+
# generates:
|
739
|
+
#
|
740
|
+
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id")
|
741
|
+
#
|
742
|
+
# ====== Creating a cascading foreign key
|
743
|
+
#
|
744
|
+
# add_foreign_key :articles, :authors, on_delete: :cascade
|
745
|
+
#
|
746
|
+
# generates:
|
747
|
+
#
|
748
|
+
# ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
|
749
|
+
#
|
750
|
+
# The +options+ hash can include the following keys:
|
751
|
+
# [<tt>:column</tt>]
|
752
|
+
# The foreign key column name on +from_table+. Defaults to <tt>to_table.singularize + "_id"</tt>
|
753
|
+
# [<tt>:primary_key</tt>]
|
754
|
+
# The primary key column name on +to_table+. Defaults to +id+.
|
755
|
+
# [<tt>:name</tt>]
|
756
|
+
# The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
|
757
|
+
# [<tt>:on_delete</tt>]
|
758
|
+
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade:+ and +:restrict+
|
759
|
+
# [<tt>:on_update</tt>]
|
760
|
+
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade:+ and +:restrict+
|
761
|
+
def add_foreign_key(from_table, to_table, options = {})
|
762
|
+
return unless supports_foreign_keys?
|
763
|
+
|
764
|
+
options[:column] ||= foreign_key_column_for(to_table)
|
431
765
|
|
432
|
-
|
433
|
-
|
434
|
-
|
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
|
+
}
|
773
|
+
at = create_alter_table from_table
|
774
|
+
at.add_foreign_key to_table, options
|
435
775
|
|
436
|
-
|
437
|
-
|
776
|
+
execute schema_creation.accept(at)
|
777
|
+
end
|
438
778
|
|
439
|
-
|
440
|
-
|
441
|
-
|
779
|
+
# Removes the given foreign key from the table.
|
780
|
+
#
|
781
|
+
# Removes the foreign key on +accounts.branch_id+.
|
782
|
+
#
|
783
|
+
# remove_foreign_key :accounts, :branches
|
784
|
+
#
|
785
|
+
# Removes the foreign key on +accounts.owner_id+.
|
786
|
+
#
|
787
|
+
# remove_foreign_key :accounts, column: :owner_id
|
788
|
+
#
|
789
|
+
# Removes the foreign key named +special_fk_name+ on the +accounts+ table.
|
790
|
+
#
|
791
|
+
# remove_foreign_key :accounts, name: :special_fk_name
|
792
|
+
#
|
793
|
+
def remove_foreign_key(from_table, options_or_to_table = {})
|
794
|
+
return unless supports_foreign_keys?
|
795
|
+
|
796
|
+
if options_or_to_table.is_a?(Hash)
|
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]}'"
|
442
809
|
end
|
443
810
|
end
|
811
|
+
|
812
|
+
at = create_alter_table from_table
|
813
|
+
at.drop_foreign_key fk_name_to_delete
|
814
|
+
|
815
|
+
execute schema_creation.accept(at)
|
816
|
+
end
|
817
|
+
|
818
|
+
def foreign_key_column_for(table_name) # :nodoc:
|
819
|
+
prefix = Base.table_name_prefix
|
820
|
+
suffix = Base.table_name_suffix
|
821
|
+
name = table_name.to_s =~ /#{prefix}(.+)#{suffix}/ ? $1 : table_name.to_s
|
822
|
+
"#{name.singularize}_id"
|
823
|
+
end
|
824
|
+
|
825
|
+
def dump_schema_information #:nodoc:
|
826
|
+
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
827
|
+
|
828
|
+
ActiveRecord::SchemaMigration.order('version').map { |sm|
|
829
|
+
"INSERT INTO #{sm_table} (version) VALUES ('#{sm.version}');"
|
830
|
+
}.join "\n\n"
|
831
|
+
end
|
832
|
+
|
833
|
+
# Should not be called normally, but this operation is non-destructive.
|
834
|
+
# The migrations module handles this automatically.
|
835
|
+
def initialize_schema_migrations_table
|
836
|
+
ActiveRecord::SchemaMigration.create_table
|
444
837
|
end
|
445
838
|
|
446
839
|
def assume_migrated_upto_version(version, migrations_paths = ActiveRecord::Migrator.migrations_paths)
|
447
|
-
migrations_paths = Array
|
840
|
+
migrations_paths = Array(migrations_paths)
|
448
841
|
version = version.to_i
|
449
842
|
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
450
843
|
|
451
|
-
migrated = select_values("SELECT version FROM #{sm_table}").map
|
452
|
-
|
453
|
-
|
454
|
-
filename.split('/').last.split('_').first.to_i
|
844
|
+
migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
|
845
|
+
versions = ActiveRecord::Migrator.migration_files(migrations_paths).map do |file|
|
846
|
+
ActiveRecord::Migrator.parse_migration_filename(file).first.to_i
|
455
847
|
end
|
456
848
|
|
457
849
|
unless migrated.include?(version)
|
@@ -483,7 +875,7 @@ module ActiveRecord
|
|
483
875
|
column_type_sql << "(#{precision})"
|
484
876
|
end
|
485
877
|
elsif scale
|
486
|
-
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale
|
878
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
|
487
879
|
end
|
488
880
|
|
489
881
|
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
@@ -492,48 +884,85 @@ module ActiveRecord
|
|
492
884
|
|
493
885
|
column_type_sql
|
494
886
|
else
|
495
|
-
type
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
def add_column_options!(sql, options) #:nodoc:
|
500
|
-
sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
|
501
|
-
# must explicitly check for :null to allow change_column to work on migrations
|
502
|
-
if options[:null] == false
|
503
|
-
sql << " NOT NULL"
|
887
|
+
type.to_s
|
504
888
|
end
|
505
889
|
end
|
506
890
|
|
507
|
-
#
|
508
|
-
#
|
891
|
+
# Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT.
|
892
|
+
# PostgreSQL, MySQL, and Oracle overrides this for custom DISTINCT syntax - they
|
893
|
+
# require the order columns appear in the SELECT.
|
894
|
+
#
|
895
|
+
# columns_for_distinct("posts.id", ["posts.created_at desc"])
|
509
896
|
#
|
510
|
-
|
511
|
-
|
512
|
-
"DISTINCT #{columns}"
|
897
|
+
def columns_for_distinct(columns, orders) # :nodoc:
|
898
|
+
columns
|
513
899
|
end
|
514
900
|
|
515
|
-
|
516
|
-
#
|
517
|
-
#
|
518
|
-
|
519
|
-
|
520
|
-
|
901
|
+
include TimestampDefaultDeprecation
|
902
|
+
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
903
|
+
# Additional options (like <tt>null: false</tt>) are forwarded to #add_column.
|
904
|
+
#
|
905
|
+
# add_timestamps(:suppliers, null: false)
|
906
|
+
#
|
907
|
+
def add_timestamps(table_name, options = {})
|
908
|
+
emit_warning_if_null_unspecified(:add_timestamps, options)
|
909
|
+
add_column table_name, :created_at, :datetime, options
|
910
|
+
add_column table_name, :updated_at, :datetime, options
|
521
911
|
end
|
522
912
|
|
523
|
-
# Removes the timestamp columns (created_at and updated_at) from the table definition.
|
524
|
-
#
|
913
|
+
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
|
914
|
+
#
|
525
915
|
# remove_timestamps(:suppliers)
|
526
|
-
|
916
|
+
#
|
917
|
+
def remove_timestamps(table_name, options = {})
|
527
918
|
remove_column table_name, :updated_at
|
528
919
|
remove_column table_name, :created_at
|
529
920
|
end
|
530
921
|
|
922
|
+
def update_table_definition(table_name, base) #:nodoc:
|
923
|
+
Table.new(table_name, base)
|
924
|
+
end
|
925
|
+
|
926
|
+
def add_index_options(table_name, column_name, options = {}) #:nodoc:
|
927
|
+
column_names = Array(column_name)
|
928
|
+
index_name = index_name(table_name, column: column_names)
|
929
|
+
|
930
|
+
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
931
|
+
|
932
|
+
index_type = options[:unique] ? "UNIQUE" : ""
|
933
|
+
index_type = options[:type].to_s if options.key?(:type)
|
934
|
+
index_name = options[:name].to_s if options.key?(:name)
|
935
|
+
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
936
|
+
|
937
|
+
if options.key?(:algorithm)
|
938
|
+
algorithm = index_algorithms.fetch(options[:algorithm]) {
|
939
|
+
raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
|
940
|
+
}
|
941
|
+
end
|
942
|
+
|
943
|
+
using = "USING #{options[:using]}" if options[:using].present?
|
944
|
+
|
945
|
+
if supports_partial_index?
|
946
|
+
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
|
947
|
+
end
|
948
|
+
|
949
|
+
if index_name.length > max_index_length
|
950
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
951
|
+
end
|
952
|
+
if table_exists?(table_name) && index_name_exists?(table_name, index_name, false)
|
953
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
954
|
+
end
|
955
|
+
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
956
|
+
|
957
|
+
[index_name, index_type, index_columns, index_options, algorithm, using]
|
958
|
+
end
|
959
|
+
|
531
960
|
protected
|
532
961
|
def add_index_sort_order(option_strings, column_names, options = {})
|
533
962
|
if options.is_a?(Hash) && order = options[:order]
|
534
963
|
case order
|
535
964
|
when Hash
|
536
|
-
column_names.each {|name| option_strings[name] += " #{order[name].
|
965
|
+
column_names.each {|name| option_strings[name] += " #{order[name].upcase}" if order.has_key?(name)}
|
537
966
|
when String
|
538
967
|
column_names.each {|name| option_strings[name] += " #{order.upcase}"}
|
539
968
|
end
|
@@ -542,7 +971,7 @@ module ActiveRecord
|
|
542
971
|
return option_strings
|
543
972
|
end
|
544
973
|
|
545
|
-
# Overridden by the
|
974
|
+
# Overridden by the MySQL adapter for supporting index lengths
|
546
975
|
def quoted_columns_for_index(column_names, options = {})
|
547
976
|
option_strings = Hash[column_names.map {|name| [name, '']}]
|
548
977
|
|
@@ -558,48 +987,67 @@ module ActiveRecord
|
|
558
987
|
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
559
988
|
end
|
560
989
|
|
561
|
-
def add_index_options(table_name, column_name, options = {})
|
562
|
-
column_names = Array.wrap(column_name)
|
563
|
-
index_name = index_name(table_name, :column => column_names)
|
564
|
-
|
565
|
-
if Hash === options # legacy support, since this param was a string
|
566
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
567
|
-
index_name = options[:name].to_s if options.key?(:name)
|
568
|
-
else
|
569
|
-
index_type = options
|
570
|
-
end
|
571
|
-
|
572
|
-
if index_name.length > index_name_length
|
573
|
-
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters"
|
574
|
-
end
|
575
|
-
if index_name_exists?(table_name, index_name, false)
|
576
|
-
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
577
|
-
end
|
578
|
-
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
579
|
-
|
580
|
-
[index_name, index_type, index_columns]
|
581
|
-
end
|
582
|
-
|
583
990
|
def index_name_for_remove(table_name, options = {})
|
584
991
|
index_name = index_name(table_name, options)
|
585
992
|
|
586
993
|
unless index_name_exists?(table_name, index_name, true)
|
994
|
+
if options.is_a?(Hash) && options.has_key?(:name)
|
995
|
+
options_without_column = options.dup
|
996
|
+
options_without_column.delete :column
|
997
|
+
index_name_without_column = index_name(table_name, options_without_column)
|
998
|
+
|
999
|
+
return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
|
1000
|
+
end
|
1001
|
+
|
587
1002
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
588
1003
|
end
|
589
1004
|
|
590
1005
|
index_name
|
591
1006
|
end
|
592
1007
|
|
593
|
-
def
|
594
|
-
|
1008
|
+
def rename_table_indexes(table_name, new_name)
|
1009
|
+
indexes(new_name).each do |index|
|
1010
|
+
generated_index_name = index_name(table_name, column: index.columns)
|
1011
|
+
if generated_index_name == index.name
|
1012
|
+
rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
end
|
595
1016
|
|
596
|
-
|
597
|
-
|
1017
|
+
def rename_column_indexes(table_name, column_name, new_column_name)
|
1018
|
+
column_name, new_column_name = column_name.to_s, new_column_name.to_s
|
1019
|
+
indexes(table_name).each do |index|
|
1020
|
+
next unless index.columns.include?(new_column_name)
|
1021
|
+
old_columns = index.columns.dup
|
1022
|
+
old_columns[old_columns.index(new_column_name)] = column_name
|
1023
|
+
generated_index_name = index_name(table_name, column: old_columns)
|
1024
|
+
if generated_index_name == index.name
|
1025
|
+
rename_index table_name, generated_index_name, index_name(table_name, column: index.columns)
|
1026
|
+
end
|
1027
|
+
end
|
598
1028
|
end
|
599
1029
|
|
600
1030
|
private
|
601
|
-
def
|
602
|
-
TableDefinition.new
|
1031
|
+
def create_table_definition(name, temporary, options, as = nil)
|
1032
|
+
TableDefinition.new native_database_types, name, temporary, options, as
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
def create_alter_table(name)
|
1036
|
+
AlterTable.new create_table_definition(name, false, {})
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
def foreign_key_name(table_name, options) # :nodoc:
|
1040
|
+
identifier = "#{table_name}_#{options.fetch(:column)}_fk"
|
1041
|
+
hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
|
1042
|
+
options.fetch(:name) do
|
1043
|
+
"fk_rails_#{hashed_identifier}"
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
def validate_index_length!(table_name, new_name)
|
1048
|
+
if new_name.length > allowed_index_name_length
|
1049
|
+
raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters"
|
1050
|
+
end
|
603
1051
|
end
|
604
1052
|
end
|
605
1053
|
end
|