activerecord 4.0.13 → 4.1.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.

Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +745 -2700
  3. data/README.rdoc +2 -2
  4. data/examples/performance.rb +30 -18
  5. data/examples/simple.rb +4 -4
  6. data/lib/active_record.rb +2 -6
  7. data/lib/active_record/aggregations.rb +2 -1
  8. data/lib/active_record/association_relation.rb +0 -4
  9. data/lib/active_record/associations.rb +87 -43
  10. data/lib/active_record/associations/alias_tracker.rb +1 -3
  11. data/lib/active_record/associations/association.rb +8 -16
  12. data/lib/active_record/associations/association_scope.rb +5 -16
  13. data/lib/active_record/associations/belongs_to_association.rb +34 -25
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  15. data/lib/active_record/associations/builder/association.rb +78 -54
  16. data/lib/active_record/associations/builder/belongs_to.rb +91 -58
  17. data/lib/active_record/associations/builder/collection_association.rb +47 -45
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
  19. data/lib/active_record/associations/builder/has_many.rb +2 -2
  20. data/lib/active_record/associations/builder/has_one.rb +5 -7
  21. data/lib/active_record/associations/builder/singular_association.rb +6 -7
  22. data/lib/active_record/associations/collection_association.rb +68 -105
  23. data/lib/active_record/associations/collection_proxy.rb +12 -15
  24. data/lib/active_record/associations/has_many_association.rb +11 -9
  25. data/lib/active_record/associations/has_many_through_association.rb +16 -12
  26. data/lib/active_record/associations/has_one_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +204 -165
  28. data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
  29. data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
  31. data/lib/active_record/associations/join_helper.rb +2 -11
  32. data/lib/active_record/associations/preloader.rb +89 -34
  33. data/lib/active_record/associations/preloader/association.rb +43 -25
  34. data/lib/active_record/associations/preloader/collection_association.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +58 -26
  38. data/lib/active_record/associations/singular_association.rb +6 -5
  39. data/lib/active_record/associations/through_association.rb +2 -2
  40. data/lib/active_record/attribute_assignment.rb +5 -2
  41. data/lib/active_record/attribute_methods.rb +45 -40
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +8 -22
  44. data/lib/active_record/attribute_methods/primary_key.rb +1 -7
  45. data/lib/active_record/attribute_methods/read.rb +55 -28
  46. data/lib/active_record/attribute_methods/serialization.rb +12 -33
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
  48. data/lib/active_record/attribute_methods/write.rb +37 -12
  49. data/lib/active_record/autosave_association.rb +207 -207
  50. data/lib/active_record/base.rb +5 -1
  51. data/lib/active_record/callbacks.rb +2 -2
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
  63. data/lib/active_record/connection_adapters/column.rb +1 -35
  64. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
  68. data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
  71. data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
  72. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
  73. data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
  74. data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
  75. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
  76. data/lib/active_record/connection_handling.rb +2 -2
  77. data/lib/active_record/core.rb +22 -43
  78. data/lib/active_record/counter_cache.rb +7 -7
  79. data/lib/active_record/enum.rb +100 -0
  80. data/lib/active_record/errors.rb +10 -5
  81. data/lib/active_record/fixture_set/file.rb +2 -1
  82. data/lib/active_record/fixtures.rb +171 -74
  83. data/lib/active_record/inheritance.rb +16 -22
  84. data/lib/active_record/integration.rb +52 -1
  85. data/lib/active_record/locking/optimistic.rb +7 -2
  86. data/lib/active_record/locking/pessimistic.rb +1 -1
  87. data/lib/active_record/log_subscriber.rb +5 -12
  88. data/lib/active_record/migration.rb +62 -46
  89. data/lib/active_record/migration/command_recorder.rb +7 -13
  90. data/lib/active_record/model_schema.rb +7 -14
  91. data/lib/active_record/nested_attributes.rb +10 -8
  92. data/lib/active_record/no_touching.rb +52 -0
  93. data/lib/active_record/null_relation.rb +3 -3
  94. data/lib/active_record/persistence.rb +16 -34
  95. data/lib/active_record/querying.rb +14 -12
  96. data/lib/active_record/railtie.rb +0 -50
  97. data/lib/active_record/railties/databases.rake +12 -15
  98. data/lib/active_record/readonly_attributes.rb +0 -6
  99. data/lib/active_record/reflection.rb +189 -75
  100. data/lib/active_record/relation.rb +69 -94
  101. data/lib/active_record/relation/batches.rb +57 -23
  102. data/lib/active_record/relation/calculations.rb +36 -43
  103. data/lib/active_record/relation/delegation.rb +54 -39
  104. data/lib/active_record/relation/finder_methods.rb +107 -62
  105. data/lib/active_record/relation/merger.rb +7 -20
  106. data/lib/active_record/relation/predicate_builder.rb +57 -38
  107. data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
  108. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  109. data/lib/active_record/relation/query_methods.rb +110 -98
  110. data/lib/active_record/relation/spawn_methods.rb +1 -2
  111. data/lib/active_record/result.rb +45 -6
  112. data/lib/active_record/runtime_registry.rb +5 -0
  113. data/lib/active_record/sanitization.rb +6 -8
  114. data/lib/active_record/schema_dumper.rb +16 -5
  115. data/lib/active_record/schema_migration.rb +24 -25
  116. data/lib/active_record/scoping/default.rb +5 -18
  117. data/lib/active_record/scoping/named.rb +8 -29
  118. data/lib/active_record/store.rb +56 -28
  119. data/lib/active_record/tasks/database_tasks.rb +8 -4
  120. data/lib/active_record/timestamp.rb +4 -4
  121. data/lib/active_record/transactions.rb +8 -10
  122. data/lib/active_record/validations/presence.rb +1 -1
  123. data/lib/active_record/validations/uniqueness.rb +1 -6
  124. data/lib/active_record/version.rb +1 -1
  125. data/lib/rails/generators/active_record.rb +2 -8
  126. data/lib/rails/generators/active_record/migration.rb +18 -0
  127. data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
  128. data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
  129. metadata +32 -45
  130. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
  131. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  132. data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
  133. data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
  134. data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
  135. data/lib/active_record/test_case.rb +0 -102
