activerecord 3.2.22.4 → 4.0.13

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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2799 -617
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +23 -32
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +40 -34
  7. data/lib/active_record/association_relation.rb +22 -0
  8. data/lib/active_record/associations/alias_tracker.rb +4 -2
  9. data/lib/active_record/associations/association.rb +60 -46
  10. data/lib/active_record/associations/association_scope.rb +46 -40
  11. data/lib/active_record/associations/belongs_to_association.rb +17 -4
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  13. data/lib/active_record/associations/builder/association.rb +81 -28
  14. data/lib/active_record/associations/builder/belongs_to.rb +73 -56
  15. data/lib/active_record/associations/builder/collection_association.rb +54 -40
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -64
  18. data/lib/active_record/associations/builder/has_one.rb +13 -50
  19. data/lib/active_record/associations/builder/singular_association.rb +13 -13
  20. data/lib/active_record/associations/collection_association.rb +130 -96
  21. data/lib/active_record/associations/collection_proxy.rb +916 -63
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +15 -13
  23. data/lib/active_record/associations/has_many_association.rb +35 -8
  24. data/lib/active_record/associations/has_many_through_association.rb +37 -17
  25. data/lib/active_record/associations/has_one_association.rb +42 -19
  26. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_association.rb +39 -22
  28. data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
  29. data/lib/active_record/associations/join_dependency/join_part.rb +21 -8
  30. data/lib/active_record/associations/join_dependency.rb +30 -9
  31. data/lib/active_record/associations/join_helper.rb +1 -11
  32. data/lib/active_record/associations/preloader/association.rb +29 -33
  33. data/lib/active_record/associations/preloader/collection_association.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
  36. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +13 -17
  38. data/lib/active_record/associations/preloader.rb +20 -43
  39. data/lib/active_record/associations/singular_association.rb +11 -11
  40. data/lib/active_record/associations/through_association.rb +3 -3
  41. data/lib/active_record/associations.rb +223 -282
  42. data/lib/active_record/attribute_assignment.rb +134 -154
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
  44. data/lib/active_record/attribute_methods/dirty.rb +36 -29
  45. data/lib/active_record/attribute_methods/primary_key.rb +45 -31
  46. data/lib/active_record/attribute_methods/query.rb +5 -4
  47. data/lib/active_record/attribute_methods/read.rb +67 -90
  48. data/lib/active_record/attribute_methods/serialization.rb +133 -70
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +51 -45
  50. data/lib/active_record/attribute_methods/write.rb +34 -39
  51. data/lib/active_record/attribute_methods.rb +268 -108
  52. data/lib/active_record/autosave_association.rb +80 -73
  53. data/lib/active_record/base.rb +54 -451
  54. data/lib/active_record/callbacks.rb +60 -22
  55. data/lib/active_record/coders/yaml_column.rb +18 -21
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +347 -197
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +146 -138
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -19
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +19 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +151 -142
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +499 -217
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +208 -0
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +209 -44
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +169 -61
  67. data/lib/active_record/connection_adapters/column.rb +67 -36
  68. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +28 -29
  70. data/lib/active_record/connection_adapters/mysql_adapter.rb +200 -73
  71. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +98 -0
  72. data/lib/active_record/connection_adapters/postgresql/cast.rb +160 -0
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +240 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +374 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +183 -0
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +508 -0
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +544 -899
  79. data/lib/active_record/connection_adapters/schema_cache.rb +76 -16
  80. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +595 -16
  81. data/lib/active_record/connection_handling.rb +98 -0
  82. data/lib/active_record/core.rb +472 -0
  83. data/lib/active_record/counter_cache.rb +107 -108
  84. data/lib/active_record/dynamic_matchers.rb +115 -63
  85. data/lib/active_record/errors.rb +36 -18
  86. data/lib/active_record/explain.rb +15 -63
  87. data/lib/active_record/explain_registry.rb +30 -0
  88. data/lib/active_record/explain_subscriber.rb +8 -4
  89. data/lib/active_record/fixture_set/file.rb +55 -0
  90. data/lib/active_record/fixtures.rb +159 -155
  91. data/lib/active_record/inheritance.rb +93 -59
  92. data/lib/active_record/integration.rb +8 -8
  93. data/lib/active_record/locale/en.yml +8 -1
  94. data/lib/active_record/locking/optimistic.rb +39 -43
  95. data/lib/active_record/locking/pessimistic.rb +4 -4
  96. data/lib/active_record/log_subscriber.rb +19 -9
  97. data/lib/active_record/migration/command_recorder.rb +102 -33
  98. data/lib/active_record/migration/join_table.rb +15 -0
  99. data/lib/active_record/migration.rb +411 -173
  100. data/lib/active_record/model_schema.rb +81 -94
  101. data/lib/active_record/nested_attributes.rb +173 -131
  102. data/lib/active_record/null_relation.rb +67 -0
  103. data/lib/active_record/persistence.rb +254 -106
  104. data/lib/active_record/query_cache.rb +18 -36
  105. data/lib/active_record/querying.rb +19 -15
  106. data/lib/active_record/railtie.rb +113 -38
  107. data/lib/active_record/railties/console_sandbox.rb +3 -4
  108. data/lib/active_record/railties/controller_runtime.rb +4 -3
  109. data/lib/active_record/railties/databases.rake +115 -368
  110. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  111. data/lib/active_record/readonly_attributes.rb +7 -3
  112. data/lib/active_record/reflection.rb +110 -61
  113. data/lib/active_record/relation/batches.rb +29 -29
  114. data/lib/active_record/relation/calculations.rb +155 -125
  115. data/lib/active_record/relation/delegation.rb +94 -18
  116. data/lib/active_record/relation/finder_methods.rb +151 -203
  117. data/lib/active_record/relation/merger.rb +188 -0
  118. data/lib/active_record/relation/predicate_builder.rb +85 -42
  119. data/lib/active_record/relation/query_methods.rb +793 -146
  120. data/lib/active_record/relation/spawn_methods.rb +43 -150
  121. data/lib/active_record/relation.rb +293 -173
  122. data/lib/active_record/result.rb +48 -7
  123. data/lib/active_record/runtime_registry.rb +17 -0
  124. data/lib/active_record/sanitization.rb +41 -54
  125. data/lib/active_record/schema.rb +19 -12
  126. data/lib/active_record/schema_dumper.rb +41 -41
  127. data/lib/active_record/schema_migration.rb +46 -0
  128. data/lib/active_record/scoping/default.rb +56 -52
  129. data/lib/active_record/scoping/named.rb +78 -103
  130. data/lib/active_record/scoping.rb +54 -124
  131. data/lib/active_record/serialization.rb +6 -2
  132. data/lib/active_record/serializers/xml_serializer.rb +9 -15
  133. data/lib/active_record/statement_cache.rb +26 -0
  134. data/lib/active_record/store.rb +131 -15
  135. data/lib/active_record/tasks/database_tasks.rb +204 -0
  136. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +144 -0
  138. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  140. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  141. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  142. data/lib/active_record/test_case.rb +67 -38
  143. data/lib/active_record/timestamp.rb +16 -11
  144. data/lib/active_record/transactions.rb +73 -51
  145. data/lib/active_record/validations/associated.rb +19 -13
  146. data/lib/active_record/validations/presence.rb +65 -0
  147. data/lib/active_record/validations/uniqueness.rb +110 -57
  148. data/lib/active_record/validations.rb +18 -17
  149. data/lib/active_record/version.rb +7 -6
  150. data/lib/active_record.rb +63 -45
  151. data/lib/rails/generators/active_record/migration/migration_generator.rb +45 -8
  152. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
  153. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  154. data/lib/rails/generators/active_record/model/model_generator.rb +5 -4
  155. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  156. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  157. data/lib/rails/generators/active_record.rb +3 -5
  158. metadata +43 -29
  159. data/examples/associations.png +0 -0
  160. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  161. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  162. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  163. data/lib/active_record/dynamic_finder_match.rb +0 -68
  164. data/lib/active_record/dynamic_scope_match.rb +0 -23
  165. data/lib/active_record/fixtures/file.rb +0 -65
  166. data/lib/active_record/identity_map.rb +0 -162
  167. data/lib/active_record/observer.rb +0 -121
  168. data/lib/active_record/session_store.rb +0 -360
  169. data/lib/rails/generators/active_record/migration.rb +0 -15
  170. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  171. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  172. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  173. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,4 +1,3 @@
