schema_definitions.rb 23.6 KB
Newer Older
1
require 'date'
2 3
require 'bigdecimal'
require 'bigdecimal/util'
4

5 6
module ActiveRecord
  module ConnectionAdapters #:nodoc:
7 8
    # An abstract definition of a column in a table.
    class Column
9 10 11 12 13
      module Format
        ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
        ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
      end

14
      attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
15
      attr_accessor :primary
16 17 18

      # Instantiates a new column in the table.
      #
P
Pratik Naik 已提交
19 20 21
      # +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
      # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
      # +sql_type+ is only used to extract the column's length, if necessary. For example +60+ in <tt>company_name varchar(60)</tt>.
22
      # +null+ determines if this column allows +NULL+ values.
23
      def initialize(name, default, sql_type = nil, null = true)
24
        @name, @sql_type, @null = name, sql_type, null
25
        @limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type)
26
        @type = simplified_type(sql_type)
27
        @default = extract_default(default)
28

29 30 31 32
        @primary = nil
      end

      def text?
33
        type == :string || type == :text
34 35 36
      end

      def number?
37
        type == :integer || type == :float || type == :decimal
38 39
      end

40
      # Returns the Ruby class that corresponds to the abstract data type.
41 42 43 44
      def klass
        case type
          when :integer       then Fixnum
          when :float         then Float
45
          when :decimal       then BigDecimal
46 47 48 49 50 51 52 53 54 55
          when :datetime      then Time
          when :date          then Date
          when :timestamp     then Time
          when :time          then Time
          when :text, :string then String
          when :binary        then String
          when :boolean       then Object
        end
      end

56
      # Casts value (which is a String) to an appropriate instance.
57
      def type_cast(value)
58
        return nil if value.nil?
59 60 61 62 63
        case type
          when :string    then value
          when :text      then value
          when :integer   then value.to_i rescue value ? 1 : 0
          when :float     then value.to_f
64
          when :decimal   then self.class.value_to_decimal(value)
65 66 67 68 69
          when :datetime  then self.class.string_to_time(value)
          when :timestamp then self.class.string_to_time(value)
          when :time      then self.class.string_to_dummy_time(value)
          when :date      then self.class.string_to_date(value)
          when :binary    then self.class.binary_to_string(value)
70
          when :boolean   then self.class.value_to_boolean(value)
71 72 73 74
          else value
        end
      end

75 76 77 78 79 80
      def type_cast_code(var_name)
        case type
          when :string    then nil
          when :text      then nil
          when :integer   then "(#{var_name}.to_i rescue #{var_name} ? 1 : 0)"
          when :float     then "#{var_name}.to_f"
81
          when :decimal   then "#{self.class.name}.value_to_decimal(#{var_name})"
82 83 84 85 86
          when :datetime  then "#{self.class.name}.string_to_time(#{var_name})"
          when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
          when :time      then "#{self.class.name}.string_to_dummy_time(#{var_name})"
          when :date      then "#{self.class.name}.string_to_date(#{var_name})"
          when :binary    then "#{self.class.name}.binary_to_string(#{var_name})"
87
          when :boolean   then "#{self.class.name}.value_to_boolean(#{var_name})"
88 89 90 91
          else nil
        end
      end

92 93 94
      # Returns the human name of the column name.
      #
      # ===== Examples
P
Pratik Naik 已提交
95
      #  Column.new('sales_stage', ...).human_name # => 'Sales stage'
96 97 98 99
      def human_name
        Base.human_attribute_name(@name)
      end

100 101 102 103
      def extract_default(default)
        type_cast(default)
      end

J
Jeremy Kemper 已提交
104 105 106 107 108
      class << self
        # Used to convert from Strings to BLOBs
        def string_to_binary(value)
          value
        end
109

J
Jeremy Kemper 已提交
110 111 112 113
        # Used to convert from BLOBs to Strings
        def binary_to_string(value)
          value
        end
114

J
Jeremy Kemper 已提交
115 116
        def string_to_date(string)
          return string unless string.is_a?(String)
117
          return nil if string.empty?
118

119
          fast_string_to_date(string) || fallback_string_to_date(string)
J
Jeremy Kemper 已提交
120
        end
121

J
Jeremy Kemper 已提交
122 123 124
        def string_to_time(string)
          return string unless string.is_a?(String)
          return nil if string.empty?
125

126
          fast_string_to_time(string) || fallback_string_to_time(string)