@@ -4,7 +4,7 @@ require 'active_support/benchmarkable'
4
4
  require 'active_support/dependencies'
5
5
  require 'active_support/descendants_tracker'
6
6
  require 'active_support/time'
7
- require 'active_support/core_ext/class/attribute_accessors'
7
+ require 'active_support/core_ext/module/attribute_accessors'
8
8
  require 'active_support/core_ext/class/delegating_attributes'
9
9
  require 'active_support/core_ext/array/extract_options'
10
10
  require 'active_support/core_ext/hash/deep_merge'
@@ -18,6 +18,7 @@ require 'arel'
18
18
  require 'active_record/errors'
19
19
  require 'active_record/log_subscriber'
20
20
  require 'active_record/explain_subscriber'
21
+ require 'active_record/relation/delegation'
21
22
 
22
23
  module ActiveRecord #:nodoc:
23
24
  # = Active Record
@@ -290,8 +291,11 @@ module ActiveRecord #:nodoc:
290
291
  extend Translation
291
292
  extend DynamicMatchers
292
293
  extend Explain
294
+ extend Enum
295
+ extend Delegation::DelegateCache
293
296
 
294
297
  include Persistence
298
+ include NoTouching
295
299
  include ReadonlyAttributes
296
300
  include ModelSchema
297
301
  include Inheritance
@@ -302,11 +302,11 @@ module ActiveRecord
302
302
  run_callbacks(:save) { super }
303
303
  end
304
304
 
305
- def _create_record #:nodoc:
305
+ def create_record #:nodoc:
306
306
  run_callbacks(:create) { super }
307
307
  end
308
308
 