1
- require 'active_support/core_ext/object/blank'
2
1
  require 'date'
3
2
  require 'set'
4
3
  require 'bigdecimal'
@@ -6,37 +5,24 @@ require 'bigdecimal/util'
6
5
 
7
6
  module ActiveRecord
8
7
  module ConnectionAdapters #:nodoc:
9
- class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders) #:nodoc:
8
+ # Abstract representation of an index definition on a table. Instances of
9
+ # this type are typically created and returned by methods in database
10
+ # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
11
+ class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using) #:nodoc:
10
12
  end
11
13
 
12
14
  # Abstract representation of a column definition. Instances of this type
13
15
  # are typically created by methods in TableDefinition, and added to the
14
16
  # +columns+ attribute of said TableDefinition object, in order to be used
15
17
  # for generating a number of table creation or table changing SQL statements.
16
- class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
17
-
18
+ class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type) #:nodoc:
18
19
  def string_to_binary(value)
19
20
  value
20
21
  end
21
22
 
22
- def sql_type
23
- base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
24
- end
25
-
26
- def to_sql
27
- column_sql = "#{base.quote_column_name(name)} #{sql_type}"
28
- column_options = {}
29
- column_options[:null] = null unless null.nil?
30
- column_options[:default] = default unless default.nil?
31
- add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key
32
- column_sql
23
+ def primary_key?
24
+ primary_key || type.to_sym == :primary_key
33
25
  end
