schema_definitions.rb 28.1 KB
Newer Older
1
require 'active_support/core_ext/object/blank'
2
require 'date'
3
require 'set'
4 5
require 'bigdecimal'
require 'bigdecimal/util'
6

7 8
module ActiveRecord
  module ConnectionAdapters #:nodoc:
9 10
    # An abstract definition of a column in a table.
    class Column
11
      TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
12
      FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
13

14 15 16 17 18
      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

19
      attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
20
      attr_accessor :primary
21 22 23

      # Instantiates a new column in the table.
      #
P
Pratik Naik 已提交
24 25
      # +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>.
26 27
      # +sql_type+ is used to extract the column's length, if necessary. For example +60+ in 
      # <tt>company_name varchar(60)</tt>.
28
      # It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
29
      # +null+ determines if this column allows +NULL+ values.
30
      def initialize(name, default, sql_type = nil, null = true)
31
        @name, @sql_type, @null = name, sql_type, null
32
        @limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type)
33
        @type = simplified_type(sql_type)
34
        @default = extract_default(default)
35

36 37 38
        @primary = nil
      end

P
Pratik Naik 已提交
39
      # Returns +true+ if the column is either of type string or text.
40
      def text?
41
        type == :string || type == :text
42 43
      end

P
Pratik Naik 已提交
44
      # Returns +true+ if the column is either of type integer, float or decimal.
45
      def number?
46
        type == :integer || type == :float || type == :decimal
47 48
      end

49 50 51 52
      def has_default?
        !default.nil?
      end

53
      # Returns the Ruby class that corresponds to the abstract data type.
54 55 56 57
      def klass
        case type
          when :integer       then Fixnum
          when :float         then Float
58
          when :decimal       then BigDecimal
59 60 61 62 63 64 65 66 67 68
          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

69
      # Casts value (which is a String) to an appropriate instance.
70
      def type_cast(value)
71
        return nil if value.nil?
72 73 74 75 76
        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
77
          when :decimal   then self.class.value_to_decimal(value)
78 79 80 81 82
          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)
83
          when :boolean   then self.class.value_to_boolean(value)
84 85 86 87
          else value
        end
      end

88 89 90 91 92 93
      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"
94
          when :decimal   then "#{self.class.name}.value_to_decimal(#{var_name})"
95 96 97 98 99
          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})"
100
          when :boolean   then "#{self.class.name}.value_to_boolean(#{var_name})"
101 102 103 104
          else nil
        end
      end

105 106 107
      # Returns the human name of the column name.
      #
      # ===== Examples
P
Pratik Naik 已提交
108
      #  Column.new('sales_stage', ...).human_name # => 'Sales stage'
109 110 111 112
      def human_name
        Base.human_attribute_name(@name)
      end

113 114 115 116
      def extract_default(default)
        type_cast(default)
      end

J
Jeremy Kemper 已提交
117 118 119 120 121
      class << self
        # Used to convert from Strings to BLOBs
        def string_to_binary(value)
          value
        end
122

J
Jeremy Kemper 已提交
123 124 125 126
        # Used to convert from BLOBs to Strings
        def binary_to_string(value)
          value
        end
127

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

132
          fast_string_to_date(string) || fallback_string_to_date(string)
J
Jeremy Kemper 已提交
133
        end
134

J
Jeremy Kemper 已提交
135 136 137
        def string_to_time(string)
          return string unless string.is_a?(String)
          return nil if string.empty?
138

139
          fast_string_to_time(string) || fallback_string_to_time(string)
140
        end
141

J
Jeremy Kemper 已提交
142 143 144
        def string_to_dummy_time(string)
          return string unless string.is_a?(String)
          return nil if string.empty?
145

J
Jeremy Kemper 已提交
146
          string_to_time "2000-01-01 #{string}"
147 148
        end

J
Jeremy Kemper 已提交
149 150
        # convert something to a boolean
        def value_to_boolean(value)
151 152 153 154 155
          if value.is_a?(String) && value.blank?
            nil
          else
            TRUE_VALUES.include?(value)
          end
156 157
        end

J
Jeremy Kemper 已提交
158 159
        # convert something to a BigDecimal
        def value_to_decimal(value)
160 161 162 163
          # 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 已提交
164 165 166 167 168 169
            value
          elsif value.respond_to?(:to_d)
            value.to_d
          else
            value.to_s.to_d
          end
170 171
        end

J
Jeremy Kemper 已提交
172
        protected
173 174
          # '0.123456' -> 123456
          # '1.123456' -> 123456
J
Jeremy Kemper 已提交
175
          def microseconds(time)