309
- def _update_record(*) #:nodoc:
309
+ def update_record(*) #:nodoc:
310
310
  run_callbacks(:update) { super }
311
311
  end
312
312
  end
@@ -332,11 +332,6 @@ module ActiveRecord
332
332
  end
333
333
  end
334
334
 
335
- def clear_stale_cached_connections! # :nodoc:
336
- reap
337
- end
338
- deprecate :clear_stale_cached_connections! => "Please use #reap instead"
339
-
340
335
  # Check-out a database connection from the pool, indicating that you want
341
336
  # to use it. You should call #checkin when you no longer need this.
342
337
  #
@@ -398,7 +393,7 @@ module ActiveRecord
398
393
  synchronize do
399
394
  stale = Time.now - @dead_connection_timeout
400
395
  connections.dup.each do |conn|
401
- if conn.in_use? && stale > conn.last_use && !conn.active_threadsafe?
396
+ if conn.in_use? && stale > conn.last_use && !conn.active?
402
397
  remove conn
403
398
  end
404
399
  end
@@ -629,7 +624,7 @@ module ActiveRecord
629
624
  end
630
625
 
631
626
  response
632
- rescue
627
+ rescue Exception
633
628
  ActiveRecord::Base.clear_active_connections! unless testing
634
629
  raise
635
630
  end
@@ -18,18 +18,15 @@ module ActiveRecord
18
18
  end
19
19
  end
20
20
 
21
- # Returns an array of record hashes with the column names as keys and
22
- # column values as values.
21
+ # Returns an ActiveRecord::Result instance.
23
22
  def select_all(arel, name = nil, binds = [])
24
- arel, binds = binds_from_relation arel, binds
25
23
  select(to_sql(arel, binds), name, binds)
26
24
  end
27
25
 
28
26
  # Returns a record hash with the column names as keys and column values
29
27
  # as values.
30
28
  def select_one(arel, name = nil, binds = [])
31
- result = select_all(arel, name, binds)
32
- result.first if result
29
+ select_all(arel, name, binds).first
33
30
  end
34
31
 
35
32
  # Returns a single value from a record
@@ -42,13 +39,13 @@ module ActiveRecord
42
39
  # Returns an array of the values of the first column in a select:
43
40
  # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
44
41
  def select_values(arel, name = nil)
45
- arel, binds = binds_from_relation arel, []
46
- select_rows(to_sql(arel, binds), name, binds).map(&:first)
42
+ select_rows(to_sql(arel, []), name)
43
+ .map { |v| v[0] }
47
44
  end
48
45
 
49
46
  # Returns an array of arrays containing the field values.
50
47
  # Order is the same as that returned by +columns+.
51
- def select_rows(sql, name = nil, binds = [])
48
+ def select_rows(sql, name = nil)
52
49
  end
53
50
  undef_method :select_rows
54
51
 
@@ -289,6 +286,10 @@ module ActiveRecord
289
286
  # Inserts the given fixture into the table. Overridden in adapters that require
290
287
  # something beyond a simple insert (eg. Oracle).
291
288
  def insert_fixture(fixture, table_name)
289
+ execute fixture_sql(fixture, table_name), 'Fixture Insert'
290
+ end
291
+
292
+ def fixture_sql(fixture, table_name)
292
293
  columns = schema_cache.columns_hash(table_name)
293
294
 
294
295
  key_list = []
@@ -297,17 +298,13 @@ module ActiveRecord
297
298
  quote(value, columns[name])
298
299
  end
299
300
 
300
- execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
301
+ "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})"
301
302
  end
302
303
 
303
304
  def empty_insert_statement_value
304
305
  "DEFAULT VALUES"
305
306
  end
306
307
 
307
- def case_sensitive_equality_operator
308
- "="
309
- end
310
-
311
308
  def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key)
312
309
  "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{quoted_table_name} #{where_sql})"
313
310
  end
@@ -356,8 +353,7 @@ module ActiveRecord
356
353
  subselect
357
354
  end