34
-
35
- private
36
-
37
- def add_column_options!(sql, options)
38
- base.add_column_options!(sql, options.merge(:column => self))
39
- end
40
26
  end
41
27
 
42
28
  # Represents the schema of an SQL table in an abstract way. This class
@@ -62,27 +48,24 @@ module ActiveRecord
62
48
  class TableDefinition
63
49
  # An array of ColumnDefinition objects, representing the column changes
64
50
  # that have been defined.
65
- attr_accessor :columns
51
+ attr_accessor :indexes
52
+ attr_reader :name, :temporary, :options
66
53
 
67
- def initialize(base)
68
- @columns = []
54
+ def initialize(types, name, temporary, options)
69
55
  @columns_hash = {}
70
- @base = base
56
+ @indexes = {}
57
+ @native = types
58
+ @temporary = temporary
59
+ @options = options
60
+ @name = name
71
61
  end
72
62
 
73
- def xml(*args)
74
- raise NotImplementedError unless %w{
75
- sqlite mysql mysql2
76
- }.include? @base.adapter_name.downcase
77
-
78
- options = args.extract_options!
79
- column(args[0], :text, options)
80
- end
63
+ def columns; @columns_hash.values; end
81
64
 
82
65
  # Appends a primary key definition to the table definition.
83
66
  # Can be called multiple times, but this is probably not a good idea.
84
- def primary_key(name)
85
- column(name, :primary_key)
67
+ def primary_key(name, type = :primary_key, options = {})
68
+ column(name, type, options.merge(:primary_key => true))
86
69
  end
87
70
 
88
71
  # Returns a ColumnDefinition for the column with name +name+.
@@ -158,21 +141,21 @@ module ActiveRecord
158
141
  # td.column(:granted, :boolean)
159
142
  # # granted BOOLEAN
160
143
  #
161
- # td.column(:picture, :binary, :limit => 2.megabytes)
144
+ # td.column(:picture, :binary, limit: 2.megabytes)
162
145
  # # => picture BLOB(2097152)
163
146
  #
164
- # td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
147
+ # td.column(:sales_stage, :string, limit: 20, default: 'new', null: false)
165
148
  # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
166
149
  #
167
- # td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
150
+ # td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
168
151
  # # => bill_gates_money DECIMAL(15,2)
169
152
  #
170
- # td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
153
+ # td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
171
154
  # # => sensor_reading DECIMAL(30,20)
172
155
  #
173
156
  # # While <tt>:scale</tt> defaults to zero on most databases, it
174
157
  # # probably wouldn't hurt to include it.
175
- # td.column(:huge_integer, :decimal, :precision => 30)
158
+ # td.column(:huge_integer, :decimal, precision: 30)
176
159
  # # => huge_integer DECIMAL(30)
177
160
  #
178
161
  # # Defines a column with a database-specific type.
@@ -187,20 +170,20 @@ module ActiveRecord
187
170
  #
188
171
  # What can be written like this with the regular calls to column:
189
172
  #