176
            ((time[:sec_fraction].to_f % 1) * 1_000_000).to_i
J
Jeremy Kemper 已提交
177 178 179
          end

          def new_date(year, mon, mday)
180 181 182
            if year && year != 0
              Date.new(year, mon, mday) rescue nil
            end
J
Jeremy Kemper 已提交
183 184 185 186
          end

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

189
            Time.time_with_datetime_fallback(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
J
Jeremy Kemper 已提交
190
          end
191 192 193 194 195 196 197 198 199

          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)
200 201 202
            if string =~ Format::ISO_DATETIME
              microsec = ($7.to_f * 1_000_000).to_i
              new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
203 204 205 206
            end
          end

          def fallback_string_to_date(string)
207
            new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday))
208 209 210 211 212 213
          end

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

214
            new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
215
          end
J
Jeremy Kemper 已提交
216 217 218
      end

      private
219 220 221 222
        def extract_limit(sql_type)
          $1.to_i if sql_type =~ /\((.*)\)/
        end

223
        def extract_precision(sql_type)
224
          $2.to_i if sql_type =~ /^(numeric|decimal|number)\((\d+)(,\d+)?\)/i
225 226 227 228
        end

        def extract_scale(sql_type)
          case sql_type
229 230
            when /^(numeric|decimal|number)\((\d+)\)/i then 0
            when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
231 232 233
          end
        end

234 235 236 237
        def simplified_type(field_type)
          case field_type
            when /int/i
              :integer
238
            when /float|double/i
239
              :float
240
            when /decimal|numeric|number/i
241
              extract_scale(field_type) == 0 ? :integer : :decimal
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
            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
261

262
    class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
263 264
    end

P
Pratik Naik 已提交
265 266 267 268
    # Abstract representation of a column definition. Instances of this type
    # are typically created by methods in TableDefinition, and added to the
    # +columns+ attribute of said TableDefinition object, in order to be used
    # for generating a number of table creation or table changing SQL statements.
269
    class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
270

271 272 273
      def sql_type
        base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
      end
274

275
      def to_sql
276
        column_sql = "#{base.quote_column_name(name)} #{sql_type}"
277 278 279
        column_options = {}
        column_options[:null] = null unless null.nil?
        column_options[:default] = default unless default.nil?
280
        add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key
281 282
        column_sql
      end
283

284 285 286 287 288 289 290
      private

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

P
Pratik Naik 已提交
291 292 293 294 295 296 297 298 299 300 301 302
    # Represents the schema of an SQL table in an abstract way. This class
    # provides methods for manipulating the schema representation.
    #
    # Inside migration files, the +t+ object in +create_table+ and
    # +change_table+ is actually of this type:
    #
    #   class SomeMigration < ActiveRecord::Migration
    #     def self.up
    #       create_table :foo do |t|
    #         puts t.class  # => "ActiveRecord::ConnectionAdapters::TableDefinition"
    #       end
    #     end
P
Pratik Naik 已提交
303
    #
P
Pratik Naik 已提交
304 305 306 307 308 309 310
    #     def self.down
    #       ...
    #     end
    #   end
    #
    # The table definitions
    # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
311
    class TableDefinition
P
Pratik Naik 已提交
312 313
      # An array of ColumnDefinition objects, representing the column changes
      # that have been defined.
314 315 316 317 318 319 320
      attr_accessor :columns

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

321 322 323 324
      #Handles non supported datatypes - e.g. XML
      def method_missing(symbol, *args)
        if symbol.to_s == 'xml'
          xml_column_fallback(args)
325 326
        else
          super
327 328 329 330 331
        end
      end

      def xml_column_fallback(*args)
        case @base.adapter_name.downcase
332 333 334
        when 'sqlite', 'mysql'
          options = args.extract_options!
          column(args[0], :text, options)
335
        end
336 337
      end

338 339
      # Appends a primary key definition to the table definition.
      # Can be called multiple times, but this is probably not a good idea.
340 341
      def primary_key(name)
        column(name, :primary_key)
342
      end
343 344

      # Returns a ColumnDefinition for the column with name +name+.
345
      def [](name)
346
        @columns.find {|column| column.name.to_s == name.to_s}
347 348
      end

349
      # Instantiates a new column for the table.
350 351
      # The +type+ parameter is normally one of the migrations native types,
      # which is one of the following:
352
      # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
353 354 355
      # <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>.
356
      #
357 358 359 360
      # 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.
      #
361
      # Available options are (none of these exists by default):
362
      # * <tt>:limit</tt> -
363 364
      #   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.
365
      # * <tt>:default</tt> -
366
      #   The column's default value. Use nil for NULL.