127
        end
128

J
Jeremy Kemper 已提交
129 130 131
        def string_to_dummy_time(string)
          return string unless string.is_a?(String)
          return nil if string.empty?
132

J
Jeremy Kemper 已提交
133
          string_to_time "2000-01-01 #{string}"
134 135
        end

J
Jeremy Kemper 已提交
136 137 138 139 140
        # convert something to a boolean
        def value_to_boolean(value)
          if value == true || value == false
            value
          else
141
            !(value.to_s !~ /\A(?:1|t|true)\Z/i)
J
Jeremy Kemper 已提交
142
          end
143 144
        end

J
Jeremy Kemper 已提交
145 146
        # convert something to a BigDecimal
        def value_to_decimal(value)
147 148 149 150
          # Using .class is faster than .is_a? and
          # subclasses of BigDecimal will be handled
          # in the else clause
          if value.class == BigDecimal
J
Jeremy Kemper 已提交
151 152 153 154 155 156
            value
          elsif value.respond_to?(:to_d)
            value.to_d
          else
            value.to_s.to_d
          end
157 158
        end

J
Jeremy Kemper 已提交
159 160 161 162 163 164 165 166
        protected
          # '0.123456' -> 123456
          # '1.123456' -> 123456
          def microseconds(time)
            ((time[:sec_fraction].to_f % 1) * 1_000_000).to_i
          end

          def new_date(year, mon, mday)
167 168 169
            if year && year != 0
              Date.new(year, mon, mday) rescue nil
            end
J
Jeremy Kemper 已提交
170 171 172 173
          end

          def new_time(year, mon, mday, hour, min, sec, microsec)
            # Treat 0000-00-00 00:00:00 as nil.
174
            return nil if year.nil? || year == 0
175

176
            Time.time_with_datetime_fallback(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
J
Jeremy Kemper 已提交
177
          end
178 179 180 181 182 183 184 185 186 187

          def fast_string_to_date(string)
            if string =~ Format::ISO_DATE
              new_date $1.to_i, $2.to_i, $3.to_i
            end
          end

          # Doesn't handle time zones.
          def fast_string_to_time(string)
            if string =~ Format::ISO_DATETIME
J
Jeremy Kemper 已提交
188
              microsec = ($7.to_f * 1_000_000).to_i
189 190 191 192 193
              new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
            end
          end

          def fallback_string_to_date(string)
194
            new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday))
195 196 197 198 199 200
          end

          def fallback_string_to_time(string)
            time_hash = Date._parse(string)
            time_hash[:sec_fraction] = microseconds(time_hash)

201
            new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
202
          end
J
Jeremy Kemper 已提交
203 204 205
      end

      private
206 207 208 209
        def extract_limit(sql_type)
          $1.to_i if sql_type =~ /\((.*)\)/
        end

210
        def extract_precision(sql_type)
211
          $2.to_i if sql_type =~ /^(numeric|decimal|number)\((\d+)(,\d+)?\)/i
212 213 214 215
        end

        def extract_scale(sql_type)
          case sql_type
216 217
            when /^(numeric|decimal|number)\((\d+)\)/i then 0
            when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
218 219 220
          end
        end

221 222 223 224
        def simplified_type(field_type)
          case field_type
            when /int/i
              :integer
225
            when /float|double/i
226
              :float
227
            when /decimal|numeric|number/i
228
              extract_scale(field_type) == 0 ? :integer : :decimal
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
            when /datetime/i
              :datetime
            when /timestamp/i
              :timestamp
            when /time/i
              :time
            when /date/i
              :date
            when /clob/i, /text/i
              :text
            when /blob/i, /binary/i
              :binary
            when /char/i, /string/i
              :string
            when /boolean/i
              :boolean
          end
        end
    end
248

249 250 251
    class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc:
    end

252
    class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
253

254 255 256
      def sql_type
        base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
      end
257

258
      def to_sql
259
        column_sql = "#{base.quote_column_name(name)} #{sql_type}"
260 261 262 263
        column_options = {}
        column_options[:null] = null unless null.nil?
        column_options[:default] = default unless default.nil?
        add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key
264 265 266
        column_sql
      end
      alias to_s :to_sql
267

268 269 270 271 272 273 274
      private

        def add_column_options!(sql, options)
          base.add_column_options!(sql, options.merge(:column => self))
        end
    end