190
- # create_table "products", :force => true do |t|
191
- # t.column "shop_id", :integer
192
- # t.column "creator_id", :integer
193
- # t.column "name", :string, :default => "Untitled"
194
- # t.column "value", :string, :default => "Untitled"
195
- # t.column "created_at", :datetime
196
- # t.column "updated_at", :datetime
173
+ # create_table :products do |t|
174
+ # t.column :shop_id, :integer
175
+ # t.column :creator_id, :integer
176
+ # t.column :name, :string, default: "Untitled"
177
+ # t.column :value, :string, default: "Untitled"
178
+ # t.column :created_at, :datetime
179
+ # t.column :updated_at, :datetime
197
180
  # end
198
181
  #
199
- # Can also be written as follows using the short-hand:
182
+ # can also be written as follows using the short-hand:
200
183
  #
201
184
  # create_table :products do |t|
202
185
  # t.integer :shop_id, :creator_id
203
- # t.string :name, :value, :default => "Untitled"
186
+ # t.string :name, :value, default: "Untitled"
204
187
  # t.timestamps
205
188
  # end
206
189
  #
@@ -209,54 +192,60 @@ module ActiveRecord
209
192
  #
210
193
  # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
211
194
  # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
212
- # options, these will be used when creating the <tt>_type</tt> column. So what can be written like this:
195
+ # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
196
+ # will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
213
197
  #
214
198
  # create_table :taggings do |t|
215
199
  # t.integer :tag_id, :tagger_id, :taggable_id
216
200
  # t.string :tagger_type
217
- # t.string :taggable_type, :default => 'Photo'
201
+ # t.string :taggable_type, default: 'Photo'
218
202
  # end
203
+ # add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id'
204
+ # add_index :taggings, [:tagger_id, :tagger_type]
219
205
  #
220
206
  # Can also be written as follows using references:
221
207
  #
222
208
  # create_table :taggings do |t|
223
- # t.references :tag
224
- # t.references :tagger, :polymorphic => true
225
- # t.references :taggable, :polymorphic => { :default => 'Photo' }
209
+ # t.references :tag, index: { name: 'index_taggings_on_tag_id' }
210
+ # t.references :tagger, polymorphic: true, index: true
211
+ # t.references :taggable, polymorphic: { default: 'Photo' }
226
212
  # end
227
213
  def column(name, type, options = {})
228
214
  name = name.to_s
229
215
  type = type.to_sym
230
216
 
231
- column = self[name] || new_column_definition(@base, name, type)
232
-
233
- limit = options.fetch(:limit) do
234
- native[type][:limit] if native[type].is_a?(Hash)
217
+ if primary_key_column_name == name
218
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
235
219
  end
236
220
 
237
- column.limit = limit
238
- column.precision = options[:precision]
239
- column.scale = options[:scale]
240
- column.default = options[:default]
241
- column.null = options[:null]
221
+ @columns_hash[name] = new_column_definition(name, type, options)
242
222
  self
243
223
  end
244
224
 