367
      # * <tt>:null</tt> -
368
      #   Allows or disallows +NULL+ values in the column. This option could
369
      #   have been named <tt>:null_allowed</tt>.
370
      # * <tt>:precision</tt> -
371
      #   Specifies the precision for a <tt>:decimal</tt> column.
372
      # * <tt>:scale</tt> -
373
      #   Specifies the scale for a <tt>:decimal</tt> column.
374
      #
P
Pratik Naik 已提交
375 376 377 378 379 380
      # For clarity's sake: the precision is the number of significant digits,
      # while the scale is the number of digits that can be stored following
      # the decimal point. For example, the number 123.45 has a precision of 5
      # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
      # range from -999.99 to 999.99.
      #
381 382 383 384 385
      # 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>.
386
      # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
387
      #   Default is (10,0).
388
      # * PostgreSQL: <tt>:precision</tt> [1..infinity],
389
      #   <tt>:scale</tt> [0..infinity]. No default.
390
      # * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
391
      #   Internal storage as strings. No default.
392
      # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
393
      #   but the maximum supported <tt>:precision</tt> is 16. No default.
394
      # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
395
      #   Default is (38,0).
396
      # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
397
      #   Default unknown.
398
      # * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
399 400
      #   Default (9,0). Internal types NUMERIC and DECIMAL have different
      #   storage rules, decimal being better.
401
      # * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
402 403
      #   Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
      #   NUMERIC is 19, and DECIMAL is 38.
404
      # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
405
      #   Default (38,0).
406
      # * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
407 408
      #   Default (38,0).
      # * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
409 410 411
      #
      # This method returns <tt>self</tt>.
      #
412
      # == Examples
413 414
      #  # Assuming td is an instance of TableDefinition
      #  td.column(:granted, :boolean)
P
Pratik Naik 已提交
415
      #  # granted BOOLEAN
416
      #
417
      #  td.column(:picture, :binary, :limit => 2.megabytes)
P
Pratik Naik 已提交
418
      #  # => picture BLOB(2097152)
419
      #
420
      #  td.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
P
Pratik Naik 已提交
421
      #  # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
422
      #
P
Pratik Naik 已提交
423 424
      #  td.column(:bill_gates_money, :decimal, :precision => 15, :scale => 2)
      #  # => bill_gates_money DECIMAL(15,2)
425
      #
P
Pratik Naik 已提交
426 427
      #  td.column(:sensor_reading, :decimal, :precision => 30, :scale => 20)
      #  # => sensor_reading DECIMAL(30,20)
428 429 430
      #
      #  # While <tt>:scale</tt> defaults to zero on most databases, it
      #  # probably wouldn't hurt to include it.
P
Pratik Naik 已提交
431 432
      #  td.column(:huge_integer, :decimal, :precision => 30)
      #  # => huge_integer DECIMAL(30)
433
      #
P
Pratik Naik 已提交
434 435 436 437
      #  # Defines a column with a database-specific type.
      #  td.column(:foo, 'polygon')
      #  # => foo polygon
      #
438 439
      # == Short-hand examples
      #
P
Pratik Naik 已提交
440
      # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
      # 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
      #
463
      # There's a short-hand method for each of the type values declared at the top. And then there's
P
Pratik Naik 已提交
464
      # TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes.
465 466
      #
      # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
467 468
      # 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:
469 470 471 472 473 474 475 476 477 478 479 480 481 482
      #
      #   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
483
      def column(name, type, options = {})
484
        column = self[name] || ColumnDefinition.new(@base, name, type)
485 486 487 488 489
        if options[:limit]
          column.limit = options[:limit]
        elsif native[type.to_sym].is_a?(Hash)
          column.limit = native[type.to_sym][:limit]
        end
490 491
        column.precision = options[:precision]
        column.scale = options[:scale]
492 493 494 495 496
        column.default = options[:default]
        column.null = options[:null]
        @columns << column unless @columns.include? column
        self
      end
497

498
      %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
499
        class_eval <<-EOV, __FILE__, __LINE__ + 1
500 501 502 503 504 505
          def #{column_type}(*args)                                               # def string(*args)
            options = args.extract_options!                                       #   options = args.extract_options!
            column_names = args                                                   #   column_names = args
                                                                                  #
            column_names.each { |name| column(name, '#{column_type}', options) }  #   column_names.each { |name| column(name, 'string', options) }
          end                                                                     # end
506 507
        EOV
      end
508 509

      # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
510
      # <tt>:updated_at</tt> to the table.
511 512 513 514
      def timestamps(*args)
        options = args.extract_options!
        column(:created_at, :datetime, options)
        column(:updated_at, :datetime, options)
