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
@@ -18,9 +18,9 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# Returns the maximum allowed length for an index name. This
|
21
|
-
# limit is enforced by
|
22
|
-
#
|
23
|
-
#
|
21
|
+
# limit is enforced by \Rails and is less than or equal to
|
22
|
+
# #index_name_length. The gap between
|
23
|
+
# #index_name_length is to allow internal \Rails
|
24
24
|
# operations to use prefixes in temporary operations.
|
25
25
|
def allowed_index_name_length
|
26
26
|
index_name_length
|
@@ -29,7 +29,17 @@ module ActiveRecord
|
|
29
29
|
# Returns an ActiveRecord::Result instance.
|
30
30
|
def select_all(arel, name = nil, binds = [])
|
31
31
|
arel, binds = binds_from_relation arel, binds
|
32
|
-
|
32
|
+
sql = to_sql(arel, binds)
|
33
|
+
if arel.is_a?(String)
|
34
|
+
preparable = false
|
35
|
+
else
|
36
|
+
preparable = visitor.preparable
|
37
|
+
end
|
38
|
+
if prepared_statements && preparable
|
39
|
+
select_prepared(sql, name, binds)
|
40
|
+
else
|
41
|
+
select(sql, name, binds)
|
42
|
+
end
|
33
43
|
end
|
34
44
|
|
35
45
|
# Returns a record hash with the column names as keys and column values
|
@@ -40,8 +50,9 @@ module ActiveRecord
|
|
40
50
|
|
41
51
|
# Returns a single value from a record
|
42
52
|
def select_value(arel, name = nil, binds = [])
|
43
|
-
|
44
|
-
|
53
|
+
arel, binds = binds_from_relation arel, binds
|
54
|
+
if result = select_rows(to_sql(arel, binds), name, binds).first
|
55
|
+
result.first
|
45
56
|
end
|
46
57
|
end
|
47
58
|
|
@@ -66,7 +77,7 @@ module ActiveRecord
|
|
66
77
|
# Executes +sql+ statement in the context of this connection using
|
67
78
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
68
79
|
# the executed +sql+ statement.
|
69
|
-
def exec_query(sql, name = 'SQL', binds = [])
|
80
|
+
def exec_query(sql, name = 'SQL', binds = [], prepare: false)
|
70
81
|
end
|
71
82
|
|
72
83
|
# Executes insert +sql+ statement in the context of this connection using
|
@@ -136,7 +147,7 @@ module ActiveRecord
|
|
136
147
|
#
|
137
148
|
# In order to get around this problem, #transaction will emulate the effect
|
138
149
|
# of nested transactions, by using savepoints:
|
139
|
-
# http://dev.mysql.com/doc/refman/5.
|
150
|
+
# http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
140
151
|
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
141
152
|
# supports savepoints.
|
142
153
|
#
|
@@ -188,10 +199,10 @@ module ActiveRecord
|
|
188
199
|
# You should consult the documentation for your database to understand the
|
189
200
|
# semantics of these different levels:
|
190
201
|
#
|
191
|
-
# * http://www.postgresql.org/docs/
|
192
|
-
# * https://dev.mysql.com/doc/refman/5.
|
202
|
+
# * http://www.postgresql.org/docs/current/static/transaction-iso.html
|
203
|
+
# * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
|
193
204
|
#
|
194
|
-
# An
|
205
|
+
# An ActiveRecord::TransactionIsolationError will be raised if:
|
195
206
|
#
|
196
207
|
# * The adapter does not support setting the isolation level
|
197
208
|
# * You are joining an existing open transaction
|
@@ -201,16 +212,14 @@ module ActiveRecord
|
|
201
212
|
# isolation level. However, support is disabled for MySQL versions below 5,
|
202
213
|
# because they are affected by a bug[http://bugs.mysql.com/bug.php?id=39170]
|
203
214
|
# which means the isolation level gets persisted outside the transaction.
|
204
|
-
def transaction(
|
205
|
-
|
206
|
-
|
207
|
-
if !options[:requires_new] && current_transaction.joinable?
|
208
|
-
if options[:isolation]
|
215
|
+
def transaction(requires_new: nil, isolation: nil, joinable: true)
|
216
|
+
if !requires_new && current_transaction.joinable?
|
217
|
+
if isolation
|
209
218
|
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
210
219
|
end
|
211
220
|
yield
|
212
221
|
else
|
213
|
-
transaction_manager.within_new_transaction(
|
222
|
+
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
|
214
223
|
end
|
215
224
|
rescue ActiveRecord::Rollback
|
216
225
|
# rollbacks are silently swallowed
|
@@ -287,16 +296,22 @@ module ActiveRecord
|
|
287
296
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
288
297
|
# something beyond a simple insert (eg. Oracle).
|
289
298
|
def insert_fixture(fixture, table_name)
|
290
|
-
fixture = fixture.stringify_keys
|
291
299
|
columns = schema_cache.columns_hash(table_name)
|
292
300
|
|
293
|
-
|
294
|
-
value_list = fixture.map do |name, value|
|
301
|
+
binds = fixture.map do |name, value|
|
295
302
|
if column = columns[name]
|
296
|
-
|
297
|
-
|
303
|
+
type = lookup_cast_type_from_column(column)
|
304
|
+
Relation::QueryAttribute.new(name, value, type)
|
298
305
|
else
|
299
|
-
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name
|
306
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no column named "#{name}".)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
key_list = fixture.keys.map { |name| quote_column_name(name) }
|
310
|
+
value_list = prepare_binds_for_database(binds).map do |value|
|
311
|
+
begin
|
312
|
+
quote(value)
|
313
|
+
rescue TypeError
|
314
|
+
quote(YAML.dump(value))
|
300
315
|
end
|
301
316
|
end
|
302
317
|
|
@@ -353,9 +368,12 @@ module ActiveRecord
|
|
353
368
|
|
354
369
|
# Returns an ActiveRecord::Result instance.
|
355
370
|
def select(sql, name = nil, binds = [])
|
356
|
-
exec_query(sql, name, binds)
|
371
|
+
exec_query(sql, name, binds, prepare: false)
|
357
372
|
end
|
358
373
|
|
374
|
+
def select_prepared(sql, name = nil, binds = [])
|
375
|
+
exec_query(sql, name, binds, prepare: true)
|
376
|
+
end
|
359
377
|
|
360
378
|
# Returns the last auto-generated ID from the affected table.
|
361
379
|
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
@@ -384,7 +402,7 @@ module ActiveRecord
|
|
384
402
|
|
385
403
|
def binds_from_relation(relation, binds)
|
386
404
|
if relation.is_a?(Relation) && binds.empty?
|
387
|
-
relation, binds = relation.arel, relation.
|
405
|
+
relation, binds = relation.arel, relation.bound_attributes
|
388
406
|
end
|
389
407
|
[relation, binds]
|
390
408
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'active_support/core_ext/big_decimal/conversions'
|
2
|
-
require "active_support/multibyte/chars"
|
3
2
|
|
4
3
|
module ActiveRecord
|
5
4
|
module ConnectionAdapters # :nodoc:
|
@@ -11,7 +10,13 @@ module ActiveRecord
|
|
11
10
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
12
11
|
|
13
12
|
if column
|
14
|
-
|
13
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
14
|
+
Passing a column to `quote` has been deprecated. It is only used
|
15
|
+
for type casting, which should be handled elsewhere. See
|
16
|
+
https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
|
17
|
+
for more information.
|
18
|
+
MSG
|
19
|
+
value = type_cast_from_column(column, value)
|
15
20
|
end
|
16
21
|
|
17
22
|
_quote(value)
|
@@ -20,13 +25,13 @@ module ActiveRecord
|
|
20
25
|
# Cast a +value+ to a type that the database understands. For example,
|
21
26
|
# SQLite does not understand dates, so this method will convert a Date
|
22
27
|
# to a String.
|
23
|
-
def type_cast(value, column)
|
28
|
+
def type_cast(value, column = nil)
|
24
29
|
if value.respond_to?(:quoted_id) && value.respond_to?(:id)
|
25
30
|
return value.id
|
26
31
|
end
|
27
32
|
|
28
33
|
if column
|
29
|
-
value = column
|
34
|
+
value = type_cast_from_column(column, value)
|
30
35
|
end
|
31
36
|
|
32
37
|
_type_cast(value)
|
@@ -35,10 +40,44 @@ module ActiveRecord
|
|
35
40
|
raise TypeError, "can't cast #{value.class}#{to_type}"
|
36
41
|
end
|
37
42
|
|
43
|
+
# If you are having to call this function, you are likely doing something
|
44
|
+
# wrong. The column does not have sufficient type information if the user
|
45
|
+
# provided a custom type on the class level either explicitly (via
|
46
|
+
# Attributes::ClassMethods#attribute) or implicitly (via
|
47
|
+
# AttributeMethods::Serialization::ClassMethods#serialize, +time_zone_aware_attributes+).
|
48
|
+
# In almost all cases, the sql type should only be used to change quoting behavior, when the primitive to
|
49
|
+
# represent the type doesn't sufficiently reflect the differences
|
50
|
+
# (varchar vs binary) for example. The type used to get this primitive
|
51
|
+
# should have been provided before reaching the connection adapter.
|
52
|
+
def type_cast_from_column(column, value) # :nodoc:
|
53
|
+
if column
|
54
|
+
type = lookup_cast_type_from_column(column)
|
55
|
+
type.serialize(value)
|
56
|
+
else
|
57
|
+
value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# See docs for #type_cast_from_column
|
62
|
+
def lookup_cast_type_from_column(column) # :nodoc:
|
63
|
+
lookup_cast_type(column.sql_type)
|
64
|
+
end
|
65
|
+
|
66
|
+
def fetch_type_metadata(sql_type)
|
67
|
+
cast_type = lookup_cast_type(sql_type)
|
68
|
+
SqlTypeMetadata.new(
|
69
|
+
sql_type: sql_type,
|
70
|
+
type: cast_type.type,
|
71
|
+
limit: cast_type.limit,
|
72
|
+
precision: cast_type.precision,
|
73
|
+
scale: cast_type.scale,
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
38
77
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
39
78
|
# characters.
|
40
79
|
def quote_string(s)
|
41
|
-
s.gsub(
|
80
|
+
s.gsub('\\'.freeze, '\&\&'.freeze).gsub("'".freeze, "''".freeze) # ' (for ruby-mode)
|
42
81
|
end
|
43
82
|
|
44
83
|
# Quotes the column name. Defaults to no quoting.
|
@@ -63,6 +102,11 @@ module ActiveRecord
|
|
63
102
|
quote_table_name("#{table}.#{attr}")
|
64
103
|
end
|
65
104
|
|
105
|
+
def quote_default_expression(value, column) #:nodoc:
|
106
|
+
value = lookup_cast_type(column.sql_type).serialize(value)
|
107
|
+
quote(value)
|
108
|
+
end
|
109
|
+
|
66
110
|
def quoted_true
|
67
111
|
"'t'"
|
68
112
|
end
|
@@ -79,6 +123,8 @@ module ActiveRecord
|
|
79
123
|
'f'
|
80
124
|
end
|
81
125
|
|
126
|
+
# Quote date/time values for use in SQL input. Includes microseconds
|
127
|
+
# if the value is a Time responding to usec.
|
82
128
|
def quoted_date(value)
|
83
129
|
if value.acts_like?(:time)
|
84
130
|
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
@@ -88,7 +134,16 @@ module ActiveRecord
|
|
88
134
|
end
|
89
135
|
end
|
90
136
|
|
91
|
-
value.to_s(:db)
|
137
|
+
result = value.to_s(:db)
|
138
|
+
if value.respond_to?(:usec) && value.usec > 0
|
139
|
+
"#{result}.#{sprintf("%06d", value.usec)}"
|
140
|
+
else
|
141
|
+
result
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def prepare_binds_for_database(binds) # :nodoc:
|
146
|
+
binds.map(&:value_for_database)
|
92
147
|
end
|
93
148
|
|
94
149
|
private
|
@@ -110,8 +165,7 @@ module ActiveRecord
|
|
110
165
|
when Date, Time then "'#{quoted_date(value)}'"
|
111
166
|
when Symbol then "'#{quote_string(value.to_s)}'"
|
112
167
|
when Class then "'#{value}'"
|
113
|
-
else
|
114
|
-
"'#{quote_string(YAML.dump(value))}'"
|
168
|
+
else raise TypeError, "can't quote #{value.class.name}"
|
115
169
|
end
|
116
170
|
end
|
117
171
|
|
@@ -14,38 +14,58 @@ module ActiveRecord
|
|
14
14
|
send m, o
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
18
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
|
19
|
+
private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
20
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options
|
20
21
|
|
21
22
|
private
|
22
23
|
|
23
24
|
def visit_AlterTable(o)
|
24
25
|
sql = "ALTER TABLE #{quote_table_name(o.name)} "
|
25
|
-
sql << o.adds.map { |col|
|
26
|
+
sql << o.adds.map { |col| accept col }.join(' ')
|
26
27
|
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
|
27
28
|
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
|
28
29
|
end
|
29
30
|
|
30
31
|
def visit_ColumnDefinition(o)
|
31
|
-
sql_type
|
32
|
-
column_sql = "#{quote_column_name(o.name)} #{sql_type}"
|
33
|
-
add_column_options!(column_sql, column_options(o)) unless o.primary_key
|
32
|
+
o.sql_type ||= type_to_sql(o.type, o.limit, o.precision, o.scale)
|
33
|
+
column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
|
34
|
+
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
34
35
|
column_sql
|
35
36
|
end
|
36
37
|
|
38
|
+
def visit_AddColumnDefinition(o)
|
39
|
+
"ADD #{accept(o.column)}"
|
40
|
+
end
|
41
|
+
|
37
42
|
def visit_TableDefinition(o)
|
38
|
-
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE "
|
39
|
-
|
40
|
-
|
43
|
+
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
|
44
|
+
|
45
|
+
statements = o.columns.map { |c| accept c }
|
46
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
47
|
+
|
48
|
+
if supports_indexes_in_create?
|
49
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
50
|
+
end
|
51
|
+
|
52
|
+
if supports_foreign_keys?
|
53
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
54
|
+
end
|
55
|
+
|
56
|
+
create_sql << "(#{statements.join(', ')}) " if statements.present?
|
41
57
|
create_sql << "#{o.options}"
|
42
58
|
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
43
59
|
create_sql
|
44
60
|
end
|
45
61
|
|
46
|
-
def
|
62
|
+
def visit_PrimaryKeyDefinition(o)
|
63
|
+
"PRIMARY KEY (#{o.name.join(', ')})"
|
64
|
+
end
|
65
|
+
|
66
|
+
def visit_ForeignKeyDefinition(o)
|
47
67
|
sql = <<-SQL.strip_heredoc
|
48
|
-
|
68
|
+
CONSTRAINT #{quote_column_name(o.name)}
|
49
69
|
FOREIGN KEY (#{quote_column_name(o.column)})
|
50
70
|
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
|
51
71
|
SQL
|
@@ -54,6 +74,10 @@ module ActiveRecord
|
|
54
74
|
sql
|
55
75
|
end
|
56
76
|
|
77
|
+
def visit_AddForeignKey(o)
|
78
|
+
"ADD #{accept(o)}"
|
79
|
+
end
|
80
|
+
|
57
81
|
def visit_DropForeignKey(name)
|
58
82
|
"DROP CONSTRAINT #{quote_column_name(name)}"
|
59
83
|
end
|
@@ -65,23 +89,14 @@ module ActiveRecord
|
|
65
89
|
column_options[:column] = o
|
66
90
|
column_options[:first] = o.first
|
67
91
|
column_options[:after] = o.after
|
92
|
+
column_options[:auto_increment] = o.auto_increment
|
93
|
+
column_options[:primary_key] = o.primary_key
|
94
|
+
column_options[:collation] = o.collation
|
68
95
|
column_options
|
69
96
|
end
|
70
97
|
|
71
|
-
def quote_column_name(name)
|
72
|
-
@conn.quote_column_name name
|
73
|
-
end
|
74
|
-
|
75
|
-
def quote_table_name(name)
|
76
|
-
@conn.quote_table_name name
|
77
|
-
end
|
78
|
-
|
79
|
-
def type_to_sql(type, limit, precision, scale)
|
80
|
-
@conn.type_to_sql type.to_sym, limit, precision, scale
|
81
|
-
end
|
82
|
-
|
83
98
|
def add_column_options!(sql, options)
|
84
|
-
sql << " DEFAULT #{
|
99
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
85
100
|
# must explicitly check for :null to allow change_column to work on migrations
|
86
101
|
if options[:null] == false
|
87
102
|
sql << " NOT NULL"
|
@@ -89,18 +104,15 @@ module ActiveRecord
|
|
89
104
|
if options[:auto_increment] == true
|
90
105
|
sql << " AUTO_INCREMENT"
|
91
106
|
end
|
107
|
+
if options[:primary_key] == true
|
108
|
+
sql << " PRIMARY KEY"
|
109
|
+
end
|
92
110
|
sql
|
93
111
|
end
|
94
112
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
@conn.quote(value, column)
|
100
|
-
end
|
101
|
-
|
102
|
-
def options_include_default?(options)
|
103
|
-
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
113
|
+
def foreign_key_in_create(from_table, to_table, options)
|
114
|
+
options = foreign_key_options(from_table, to_table, options)
|
115
|
+
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
104
116
|
end
|
105
117
|
|
106
118
|
def action_sql(action, dependency)
|
@@ -115,10 +127,6 @@ module ActiveRecord
|
|
115
127
|
MSG
|
116
128
|
end
|
117
129
|
end
|
118
|
-
|
119
|
-
def type_for_column(column)
|
120
|
-
@conn.lookup_cast_type(column.sql_type)
|
121
|
-
end
|
122
130
|
end
|
123
131
|
end
|
124
132
|
end
|
@@ -1,8 +1,3 @@
|
|
1
|
-
require 'date'
|
2
|
-
require 'set'
|
3
|
-
require 'bigdecimal'
|
4
|
-
require 'bigdecimal/util'
|
5
|
-
|
6
1
|
module ActiveRecord
|
7
2
|
module ConnectionAdapters #:nodoc:
|
8
3
|
# Abstract representation of an index definition on a table. Instances of
|
@@ -15,14 +10,20 @@ module ActiveRecord
|
|
15
10
|
# are typically created by methods in TableDefinition, and added to the
|
16
11
|
# +columns+ attribute of said TableDefinition object, in order to be used
|
17
12
|
# for generating a number of table creation or table changing SQL statements.
|
18
|
-
class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :
|
13
|
+
class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type) #:nodoc:
|
19
14
|
|
20
15
|
def primary_key?
|
21
16
|
primary_key || type.to_sym == :primary_key
|
22
17
|
end
|
23
18
|
end
|
24
19
|
|
25
|
-
class
|
20
|
+
class AddColumnDefinition < Struct.new(:column) # :nodoc:
|
21
|
+
end
|
22
|
+
|
23
|
+
class ChangeColumnDefinition < Struct.new(:column, :name) #:nodoc:
|
24
|
+
end
|
25
|
+
|
26
|
+
class PrimaryKeyDefinition < Struct.new(:name) # :nodoc:
|
26
27
|
end
|
27
28
|
|
28
29
|
class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
|
@@ -50,31 +51,146 @@ module ActiveRecord
|
|
50
51
|
options[:primary_key] != default_primary_key
|
51
52
|
end
|
52
53
|
|
54
|
+
def defined_for?(options_or_to_table = {})
|
55
|
+
if options_or_to_table.is_a?(Hash)
|
56
|
+
options_or_to_table.all? {|key, value| options[key].to_s == value.to_s }
|
57
|
+
else
|
58
|
+
to_table == options_or_to_table.to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
53
62
|
private
|
54
63
|
def default_primary_key
|
55
64
|
"id"
|
56
65
|
end
|
57
66
|
end
|
58
67
|
|
59
|
-
|
60
|
-
def
|
61
|
-
|
68
|
+
class ReferenceDefinition # :nodoc:
|
69
|
+
def initialize(
|
70
|
+
name,
|
71
|
+
polymorphic: false,
|
72
|
+
index: false,
|
73
|
+
foreign_key: false,
|
74
|
+
type: :integer,
|
75
|
+
**options
|
76
|
+
)
|
77
|
+
@name = name
|
78
|
+
@polymorphic = polymorphic
|
79
|
+
@index = index
|
80
|
+
@foreign_key = foreign_key
|
81
|
+
@type = type
|
82
|
+
@options = options
|
83
|
+
|
84
|
+
if polymorphic && foreign_key
|
85
|
+
raise ArgumentError, "Cannot add a foreign key to a polymorphic relation"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def add_to(table)
|
90
|
+
columns.each do |column_options|
|
91
|
+
table.column(*column_options)
|
92
|
+
end
|
93
|
+
|
94
|
+
if index
|
95
|
+
table.index(column_names, index_options)
|
96
|
+
end
|
97
|
+
|
98
|
+
if foreign_key
|
99
|
+
table.foreign_key(foreign_table_name, foreign_key_options)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
|
105
|
+
attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def as_options(value, default = {})
|
110
|
+
if value.is_a?(Hash)
|
111
|
+
value
|
112
|
+
else
|
113
|
+
default
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def polymorphic_options
|
118
|
+
as_options(polymorphic, options)
|
119
|
+
end
|
120
|
+
|
121
|
+
def index_options
|
122
|
+
as_options(index)
|
123
|
+
end
|
124
|
+
|
125
|
+
def foreign_key_options
|
126
|
+
as_options(foreign_key).merge(column: column_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
def columns
|
130
|
+
result = [[column_name, type, options]]
|
131
|
+
if polymorphic
|
132
|
+
result.unshift(["#{name}_type", :string, polymorphic_options])
|
133
|
+
end
|
134
|
+
result
|
135
|
+
end
|
136
|
+
|
137
|
+
def column_name
|
138
|
+
"#{name}_id"
|
139
|
+
end
|
140
|
+
|
141
|
+
def column_names
|
142
|
+
columns.map(&:first)
|
143
|
+
end
|
144
|
+
|
145
|
+
def foreign_table_name
|
146
|
+
foreign_key_options.fetch(:to_table) do
|
147
|
+
Base.pluralize_table_names ? name.to_s.pluralize : name
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
module ColumnMethods
|
153
|
+
# Appends a primary key definition to the table definition.
|
154
|
+
# Can be called multiple times, but this is probably not a good idea.
|
155
|
+
def primary_key(name, type = :primary_key, **options)
|
156
|
+
column(name, type, options.merge(primary_key: true))
|
157
|
+
end
|
62
158
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
159
|
+
# Appends a column or columns of a specified type.
|
160
|
+
#
|
161
|
+
# t.string(:goat)
|
162
|
+
# t.string(:goat, :sheep)
|
163
|
+
#
|
164
|
+
# See TableDefinition#column
|
165
|
+
[
|
166
|
+
:bigint,
|
167
|
+
:binary,
|
168
|
+
:boolean,
|
169
|
+
:date,
|
170
|
+
:datetime,
|
171
|
+
:decimal,
|
172
|
+
:float,
|
173
|
+
:integer,
|
174
|
+
:string,
|
175
|
+
:text,
|
176
|
+
:time,
|
177
|
+
:timestamp,
|
178
|
+
].each do |column_type|
|
179
|
+
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
180
|
+
def #{column_type}(*args, **options)
|
181
|
+
args.each { |name| column(name, :#{column_type}, options) }
|
182
|
+
end
|
183
|
+
CODE
|
68
184
|
end
|
69
185
|
end
|
70
186
|
|
71
187
|
# Represents the schema of an SQL table in an abstract way. This class
|
72
188
|
# provides methods for manipulating the schema representation.
|
73
189
|
#
|
74
|
-
# Inside migration files, the +t+ object in
|
190
|
+
# Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
|
75
191
|
# is actually of this type:
|
76
192
|
#
|
77
|
-
# class SomeMigration < ActiveRecord::Migration
|
193
|
+
# class SomeMigration < ActiveRecord::Migration[5.0]
|
78
194
|
# def up
|
79
195
|
# create_table :foo do |t|
|
80
196
|
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
|
@@ -86,125 +202,54 @@ module ActiveRecord
|
|
86
202
|
# end
|
87
203
|
# end
|
88
204
|
#
|
89
|
-
# The table definitions
|
90
|
-
# The Columns are stored as a ColumnDefinition in the +columns+ attribute.
|
91
205
|
class TableDefinition
|
92
|
-
include
|
206
|
+
include ColumnMethods
|
93
207
|
|
94
|
-
# An array of ColumnDefinition objects, representing the column changes
|
95
|
-
# that have been defined.
|
96
208
|
attr_accessor :indexes
|
97
209
|
attr_reader :name, :temporary, :options, :as, :foreign_keys
|
98
210
|
|
99
|
-
def initialize(
|
211
|
+
def initialize(name, temporary, options, as = nil)
|
100
212
|
@columns_hash = {}
|
101
213
|
@indexes = {}
|
102
|
-
@foreign_keys =
|
103
|
-
@
|
214
|
+
@foreign_keys = {}
|
215
|
+
@primary_keys = nil
|
104
216
|
@temporary = temporary
|
105
217
|
@options = options
|
106
218
|
@as = as
|
107
219
|
@name = name
|
108
220
|
end
|
109
221
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
113
|
-
# Can be called multiple times, but this is probably not a good idea.
|
114
|
-
def primary_key(name, type = :primary_key, options = {})
|
115
|
-
column(name, type, options.merge(:primary_key => true))
|
222
|
+
def primary_keys(name = nil) # :nodoc:
|
223
|
+
@primary_keys = PrimaryKeyDefinition.new(name) if name
|
224
|
+
@primary_keys
|
116
225
|
end
|
117
226
|
|
227
|
+
# Returns an array of ColumnDefinition objects for the columns of the table.
|
228
|
+
def columns; @columns_hash.values; end
|
229
|
+
|
118
230
|
# Returns a ColumnDefinition for the column with name +name+.
|
119
231
|
def [](name)
|
120
232
|
@columns_hash[name.to_s]
|
121
233
|
end
|
122
234
|
|
123
235
|
# Instantiates a new column for the table.
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
# <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
|
129
|
-
# <tt>:binary</tt>, <tt>:boolean</tt>.
|
130
|
-
#
|
131
|
-
# You may use a type not in this list as long as it is supported by your
|
132
|
-
# database (for example, "polygon" in MySQL), but this will not be database
|
133
|
-
# agnostic and should usually be avoided.
|
134
|
-
#
|
135
|
-
# Available options are (none of these exists by default):
|
136
|
-
# * <tt>:limit</tt> -
|
137
|
-
# Requests a maximum column length. This is number of characters for <tt>:string</tt> and
|
138
|
-
# <tt>:text</tt> columns and number of bytes for <tt>:binary</tt> and <tt>:integer</tt> columns.
|
139
|
-
# * <tt>:default</tt> -
|
140
|
-
# The column's default value. Use nil for NULL.
|
141
|
-
# * <tt>:null</tt> -
|
142
|
-
# Allows or disallows +NULL+ values in the column. This option could
|
143
|
-
# have been named <tt>:null_allowed</tt>.
|
144
|
-
# * <tt>:precision</tt> -
|
145
|
-
# Specifies the precision for a <tt>:decimal</tt> column.
|
146
|
-
# * <tt>:scale</tt> -
|
147
|
-
# Specifies the scale for a <tt>:decimal</tt> column.
|
236
|
+
# See {connection.add_column}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_column]
|
237
|
+
# for available options.
|
238
|
+
#
|
239
|
+
# Additional options are:
|
148
240
|
# * <tt>:index</tt> -
|
149
241
|
# Create an index for the column. Can be either <tt>true</tt> or an options hash.
|
150
242
|
#
|
151
|
-
# Note: The precision is the total number of significant digits
|
152
|
-
# and the scale is the number of digits that can be stored following
|
153
|
-
# the decimal point. For example, the number 123.45 has a precision of 5
|
154
|
-
# and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
|
155
|
-
# range from -999.99 to 999.99.
|
156
|
-
#
|
157
|
-
# Please be aware of different RDBMS implementations behavior with
|
158
|
-
# <tt>:decimal</tt> columns:
|
159
|
-
# * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
|
160
|
-
# <tt>:precision</tt>, and makes no comments about the requirements of
|
161
|
-
# <tt>:precision</tt>.
|
162
|
-
# * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
|
163
|
-
# Default is (10,0).
|
164
|
-
# * PostgreSQL: <tt>:precision</tt> [1..infinity],
|
165
|
-
# <tt>:scale</tt> [0..infinity]. No default.
|
166
|
-
# * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
|
167
|
-
# Internal storage as strings. No default.
|
168
|
-
# * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
|
169
|
-
# but the maximum supported <tt>:precision</tt> is 16. No default.
|
170
|
-
# * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
|
171
|
-
# Default is (38,0).
|
172
|
-
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
173
|
-
# Default unknown.
|
174
|
-
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
175
|
-
# Default (38,0).
|
176
|
-
#
|
177
243
|
# This method returns <tt>self</tt>.
|
178
244
|
#
|
179
245
|
# == Examples
|
180
|
-
# # Assuming +td+ is an instance of TableDefinition
|
181
|
-
# td.column(:granted, :boolean)
|
182
|
-
# # granted BOOLEAN
|
183
|
-
#
|
184
|
-
# td.column(:picture, :binary, limit: 2.megabytes)
|
185
|
-
# # => picture BLOB(2097152)
|
186
246
|
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
# td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
|
191
|
-
# # => bill_gates_money DECIMAL(15,2)
|
192
|
-
#
|
193
|
-
# td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
|
194
|
-
# # => sensor_reading DECIMAL(30,20)
|
195
|
-
#
|
196
|
-
# # While <tt>:scale</tt> defaults to zero on most databases, it
|
197
|
-
# # probably wouldn't hurt to include it.
|
198
|
-
# td.column(:huge_integer, :decimal, precision: 30)
|
199
|
-
# # => huge_integer DECIMAL(30)
|
200
|
-
#
|
201
|
-
# # Defines a column with a database-specific type.
|
202
|
-
# td.column(:foo, 'polygon')
|
203
|
-
# # => foo polygon
|
247
|
+
# # Assuming +td+ is an instance of TableDefinition
|
248
|
+
# td.column(:granted, :boolean, index: true)
|
204
249
|
#
|
205
250
|
# == Short-hand examples
|
206
251
|
#
|
207
|
-
# Instead of calling
|
252
|
+
# Instead of calling #column directly, you can also work with the short-hand definitions for the default types.
|
208
253
|
# They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
|
209
254
|
# in a single statement.
|
210
255
|
#
|
@@ -236,7 +281,8 @@ module ActiveRecord
|
|
236
281
|
# TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
|
237
282
|
# column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
|
238
283
|
# options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
|
239
|
-
# will also create an index, similar to calling
|
284
|
+
# will also create an index, similar to calling {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index].
|
285
|
+
# So what can be written like this:
|
240
286
|
#
|
241
287
|
# create_table :taggings do |t|
|
242
288
|
# t.integer :tag_id, :tagger_id, :taggable_id
|
@@ -268,18 +314,12 @@ module ActiveRecord
|
|
268
314
|
self
|
269
315
|
end
|
270
316
|
|
317
|
+
# remove the column +name+ from the table.
|
318
|
+
# remove_column(:account_id)
|
271
319
|
def remove_column(name)
|
272
320
|
@columns_hash.delete name.to_s
|
273
321
|
end
|
274
322
|
|
275
|
-
[:string, :text, :integer, :bigint, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
|
276
|
-
define_method column_type do |*args|
|
277
|
-
options = args.extract_options!
|
278
|
-
column_names = args
|
279
|
-
column_names.each { |name| column(name, column_type, options) }
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
323
|
# Adds index options to the indexes hash, keyed by column name
|
284
324
|
# This is primarily used to track indexes that need to be created after the table
|
285
325
|
#
|
@@ -289,16 +329,18 @@ module ActiveRecord
|
|
289
329
|
end
|
290
330
|
|
291
331
|
def foreign_key(table_name, options = {}) # :nodoc:
|
292
|
-
foreign_keys
|
332
|
+
foreign_keys[table_name] = options
|
293
333
|
end
|
294
334
|
|
295
335
|
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
296
|
-
# <tt>:updated_at</tt> to the table. See SchemaStatements#add_timestamps
|
336
|
+
# <tt>:updated_at</tt> to the table. See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
|
297
337
|
#
|
298
338
|
# t.timestamps null: false
|
299
339
|
def timestamps(*args)
|
300
340
|
options = args.extract_options!
|
301
|
-
|
341
|
+
|
342
|
+
options[:null] = false if options[:null].nil?
|
343
|
+
|
302
344
|
column(:created_at, :datetime, options)
|
303
345
|
column(:updated_at, :datetime, options)
|
304
346
|
end
|
@@ -308,26 +350,10 @@ module ActiveRecord
|
|
308
350
|
# t.references(:user)
|
309
351
|
# t.belongs_to(:supplier, foreign_key: true)
|
310
352
|
#
|
311
|
-
# See SchemaStatements#add_reference for details of the options you can use.
|
312
|
-
def references(*args)
|
313
|
-
options = args.extract_options!
|
314
|
-
polymorphic = options.delete(:polymorphic)
|
315
|
-
index_options = options.delete(:index)
|
316
|
-
foreign_key_options = options.delete(:foreign_key)
|
317
|
-
type = options.delete(:type) || :integer
|
318
|
-
|
319
|
-
if polymorphic && foreign_key_options
|
320
|
-
raise ArgumentError, "Cannot add a foreign key on a polymorphic relation"
|
321
|
-
end
|
322
|
-
|
353
|
+
# See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
|
354
|
+
def references(*args, **options)
|
323
355
|
args.each do |col|
|
324
|
-
|
325
|
-
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
|
326
|
-
index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
|
327
|
-
if foreign_key_options
|
328
|
-
to_table = Base.pluralize_table_names ? col.to_s.pluralize : col.to_s
|
329
|
-
foreign_key(to_table, foreign_key_options.is_a?(Hash) ? foreign_key_options : {})
|
330
|
-
end
|
356
|
+
ReferenceDefinition.new(col, **options).add_to(self)
|
331
357
|
end
|
332
358
|
end
|
333
359
|
alias :belongs_to :references
|
@@ -335,18 +361,17 @@ module ActiveRecord
|
|
335
361
|
def new_column_definition(name, type, options) # :nodoc:
|
336
362
|
type = aliased_types(type.to_s, type)
|
337
363
|
column = create_column_definition name, type
|
338
|
-
limit = options.fetch(:limit) do
|
339
|
-
native[type][:limit] if native[type].is_a?(Hash)
|
340
|
-
end
|
341
364
|
|
342
|
-
column.limit = limit
|
365
|
+
column.limit = options[:limit]
|
343
366
|
column.precision = options[:precision]
|
344
367
|
column.scale = options[:scale]
|
345
368
|
column.default = options[:default]
|
346
369
|
column.null = options[:null]
|
347
370
|
column.first = options[:first]
|
348
371
|
column.after = options[:after]
|
372
|
+
column.auto_increment = options[:auto_increment]
|
349
373
|
column.primary_key = type == :primary_key || options[:primary_key]
|
374
|
+
column.collation = options[:collation]
|
350
375
|
column
|
351
376
|
end
|
352
377
|
|
@@ -355,10 +380,6 @@ module ActiveRecord
|
|
355
380
|
ColumnDefinition.new name, type
|
356
381
|
end
|
357
382
|
|
358
|
-
def native
|
359
|
-
@native
|
360
|
-
end
|
361
|
-
|
362
383
|
def aliased_types(name, fallback)
|
363
384
|
'timestamp' == name ? :datetime : fallback
|
364
385
|
end
|
@@ -389,16 +410,17 @@ module ActiveRecord
|
|
389
410
|
def add_column(name, type, options)
|
390
411
|
name = name.to_s
|
391
412
|
type = type.to_sym
|
392
|
-
@adds << @td.new_column_definition(name, type, options)
|
413
|
+
@adds << AddColumnDefinition.new(@td.new_column_definition(name, type, options))
|
393
414
|
end
|
394
415
|
end
|
395
416
|
|
396
417
|
# Represents an SQL table in an abstract way for updating a table.
|
397
|
-
# Also see TableDefinition and SchemaStatements#create_table
|
418
|
+
# Also see TableDefinition and {connection.create_table}[rdoc-ref:SchemaStatements#create_table]
|
398
419
|
#
|
399
420
|
# Available transformations are:
|
400
421
|
#
|
401
422
|
# change_table :table do |t|
|
423
|
+
# t.primary_key
|
402
424
|
# t.column
|
403
425
|
# t.index
|
404
426
|
# t.rename_index
|
@@ -411,6 +433,7 @@ module ActiveRecord
|
|
411
433
|
# t.string
|
412
434
|
# t.text
|
413
435
|
# t.integer
|
436
|
+
# t.bigint
|
414
437
|
# t.float
|
415
438
|
# t.decimal
|
416
439
|
# t.datetime
|
@@ -427,6 +450,8 @@ module ActiveRecord
|
|
427
450
|
# end
|
428
451
|
#
|
429
452
|
class Table
|
453
|
+
include ColumnMethods
|
454
|
+
|
430
455
|
attr_reader :name
|
431
456
|
|
432
457
|
def initialize(table_name, base)
|
@@ -435,33 +460,42 @@ module ActiveRecord
|
|
435
460
|
end
|
436
461
|
|
437
462
|
# Adds a new column to the named table.
|
438
|
-
# See TableDefinition#column for details of the options you can use.
|
439
463
|
#
|
440
|
-
# ====== Creating a simple column
|
441
464
|
# t.column(:name, :string)
|
465
|
+
#
|
466
|
+
# See TableDefinition#column for details of the options you can use.
|
442
467
|
def column(column_name, type, options = {})
|
443
468
|
@base.add_column(name, column_name, type, options)
|
444
469
|
end
|
445
470
|
|
446
|
-
# Checks to see if a column exists.
|
471
|
+
# Checks to see if a column exists.
|
472
|
+
#
|
473
|
+
# t.string(:name) unless t.column_exists?(:name, :string)
|
474
|
+
#
|
475
|
+
# See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?]
|
447
476
|
def column_exists?(column_name, type = nil, options = {})
|
448
477
|
@base.column_exists?(name, column_name, type, options)
|
449
478
|
end
|
450
479
|
|
451
480
|
# Adds a new index to the table. +column_name+ can be a single Symbol, or
|
452
|
-
# an Array of Symbols.
|
481
|
+
# an Array of Symbols.
|
453
482
|
#
|
454
|
-
# ====== Creating a simple index
|
455
483
|
# t.index(:name)
|
456
|
-
# ====== Creating a unique index
|
457
484
|
# t.index([:branch_id, :party_id], unique: true)
|
458
|
-
# ====== Creating a named index
|
459
485
|
# t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
|
486
|
+
#
|
487
|
+
# See {connection.add_index}[rdoc-ref:SchemaStatements#add_index] for details of the options you can use.
|
460
488
|
def index(column_name, options = {})
|
461
489
|
@base.add_index(name, column_name, options)
|
462
490
|
end
|
463
491
|
|
464
|
-
# Checks to see if an index exists.
|
492
|
+
# Checks to see if an index exists.
|
493
|
+
#
|
494
|
+
# unless t.index_exists?(:branch_id)
|
495
|
+
# t.index(:branch_id)
|
496
|
+
# end
|
497
|
+
#
|
498
|
+
# See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
|
465
499
|
def index_exists?(column_name, options = {})
|
466
500
|
@base.index_exists?(name, column_name, options)
|
467
501
|
end
|
@@ -469,52 +503,59 @@ module ActiveRecord
|
|
469
503
|
# Renames the given index on the table.
|
470
504
|
#
|
471
505
|
# t.rename_index(:user_id, :account_id)
|
506
|
+
#
|
507
|
+
# See {connection.rename_index}[rdoc-ref:SchemaStatements#rename_index]
|
472
508
|
def rename_index(index_name, new_index_name)
|
473
509
|
@base.rename_index(name, index_name, new_index_name)
|
474
510
|
end
|
475
511
|
|
476
|
-
# Adds timestamps (+created_at+ and +updated_at+) columns to the table.
|
512
|
+
# Adds timestamps (+created_at+ and +updated_at+) columns to the table.
|
477
513
|
#
|
478
|
-
# t.timestamps
|
514
|
+
# t.timestamps(null: false)
|
515
|
+
#
|
516
|
+
# See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
|
479
517
|
def timestamps(options = {})
|
480
518
|
@base.add_timestamps(name, options)
|
481
519
|
end
|
482
520
|
|
483
521
|
# Changes the column's definition according to the new options.
|
484
|
-
# See TableDefinition#column for details of the options you can use.
|
485
522
|
#
|
486
523
|
# t.change(:name, :string, limit: 80)
|
487
524
|
# t.change(:description, :text)
|
525
|
+
#
|
526
|
+
# See TableDefinition#column for details of the options you can use.
|
488
527
|
def change(column_name, type, options = {})
|
489
528
|
@base.change_column(name, column_name, type, options)
|
490
529
|
end
|
491
530
|
|
492
|
-
# Sets a new default value for a column.
|
531
|
+
# Sets a new default value for a column.
|
493
532
|
#
|
494
533
|
# t.change_default(:qualification, 'new')
|
495
534
|
# t.change_default(:authorized, 1)
|
496
|
-
|
497
|
-
|
535
|
+
# t.change_default(:status, from: nil, to: "draft")
|
536
|
+
#
|
537
|
+
# See {connection.change_column_default}[rdoc-ref:SchemaStatements#change_column_default]
|
538
|
+
def change_default(column_name, default_or_changes)
|
539
|
+
@base.change_column_default(name, column_name, default_or_changes)
|
498
540
|
end
|
499
541
|
|
500
542
|
# Removes the column(s) from the table definition.
|
501
543
|
#
|
502
544
|
# t.remove(:qualification)
|
503
545
|
# t.remove(:qualification, :experience)
|
546
|
+
#
|
547
|
+
# See {connection.remove_columns}[rdoc-ref:SchemaStatements#remove_columns]
|
504
548
|
def remove(*column_names)
|
505
549
|
@base.remove_columns(name, *column_names)
|
506
550
|
end
|
507
551
|
|
508
552
|
# Removes the given index from the table.
|
509
553
|
#
|
510
|
-
#
|
511
|
-
# t.remove_index :
|
512
|
-
#
|
513
|
-
#
|
514
|
-
#
|
515
|
-
# t.remove_index column: [:branch_id, :party_id]
|
516
|
-
# ====== Remove the index named by_branch_party in the table_name table
|
517
|
-
# t.remove_index name: :by_branch_party
|
554
|
+
# t.remove_index(:branch_id)
|
555
|
+
# t.remove_index(column: [:branch_id, :party_id])
|
556
|
+
# t.remove_index(name: :by_branch_party)
|
557
|
+
#
|
558
|
+
# See {connection.remove_index}[rdoc-ref:SchemaStatements#remove_index]
|
518
559
|
def remove_index(options = {})
|
519
560
|
@base.remove_index(name, options)
|
520
561
|
end
|
@@ -522,6 +563,8 @@ module ActiveRecord
|
|
522
563
|
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
|
523
564
|
#
|
524
565
|
# t.remove_timestamps
|
566
|
+
#
|
567
|
+
# See {connection.remove_timestamps}[rdoc-ref:SchemaStatements#remove_timestamps]
|
525
568
|
def remove_timestamps(options = {})
|
526
569
|
@base.remove_timestamps(name, options)
|
527
570
|
end
|
@@ -529,6 +572,8 @@ module ActiveRecord
|
|
529
572
|
# Renames a column.
|
530
573
|
#
|
531
574
|
# t.rename(:description, :name)
|
575
|
+
#
|
576
|
+
# See {connection.rename_column}[rdoc-ref:SchemaStatements#rename_column]
|
532
577
|
def rename(column_name, new_column_name)
|
533
578
|
@base.rename_column(name, column_name, new_column_name)
|
534
579
|
end
|
@@ -538,7 +583,7 @@ module ActiveRecord
|
|
538
583
|
# t.references(:user)
|
539
584
|
# t.belongs_to(:supplier, foreign_key: true)
|
540
585
|
#
|
541
|
-
# See SchemaStatements#add_reference for details of the options you can use.
|
586
|
+
# See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
|
542
587
|
def references(*args)
|
543
588
|
options = args.extract_options!
|
544
589
|
args.each do |ref_name|
|
@@ -548,12 +593,11 @@ module ActiveRecord
|
|
548
593
|
alias :belongs_to :references
|
549
594
|
|
550
595
|
# Removes a reference. Optionally removes a +type+ column.
|
551
|
-
# <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
|
552
596
|
#
|
553
597
|
# t.remove_references(:user)
|
554
598
|
# t.remove_belongs_to(:supplier, polymorphic: true)
|
555
599
|
#
|
556
|
-
# See SchemaStatements#remove_reference
|
600
|
+
# See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
|
557
601
|
def remove_references(*args)
|
558
602
|
options = args.extract_options!
|
559
603
|
args.each do |ref_name|
|
@@ -562,23 +606,23 @@ module ActiveRecord
|
|
562
606
|
end
|
563
607
|
alias :remove_belongs_to :remove_references
|
564
608
|
|
565
|
-
# Adds a
|
609
|
+
# Adds a foreign key.
|
566
610
|
#
|
567
|
-
#
|
568
|
-
#
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
args.each do |column_name|
|
573
|
-
@base.add_column(name, column_name, column_type, options)
|
574
|
-
end
|
575
|
-
end
|
611
|
+
# t.foreign_key(:authors)
|
612
|
+
#
|
613
|
+
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
614
|
+
def foreign_key(*args) # :nodoc:
|
615
|
+
@base.add_foreign_key(name, *args)
|
576
616
|
end
|
577
617
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
618
|
+
# Checks to see if a foreign key exists.
|
619
|
+
#
|
620
|
+
# t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
|
621
|
+
#
|
622
|
+
# See {connection.foreign_key_exists?}[rdoc-ref:SchemaStatements#foreign_key_exists?]
|
623
|
+
def foreign_key_exists?(*args) # :nodoc:
|
624
|
+
@base.foreign_key_exists?(name, *args)
|
625
|
+
end
|
582
626
|
end
|
583
627
|
end
|
584
628
|
end
|