245
- %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
246
- class_eval <<-EOV, __FILE__, __LINE__ + 1
247
- def #{column_type}(*args) # def string(*args)
248
- options = args.extract_options! # options = args.extract_options!
249
- column_names = args # column_names = args
250
- type = :'#{column_type}' # type = :string
251
- column_names.each { |name| column(name, type, options) } # column_names.each { |name| column(name, type, options) }
252
- end # end
253
- EOV
225
+ def remove_column(name)
226
+ @columns_hash.delete name.to_s
227
+ end
228
+
229
+ [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
230
+ define_method column_type do |*args|
231
+ options = args.extract_options!
232
+ column_names = args
233
+ column_names.each { |name| column(name, column_type, options) }
234
+ end
235
+ end
236
+
237
+ # Adds index options to the indexes hash, keyed by column name
238
+ # This is primarily used to track indexes that need to be created after the table
239
+ #
240
+ # index(:account_id, name: 'index_projects_on_account_id')
241
+ def index(column_name, options = {})
242
+ indexes[column_name] = options
254
243
  end
255
244
 
256
245
  # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
257
246
  # <tt>:updated_at</tt> to the table.
258
247
  def timestamps(*args)
259
- options = { :null => false }.merge(args.extract_options!)
248
+ options = args.extract_options!
260
249
  column(:created_at, :datetime, options)
261
250
  column(:updated_at, :datetime, options)
262
251
  end
@@ -264,30 +253,62 @@ module ActiveRecord
264
253
  def references(*args)
265
254
  options = args.extract_options!
266
255
  polymorphic = options.delete(:polymorphic)
256
+ index_options = options.delete(:index)
267
257
  args.each do |col|
268
258
  column("#{col}_id", :integer, options)
269
- column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
259
+ column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
260
+ index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
270
261
  end
271
262
  end
272
263
  alias :belongs_to :references
273
264
 
274
- # Returns a String whose contents are the column definitions
275
- # concatenated together. This string can then be prepended and appended to
276
- # to generate the final SQL to create the table.
277
- def to_sql
278
- @columns.map { |c| c.to_sql } * ', '
265
+ def new_column_definition(name, type, options) # :nodoc:
266
+ column = create_column_definition name, type
267
+ limit = options.fetch(:limit) do
268
+ native[type][:limit] if native[type].is_a?(Hash)
269
+ end
270
+
271
+ column.limit = limit
272
+ column.array = options[:array] if column.respond_to?(:array)
273
+ column.precision = options[:precision]
274
+ column.scale = options[:scale]
275
+ column.default = options[:default]
276
+ column.null = options[:null]
277
+ column.first = options[:first]
278
+ column.after = options[:after]
279
+ column.primary_key = type == :primary_key || options[:primary_key]
280
+ column
279
281
  end
280
282
 
281
283
  private
282
- def new_column_definition(base, name, type)
283
- definition = ColumnDefinition.new base, name, type
284
- @columns << definition
285
- @columns_hash[name] = definition
286
- definition
284
+ def create_column_definition(name, type)
285
+ ColumnDefinition.new name, type
286
+ end
287
+
288
+ def primary_key_column_name
289
+ primary_key_column = columns.detect { |c| c.primary_key? }
290
+ primary_key_column && primary_key_column.name
287
291
  end
288
292
 
289
293
  def native
290
- @base.native_database_types
294
+ @native
295
+ end
296
+ end
297
+
298
+ class AlterTable # :nodoc:
299
+ attr_reader :adds
300
+
301
+ def initialize(td)
302
+ @td = td
303
+ @adds = []
304
+ end
305
+
306
+ def name; @td.name; end
307
+
308
+ def add_column(name, type, options)
309
+ name = name.to_s
310
+ type = type.to_sym
311
+ @adds << @td.new_column_definition(name, type, options)
291
312
  end
292
313
  end
293
314
 
@@ -299,6 +320,7 @@ module ActiveRecord
299
320
  # change_table :table do |t|
300
321
  # t.column
301
322
  # t.index
323
+ # t.rename_index
302
324
  # t.timestamps
303
325
  # t.change
304
326
  # t.change_default
@@ -331,7 +353,7 @@ module ActiveRecord
331
353
 
332
354
  # Adds a new column to the named table.
333
355
  # See TableDefinition#column for details of the options you can use.
334
- # ===== Example
356
+ #
335
357
  # ====== Creating a simple column
336
358
  # t.column(:name, :string)
337
359
  def column(column_name, type, options = {})
@@ -346,13 +368,12 @@ module ActiveRecord
346
368
  # Adds a new index to the table. +column_name+ can be a single Symbol, or
347
369
  # an Array of Symbols. See SchemaStatements#add_index
348
370
  #
349
- # ===== Examples
350
371
  # ====== Creating a simple index
351
372
  # t.index(:name)
352
373
  # ====== Creating a unique index
353
- # t.index([:branch_id, :party_id], :unique => true)
374
+ # t.index([:branch_id, :party_id], unique: true)
354
375
  # ====== Creating a named index
355
- # t.index([:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
376
+ # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
356
377
  def index(column_name, options = {})
357
378
  @base.add_index(@table_name, column_name, options)
358
379
  end
@@ -362,24 +383,31 @@ module ActiveRecord
362
383
  @base.index_exists?(@table_name, column_name, options)
363
384
  end
364
385
 
386
+ # Renames the given index on the table.
387
+ #
388
+ # t.rename_index(:user_id, :account_id)
389
+ def rename_index(index_name, new_index_name)
390
+ @base.rename_index(@table_name, index_name, new_index_name)
391
+ end
392
+
365
393
  # Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
366
- # ===== Example
394
+ #
367
395
  # t.timestamps
368
- def timestamps
369
- @base.add_timestamps(@table_name)
396
+ def timestamps(options = {})
397
+ @base.add_timestamps(@table_name, options)
370
398
  end
371
399
 
372
400
  # Changes the column's definition according to the new options.
373
401
  # See TableDefinition#column for details of the options you can use.
374
- # ===== Examples
375
- # t.change(:name, :string, :limit => 80)
402
+ #
403
+ # t.change(:name, :string, limit: 80)
376
404
  # t.change(:description, :text)
377
405
  def change(column_name, type, options = {})
378
406
  @base.change_column(@table_name, column_name, type, options)
379
407
  end
380
408
 
381
409
  # Sets a new default value for a column. See SchemaStatements#change_column_default
382
- # ===== Examples
410
+ #
383
411
  # t.change_default(:qualification, 'new')
384
412
  # t.change_default(:authorized, 1)
385
413
  def change_default(column_name, default)
@@ -387,37 +415,36 @@ module ActiveRecord
387
415
  end
388
416
 
389
417
  # Removes the column(s) from the table definition.
390
- # ===== Examples
418
+ #
391
419
  # t.remove(:qualification)
392
420
  # t.remove(:qualification, :experience)
393
421
  def remove(*column_names)
394
- @base.remove_column(@table_name, *column_names)
422
+ @base.remove_columns(@table_name, *column_names)
395
423
  end
396
424
 
397
425
  # Removes the given index from the table.
398
426
  #
399
- # ===== Examples
400
427
  # ====== Remove the index_table_name_on_column in the table_name table
401
428
  # t.remove_index :column
402
429
  # ====== Remove the index named index_table_name_on_branch_id in the table_name table
403
- # t.remove_index :column => :branch_id
430
+ # t.remove_index column: :branch_id
404
431
  # ====== Remove the index named index_table_name_on_branch_id_and_party_id in the table_name table
405
- # t.remove_index :column => [:branch_id, :party_id]
432
+ # t.remove_index column: [:branch_id, :party_id]
406
433
  # ====== Remove the index named by_branch_party in the table_name table
407
- # t.remove_index :name => :by_branch_party
434
+ # t.remove_index name: :by_branch_party
408
435
  def remove_index(options = {})
409
436
  @base.remove_index(@table_name, options)
410
437
  end
411
438
 
412
439
  # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
413
- # ===== Example
440
+ #
414
441
  # t.remove_timestamps
415
442
  def remove_timestamps
416
443
  @base.remove_timestamps(@table_name)
417
444
  end
418
445
 
419
446
  # Renames a column.
420
- # ===== Example
447
+ #
421
448
  # t.rename(:description, :name)
422
449
  def rename(column_name, new_column_name)
423
450
  @base.rename_column(@table_name, column_name, new_column_name)
@@ -425,61 +452,43 @@ module ActiveRecord
425
452
 
426
453
  # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
427
454
  # <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
428
- # ===== Examples
429
- # t.references(:goat)
430
- # t.references(:goat, :polymorphic => true)
431
- # t.belongs_to(:goat)
455
+ #
456
+ # t.references(:user)
457
+ # t.belongs_to(:supplier, polymorphic: true)
458
+ #
432
459
  def references(*args)
433
460
  options = args.extract_options!
434
- polymorphic = options.delete(:polymorphic)
435
- args.each do |col|
436
- @base.add_column(@table_name, "#{col}_id", :integer, options)
437
- @base.add_column(@table_name, "#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
461
+ args.each do |ref_name|
462
+ @base.add_reference(@table_name, ref_name, options)
438
463
  end
439
464
  end
440
465
  alias :belongs_to :references
441
466
 
442
467
  # Removes a reference. Optionally removes a +type+ column.
443
468
  # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
444
- # ===== Examples
445
- # t.remove_references(:goat)
446
- # t.remove_references(:goat, :polymorphic => true)
447
- # t.remove_belongs_to(:goat)
469
+ #
470
+ # t.remove_references(:user)
471
+ # t.remove_belongs_to(:supplier, polymorphic: true)
472
+ #
448
473
  def remove_references(*args)
449
474
  options = args.extract_options!
450
- polymorphic = options.delete(:polymorphic)
451
- args.each do |col|
452
- @base.remove_column(@table_name, "#{col}_id")
453
- @base.remove_column(@table_name, "#{col}_type") unless polymorphic.nil?
475
+ args.each do |ref_name|
476
+ @base.remove_reference(@table_name, ref_name, options)
454
477
  end
455
478
  end
456
- alias :remove_belongs_to :remove_references
479
+ alias :remove_belongs_to :remove_references
457
480
 
458
481
  # Adds a column or columns of a specified type
459
- # ===== Examples
482
+ #
460
483
  # t.string(:goat)
461
484
  # t.string(:goat, :sheep)
462
- %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
463
- class_eval <<-EOV, __FILE__, __LINE__ + 1
464
- def #{column_type}(*args) # def string(*args)
465
- options = args.extract_options! # options = args.extract_options!
466
- column_names = args # column_names = args
467
- type = :'#{column_type}' # type = :string
468
- column_names.each do |name| # column_names.each do |name|
469
- column = ColumnDefinition.new(@base, name.to_s, type) # column = ColumnDefinition.new(@base, name, type)
470
- if options[:limit] # if options[:limit]
471
- column.limit = options[:limit] # column.limit = options[:limit]
472
- elsif native[type].is_a?(Hash) # elsif native[type].is_a?(Hash)
473
- column.limit = native[type][:limit] # column.limit = native[type][:limit]
474
- end # end
475
- column.precision = options[:precision] # column.precision = options[:precision]
476
- column.scale = options[:scale] # column.scale = options[:scale]
477
- column.default = options[:default] # column.default = options[:default]
478
- column.null = options[:null] # column.null = options[:null]
479
- @base.add_column(@table_name, name, column.sql_type, options) # @base.add_column(@table_name, name, column.sql_type, options)
480
- end # end
481
- end # end
482
- EOV
485
+ [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
486
+ define_method column_type do |*args|
487
+ options = args.extract_options!
488
+ args.each do |name|
489
+ @base.add_column(@table_name, name, column_type, options)
490
+ end
491
+ end
483
492
  end
484
493
 
485
494
  private
@@ -0,0 +1,70 @@
1
+ require 'ipaddr'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters # :nodoc:
5
+ # The goal of this module is to move Adapter specific column
6
+ # definitions to the Adapter instead of having it in the schema
7
+ # dumper itself. This code represents the normal case.
8
+ # We can then redefine how certain data types may be handled in the schema dumper on the
9
+ # Adapter level by over-writing this code inside the database specific adapters
10
+ module ColumnDumper
11
+ def column_spec(column, types)
12
+ spec = prepare_column_options(column, types)
13
+ (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.to_s}: ")}
14
+ spec
15
+ end
16
+
17
+ # This can be overridden on a Adapter level basis to support other
18
+ # extended datatypes (Example: Adding an array option in the
19
+ # PostgreSQLAdapter)
20
+ def prepare_column_options(column, types)
21
+ spec = {}
22
+ spec[:name] = column.name.inspect
23
+
24
+ # AR has an optimization which handles zero-scale decimals as integers. This
25
+ # code ensures that the dumper still dumps the column as a decimal.
26
+ spec[:type] = if column.type == :integer && /^(numeric|decimal)/ =~ column.sql_type
27
+ 'decimal'
28
+ else
29
+ column.type.to_s
30
+ end
31
+ spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit] && spec[:type] != 'decimal'
32
+ spec[:precision] = column.precision.inspect if column.precision
33
+ spec[:scale] = column.scale.inspect if column.scale
34
+ spec[:null] = 'false' unless column.null
35
+ spec[:default] = default_string(column.default) if column.has_default?
36
+ spec
37
+ end
38
+
39
+ # Lists the valid migration options
40
+ def migration_keys
41
+ [:name, :limit, :precision, :scale, :default, :null]
42
+ end
43
+
44
+ private
45
+
46
+ def default_string(value)
47
+ case value
48
+ when BigDecimal
49
+ value.to_s
50
+ when Date, DateTime, Time
51
+ "'#{value.to_s(:db)}'"
52
+ when Range
53
+ # infinity dumps as Infinity, which causes uninitialized constant error
54
+ value.inspect.gsub('Infinity', '::Float::INFINITY')
55
+ when IPAddr
56
+ subnet_mask = value.instance_variable_get(:@mask_addr)
57
+
58
+ # If the subnet mask is equal to /32, don't output it
59
+ if subnet_mask == (2**32 - 1)
60
+ "\"#{value.to_s}\""
61
+ else
62
+ "\"#{value.to_s}/#{subnet_mask.to_s(2).count('1')}\""
63
+ end
64
+ else
65
+ value.inspect
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end