515 516
      end

517 518 519 520 521
      def references(*args)
        options = args.extract_options!
        polymorphic = options.delete(:polymorphic)
        args.each do |col|
          column("#{col}_id", :integer, options)
522
          column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
523 524 525 526
        end
      end
      alias :belongs_to :references

527
      # Returns a String whose contents are the column definitions
528
      # concatenated together. This string can then be prepended and appended to
529
      # to generate the final SQL to create the table.
530
      def to_sql
531
        @columns.map { |c| c.to_sql } * ', '
532
      end
533

534 535 536 537 538
      private
        def native
          @base.native_database_types
        end
    end
539

540
    # Represents an SQL table in an abstract way for updating a table.
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
    # 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.
580 581
      # ===== Example
      # ====== Creating a simple column
582 583 584 585 586
      #  t.column(:name, :string)
      def column(column_name, type, options = {})
        @base.add_column(@table_name, column_name, type, options)
      end

587 588 589 590 591
      # Checks to see if a column exists. See SchemaStatements#column_exists?
      def column_exists?(column_name, type = nil, options = nil)
        @base.column_exists?(@table_name, column_name, type, options)
      end

592 593
      # Adds a new index to the table. +column_name+ can be a single Symbol, or
      # an Array of Symbols. See SchemaStatements#add_index
594 595 596 597 598 599 600 601 602 603 604 605
      #
      # ===== 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

606 607 608 609 610
      # Checks to see if an index exists. See SchemaStatements#index_exists?
      def index_exists?(column_name, options = {})
        @base.index_exists?(@table_name, column_name, options)
      end

611 612
      # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#add_timestamps
      # ===== Example
613 614 615 616 617 618 619 620 621 622 623 624 625 626
      #  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

627
      # Sets a new default value for a column. See SchemaStatements#change_column_default
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
      # ===== 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

643
      # Removes the given index from the table.
644
      #
645 646
      # ===== Examples
      # ====== Remove the suppliers_name_index in the suppliers table
647
      #   t.remove_index :name
648
      # ====== Remove the index named accounts_branch_id_index in the accounts table
649
      #   t.remove_index :column => :branch_id
650
      # ====== Remove the index named accounts_branch_id_party_id_index in the accounts table
651
      #   t.remove_index :column => [:branch_id, :party_id]
652
      # ====== Remove the index named by_branch_party in the accounts table
653 654 655 656 657 658
      #   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.
659
      # ===== Example
660 661 662 663 664 665 666 667 668 669 670 671
      #  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

672 673 674
      # Adds a reference. Optionally adds a +type+ column.
      # <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
      # ===== Examples
675 676 677 678 679 680 681 682 683 684 685 686 687
      #  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

688 689 690
      # Removes a reference. Optionally removes a +type+ column.
      # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
      # ===== Examples
691
      #  t.remove_references(:goat)
692
      #  t.remove_references(:goat, :polymorphic => true)
693 694 695 696 697 698 699 700 701 702 703 704
      #  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
705
      # ===== Examples
706 707 708
      #  t.string(:goat)
      #  t.string(:goat, :sheep)
      %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
709
        class_eval <<-EOV, __FILE__, __LINE__ + 1
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
          def #{column_type}(*args)                                          # def string(*args)
            options = args.extract_options!                                  #   options = args.extract_options!
            column_names = args                                              #   column_names = args
                                                                             #
            column_names.each do |name|                                      #   column_names.each do |name|
              column = ColumnDefinition.new(@base, name, '#{column_type}')   #     column = ColumnDefinition.new(@base, name, 'string')
              if options[:limit]                                             #     if options[:limit]
                column.limit = options[:limit]                               #       column.limit = options[:limit]
              elsif native['#{column_type}'.to_sym].is_a?(Hash)              #     elsif native['string'.to_sym].is_a?(Hash)
                column.limit = native['#{column_type}'.to_sym][:limit]       #       column.limit = native['string'.to_sym][:limit]
              end                                                            #     end
              column.precision = options[:precision]                         #     column.precision = options[:precision]
              column.scale = options[:scale]                                 #     column.scale = options[:scale]
              column.default = options[:default]                             #     column.default = options[:default]
              column.null = options[:null]                                   #     column.null = options[:null]
              @base.add_column(@table_name, name, column.sql_type, options)  #     @base.add_column(@table_name, name, column.sql_type, options)
            end                                                              #   end
          end                                                                # end
728 729 730 731 732 733 734 735 736
        EOV
      end

      private
        def native
          @base.native_database_types
        end
    end

737
  end
738
end
739