activerecord 4.0.4 → 4.1.16
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1632 -1797
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +49 -29
- data/lib/active_record/associations/association.rb +9 -17
- data/lib/active_record/associations/association_scope.rb +59 -49
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +6 -1
- data/lib/active_record/associations/builder/association.rb +84 -54
- data/lib/active_record/associations/builder/belongs_to.rb +90 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +119 -25
- data/lib/active_record/associations/builder/has_many.rb +3 -3
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +121 -111
- data/lib/active_record/associations/collection_proxy.rb +73 -18
- data/lib/active_record/associations/has_many_association.rb +14 -11
- data/lib/active_record/associations/has_many_through_association.rb +33 -6
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +46 -104
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_dependency.rb +208 -168
- data/lib/active_record/associations/preloader/association.rb +69 -27
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/preloader.rb +63 -49
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +30 -9
- data/lib/active_record/associations.rb +116 -42
- data/lib/active_record/attribute_assignment.rb +6 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +35 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -1
- data/lib/active_record/attribute_methods/read.rb +56 -29
- data/lib/active_record/attribute_methods/serialization.rb +44 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +13 -1
- data/lib/active_record/attribute_methods/write.rb +59 -26
- data/lib/active_record/attribute_methods.rb +82 -43
- data/lib/active_record/autosave_association.rb +209 -194
- data/lib/active_record/base.rb +6 -2
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +14 -24
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +13 -13
- data/lib/active_record/connection_adapters/abstract/quoting.rb +6 -3
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +90 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +45 -70
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -96
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +74 -66
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +231 -43
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +24 -17
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +22 -15
- data/lib/active_record/connection_adapters/postgresql/cast.rb +12 -4
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -44
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -14
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +37 -12
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +20 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +98 -52
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -60
- data/lib/active_record/connection_handling.rb +39 -5
- data/lib/active_record/core.rb +38 -54
- data/lib/active_record/counter_cache.rb +9 -10
- data/lib/active_record/dynamic_matchers.rb +6 -2
- data/lib/active_record/enum.rb +199 -0
- data/lib/active_record/errors.rb +22 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +173 -76
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +23 -9
- data/lib/active_record/integration.rb +54 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +6 -13
- data/lib/active_record/migration/command_recorder.rb +8 -2
- data/lib/active_record/migration.rb +91 -56
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +25 -13
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +26 -6
- data/lib/active_record/persistence.rb +23 -29
- data/lib/active_record/querying.rb +15 -12
- data/lib/active_record/railtie.rb +12 -61
- data/lib/active_record/railties/databases.rake +37 -56
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +230 -79
- data/lib/active_record/relation/batches.rb +74 -24
- data/lib/active_record/relation/calculations.rb +52 -48
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +210 -67
- data/lib/active_record/relation/merger.rb +15 -12
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder.rb +81 -40
- data/lib/active_record/relation/query_methods.rb +185 -108
- data/lib/active_record/relation/spawn_methods.rb +8 -5
- data/lib/active_record/relation.rb +79 -84
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +4 -4
- data/lib/active_record/schema_dumper.rb +18 -6
- data/lib/active_record/schema_migration.rb +31 -18
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +14 -29
- data/lib/active_record/scoping.rb +5 -0
- data/lib/active_record/store.rb +67 -18
- data/lib/active_record/tasks/database_tasks.rb +66 -26
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -10
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/transactions.rb +10 -12
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +19 -9
- data/lib/active_record/version.rb +4 -7
- data/lib/active_record.rb +5 -7
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- data/lib/rails/generators/active_record.rb +2 -8
- metadata +18 -30
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/join_helper.rb +0 -45
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -96
@@ -18,25 +18,16 @@ module ActiveRecord
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
# Returns an
|
22
|
-
# column values as values.
|
21
|
+
# Returns an ActiveRecord::Result instance.
|
23
22
|
def select_all(arel, name = nil, binds = [])
|
24
|
-
|
25
|
-
relation = arel
|
26
|
-
arel = relation.arel
|
27
|
-
if !binds || binds.empty?
|
28
|
-
binds = relation.bind_values
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
23
|
+
arel, binds = binds_from_relation arel, binds
|
32
24
|
select(to_sql(arel, binds), name, binds)
|
33
25
|
end
|
34
26
|
|
35
27
|
# Returns a record hash with the column names as keys and column values
|
36
28
|
# as values.
|
37
29
|
def select_one(arel, name = nil, binds = [])
|
38
|
-
|
39
|
-
result.first if result
|
30
|
+
select_all(arel, name, binds).first
|
40
31
|
end
|
41
32
|
|
42
33
|
# Returns a single value from a record
|
@@ -49,10 +40,7 @@ module ActiveRecord
|
|
49
40
|
# Returns an array of the values of the first column in a select:
|
50
41
|
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
|
51
42
|
def select_values(arel, name = nil)
|
52
|
-
binds = []
|
53
|
-
if arel.is_a?(Relation)
|
54
|
-
arel, binds = arel.arel, arel.bind_values
|
55
|
-
end
|
43
|
+
arel, binds = binds_from_relation arel, []
|
56
44
|
select_rows(to_sql(arel, binds), name, binds).map(&:first)
|
57
45
|
end
|
58
46
|
|
@@ -314,10 +302,6 @@ module ActiveRecord
|
|
314
302
|
"DEFAULT VALUES"
|
315
303
|
end
|
316
304
|
|
317
|
-
def case_sensitive_equality_operator
|
318
|
-
"="
|
319
|
-
end
|
320
|
-
|
321
305
|
def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
|
322
306
|
"WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
|
323
307
|
end
|
@@ -334,7 +318,7 @@ module ActiveRecord
|
|
334
318
|
def sanitize_limit(limit)
|
335
319
|
if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
|
336
320
|
limit
|
337
|
-
elsif limit.to_s
|
321
|
+
elsif limit.to_s.include?(',')
|
338
322
|
Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
|
339
323
|
else
|
340
324
|
Integer(limit)
|
@@ -359,15 +343,14 @@ module ActiveRecord
|
|
359
343
|
|
360
344
|
protected
|
361
345
|
|
362
|
-
#
|
346
|
+
# Returns a subquery for the given key using the join information.
|
363
347
|
def subquery_for(key, select)
|
364
348
|
subselect = select.clone
|
365
349
|
subselect.projections = [key]
|
366
350
|
subselect
|
367
351
|
end
|
368
352
|
|
369
|
-
# Returns an
|
370
|
-
# column values as values.
|
353
|
+
# Returns an ActiveRecord::Result instance.
|
371
354
|
def select(sql, name = nil, binds = [])
|
372
355
|
end
|
373
356
|
undef_method :select
|
@@ -396,6 +379,13 @@ module ActiveRecord
|
|
396
379
|
row = result.rows.first
|
397
380
|
row && row.first
|
398
381
|
end
|
382
|
+
|
383
|
+
def binds_from_relation(relation, binds)
|
384
|
+
if relation.is_a?(Relation) && binds.blank?
|
385
|
+
relation, binds = relation.arel, relation.bind_values
|
386
|
+
end
|
387
|
+
[relation, binds]
|
388
|
+
end
|
399
389
|
end
|
400
390
|
end
|
401
391
|
end
|
@@ -9,10 +9,10 @@ module ActiveRecord
|
|
9
9
|
def dirties_query_cache(base, *method_names)
|
10
10
|
method_names.each do |method_name|
|
11
11
|
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
12
|
-
def #{method_name}(*)
|
13
|
-
clear_query_cache if @query_cache_enabled
|
14
|
-
super
|
15
|
-
end
|
12
|
+
def #{method_name}(*)
|
13
|
+
clear_query_cache if @query_cache_enabled
|
14
|
+
super
|
15
|
+
end
|
16
16
|
end_code
|
17
17
|
end
|
18
18
|
end
|
@@ -20,13 +20,19 @@ module ActiveRecord
|
|
20
20
|
|
21
21
|
attr_reader :query_cache, :query_cache_enabled
|
22
22
|
|
23
|
+
def initialize(*)
|
24
|
+
super
|
25
|
+
@query_cache = Hash.new { |h,sql| h[sql] = {} }
|
26
|
+
@query_cache_enabled = false
|
27
|
+
end
|
28
|
+
|
23
29
|
# Enable the query cache within the block.
|
24
30
|
def cache
|
25
31
|
old, @query_cache_enabled = @query_cache_enabled, true
|
26
32
|
yield
|
27
33
|
ensure
|
28
|
-
clear_query_cache
|
29
34
|
@query_cache_enabled = old
|
35
|
+
clear_query_cache unless @query_cache_enabled
|
30
36
|
end
|
31
37
|
|
32
38
|
def enable_query_cache!
|
@@ -57,6 +63,7 @@ module ActiveRecord
|
|
57
63
|
|
58
64
|
def select_all(arel, name = nil, binds = [])
|
59
65
|
if @query_cache_enabled && !locked?(arel)
|
66
|
+
arel, binds = binds_from_relation arel, binds
|
60
67
|
sql = to_sql(arel, binds)
|
61
68
|
cache_sql(sql, binds) { super(sql, name, binds) }
|
62
69
|
else
|
@@ -75,14 +82,7 @@ module ActiveRecord
|
|
75
82
|
else
|
76
83
|
@query_cache[sql][binds] = yield
|
77
84
|
end
|
78
|
-
|
79
|
-
# FIXME: we should guarantee that all cached items are Result
|
80
|
-
# objects. Then we can avoid this conditional
|
81
|
-
if ActiveRecord::Result === result
|
82
|
-
result.dup
|
83
|
-
else
|
84
|
-
result.collect { |row| row.dup }
|
85
|
-
end
|
85
|
+
result.dup
|
86
86
|
end
|
87
87
|
|
88
88
|
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
@@ -15,7 +15,6 @@ module ActiveRecord
|
|
15
15
|
return "'#{quote_string(value)}'" unless column
|
16
16
|
|
17
17
|
case column.type
|
18
|
-
when :binary then "'#{quote_string(column.string_to_binary(value))}'"
|
19
18
|
when :integer then value.to_i.to_s
|
20
19
|
when :float then value.to_f.to_s
|
21
20
|
else
|
@@ -31,7 +30,12 @@ module ActiveRecord
|
|
31
30
|
# BigDecimals need to be put in a non-normalized form and quoted.
|
32
31
|
when nil then "NULL"
|
33
32
|
when BigDecimal then value.to_s('F')
|
34
|
-
when Numeric, ActiveSupport::Duration
|
33
|
+
when Numeric, ActiveSupport::Duration
|
34
|
+
if column.try(:type) == :string
|
35
|
+
quote(value.to_s, column)
|
36
|
+
else
|
37
|
+
value.to_s
|
38
|
+
end
|
35
39
|
when Date, Time then "'#{quoted_date(value)}'"
|
36
40
|
when Symbol then "'#{quote_string(value.to_s)}'"
|
37
41
|
when Class then "'#{value.to_s}'"
|
@@ -54,7 +58,6 @@ module ActiveRecord
|
|
54
58
|
return value unless column
|
55
59
|
|
56
60
|
case column.type
|
57
|
-
when :binary then value
|
58
61
|
when :integer then value.to_i
|
59
62
|
when :float then value.to_f
|
60
63
|
else
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Savepoints #:nodoc:
|
4
|
+
def supports_savepoints?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_savepoint(name = current_savepoint_name)
|
9
|
+
execute("SAVEPOINT #{name}")
|
10
|
+
end
|
11
|
+
|
12
|
+
def rollback_to_savepoint(name = current_savepoint_name)
|
13
|
+
execute("ROLLBACK TO SAVEPOINT #{name}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def release_savepoint(name = current_savepoint_name)
|
17
|
+
execute("RELEASE SAVEPOINT #{name}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class AbstractAdapter
|
4
|
+
class SchemaCreation # :nodoc:
|
5
|
+
def initialize(conn)
|
6
|
+
@conn = conn
|
7
|
+
@cache = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def accept(o)
|
11
|
+
m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
|
12
|
+
send m, o
|
13
|
+
end
|
14
|
+
|
15
|
+
def visit_AddColumn(o)
|
16
|
+
sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
|
17
|
+
sql = "ADD #{quote_column_name(o.name)} #{sql_type}"
|
18
|
+
add_column_options!(sql, column_options(o))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def visit_AlterTable(o)
|
24
|
+
sql = "ALTER TABLE #{quote_table_name(o.name)} "
|
25
|
+
sql << o.adds.map { |col| visit_AddColumn col }.join(' ')
|
26
|
+
end
|
27
|
+
|
28
|
+
def visit_ColumnDefinition(o)
|
29
|
+
sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
|
30
|
+
column_sql = "#{quote_column_name(o.name)} #{sql_type}"
|
31
|
+
add_column_options!(column_sql, column_options(o)) unless o.primary_key?
|
32
|
+
column_sql
|
33
|
+
end
|
34
|
+
|
35
|
+
def visit_TableDefinition(o)
|
36
|
+
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE "
|
37
|
+
create_sql << "#{quote_table_name(o.name)} "
|
38
|
+
create_sql << "(#{o.columns.map { |c| accept c }.join(', ')}) " unless o.as
|
39
|
+
create_sql << "#{o.options}"
|
40
|
+
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
41
|
+
create_sql
|
42
|
+
end
|
43
|
+
|
44
|
+
def column_options(o)
|
45
|
+
column_options = {}
|
46
|
+
column_options[:null] = o.null unless o.null.nil?
|
47
|
+
column_options[:default] = o.default unless o.default.nil?
|
48
|
+
column_options[:column] = o
|
49
|
+
column_options[:first] = o.first
|
50
|
+
column_options[:after] = o.after
|
51
|
+
column_options
|
52
|
+
end
|
53
|
+
|
54
|
+
def quote_column_name(name)
|
55
|
+
@conn.quote_column_name name
|
56
|
+
end
|
57
|
+
|
58
|
+
def quote_table_name(name)
|
59
|
+
@conn.quote_table_name name
|
60
|
+
end
|
61
|
+
|
62
|
+
def type_to_sql(type, limit, precision, scale)
|
63
|
+
@conn.type_to_sql type.to_sym, limit, precision, scale
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_column_options!(sql, options)
|
67
|
+
sql << " DEFAULT #{quote_value(options[:default], options[:column])}" if options_include_default?(options)
|
68
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
69
|
+
if options[:null] == false
|
70
|
+
sql << " NOT NULL"
|
71
|
+
end
|
72
|
+
if options[:auto_increment] == true
|
73
|
+
sql << " AUTO_INCREMENT"
|
74
|
+
end
|
75
|
+
sql
|
76
|
+
end
|
77
|
+
|
78
|
+
def quote_value(value, column)
|
79
|
+
column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale)
|
80
|
+
|
81
|
+
@conn.quote(value, column)
|
82
|
+
end
|
83
|
+
|
84
|
+
def options_include_default?(options)
|
85
|
+
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -15,16 +15,16 @@ module ActiveRecord
|
|
15
15
|
# are typically created by methods in TableDefinition, and added to the
|
16
16
|
# +columns+ attribute of said TableDefinition object, in order to be used
|
17
17
|
# 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) #:nodoc:
|
19
|
-
def string_to_binary(value)
|
20
|
-
value
|
21
|
-
end
|
18
|
+
class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type) #:nodoc:
|
22
19
|
|
23
20
|
def primary_key?
|
24
21
|
primary_key || type.to_sym == :primary_key
|
25
22
|
end
|
26
23
|
end
|
27
24
|
|
25
|
+
class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc:
|
26
|
+
end
|
27
|
+
|
28
28
|
# Represents the schema of an SQL table in an abstract way. This class
|
29
29
|
# provides methods for manipulating the schema representation.
|
30
30
|
#
|
@@ -49,14 +49,15 @@ module ActiveRecord
|
|
49
49
|
# An array of ColumnDefinition objects, representing the column changes
|
50
50
|
# that have been defined.
|
51
51
|
attr_accessor :indexes
|
52
|
-
attr_reader :name, :temporary, :options
|
52
|
+
attr_reader :name, :temporary, :options, :as
|
53
53
|
|
54
|
-
def initialize(types, name, temporary, options)
|
54
|
+
def initialize(types, name, temporary, options, as = nil)
|
55
55
|
@columns_hash = {}
|
56
56
|
@indexes = {}
|
57
57
|
@native = types
|
58
58
|
@temporary = temporary
|
59
59
|
@options = options
|
60
|
+
@as = as
|
60
61
|
@name = name
|
61
62
|
end
|
62
63
|
|
@@ -393,8 +394,8 @@ module ActiveRecord
|
|
393
394
|
# Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
|
394
395
|
#
|
395
396
|
# t.timestamps
|
396
|
-
def timestamps
|
397
|
-
@base.add_timestamps(@table_name)
|
397
|
+
def timestamps(options = {})
|
398
|
+
@base.add_timestamps(@table_name, options)
|
398
399
|
end
|
399
400
|
|
400
401
|
# Changes the column's definition according to the new options.
|
@@ -40,7 +40,7 @@ module ActiveRecord
|
|
40
40
|
# index_exists?(:suppliers, :company_id, unique: true)
|
41
41
|
#
|
42
42
|
# # Check an index with a custom name exists
|
43
|
-
# index_exists?(:suppliers, :company_id, name: "idx_company_id"
|
43
|
+
# index_exists?(:suppliers, :company_id, name: "idx_company_id")
|
44
44
|
#
|
45
45
|
def index_exists?(table_name, column_name, options = {})
|
46
46
|
column_names = Array(column_name)
|
@@ -131,6 +131,9 @@ module ActiveRecord
|
|
131
131
|
# [<tt>:force</tt>]
|
132
132
|
# Set to true to drop the table before creating it.
|
133
133
|
# Defaults to false.
|
134
|
+
# [<tt>:as</tt>]
|
135
|
+
# SQL to use to generate the table. When this option is used, the block is
|
136
|
+
# ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options.
|
134
137
|
#
|
135
138
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
136
139
|
#
|
@@ -169,19 +172,31 @@ module ActiveRecord
|
|
169
172
|
# supplier_id int
|
170
173
|
# )
|
171
174
|
#
|
175
|
+
# ====== Create a temporary table based on a query
|
176
|
+
#
|
177
|
+
# create_table(:long_query, temporary: true,
|
178
|
+
# as: "SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id")
|
179
|
+
#
|
180
|
+
# generates:
|
181
|
+
#
|
182
|
+
# CREATE TEMPORARY TABLE long_query AS
|
183
|
+
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
|
184
|
+
#
|
172
185
|
# See also TableDefinition#column for details on how to create columns.
|
173
186
|
def create_table(table_name, options = {})
|
174
|
-
td = create_table_definition table_name, options[:temporary], options[:options]
|
187
|
+
td = create_table_definition table_name, options[:temporary], options[:options], options[:as]
|
175
188
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
189
|
+
if !options[:as]
|
190
|
+
unless options[:id] == false
|
191
|
+
pk = options.fetch(:primary_key) {
|
192
|
+
Base.get_primary_key table_name.to_s.singularize
|
193
|
+
}
|
180
194
|
|
181
|
-
|
182
|
-
|
195
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options
|
196
|
+
end
|
183
197
|
|
184
|
-
|
198
|
+
yield td if block_given?
|
199
|
+
end
|
185
200
|
|
186
201
|
if options[:force] && table_exists?(table_name)
|
187
202
|
drop_table(table_name, options)
|
@@ -558,8 +573,8 @@ module ActiveRecord
|
|
558
573
|
# this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
|
559
574
|
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
560
575
|
return unless old_index_def
|
561
|
-
|
562
|
-
|
576
|
+
add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
|
577
|
+
remove_index(table_name, name: old_name)
|
563
578
|
end
|
564
579
|
|
565
580
|
def index_name(table_name, options) #:nodoc:
|
@@ -606,7 +621,7 @@ module ActiveRecord
|
|
606
621
|
index_options = options.delete(:index)
|
607
622
|
add_column(table_name, "#{ref_name}_id", :integer, options)
|
608
623
|
add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
|
609
|
-
add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options :
|
624
|
+
add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
|
610
625
|
end
|
611
626
|
alias :add_belongs_to :add_reference
|
612
627
|
|
@@ -694,26 +709,6 @@ module ActiveRecord
|
|
694
709
|
end
|
695
710
|
end
|
696
711
|
|
697
|
-
def add_column_options!(sql, options) #:nodoc:
|
698
|
-
sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
|
699
|
-
# must explicitly check for :null to allow change_column to work on migrations
|
700
|
-
if options[:null] == false
|
701
|
-
sql << " NOT NULL"
|
702
|
-
end
|
703
|
-
if options[:auto_increment] == true
|
704
|
-
sql << " AUTO_INCREMENT"
|
705
|
-
end
|
706
|
-
end
|
707
|
-
|
708
|
-
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
|
709
|
-
#
|
710
|
-
# distinct("posts.id", ["posts.created_at desc"])
|
711
|
-
#
|
712
|
-
def distinct(columns, order_by)
|
713
|
-
ActiveSupport::Deprecation.warn("#distinct is deprecated and shall be removed from future releases.")
|
714
|
-
"DISTINCT #{columns_for_distinct(columns, order_by)}"
|
715
|
-
end
|
716
|
-
|
717
712
|
# Given a set of columns and an ORDER BY clause, returns the columns for a SELECT DISTINCT.
|
718
713
|
# Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax - they
|
719
714
|
# require the order columns appear in the SELECT.
|
@@ -727,9 +722,9 @@ module ActiveRecord
|
|
727
722
|
#
|
728
723
|
# add_timestamps(:suppliers)
|
729
724
|
#
|
730
|
-
def add_timestamps(table_name)
|
731
|
-
add_column table_name, :created_at, :datetime
|
732
|
-
add_column table_name, :updated_at, :datetime
|
725
|
+
def add_timestamps(table_name, options = {})
|
726
|
+
add_column table_name, :created_at, :datetime, options
|
727
|
+
add_column table_name, :updated_at, :datetime, options
|
733
728
|
end
|
734
729
|
|
735
730
|
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
|
@@ -779,37 +774,23 @@ module ActiveRecord
|
|
779
774
|
column_names = Array(column_name)
|
780
775
|
index_name = index_name(table_name, column: column_names)
|
781
776
|
|
782
|
-
|
783
|
-
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
784
|
-
|
785
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
786
|
-
index_type = options[:type].to_s if options.key?(:type)
|
787
|
-
index_name = options[:name].to_s if options.key?(:name)
|
788
|
-
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
789
|
-
|
790
|
-
if options.key?(:algorithm)
|
791
|
-
algorithm = index_algorithms.fetch(options[:algorithm]) {
|
792
|
-
raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
|
793
|
-
}
|
794
|
-
end
|
777
|
+
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
795
778
|
|
796
|
-
|
779
|
+
index_type = options[:unique] ? "UNIQUE" : ""
|
780
|
+
index_type = options[:type].to_s if options.key?(:type)
|
781
|
+
index_name = options[:name].to_s if options.key?(:name)
|
782
|
+
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
797
783
|
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
message = "Passing a string as third argument of `add_index` is deprecated and will" +
|
804
|
-
" be removed in Rails 4.1." +
|
805
|
-
" Use add_index(#{table_name.inspect}, #{column_name.inspect}, unique: true) instead"
|
784
|
+
if options.key?(:algorithm)
|
785
|
+
algorithm = index_algorithms.fetch(options[:algorithm]) {
|
786
|
+
raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
|
787
|
+
}
|
788
|
+
end
|
806
789
|
|
807
|
-
|
808
|
-
end
|
790
|
+
using = "USING #{options[:using]}" if options[:using].present?
|
809
791
|
|
810
|
-
|
811
|
-
|
812
|
-
algorithm = using = nil
|
792
|
+
if supports_partial_index?
|
793
|
+
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
|
813
794
|
end
|
814
795
|
|
815
796
|
if index_name.length > max_index_length
|
@@ -841,12 +822,6 @@ module ActiveRecord
|
|
841
822
|
index_name
|
842
823
|
end
|
843
824
|
|
844
|
-
def columns_for_remove(table_name, *column_names)
|
845
|
-
ActiveSupport::Deprecation.warn("columns_for_remove is deprecated and will be removed in the future")
|
846
|
-
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)") if column_names.blank?
|
847
|
-
column_names.map {|column_name| quote_column_name(column_name) }
|
848
|
-
end
|
849
|
-
|
850
825
|
def rename_table_indexes(table_name, new_name)
|
851
826
|
indexes(new_name).each do |index|
|
852
827
|
generated_index_name = index_name(table_name, column: index.columns)
|
@@ -870,8 +845,8 @@ module ActiveRecord
|
|
870
845
|
end
|
871
846
|
|
872
847
|
private
|
873
|
-
def create_table_definition(name, temporary, options)
|
874
|
-
TableDefinition.new native_database_types, name, temporary, options
|
848
|
+
def create_table_definition(name, temporary, options, as = nil)
|
849
|
+
TableDefinition.new native_database_types, name, temporary, options, as
|
875
850
|
end
|
876
851
|
|
877
852
|
def create_alter_table(name)
|