358
355
 
359
- # Returns an array of record hashes with the column names as keys and
360
- # column values as values.
356
+ # Returns an ActiveRecord::Result instance.
361
357
  def select(sql, name = nil, binds = [])
362
358
  end
363
359
  undef_method :select
@@ -386,13 +382,6 @@ module ActiveRecord
386
382
  row = result.rows.first
387
383
  row && row.first
388
384
  end
389
-
390
- def binds_from_relation(relation, binds)
391
- if relation.is_a?(Relation) && binds.blank?
392
- relation, binds = relation.arel, relation.bind_values
393
- end
394
- [relation, binds]
395
- end
396
385
  end
397
386
  end
398
387
  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}(*) # def update_with_query_dirty(*)
13
- clear_query_cache if @query_cache_enabled # clear_query_cache if @query_cache_enabled
14
- super # super
15
- end # 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,7 +63,6 @@ module ActiveRecord
57
63
 
58
64
  def select_all(arel, name = nil, binds = [])
59
65
  if @query_cache_enabled && !locked?(arel)
60
- arel, binds = binds_from_relation arel, binds
61
66
  sql = to_sql(arel, binds)
62
67
  cache_sql(sql, binds) { super(sql, name, binds) }
63
68
  else
@@ -76,14 +81,7 @@ module ActiveRecord
76
81
  else
77
82
  @query_cache[sql][binds] = yield
78
83
  end
79
-
80
- # FIXME: we should guarantee that all cached items are Result
81
- # objects. Then we can avoid this conditional
82
- if ActiveRecord::Result === result
83
- result.dup
84
- else
85
- result.collect { |row| row.dup }
86
- end
84
+ result.dup
87
85
  end
88
86
 
89
87
  # 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
@@ -44,9 +43,7 @@ module ActiveRecord
44
43
  # SQLite does not understand dates, so this method will convert a Date
45
44
  # to a String.
46
45
  def type_cast(value, column)
47
- if value.respond_to?(:quoted_id) && value.respond_to?(:id)
48
- return value.id
49
- end
46
+ return value.id if value.respond_to?(:quoted_id)
50
47
 
51
48
  case value
52
49
  when String, ActiveSupport::Multibyte::Chars
@@ -54,7 +51,6 @@ module ActiveRecord
54
51
  return value unless column
55
52
 
56
53
  case column.type
57
- when :binary then value
58
54
  when :integer then value.to_i
59
55
  when :float then value.to_f
60
56
  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,84 @@
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 #{@conn.quote(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 options_include_default?(options)
79
+ options.include?(:default) && !(options[:null] == false && options[:default].nil?)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ 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, :sql_type) #: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) #: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(options = {})
397
- @base.add_timestamps(@table_name, options)
397
+ def timestamps
398
+ @base.add_timestamps(@table_name)
398
399
  end
399
400
 
400
401
  # Changes the column's definition according to the new options.
@@ -120,9 +120,9 @@ module ActiveRecord
120
120
  # The name of the primary key, if one is to be added automatically.
121
121
  # Defaults to +id+. If <tt>:id</tt> is false this option is ignored.
122
122
  #
123
- # Note that Active Record models will automatically detect their
124
- # primary key. This can be avoided by using +self.primary_key=+ on the model
125
- # to define the key explicitly.
123
+ # Also note that this just sets the primary key in the table. You additionally
124
+ # need to configure the primary key in the model via +self.primary_key=+.
125
+ # Models do NOT auto-detect the primary key from their table definition.
126
126
  #
127
127
  # [<tt>:options</tt>]
128
128
  # Any extra options you want appended to the table definition.
@@ -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
- unless options[:id] == false
177
- pk = options.fetch(:primary_key) {
178
- Base.get_primary_key table_name.to_s.singularize
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
- td.primary_key pk, options.fetch(:id, :primary_key), options
182
- end
195
+ td.primary_key pk, options.fetch(:id, :primary_key), options
196
+ end
183
197
 
184
- yield td if block_given?
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
- remove_index(table_name, :name => old_name)
562
- add_index(table_name, old_index_def.columns, :name => new_name, :unique => old_index_def.unique)
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 : nil) if 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,32 +709,12 @@ 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.
720
715
  #