275
    # Represents a SQL table in an abstract way.
P
Pratik Naik 已提交
276
    # Columns are stored as a ColumnDefinition in the +columns+ attribute.
277
    class TableDefinition
278 279 280 281 282 283 284
      attr_accessor :columns

      def initialize(base)
        @columns = []
        @base = base
      end

285 286
      # Appends a primary key definition to the table definition.
      # Can be called multiple times, but this is probably not a good idea.
287
      def primary_key(name)
288
        column(name, :primary_key)
289
      end
290 291

      # Returns a ColumnDefinition for the column with name +name+.
292
      def [](name)
293
        @columns.find {|column| column.name.to_s == name.to_s}
294 295
      end

296
      # Instantiates a new column for the table.
297 298
      # The +type+ parameter is normally one of the migrations native types,
      # which is one of the following:
299
      # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
300 301 302
      # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
      # <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
      # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>.
303
      #
304 305 306 307
      # You may use a type not in this list as long as it is supported by your
      # database (for example, "polygon" in MySQL), but this will not be database
      # agnostic and should usually be avoided.
      #
308
      # Available options are (none of these exists by default):
309
      # * <tt>:limit</tt> -
310
      #   Requests a maximum column length. This is number of characters for <tt>:string</tt> and <tt>:text</tt> columns and number of bytes for :binary and :integer columns.
311
      # * <tt>:default</tt> -
312
      #   The column's default value. Use nil for NULL.
313
      # * <tt>:null</tt> -
314
      #   Allows or disallows +NULL+ values in the column. This option could
315
      #   have been named <tt>:null_allowed</tt>.
316
      # * <tt>:precision</tt> -
317
      #   Specifies the precision for a <tt>:decimal</tt> column.
318
      # * <tt>:scale</tt> -
319
      #   Specifies the scale for a <tt>:decimal</tt> column.
320 321 322 323 324 325
      #
      # Please be aware of different RDBMS implementations behavior with
      # <tt>:decimal</tt> columns:
      # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
      #   <tt>:precision</tt>, and makes no comments about the requirements of
      #   <tt>:precision</tt>.
326
      # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
327
      #   Default is (10,0).
328
      # * PostgreSQL: <tt>:precision</tt> [1..infinity],
329
      #   <tt>:scale</tt> [0..infinity]. No default.
330
      # * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
331
      #   Internal storage as strings. No default.
332
      # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
333
      #   but the maximum supported <tt>:precision</tt> is 16. No default.
334
      # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
335
      #   Default is (38,0).
336
      # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
337
      #   Default unknown.
338
      # * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
339 340
      #   Default (9,0). Internal types NUMERIC and DECIMAL have different
      #   storage rules, decimal being better.
341
      # * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
342 343
      #   Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
      #   NUMERIC is 19, and DECIMAL is 38.
344
      # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
345
      #   Default (38,0).
346
      # * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
347 348
      #   Default (38,0).
      # * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
349 350 351
      #
      # This method returns <tt>self</tt>.
      #
352
      # == Examples
353 354
      #  # Assuming td is an instance of TableDefinition
      #  td.column(:granted, :boolean)
P
Pratik Naik 已提交
355
      #  # granted BOOLEAN
356
      #
357
      #  td.column(:picture, :binary, :limit => 2.megabytes)
P
Pratik Naik 已提交
358
      #  # => picture BLOB(2097152)
359
      #
360
      #  td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
P
Pratik Naik 已提交
361
      #  # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
362
      #
P
Pratik Naik 已提交
363 364
      #  td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
      #  # => bill_gates_money DECIMAL(15,2)
365
      #
P
Pratik Naik 已提交
366 367
      #  td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
      #  # => sensor_reading DECIMAL(30,20)
368 369 370
      #
      #  # While <tt>:scale</tt> defaults to zero on most databases, it
      #  # probably wouldn't hurt to include it.
P
Pratik Naik 已提交
371 372
      #  td.column(:huge_integer, :decimal, :precision => 30)
      #  # => huge_integer DECIMAL(30)
373 374 375
      #
      # == Short-hand examples
      #
