schema_definitions.rb 27.7 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>.
      # It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
28
      # +null+ determines if this column allows +NULL+ values.
29
      def initialize(name, default, sql_type = nil, null = true)
30
        @name, @sql_type, @null = name, sql_type, null
31
        @limit, @precision, @scale = extract_limit(sql_type), extract_precision(sql_type), extract_scale(sql_type)
32
        @type = simplified_type(sql_type)
33
        @default = extract_default(default)
34

35 36 37
        @primary = nil
      end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

          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)
199 200 201
            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
202 203 204 205
            end
          end

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

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

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

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

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

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

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

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

P
Pratik Naik 已提交
264 265 266 267
    # 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.
268
    class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc:
269

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

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

283 284 285 286 287 288 289
      private

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

P
Pratik Naik 已提交
290 291 292 293 294 295 296 297 298 299 300 301
    # 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 已提交
302
    #
P
Pratik Naik 已提交
303 304 305 306 307 308 309
    #     def self.down
    #       ...
    #     end
    #   end
    #
    # The table definitions
    # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
310
    class TableDefinition
P
Pratik Naik 已提交
311 312
      # An array of ColumnDefinition objects, representing the column changes
      # that have been defined.
313 314 315 316 317 318 319
      attr_accessor :columns

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

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

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

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

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

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

496
      %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
497
        class_eval <<-EOV, __FILE__, __LINE__ + 1
498 499 500 501 502 503
          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
504 505
        EOV
      end
506 507

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

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

525
      # Returns a String whose contents are the column definitions
526
      # concatenated together. This string can then be prepended and appended to
527
      # to generate the final SQL to create the table.
528
      def to_sql
529
        @columns.map(&:to_sql) * ', '
530
      end
531

532 533 534 535 536
      private
        def native
          @base.native_database_types
        end
    end
537 538 539 540 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

    # 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.
578 579
      # ===== Example
      # ====== Creating a simple column
580 581 582 583 584
      #  t.column(:name, :string)
      def column(column_name, type, options = {})
        @base.add_column(@table_name, column_name, type, options)
      end

585 586
      # Adds a new index to the table. +column_name+ can be a single Symbol, or
      # an Array of Symbols. See SchemaStatements#add_index
587 588 589 590 591 592 593 594 595 596 597 598
      #
      # ===== 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

599 600
      # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#add_timestamps
      # ===== Example
601 602 603 604 605 606 607 608 609 610 611 612 613 614
      #  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

615
      # Sets a new default value for a column. See SchemaStatements#change_column_default
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
      # ===== 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

631
      # Removes the given index from the table.
632
      #
633 634
      # ===== Examples
      # ====== Remove the suppliers_name_index in the suppliers table
635
      #   t.remove_index :name
636
      # ====== Remove the index named accounts_branch_id_index in the accounts table
637
      #   t.remove_index :column => :branch_id
638
      # ====== Remove the index named accounts_branch_id_party_id_index in the accounts table
639
      #   t.remove_index :column => [:branch_id, :party_id]
640
      # ====== Remove the index named by_branch_party in the accounts table
641 642 643 644 645 646
      #   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.
647
      # ===== Example
648 649 650 651 652 653 654 655 656 657 658 659
      #  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

660 661 662
      # Adds a reference. Optionally adds a +type+ column.
      # <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
      # ===== Examples
663 664 665 666 667 668 669 670 671 672 673 674 675
      #  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

676 677 678
      # Removes a reference. Optionally removes a +type+ column.
      # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
      # ===== Examples
679
      #  t.remove_references(:goat)
680
      #  t.remove_references(:goat, :polymorphic => true)
681 682 683 684 685 686 687 688 689 690 691 692
      #  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
693
      # ===== Examples
694 695 696
      #  t.string(:goat)
      #  t.string(:goat, :sheep)
      %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
697
        class_eval <<-EOV, __FILE__, __LINE__ + 1
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
          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
716 717 718 719 720 721 722 723 724
        EOV
      end

      private
        def native
          @base.native_database_types
        end
    end

725
  end
726
end
727