activerecord 4.2.11.3 → 5.0.0.beta1
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 +1029 -1349
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/examples/performance.rb +2 -2
- data/lib/active_record.rb +7 -3
- data/lib/active_record/aggregations.rb +35 -25
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations.rb +305 -204
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +10 -8
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +20 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +41 -18
- data/lib/active_record/associations/builder/collection_association.rb +8 -24
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +10 -5
- data/lib/active_record/associations/builder/singular_association.rb +2 -9
- data/lib/active_record/associations/collection_association.rb +40 -43
- data/lib/active_record/associations/collection_proxy.rb +55 -29
- 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 -52
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +28 -18
- data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
- data/lib/active_record/associations/preloader.rb +13 -4
- data/lib/active_record/associations/preloader/association.rb +45 -51
- 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 +5 -4
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +61 -17
- data/lib/active_record/attribute/user_provided_default.rb +23 -0
- data/lib/active_record/attribute_assignment.rb +27 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +79 -26
- 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 +26 -42
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
- data/lib/active_record/attribute_methods/write.rb +13 -24
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attributes.rb +194 -81
- data/lib/active_record/autosave_association.rb +33 -15
- data/lib/active_record/base.rb +30 -18
- data/lib/active_record/callbacks.rb +36 -40
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
- data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
- data/lib/active_record/connection_adapters/column.rb +27 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
- data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -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 +1 -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 -2
- 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 +23 -16
- 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/quoting.rb +18 -11
- 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 +54 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
- 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/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
- data/lib/active_record/connection_handling.rb +5 -5
- data/lib/active_record/core.rb +72 -104
- data/lib/active_record/counter_cache.rb +9 -20
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +110 -76
- data/lib/active_record/errors.rb +72 -47
- 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 +19 -4
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +27 -40
- data/lib/active_record/integration.rb +4 -4
- 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 +10 -14
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +40 -22
- data/lib/active_record/migration.rb +304 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +90 -0
- data/lib/active_record/model_schema.rb +92 -40
- data/lib/active_record/nested_attributes.rb +45 -34
- data/lib/active_record/null_relation.rb +15 -7
- data/lib/active_record/persistence.rb +112 -72
- data/lib/active_record/querying.rb +6 -5
- data/lib/active_record/railtie.rb +20 -13
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +47 -38
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +182 -57
- data/lib/active_record/relation.rb +152 -100
- data/lib/active_record/relation/batches.rb +133 -33
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +80 -101
- data/lib/active_record/relation/delegation.rb +6 -19
- data/lib/active_record/relation/finder_methods.rb +58 -46
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +13 -42
- data/lib/active_record/relation/predicate_builder.rb +99 -105
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -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/range_handler.rb +17 -0
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +274 -238
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -6
- data/lib/active_record/relation/where_clause.rb +173 -0
- data/lib/active_record/relation/where_clause_factory.rb +37 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +94 -65
- data/lib/active_record/schema.rb +23 -22
- data/lib/active_record/schema_dumper.rb +33 -22
- data/lib/active_record/schema_migration.rb +10 -4
- data/lib/active_record/scoping.rb +17 -6
- data/lib/active_record/scoping/default.rb +19 -6
- data/lib/active_record/scoping/named.rb +39 -28
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +15 -13
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +54 -0
- data/lib/active_record/table_metadata.rb +64 -0
- data/lib/active_record/tasks/database_tasks.rb +30 -40
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
- 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 +16 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type.rb +66 -17
- 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 +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +9 -14
- data/lib/active_record/type/time.rb +3 -21
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +24 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +36 -0
- data/lib/active_record/validations/presence.rb +12 -12
- data/lib/active_record/validations/uniqueness.rb +24 -21
- data/lib/rails/generators/active_record/migration.rb +7 -0
- 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 +4 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +50 -35
- 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
@@ -6,45 +6,84 @@ module ActiveRecord
|
|
6
6
|
# We can then redefine how certain data types may be handled in the schema dumper on the
|
7
7
|
# Adapter level by over-writing this code inside the database specific adapters
|
8
8
|
module ColumnDumper
|
9
|
-
def column_spec(column
|
10
|
-
spec = prepare_column_options(column
|
9
|
+
def column_spec(column)
|
10
|
+
spec = prepare_column_options(column)
|
11
11
|
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k}: ")}
|
12
12
|
spec
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
def column_spec_for_primary_key(column)
|
16
|
+
return if column.type == :integer
|
17
|
+
spec = { id: column.type.inspect }
|
18
|
+
spec.merge!(prepare_column_options(column).delete_if { |key, _| [:name, :type].include?(key) })
|
19
|
+
end
|
20
|
+
|
21
|
+
# This can be overridden on an Adapter level basis to support other
|
16
22
|
# extended datatypes (Example: Adding an array option in the
|
17
|
-
#
|
18
|
-
def prepare_column_options(column
|
23
|
+
# PostgreSQL::ColumnDumper)
|
24
|
+
def prepare_column_options(column)
|
19
25
|
spec = {}
|
20
26
|
spec[:name] = column.name.inspect
|
21
|
-
spec[:type] = column
|
27
|
+
spec[:type] = schema_type(column)
|
22
28
|
spec[:null] = 'false' unless column.null
|
23
29
|
|
24
|
-
limit = column
|
25
|
-
|
26
|
-
|
27
|
-
|
30
|
+
if limit = schema_limit(column)
|
31
|
+
spec[:limit] = limit
|
32
|
+
end
|
33
|
+
|
34
|
+
if precision = schema_precision(column)
|
35
|
+
spec[:precision] = precision
|
36
|
+
end
|
37
|
+
|
38
|
+
if scale = schema_scale(column)
|
39
|
+
spec[:scale] = scale
|
40
|
+
end
|
28
41
|
|
29
42
|
default = schema_default(column) if column.has_default?
|
30
43
|
spec[:default] = default unless default.nil?
|
31
44
|
|
45
|
+
if collation = schema_collation(column)
|
46
|
+
spec[:collation] = collation
|
47
|
+
end
|
48
|
+
|
32
49
|
spec
|
33
50
|
end
|
34
51
|
|
35
52
|
# Lists the valid migration options
|
36
53
|
def migration_keys
|
37
|
-
[:name, :limit, :precision, :scale, :default, :null]
|
54
|
+
[:name, :limit, :precision, :scale, :default, :null, :collation]
|
38
55
|
end
|
39
56
|
|
40
57
|
private
|
41
58
|
|
59
|
+
def schema_type(column)
|
60
|
+
column.type.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
def schema_limit(column)
|
64
|
+
limit = column.limit
|
65
|
+
limit.inspect if limit && limit != native_database_types[column.type][:limit]
|
66
|
+
end
|
67
|
+
|
68
|
+
def schema_precision(column)
|
69
|
+
column.precision.inspect if column.precision
|
70
|
+
end
|
71
|
+
|
72
|
+
def schema_scale(column)
|
73
|
+
column.scale.inspect if column.scale
|
74
|
+
end
|
75
|
+
|
42
76
|
def schema_default(column)
|
43
|
-
|
77
|
+
type = lookup_cast_type_from_column(column)
|
78
|
+
default = type.deserialize(column.default)
|
44
79
|
unless default.nil?
|
45
|
-
|
80
|
+
type.type_cast_for_schema(default)
|
46
81
|
end
|
47
82
|
end
|
83
|
+
|
84
|
+
def schema_collation(column)
|
85
|
+
column.collation.inspect if column.collation
|
86
|
+
end
|
48
87
|
end
|
49
88
|
end
|
50
89
|
end
|
@@ -14,15 +14,19 @@ module ActiveRecord
|
|
14
14
|
{}
|
15
15
|
end
|
16
16
|
|
17
|
+
def table_options(table_name)
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
17
21
|
# Truncates a table alias according to the limits of the current adapter.
|
18
22
|
def table_alias_for(table_name)
|
19
23
|
table_name[0...table_alias_length].tr('.', '_')
|
20
24
|
end
|
21
25
|
|
22
26
|
# Returns the relation names useable to back Active Record models.
|
23
|
-
# For most adapters this means all tables and views.
|
27
|
+
# For most adapters this means all #tables and #views.
|
24
28
|
def data_sources
|
25
|
-
tables
|
29
|
+
tables | views
|
26
30
|
end
|
27
31
|
|
28
32
|
# Checks to see if the data source +name+ exists on the database.
|
@@ -33,6 +37,11 @@ module ActiveRecord
|
|
33
37
|
data_sources.include?(name.to_s)
|
34
38
|
end
|
35
39
|
|
40
|
+
# Returns an array of table names defined in the database.
|
41
|
+
def tables(name = nil)
|
42
|
+
raise NotImplementedError, "#tables is not implemented"
|
43
|
+
end
|
44
|
+
|
36
45
|
# Checks to see if the table +table_name+ exists on the database.
|
37
46
|
#
|
38
47
|
# table_exists?(:developers)
|
@@ -41,6 +50,19 @@ module ActiveRecord
|
|
41
50
|
tables.include?(table_name.to_s)
|
42
51
|
end
|
43
52
|
|
53
|
+
# Returns an array of view names defined in the database.
|
54
|
+
def views
|
55
|
+
raise NotImplementedError, "#views is not implemented"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks to see if the view +view_name+ exists on the database.
|
59
|
+
#
|
60
|
+
# view_exists?(:ebooks)
|
61
|
+
#
|
62
|
+
def view_exists?(view_name)
|
63
|
+
views.include?(view_name.to_s)
|
64
|
+
end
|
65
|
+
|
44
66
|
# Returns an array of indexes for the given table.
|
45
67
|
# def indexes(table_name, name = nil) end
|
46
68
|
|
@@ -60,11 +82,10 @@ module ActiveRecord
|
|
60
82
|
#
|
61
83
|
def index_exists?(table_name, column_name, options = {})
|
62
84
|
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
85
|
checks = []
|
65
|
-
checks << lambda { |i| i.name == index_name }
|
66
86
|
checks << lambda { |i| i.columns == column_names }
|
67
87
|
checks << lambda { |i| i.unique } if options[:unique]
|
88
|
+
checks << lambda { |i| i.name == options[:name].to_s } if options[:name]
|
68
89
|
|
69
90
|
indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
|
70
91
|
end
|
@@ -98,10 +119,16 @@ module ActiveRecord
|
|
98
119
|
(!options.key?(:null) || c.null == options[:null]) }
|
99
120
|
end
|
100
121
|
|
122
|
+
# Returns just a table's primary key
|
123
|
+
def primary_key(table_name)
|
124
|
+
pks = primary_keys(table_name)
|
125
|
+
pks.first if pks.one?
|
126
|
+
end
|
127
|
+
|
101
128
|
# Creates a new table with the name +table_name+. +table_name+ may either
|
102
129
|
# be a String or a Symbol.
|
103
130
|
#
|
104
|
-
# There are two ways to work with
|
131
|
+
# There are two ways to work with #create_table. You can use the block
|
105
132
|
# form or the regular form, like this:
|
106
133
|
#
|
107
134
|
# === Block form
|
@@ -133,13 +160,16 @@ module ActiveRecord
|
|
133
160
|
# The +options+ hash can include the following keys:
|
134
161
|
# [<tt>:id</tt>]
|
135
162
|
# Whether to automatically add a primary key column. Defaults to true.
|
136
|
-
# Join tables for
|
163
|
+
# Join tables for {ActiveRecord::Base.has_and_belongs_to_many}[rdoc-ref:Associations::ClassMethods#has_and_belongs_to_many] should set it to false.
|
164
|
+
#
|
165
|
+
# A Symbol can be used to specify the type of the generated primary key column.
|
137
166
|
# [<tt>:primary_key</tt>]
|
138
167
|
# The name of the primary key, if one is to be added automatically.
|
139
168
|
# Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
|
140
169
|
#
|
141
170
|
# Note that Active Record models will automatically detect their
|
142
|
-
# primary key. This can be avoided by using
|
171
|
+
# primary key. This can be avoided by using
|
172
|
+
# {self.primary_key=}[rdoc-ref:AttributeMethods::PrimaryKey::ClassMethods#primary_key=] on the model
|
143
173
|
# to define the key explicitly.
|
144
174
|
#
|
145
175
|
# [<tt>:options</tt>]
|
@@ -161,7 +191,7 @@ module ActiveRecord
|
|
161
191
|
# generates:
|
162
192
|
#
|
163
193
|
# CREATE TABLE suppliers (
|
164
|
-
# id int
|
194
|
+
# id int auto_increment PRIMARY KEY
|
165
195
|
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
166
196
|
#
|
167
197
|
# ====== Rename the primary key column
|
@@ -173,10 +203,23 @@ module ActiveRecord
|
|
173
203
|
# generates:
|
174
204
|
#
|
175
205
|
# CREATE TABLE objects (
|
176
|
-
# guid int
|
206
|
+
# guid int auto_increment PRIMARY KEY,
|
177
207
|
# name varchar(80)
|
178
208
|
# )
|
179
209
|
#
|
210
|
+
# ====== Change the primary key column type
|
211
|
+
#
|
212
|
+
# create_table(:tags, id: :string) do |t|
|
213
|
+
# t.column :label, :string
|
214
|
+
# end
|
215
|
+
#
|
216
|
+
# generates:
|
217
|
+
#
|
218
|
+
# CREATE TABLE tags (
|
219
|
+
# id varchar PRIMARY KEY,
|
220
|
+
# label varchar
|
221
|
+
# )
|
222
|
+
#
|
180
223
|
# ====== Do not add a primary key column
|
181
224
|
#
|
182
225
|
# create_table(:categories_suppliers, id: false) do |t|
|
@@ -210,12 +253,16 @@ module ActiveRecord
|
|
210
253
|
Base.get_primary_key table_name.to_s.singularize
|
211
254
|
end
|
212
255
|
|
213
|
-
|
256
|
+
if pk.is_a?(Array)
|
257
|
+
td.primary_keys pk
|
258
|
+
else
|
259
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options
|
260
|
+
end
|
214
261
|
end
|
215
262
|
|
216
263
|
yield td if block_given?
|
217
264
|
|
218
|
-
if options[:force] &&
|
265
|
+
if options[:force] && data_source_exists?(table_name)
|
219
266
|
drop_table(table_name, options)
|
220
267
|
end
|
221
268
|
|
@@ -227,10 +274,6 @@ module ActiveRecord
|
|
227
274
|
end
|
228
275
|
end
|
229
276
|
|
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
277
|
result
|
235
278
|
end
|
236
279
|
|
@@ -253,7 +296,7 @@ module ActiveRecord
|
|
253
296
|
# Set to true to drop the table before creating it.
|
254
297
|
# Defaults to false.
|
255
298
|
#
|
256
|
-
# Note that
|
299
|
+
# Note that #create_join_table does not create any indices by default; you can use
|
257
300
|
# its block form to do so yourself:
|
258
301
|
#
|
259
302
|
# create_join_table :products, :categories do |t|
|
@@ -288,11 +331,11 @@ module ActiveRecord
|
|
288
331
|
end
|
289
332
|
|
290
333
|
# Drops the join table specified by the given arguments.
|
291
|
-
# See
|
334
|
+
# See #create_join_table for details.
|
292
335
|
#
|
293
336
|
# Although this command ignores the block if one is given, it can be helpful
|
294
337
|
# 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.
|
338
|
+
# In that case, the block will be used by #create_join_table.
|
296
339
|
def drop_join_table(table_1, table_2, options = {})
|
297
340
|
join_table_name = find_join_table_name(table_1, table_2, options)
|
298
341
|
drop_table(join_table_name)
|
@@ -310,7 +353,7 @@ module ActiveRecord
|
|
310
353
|
# [<tt>:bulk</tt>]
|
311
354
|
# Set this to true to make this a bulk alter query, such as
|
312
355
|
#
|
313
|
-
# ALTER TABLE `users` ADD COLUMN age INT
|
356
|
+
# ALTER TABLE `users` ADD COLUMN age INT, ADD COLUMN birthdate DATETIME ...
|
314
357
|
#
|
315
358
|
# Defaults to false.
|
316
359
|
#
|
@@ -391,16 +434,92 @@ module ActiveRecord
|
|
391
434
|
# [<tt>:force</tt>]
|
392
435
|
# Set to +:cascade+ to drop dependent objects as well.
|
393
436
|
# Defaults to false.
|
437
|
+
# [<tt>:if_exists</tt>]
|
438
|
+
# Set to +true+ to only drop the table if it exists.
|
439
|
+
# Defaults to false.
|
394
440
|
#
|
395
441
|
# Although this command ignores most +options+ and the block if one is given,
|
396
442
|
# 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.
|
443
|
+
# In that case, +options+ and the block will be used by #create_table.
|
398
444
|
def drop_table(table_name, options = {})
|
399
|
-
execute "DROP TABLE #{quote_table_name(table_name)}"
|
445
|
+
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
|
400
446
|
end
|
401
447
|
|
402
|
-
#
|
403
|
-
#
|
448
|
+
# Add a new +type+ column named +column_name+ to +table_name+.
|
449
|
+
#
|
450
|
+
# The +type+ parameter is normally one of the migrations native types,
|
451
|
+
# which is one of the following:
|
452
|
+
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
|
453
|
+
# <tt>:integer</tt>, <tt>:bigint</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
|
454
|
+
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
455
|
+
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
456
|
+
#
|
457
|
+
# You may use a type not in this list as long as it is supported by your
|
458
|
+
# database (for example, "polygon" in MySQL), but this will not be database
|
459
|
+
# agnostic and should usually be avoided.
|
460
|
+
#
|
461
|
+
# Available options are (none of these exists by default):
|
462
|
+
# * <tt>:limit</tt> -
|
463
|
+
# Requests a maximum column length. This is number of characters for a <tt>:string</tt> column
|
464
|
+
# and number of bytes for <tt>:text</tt>, <tt>:binary</tt> and <tt>:integer</tt> columns.
|
465
|
+
# * <tt>:default</tt> -
|
466
|
+
# The column's default value. Use nil for NULL.
|
467
|
+
# * <tt>:null</tt> -
|
468
|
+
# Allows or disallows +NULL+ values in the column. This option could
|
469
|
+
# have been named <tt>:null_allowed</tt>.
|
470
|
+
# * <tt>:precision</tt> -
|
471
|
+
# Specifies the precision for a <tt>:decimal</tt> column.
|
472
|
+
# * <tt>:scale</tt> -
|
473
|
+
# Specifies the scale for a <tt>:decimal</tt> column.
|
474
|
+
#
|
475
|
+
# Note: The precision is the total number of significant digits
|
476
|
+
# and the scale is the number of digits that can be stored following
|
477
|
+
# the decimal point. For example, the number 123.45 has a precision of 5
|
478
|
+
# and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
|
479
|
+
# range from -999.99 to 999.99.
|
480
|
+
#
|
481
|
+
# Please be aware of different RDBMS implementations behavior with
|
482
|
+
# <tt>:decimal</tt> columns:
|
483
|
+
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
|
484
|
+
# <tt>:precision</tt>, and makes no comments about the requirements of
|
485
|
+
# <tt>:precision</tt>.
|
486
|
+
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
|
487
|
+
# Default is (10,0).
|
488
|
+
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
489
|
+
# <tt>:scale</tt> [0..infinity]. No default.
|
490
|
+
# * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
|
491
|
+
# Internal storage as strings. No default.
|
492
|
+
# * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
|
493
|
+
# but the maximum supported <tt>:precision</tt> is 16. No default.
|
494
|
+
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
495
|
+
# Default is (38,0).
|
496
|
+
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
497
|
+
# Default unknown.
|
498
|
+
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
499
|
+
# Default (38,0).
|
500
|
+
#
|
501
|
+
# == Examples
|
502
|
+
#
|
503
|
+
# add_column(:users, :picture, :binary, limit: 2.megabytes)
|
504
|
+
# # ALTER TABLE "users" ADD "picture" blob(2097152)
|
505
|
+
#
|
506
|
+
# add_column(:articles, :status, :string, limit: 20, default: 'draft', null: false)
|
507
|
+
# # ALTER TABLE "articles" ADD "status" varchar(20) DEFAULT 'draft' NOT NULL
|
508
|
+
#
|
509
|
+
# add_column(:answers, :bill_gates_money, :decimal, precision: 15, scale: 2)
|
510
|
+
# # ALTER TABLE "answers" ADD "bill_gates_money" decimal(15,2)
|
511
|
+
#
|
512
|
+
# add_column(:measurements, :sensor_reading, :decimal, precision: 30, scale: 20)
|
513
|
+
# # ALTER TABLE "measurements" ADD "sensor_reading" decimal(30,20)
|
514
|
+
#
|
515
|
+
# # While :scale defaults to zero on most databases, it
|
516
|
+
# # probably wouldn't hurt to include it.
|
517
|
+
# add_column(:measurements, :huge_integer, :decimal, precision: 30)
|
518
|
+
# # ALTER TABLE "measurements" ADD "huge_integer" decimal(30)
|
519
|
+
#
|
520
|
+
# # Defines a column with a database-specific type.
|
521
|
+
# add_column(:shapes, :triangle, 'polygon')
|
522
|
+
# # ALTER TABLE "shapes" ADD "triangle" polygon
|
404
523
|
def add_column(table_name, column_name, type, options = {})
|
405
524
|
at = create_alter_table table_name
|
406
525
|
at.add_column(column_name, type, options)
|
@@ -448,11 +567,16 @@ module ActiveRecord
|
|
448
567
|
#
|
449
568
|
# change_column_default(:users, :email, nil)
|
450
569
|
#
|
451
|
-
|
570
|
+
# Passing a hash containing +:from+ and +:to+ will make this change
|
571
|
+
# reversible in migration:
|
572
|
+
#
|
573
|
+
# change_column_default(:posts, :state, from: nil, to: "draft")
|
574
|
+
#
|
575
|
+
def change_column_default(table_name, column_name, default_or_changes)
|
452
576
|
raise NotImplementedError, "change_column_default is not implemented"
|
453
577
|
end
|
454
578
|
|
455
|
-
# Sets or removes a
|
579
|
+
# Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag
|
456
580
|
# indicates whether the value can be +NULL+. For example
|
457
581
|
#
|
458
582
|
# change_column_null(:users, :nickname, false)
|
@@ -464,7 +588,7 @@ module ActiveRecord
|
|
464
588
|
# allows them to be +NULL+ (drops the constraint).
|
465
589
|
#
|
466
590
|
# The method accepts an optional fourth argument to replace existing
|
467
|
-
#
|
591
|
+
# <tt>NULL</tt>s with some other value. Use that one when enabling the
|
468
592
|
# constraint if needed, since otherwise those rows would not be valid.
|
469
593
|
#
|
470
594
|
# Please note the fourth argument does not set a column's default.
|
@@ -518,6 +642,8 @@ module ActiveRecord
|
|
518
642
|
#
|
519
643
|
# CREATE INDEX by_name ON accounts(name(10))
|
520
644
|
#
|
645
|
+
# ====== Creating an index with specific key lengths for multiple keys
|
646
|
+
#
|
521
647
|
# add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
|
522
648
|
#
|
523
649
|
# generates:
|
@@ -573,15 +699,15 @@ module ActiveRecord
|
|
573
699
|
|
574
700
|
# Removes the given index from the table.
|
575
701
|
#
|
576
|
-
# Removes the +
|
702
|
+
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
577
703
|
#
|
578
|
-
# remove_index :accounts, :
|
704
|
+
# remove_index :accounts, :branch_id
|
579
705
|
#
|
580
|
-
# Removes the index
|
706
|
+
# Removes the index on +branch_id+ in the +accounts+ table if exactly one such index exists.
|
581
707
|
#
|
582
708
|
# remove_index :accounts, column: :branch_id
|
583
709
|
#
|
584
|
-
# Removes the index
|
710
|
+
# Removes the index on +branch_id+ and +party_id+ in the +accounts+ table if exactly one such index exists.
|
585
711
|
#
|
586
712
|
# remove_index :accounts, column: [:branch_id, :party_id]
|
587
713
|
#
|
@@ -590,10 +716,7 @@ module ActiveRecord
|
|
590
716
|
# remove_index :accounts, name: :by_branch_party
|
591
717
|
#
|
592
718
|
def remove_index(table_name, options = {})
|
593
|
-
|
594
|
-
end
|
595
|
-
|
596
|
-
def remove_index!(table_name, index_name) #:nodoc:
|
719
|
+
index_name = index_name_for_remove(table_name, options)
|
597
720
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
598
721
|
end
|
599
722
|
|
@@ -640,7 +763,7 @@ module ActiveRecord
|
|
640
763
|
# Adds a reference. The reference column is an integer by default,
|
641
764
|
# the <tt>:type</tt> option can be used to specify a different type.
|
642
765
|
# Optionally adds a +_type+ column, if <tt>:polymorphic</tt> option is provided.
|
643
|
-
#
|
766
|
+
# #add_reference and #add_belongs_to are acceptable.
|
644
767
|
#
|
645
768
|
# The +options+ hash can include the following keys:
|
646
769
|
# [<tt>:type</tt>]
|
@@ -648,9 +771,11 @@ module ActiveRecord
|
|
648
771
|
# [<tt>:index</tt>]
|
649
772
|
# Add an appropriate index. Defaults to false.
|
650
773
|
# [<tt>:foreign_key</tt>]
|
651
|
-
# Add an appropriate foreign key. Defaults to false.
|
774
|
+
# Add an appropriate foreign key constraint. Defaults to false.
|
652
775
|
# [<tt>:polymorphic</tt>]
|
653
|
-
#
|
776
|
+
# Whether an additional +_type+ column should be added. Defaults to false.
|
777
|
+
# [<tt>:null</tt>]
|
778
|
+
# Whether the column allows nulls. Defaults to true.
|
654
779
|
#
|
655
780
|
# ====== Create a user_id integer column
|
656
781
|
#
|
@@ -664,28 +789,21 @@ module ActiveRecord
|
|
664
789
|
#
|
665
790
|
# add_reference(:products, :supplier, polymorphic: true, index: true)
|
666
791
|
#
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
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
|
792
|
+
# ====== Create a supplier_id column and appropriate foreign key
|
793
|
+
#
|
794
|
+
# add_reference(:products, :supplier, foreign_key: true)
|
795
|
+
#
|
796
|
+
# ====== Create a supplier_id column and a foreign key to the firms table
|
797
|
+
#
|
798
|
+
# add_reference(:products, :supplier, foreign_key: {to_table: :firms})
|
799
|
+
#
|
800
|
+
def add_reference(table_name, *args)
|
801
|
+
ReferenceDefinition.new(*args).add_to(update_table_definition(table_name, self))
|
684
802
|
end
|
685
803
|
alias :add_belongs_to :add_reference
|
686
804
|
|
687
805
|
# Removes the reference(s). Also removes a +type+ column if one exists.
|
688
|
-
#
|
806
|
+
# #remove_reference and #remove_belongs_to are acceptable.
|
689
807
|
#
|
690
808
|
# ====== Remove the reference
|
691
809
|
#
|
@@ -701,8 +819,8 @@ module ActiveRecord
|
|
701
819
|
#
|
702
820
|
def remove_reference(table_name, ref_name, options = {})
|
703
821
|
if options[:foreign_key]
|
704
|
-
|
705
|
-
remove_foreign_key(table_name,
|
822
|
+
reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
|
823
|
+
remove_foreign_key(table_name, reference_name)
|
706
824
|
end
|
707
825
|
|
708
826
|
remove_column(table_name, "#{ref_name}_id")
|
@@ -711,7 +829,7 @@ module ActiveRecord
|
|
711
829
|
alias :remove_belongs_to :remove_reference
|
712
830
|
|
713
831
|
# Returns an array of foreign keys for the given table.
|
714
|
-
# The foreign keys are represented as
|
832
|
+
# The foreign keys are represented as ForeignKeyDefinition objects.
|
715
833
|
def foreign_keys(table_name)
|
716
834
|
raise NotImplementedError, "foreign_keys is not implemented"
|
717
835
|
end
|
@@ -733,7 +851,7 @@ module ActiveRecord
|
|
733
851
|
#
|
734
852
|
# ====== Creating a foreign key on a specific column
|
735
853
|
#
|
736
|
-
# add_foreign_key :articles, :users, column: :author_id, primary_key:
|
854
|
+
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
737
855
|
#
|
738
856
|
# generates:
|
739
857
|
#
|
@@ -755,28 +873,23 @@ module ActiveRecord
|
|
755
873
|
# [<tt>:name</tt>]
|
756
874
|
# The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
|
757
875
|
# [<tt>:on_delete</tt>]
|
758
|
-
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade
|
876
|
+
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
759
877
|
# [<tt>:on_update</tt>]
|
760
|
-
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade
|
878
|
+
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade+ and +:restrict+
|
761
879
|
def add_foreign_key(from_table, to_table, options = {})
|
762
880
|
return unless supports_foreign_keys?
|
763
881
|
|
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
|
-
}
|
882
|
+
options = foreign_key_options(from_table, to_table, options)
|
773
883
|
at = create_alter_table from_table
|
774
884
|
at.add_foreign_key to_table, options
|
775
885
|
|
776
886
|
execute schema_creation.accept(at)
|
777
887
|
end
|
778
888
|
|
779
|
-
# Removes the given foreign key from the table.
|
889
|
+
# Removes the given foreign key from the table. Any option parameters provided
|
890
|
+
# will be used to re-add the foreign key in case of a migration rollback.
|
891
|
+
# It is recommended that you provide any options used when creating the foreign
|
892
|
+
# key so that the migration can be reverted properly.
|
780
893
|
#
|
781
894
|
# Removes the foreign key on +accounts.branch_id+.
|
782
895
|
#
|
@@ -790,24 +903,11 @@ module ActiveRecord
|
|
790
903
|
#
|
791
904
|
# remove_foreign_key :accounts, name: :special_fk_name
|
792
905
|
#
|
906
|
+
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key.
|
793
907
|
def remove_foreign_key(from_table, options_or_to_table = {})
|
794
908
|
return unless supports_foreign_keys?
|
795
909
|
|
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
|
910
|
+
fk_name_to_delete = foreign_key_for!(from_table, options_or_to_table).name
|
811
911
|
|
812
912
|
at = create_alter_table from_table
|
813
913
|
at.drop_foreign_key fk_name_to_delete
|
@@ -815,6 +915,31 @@ module ActiveRecord
|
|
815
915
|
execute schema_creation.accept(at)
|
816
916
|
end
|
817
917
|
|
918
|
+
# Checks to see if a foreign key exists on a table for a given foreign key definition.
|
919
|
+
#
|
920
|
+
# # Check a foreign key exists
|
921
|
+
# foreign_key_exists?(:accounts, :branches)
|
922
|
+
#
|
923
|
+
# # Check a foreign key on a specified column exists
|
924
|
+
# foreign_key_exists?(:accounts, column: :owner_id)
|
925
|
+
#
|
926
|
+
# # Check a foreign key with a custom name exists
|
927
|
+
# foreign_key_exists?(:accounts, name: "special_fk_name")
|
928
|
+
#
|
929
|
+
def foreign_key_exists?(from_table, options_or_to_table = {})
|
930
|
+
foreign_key_for(from_table, options_or_to_table).present?
|
931
|
+
end
|
932
|
+
|
933
|
+
def foreign_key_for(from_table, options_or_to_table = {}) # :nodoc:
|
934
|
+
return unless supports_foreign_keys?
|
935
|
+
foreign_keys(from_table).detect {|fk| fk.defined_for? options_or_to_table }
|
936
|
+
end
|
937
|
+
|
938
|
+
def foreign_key_for!(from_table, options_or_to_table = {}) # :nodoc:
|
939
|
+
foreign_key_for(from_table, options_or_to_table) or \
|
940
|
+
raise ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}"
|
941
|
+
end
|
942
|
+
|
818
943
|
def foreign_key_column_for(table_name) # :nodoc:
|
819
944
|
prefix = Base.table_name_prefix
|
820
945
|
suffix = Base.table_name_suffix
|
@@ -822,6 +947,13 @@ module ActiveRecord
|
|
822
947
|
"#{name.singularize}_id"
|
823
948
|
end
|
824
949
|
|
950
|
+
def foreign_key_options(from_table, to_table, options) # :nodoc:
|
951
|
+
options = options.dup
|
952
|
+
options[:column] ||= foreign_key_column_for(to_table)
|
953
|
+
options[:name] ||= foreign_key_name(from_table, options)
|
954
|
+
options
|
955
|
+
end
|
956
|
+
|
825
957
|
def dump_schema_information #:nodoc:
|
826
958
|
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
827
959
|
|
@@ -836,14 +968,15 @@ module ActiveRecord
|
|
836
968
|
ActiveRecord::SchemaMigration.create_table
|
837
969
|
end
|
838
970
|
|
839
|
-
def assume_migrated_upto_version(version, migrations_paths
|
971
|
+
def assume_migrated_upto_version(version, migrations_paths)
|
840
972
|
migrations_paths = Array(migrations_paths)
|
841
973
|
version = version.to_i
|
842
974
|
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
843
975
|
|
844
976
|
migrated = select_values("SELECT version FROM #{sm_table}").map(&:to_i)
|
845
|
-
|
846
|
-
|
977
|
+
paths = migrations_paths.map {|p| "#{p}/[0-9]*_*.rb" }
|
978
|
+
versions = Dir[*paths].map do |filename|
|
979
|
+
filename.split('/').last.split('_').first.to_i
|
847
980
|
end
|
848
981
|
|
849
982
|
unless migrated.include?(version)
|
@@ -878,6 +1011,12 @@ module ActiveRecord
|
|
878
1011
|
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
|
879
1012
|
end
|
880
1013
|
|
1014
|
+
elsif [:datetime, :time].include?(type) && precision ||= native[:precision]
|
1015
|
+
if (0..6) === precision
|
1016
|
+
column_type_sql << "(#{precision})"
|
1017
|
+
else
|
1018
|
+
raise(ActiveRecordError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6")
|
1019
|
+
end
|
881
1020
|
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
882
1021
|
column_type_sql << "(#{limit})"
|
883
1022
|
end
|
@@ -889,23 +1028,22 @@ module ActiveRecord
|
|
889
1028
|
end
|
890
1029
|
|
891
1030
|
# Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT.
|
892
|
-
# PostgreSQL
|
1031
|
+
# Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax - they
|
893
1032
|
# require the order columns appear in the SELECT.
|
894
1033
|
#
|
895
1034
|
# columns_for_distinct("posts.id", ["posts.created_at desc"])
|
896
|
-
|
897
|
-
def columns_for_distinct(columns, orders) # :nodoc:
|
1035
|
+
def columns_for_distinct(columns, orders) #:nodoc:
|
898
1036
|
columns
|
899
1037
|
end
|
900
1038
|
|
901
|
-
include TimestampDefaultDeprecation
|
902
1039
|
# Adds timestamps (+created_at+ and +updated_at+) columns to +table_name+.
|
903
1040
|
# Additional options (like <tt>null: false</tt>) are forwarded to #add_column.
|
904
1041
|
#
|
905
1042
|
# add_timestamps(:suppliers, null: false)
|
906
1043
|
#
|
907
1044
|
def add_timestamps(table_name, options = {})
|
908
|
-
|
1045
|
+
options[:null] = false if options[:null].nil?
|
1046
|
+
|
909
1047
|
add_column table_name, :created_at, :datetime, options
|
910
1048
|
add_column table_name, :updated_at, :datetime, options
|
911
1049
|
end
|
@@ -925,13 +1063,13 @@ module ActiveRecord
|
|
925
1063
|
|
926
1064
|
def add_index_options(table_name, column_name, options = {}) #:nodoc:
|
927
1065
|
column_names = Array(column_name)
|
928
|
-
index_name = index_name(table_name, column: column_names)
|
929
1066
|
|
930
1067
|
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
931
1068
|
|
932
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
933
1069
|
index_type = options[:type].to_s if options.key?(:type)
|
1070
|
+
index_type ||= options[:unique] ? "UNIQUE" : ""
|
934
1071
|
index_name = options[:name].to_s if options.key?(:name)
|
1072
|
+
index_name ||= index_name(table_name, column: column_names)
|
935
1073
|
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
936
1074
|
|
937
1075
|
if options.key?(:algorithm)
|
@@ -949,7 +1087,7 @@ module ActiveRecord
|
|
949
1087
|
if index_name.length > max_index_length
|
950
1088
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
951
1089
|
end
|
952
|
-
if
|
1090
|
+
if data_source_exists?(table_name) && index_name_exists?(table_name, index_name, false)
|
953
1091
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
954
1092
|
end
|
955
1093
|
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
@@ -957,6 +1095,10 @@ module ActiveRecord
|
|
957
1095
|
[index_name, index_type, index_columns, index_options, algorithm, using]
|
958
1096
|
end
|
959
1097
|
|
1098
|
+
def options_include_default?(options)
|
1099
|
+
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
1100
|
+
end
|
1101
|
+
|
960
1102
|
protected
|
961
1103
|
def add_index_sort_order(option_strings, column_names, options = {})
|
962
1104
|
if options.is_a?(Hash) && order = options[:order]
|
@@ -983,26 +1125,36 @@ module ActiveRecord
|
|
983
1125
|
column_names.map {|name| quote_column_name(name) + option_strings[name]}
|
984
1126
|
end
|
985
1127
|
|
986
|
-
def options_include_default?(options)
|
987
|
-
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
988
|
-
end
|
989
|
-
|
990
1128
|
def index_name_for_remove(table_name, options = {})
|
991
|
-
|
1129
|
+
# if the adapter doesn't support the indexes call the best we can do
|
1130
|
+
# is return the default index name for the options provided
|
1131
|
+
return index_name(table_name, options) unless respond_to?(:indexes)
|
992
1132
|
|
993
|
-
|
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)
|
1133
|
+
checks = []
|
998
1134
|
|
999
|
-
|
1000
|
-
|
1135
|
+
if options.is_a?(Hash)
|
1136
|
+
checks << lambda { |i| i.name == options[:name].to_s } if options.has_key?(:name)
|
1137
|
+
column_names = Array(options[:column]).map(&:to_s)
|
1138
|
+
else
|
1139
|
+
column_names = Array(options).map(&:to_s)
|
1140
|
+
end
|
1001
1141
|
|
1002
|
-
|
1142
|
+
if column_names.any?
|
1143
|
+
checks << lambda { |i| i.columns.join('_and_') == column_names.join('_and_') }
|
1003
1144
|
end
|
1004
1145
|
|
1005
|
-
|
1146
|
+
raise ArgumentError "No name or columns specified" if checks.none?
|
1147
|
+
|
1148
|
+
matching_indexes = indexes(table_name).select { |i| checks.all? { |check| check[i] } }
|
1149
|
+
|
1150
|
+
if matching_indexes.count > 1
|
1151
|
+
raise ArgumentError, "Multiple indexes found on #{table_name} columns #{column_names}. " \
|
1152
|
+
"Specify an index name from #{matching_indexes.map(&:name).join(', ')}"
|
1153
|
+
elsif matching_indexes.none?
|
1154
|
+
raise ArgumentError, "No indexes found on #{table_name} with the options provided."
|
1155
|
+
else
|
1156
|
+
matching_indexes.first.name
|
1157
|
+
end
|
1006
1158
|
end
|
1007
1159
|
|
1008
1160
|
def rename_table_indexes(table_name, new_name)
|
@@ -1028,12 +1180,12 @@ module ActiveRecord
|
|
1028
1180
|
end
|
1029
1181
|
|
1030
1182
|
private
|
1031
|
-
def create_table_definition(name, temporary, options, as = nil)
|
1032
|
-
TableDefinition.new
|
1183
|
+
def create_table_definition(name, temporary = false, options = nil, as = nil)
|
1184
|
+
TableDefinition.new(name, temporary, options, as)
|
1033
1185
|
end
|
1034
1186
|
|
1035
1187
|
def create_alter_table(name)
|
1036
|
-
AlterTable.new create_table_definition(name
|
1188
|
+
AlterTable.new create_table_definition(name)
|
1037
1189
|
end
|
1038
1190
|
|
1039
1191
|
def foreign_key_name(table_name, options) # :nodoc:
|
@@ -1044,11 +1196,19 @@ module ActiveRecord
|
|
1044
1196
|
end
|
1045
1197
|
end
|
1046
1198
|
|
1047
|
-
def validate_index_length!(table_name, new_name)
|
1199
|
+
def validate_index_length!(table_name, new_name) # :nodoc:
|
1048
1200
|
if new_name.length > allowed_index_name_length
|
1049
1201
|
raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters"
|
1050
1202
|
end
|
1051
1203
|
end
|
1204
|
+
|
1205
|
+
def extract_new_default_value(default_or_changes)
|
1206
|
+
if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
|
1207
|
+
default_or_changes[:to]
|
1208
|
+
else
|
1209
|
+
default_or_changes
|
1210
|
+
end
|
1211
|
+
end
|
1052
1212
|
end
|
1053
1213
|
end
|
1054
1214
|
end
|