P
Pratik Naik 已提交
376
      # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
      # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
      # in a single statement.
      #
      # What can be written like this with the regular calls to column:
      #
      #   create_table "products", :force => true do |t|
      #     t.column "shop_id",    :integer
      #     t.column "creator_id", :integer
      #     t.column "name",       :string,   :default => "Untitled"
      #     t.column "value",      :string,   :default => "Untitled"
      #     t.column "created_at", :datetime
      #     t.column "updated_at", :datetime
      #   end
      #
      # Can also be written as follows using the short-hand:
      #
      #   create_table :products do |t|
      #     t.integer :shop_id, :creator_id
      #     t.string  :name, :value, :default => "Untitled"
      #     t.timestamps
      #   end
      #
399
      # There's a short-hand method for each of the type values declared at the top. And then there's
P
Pratik Naik 已提交
400
      # TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes.
401 402
      #
      # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
403 404
      # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of options, these will be
      # used when creating the <tt>_type</tt> column. So what can be written like this:
405 406 407 408 409 410 411 412 413 414 415 416 417 418
      #
      #   create_table :taggings do |t|
      #     t.integer :tag_id, :tagger_id, :taggable_id
      #     t.string  :tagger_type
      #     t.string  :taggable_type, :default => 'Photo'
      #   end
      #
      # Can also be written as follows using references:
      #
      #   create_table :taggings do |t|
      #     t.references :tag
      #     t.references :tagger, :polymorphic => true
      #     t.references :taggable, :polymorphic => { :default => 'Photo' }
      #   end
419
      def column(name, type, options = {})
420
        column = self[name] || ColumnDefinition.new(@base, name, type)
421 422 423 424 425
        if options[:limit]
          column.limit = options[:limit]
        elsif native[type.to_sym].is_a?(Hash)
          column.limit = native[type.to_sym][:limit]
        end
426 427
        column.precision = options[:precision]
        column.scale = options[:scale]
428 429 430 431 432
        column.default = options[:default]
        column.null = options[:null]
        @columns << column unless @columns.include? column
        self
      end
433

434 435 436
      %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
        class_eval <<-EOV
          def #{column_type}(*args)
437
            options = args.extract_options!
438
            column_names = args
439

440 441 442 443
            column_names.each { |name| column(name, '#{column_type}', options) }
          end
        EOV
      end
444 445

      # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
446
      # <tt>:updated_at</tt> to the table.
447 448 449 450 451
      def timestamps
        column(:created_at, :datetime)
        column(:updated_at, :datetime)
      end

452 453 454 455 456
      def references(*args)
        options = args.extract_options!
        polymorphic = options.delete(:polymorphic)
        args.each do |col|
          column("#{col}_id", :integer, options)
457
          column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
458 459 460 461
        end
      end
      alias :belongs_to :references

462
      # Returns a String whose contents are the column definitions
463
      # concatenated together. This string can then be prepended and appended to
464
      # to generate the final SQL to create the table.
465 466 467
      def to_sql
        @columns * ', '
      end
468

469 470 471 472 473
      private
        def native
          @base.native_database_types
        end
    end
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514

    # Represents a SQL table in an abstract way for updating a table.
    # Also see TableDefinition and SchemaStatements#create_table
    #
    # Available transformations are:
    #
    #   change_table :table do |t|
    #     t.column
    #     t.index
    #     t.timestamps
    #     t.change
    #     t.change_default
    #     t.rename
    #     t.references
    #     t.belongs_to
    #     t.string
    #     t.text
    #     t.integer
    #     t.float
    #     t.decimal
    #     t.datetime
    #     t.timestamp
    #     t.time
    #     t.date
    #     t.binary
    #     t.boolean
    #     t.remove
    #     t.remove_references
    #     t.remove_belongs_to
    #     t.remove_index
    #     t.remove_timestamps
    #   end
    #
    class Table
      def initialize(table_name, base)
        @table_name = table_name
        @base = base
      end

      # Adds a new column to the named table.
      # See TableDefinition#column for details of the options you can use.
515 516
      # ===== Example
      # ====== Creating a simple column
517 518 519 520 521
      #  t.column(:name, :string)
      def column(column_name, type, options = {})
        @base.add_column(@table_name, column_name, type, options)
      end

522 523
      # Adds a new index to the table. +column_name+ can be a single Symbol, or
      # an Array of Symbols. See SchemaStatements#add_index
524 525 526 527 528 529 530 531 532 533 534 535
      #
      # ===== Examples
      # ====== Creating a simple index
      #  t.index(:name)
      # ====== Creating a unique index
      #  t.index([:branch_id, :party_id], :unique => true)
      # ====== Creating a named index
      #  t.index([:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
      def index(column_name, options = {})
        @base.add_index(@table_name, column_name, options)
      end