721
716
  # columns_for_distinct("posts.id", ["posts.created_at desc"])
722
- def columns_for_distinct(columns, orders) #:nodoc:
717
+ def columns_for_distinct(columns, orders) # :nodoc:
723
718
  columns
724
719
  end
725
720
 
@@ -727,9 +722,9 @@ module ActiveRecord
727
722
  #
728
723
  # add_timestamps(:suppliers)
729
724
  #
730
- def add_timestamps(table_name, options = {})
731
- add_column table_name, :created_at, :datetime, options
732
- add_column table_name, :updated_at, :datetime, options
725
+ def add_timestamps(table_name)
726
+ add_column table_name, :created_at, :datetime
727
+ add_column table_name, :updated_at, :datetime
733
728
  end
734
729
 
735
730
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
@@ -741,10 +736,6 @@ module ActiveRecord
741
736
  remove_column table_name, :created_at
742
737
  end
743
738
 
744
- def update_table_definition(table_name, base) #:nodoc:
745
- Table.new(table_name, base)
746
- end
747
-
748
739
  protected
749
740
  def add_index_sort_order(option_strings, column_names, options = {})
750
741
  if options.is_a?(Hash) && order = options[:order]
@@ -779,37 +770,23 @@ module ActiveRecord
779
770
  column_names = Array(column_name)
780
771
  index_name = index_name(table_name, column: column_names)
781
772
 
782
- if Hash === options # legacy support, since this param was a string
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
773
+ options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
795
774
 
796
- using = "USING #{options[:using]}" if options[:using].present?
775
+ index_type = options[:unique] ? "UNIQUE" : ""
776
+ index_type = options[:type].to_s if options.key?(:type)
777
+ index_name = options[:name].to_s if options.key?(:name)
778
+ max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
797
779
 
798
- if supports_partial_index?
799
- index_options = options[:where] ? " WHERE #{options[:where]}" : ""
800
- end
801
- else
802
- if options
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"
780
+ if options.key?(:algorithm)
781
+ algorithm = index_algorithms.fetch(options[:algorithm]) {
782
+ raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
783
+ }
784
+ end
806
785
 
807
- ActiveSupport::Deprecation.warn message
808
- end
786
+ using = "USING #{options[:using]}" if options[:using].present?
809
787
 
810
- index_type = options
811
- max_index_length = allowed_index_name_length
812
- algorithm = using = nil
788
+ if supports_partial_index?
789
+ index_options = options[:where] ? " WHERE #{options[:where]}" : ""
813
790
  end
814
791
 
815
792
  if index_name.length > max_index_length
@@ -841,12 +818,6 @@ module ActiveRecord
841
818
  index_name
842
819
  end
843
820
 
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
821
  def rename_table_indexes(table_name, new_name)
851
822
  indexes(new_name).each do |index|
852
823
  generated_index_name = index_name(table_name, column: index.columns)
@@ -869,20 +840,18 @@ module ActiveRecord
869
840
  end
870
841
  end
871
842
 
872
- def quote_value(value, column)
873
- column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale)
874
-
875
- quote(value, column)
876
- end
877
-
878
843
  private
879
- def create_table_definition(name, temporary, options)
880
- TableDefinition.new native_database_types, name, temporary, options
844
+ def create_table_definition(name, temporary, options, as = nil)
845
+ TableDefinition.new native_database_types, name, temporary, options, as
881
846
  end
882
847
 
883
848
  def create_alter_table(name)
884
849
  AlterTable.new create_table_definition(name, false, {})
885
850
  end
851
+
852
+ def update_table_definition(table_name, base)
853
+ Table.new(table_name, base)
854
+ end
886
855
  end
887
856
  end
888
857
  end