536 537
      # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#add_timestamps
      # ===== Example
538 539 540 541 542 543 544 545 546 547 548 549 550 551
      #  t.timestamps
      def timestamps
        @base.add_timestamps(@table_name)
      end

      # Changes the column's definition according to the new options.
      # See TableDefinition#column for details of the options you can use.
      # ===== Examples
      #  t.change(:name, :string, :limit => 80)
      #  t.change(:description, :text)
      def change(column_name, type, options = {})
        @base.change_column(@table_name, column_name, type, options)
      end

552
      # Sets a new default value for a column. See SchemaStatements#change_column_default
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
      # ===== Examples
      #  t.change_default(:qualification, 'new')
      #  t.change_default(:authorized, 1)
      def change_default(column_name, default)
        @base.change_column_default(@table_name, column_name, default)
      end

      # Removes the column(s) from the table definition.
      # ===== Examples
      #  t.remove(:qualification)
      #  t.remove(:qualification, :experience)
      def remove(*column_names)
        @base.remove_column(@table_name, column_names)
      end

568
      # Removes the given index from the table.
569
      #
570 571
      # ===== Examples
      # ====== Remove the suppliers_name_index in the suppliers table
572
      #   t.remove_index :name
573
      # ====== Remove the index named accounts_branch_id_index in the accounts table
574
      #   t.remove_index :column => :branch_id
575
      # ====== Remove the index named accounts_branch_id_party_id_index in the accounts table
576
      #   t.remove_index :column => [:branch_id, :party_id]
577
      # ====== Remove the index named by_branch_party in the accounts table
578 579 580 581 582 583
      #   t.remove_index :name => :by_branch_party
      def remove_index(options = {})
        @base.remove_index(@table_name, options)
      end

      # Removes the timestamp columns (created_at and updated_at) from the table.
584
      # ===== Example
585 586 587 588 589 590 591 592 593 594 595 596
      #  t.remove_timestamps
      def remove_timestamps
        @base.remove_timestamps(@table_name)
      end

      # Renames a column.
      # ===== Example
      #  t.rename(:description, :name)
      def rename(column_name, new_column_name)
        @base.rename_column(@table_name, column_name, new_column_name)
      end

597 598 599
      # Adds a reference. Optionally adds a +type+ column.
      # <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
      # ===== Examples
600 601 602 603 604 605 606 607 608 609 610 611 612
      #  t.references(:goat)
      #  t.references(:goat, :polymorphic => true)
      #  t.belongs_to(:goat)
      def references(*args)
        options = args.extract_options!
        polymorphic = options.delete(:polymorphic)
        args.each do |col|
          @base.add_column(@table_name, "#{col}_id", :integer, options)
          @base.add_column(@table_name, "#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
        end
      end
      alias :belongs_to :references

613 614 615
      # Removes a reference. Optionally removes a +type+ column.
      # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
      # ===== Examples
616
      #  t.remove_references(:goat)
617
      #  t.remove_references(:goat, :polymorphic => true)
618 619 620 621 622 623 624 625 626 627 628 629
      #  t.remove_belongs_to(:goat)
      def remove_references(*args)
        options = args.extract_options!
        polymorphic = options.delete(:polymorphic)
        args.each do |col|
          @base.remove_column(@table_name, "#{col}_id")
          @base.remove_column(@table_name, "#{col}_type") unless polymorphic.nil?
        end
      end
      alias :remove_belongs_to  :remove_references

      # Adds a column or columns of a specified type
630
      # ===== Examples
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
      #  t.string(:goat)
      #  t.string(:goat, :sheep)
      %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
        class_eval <<-EOV
          def #{column_type}(*args)
            options = args.extract_options!
            column_names = args

            column_names.each do |name|
              column = ColumnDefinition.new(@base, name, '#{column_type}')
              if options[:limit]
                column.limit = options[:limit]
              elsif native['#{column_type}'.to_sym].is_a?(Hash)
                column.limit = native['#{column_type}'.to_sym][:limit]
              end
              column.precision = options[:precision]
              column.scale = options[:scale]
              column.default = options[:default]
              column.null = options[:null]
              @base.add_column(@table_name, name, column.sql_type, options)
            end
          end
        EOV
      end

      private
        def native
          @base.native_database_types
        end
    end

662
  end
663
end