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

6 7
module ActiveRecord
  module ConnectionAdapters #:nodoc:
8 9 10
    # Abstract representation of an index definition on a table. Instances of
    # this type are typically created and returned by methods in database
    # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
11
    class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using) #:nodoc:
12 13
    end

P
Pratik Naik 已提交
14 15 16 17
    # 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.
18
    class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :sql_type) #:nodoc:
19

A
Aaron Patterson 已提交
20
      def primary_key?
21
        primary_key || type.to_sym == :primary_key
A
Aaron Patterson 已提交
22
      end
23 24
    end

25
    class ChangeColumnDefinition < Struct.new(:column, :name) #:nodoc:
26 27
    end

28
    class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
29 30 31 32 33 34 35 36 37
      def name
        options[:name]
      end

      def column
        options[:column]
      end

      def primary_key
Y
Yves Senn 已提交
38
        options[:primary_key] || default_primary_key
39
      end
40

41 42
      def on_delete
        options[:on_delete]
43
      end
Y
Yves Senn 已提交
44 45 46 47

      def on_update
        options[:on_update]
      end
Y
Yves Senn 已提交
48 49 50 51 52

      def custom_primary_key?
        options[:primary_key] != default_primary_key
      end

53 54
      def defined_for?(options_or_to_table = {})
        if options_or_to_table.is_a?(Hash)
55
          options_or_to_table.all? {|key, value| options[key].to_s == value.to_s }
56 57 58 59 60
        else
          to_table == options_or_to_table.to_s
        end
      end

Y
Yves Senn 已提交
61 62 63 64
      private
      def default_primary_key
        "id"
      end
65 66
    end

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    class ReferenceDefinition # :nodoc:
      def initialize(
        name,
        polymorphic: false,
        index: false,
        foreign_key: false,
        type: :integer,
        **options
      )
        @name = name
        @polymorphic = polymorphic
        @index = index
        @foreign_key = foreign_key
        @type = type
        @options = options

        if polymorphic && foreign_key
          raise ArgumentError, "Cannot add a foreign key to a polymorphic relation"
        end
      end

      def add_to(table)
        columns.each do |column_options|
          table.column(*column_options)
        end

        if index
          table.index(column_names, index_options)
        end

        if foreign_key
          table.foreign_key(foreign_table_name, foreign_key_options)
        end
      end

      protected

      attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options

      private

      def as_options(value, default = {})
        if value.is_a?(Hash)
          value
        else
          default
        end
      end

      def polymorphic_options
        as_options(polymorphic, options)
      end

      def index_options
        as_options(index)
      end

      def foreign_key_options
        as_options(foreign_key)
      end

      def columns
        result = [["#{name}_id", type, options]]
        if polymorphic
          result.unshift(["#{name}_type", :string, polymorphic_options])
        end
        result
      end

      def column_names
        columns.map(&:first)
      end

      def foreign_table_name
141
        Base.pluralize_table_names ? name.to_s.pluralize : name
142 143 144
      end
    end

145 146 147 148 149 150
    module ColumnMethods
      # Appends a primary key definition to the table definition.
      # Can be called multiple times, but this is probably not a good idea.
      def primary_key(name, type = :primary_key, **options)
        column(name, type, options.merge(primary_key: true))
      end
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177

      # Appends a column or columns of a specified type.
      #
      #  t.string(:goat)
      #  t.string(:goat, :sheep)
      #
      # See TableDefinition#column
      [
        :bigint,
        :binary,
        :boolean,
        :date,
        :datetime,
        :decimal,
        :float,
        :integer,
        :string,
        :text,
        :time,
        :timestamp,
      ].each do |column_type|
        module_eval <<-CODE, __FILE__, __LINE__ + 1
          def #{column_type}(*args, **options)
            args.each { |name| column(name, :#{column_type}, options) }
          end
        CODE
      end
178 179
    end

P
Pratik Naik 已提交
180 181 182
    # Represents the schema of an SQL table in an abstract way. This class
    # provides methods for manipulating the schema representation.
    #
183 184
    # Inside migration files, the +t+ object in +create_table+
    # is actually of this type:
P
Pratik Naik 已提交
185 186
    #
    #   class SomeMigration < ActiveRecord::Migration
A
Akira Matsuda 已提交
187
    #     def up
P
Pratik Naik 已提交
188 189 190 191
    #       create_table :foo do |t|
    #         puts t.class  # => "ActiveRecord::ConnectionAdapters::TableDefinition"
    #       end
    #     end
P
Pratik Naik 已提交
192
    #
A
Akira Matsuda 已提交
193
    #     def down
P
Pratik Naik 已提交
194 195 196 197 198 199
    #       ...
    #     end
    #   end
    #
    # The table definitions
    # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
200
    class TableDefinition
201 202
      include ColumnMethods

P
Pratik Naik 已提交
203 204
      # An array of ColumnDefinition objects, representing the column changes
      # that have been defined.
205
      attr_accessor :indexes
206
      attr_reader :name, :temporary, :options, :as, :foreign_keys
207

208
      def initialize(types, name, temporary, options, as = nil)
209
        @columns_hash = {}
210
        @indexes = {}
211
        @foreign_keys = {}
212
        @native = types
213 214
        @temporary = temporary
        @options = options
215
        @as = as
216
        @name = name
217 218
      end

219 220
      def columns; @columns_hash.values; end

221
      # Returns a ColumnDefinition for the column with name +name+.
222
      def [](name)
223
        @columns_hash[name.to_s]
224 225
      end

226
      # Instantiates a new column for the table.
227 228
      # The +type+ parameter is normally one of the migrations native types,
      # which is one of the following:
229
      # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
230
      # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
231 232
      # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
      # <tt>:binary</tt>, <tt>:boolean</tt>.
233
      #
234 235 236 237
      # 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.
      #
238
      # Available options are (none of these exists by default):
239
      # * <tt>:limit</tt> -
240
      #   Requests a maximum column length. This is number of characters for <tt>:string</tt> and
241
      #   <tt>:text</tt> columns and number of bytes for <tt>:binary</tt> and <tt>:integer</tt> columns.
242
      # * <tt>:default</tt> -
243
      #   The column's default value. Use nil for NULL.
244
      # * <tt>:null</tt> -
245
      #   Allows or disallows +NULL+ values in the column. This option could
246
      #   have been named <tt>:null_allowed</tt>.
247
      # * <tt>:precision</tt> -
248
      #   Specifies the precision for a <tt>:decimal</tt> column.
249
      # * <tt>:scale</tt> -
250
      #   Specifies the scale for a <tt>:decimal</tt> column.
251 252
      # * <tt>:index</tt> -
      #   Create an index for the column. Can be either <tt>true</tt> or an options hash.
253
      #
254 255
      # Note: The precision is the total number of significant digits
      # and the scale is the number of digits that can be stored following
P
Pratik Naik 已提交
256 257 258 259
      # 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.
      #
260 261 262 263 264
      # 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>.
265
      # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
266
      #   Default is (10,0).
267
      # * PostgreSQL: <tt>:precision</tt> [1..infinity],
268
      #   <tt>:scale</tt> [0..infinity]. No default.
269
      # * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
270
      #   Internal storage as strings. No default.
271
      # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
272
      #   but the maximum supported <tt>:precision</tt> is 16. No default.
273
      # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
274
      #   Default is (38,0).
275
      # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
276
      #   Default unknown.
277
      # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
278
      #   Default (38,0).
279 280 281
      #
      # This method returns <tt>self</tt>.
      #
282
      # == Examples
283
      #  # Assuming +td+ is an instance of TableDefinition
284
      #  td.column(:granted, :boolean)
P
Pratik Naik 已提交
285
      #  # granted BOOLEAN
286
      #
A
AvnerCohen 已提交
287
      #  td.column(:picture, :binary, limit: 2.megabytes)
P
Pratik Naik 已提交
288
      #  # => picture BLOB(2097152)
289
      #
A
AvnerCohen 已提交
290
      #  td.column(:sales_stage, :string, limit: 20, default: 'new', null: false)
P
Pratik Naik 已提交
291
      #  # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
292
      #
A
AvnerCohen 已提交
293
      #  td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
P
Pratik Naik 已提交
294
      #  # => bill_gates_money DECIMAL(15,2)
295
      #
A
AvnerCohen 已提交
296
      #  td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
P
Pratik Naik 已提交
297
      #  # => sensor_reading DECIMAL(30,20)
298 299 300
      #
      #  # While <tt>:scale</tt> defaults to zero on most databases, it
      #  # probably wouldn't hurt to include it.
A
AvnerCohen 已提交
301
      #  td.column(:huge_integer, :decimal, precision: 30)
P
Pratik Naik 已提交
302
      #  # => huge_integer DECIMAL(30)
303
      #
P
Pratik Naik 已提交
304 305 306 307
      #  # Defines a column with a database-specific type.
      #  td.column(:foo, 'polygon')
      #  # => foo polygon
      #
308 309
      # == Short-hand examples
      #
P
Pratik Naik 已提交
310
      # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
311 312 313 314 315
      # 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:
      #
316
      #   create_table :products do |t|
317 318 319 320 321 322 323
      #     t.column :shop_id,     :integer
      #     t.column :creator_id,  :integer
      #     t.column :item_number, :string
      #     t.column :name,        :string, default: "Untitled"
      #     t.column :value,       :string, default: "Untitled"
      #     t.column :created_at,  :datetime
      #     t.column :updated_at,  :datetime
324
      #   end
325
      #   add_index :products, :item_number
326
      #
327
      # can also be written as follows using the short-hand:
328 329 330
      #
      #   create_table :products do |t|
      #     t.integer :shop_id, :creator_id
331
      #     t.string  :item_number, index: true
A
AvnerCohen 已提交
332
      #     t.string  :name, :value, default: "Untitled"
333
      #     t.timestamps null: false
334 335
      #   end
      #
336
      # There's a short-hand method for each of the type values declared at the top. And then there's
337
      # TableDefinition#timestamps that'll add +created_at+ and +updated_at+ as datetimes.
338 339
      #
      # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
340
      # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
341 342
      # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
      # will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
343 344 345 346
      #
      #   create_table :taggings do |t|
      #     t.integer :tag_id, :tagger_id, :taggable_id
      #     t.string  :tagger_type
A
AvnerCohen 已提交
347
      #     t.string  :taggable_type, default: 'Photo'
348
      #   end
A
AvnerCohen 已提交
349
      #   add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id'
350
      #   add_index :taggings, [:tagger_id, :tagger_type]
351 352 353 354
      #
      # Can also be written as follows using references:
      #
      #   create_table :taggings do |t|
A
AvnerCohen 已提交
355 356 357
      #     t.references :tag, index: { name: 'index_taggings_on_tag_id' }
      #     t.references :tagger, polymorphic: true, index: true
      #     t.references :taggable, polymorphic: { default: 'Photo' }
358
      #   end
359
      def column(name, type, options = {})
360 361 362
        name = name.to_s
        type = type.to_sym

363
        if @columns_hash[name] && @columns_hash[name].primary_key?
364 365 366
          raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
        end

367 368
        index_options = options.delete(:index)
        index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
369
        @columns_hash[name] = new_column_definition(name, type, options)
370 371
        self
      end
372

373 374 375 376
      def remove_column(name)
        @columns_hash.delete name.to_s
      end

377 378
      # Adds index options to the indexes hash, keyed by column name
      # This is primarily used to track indexes that need to be created after the table
379
      #
A
AvnerCohen 已提交
380
      #   index(:account_id, name: 'index_projects_on_account_id')
381 382 383
      def index(column_name, options = {})
        indexes[column_name] = options
      end
384

385 386 387 388
      def foreign_key(table_name, options = {}) # :nodoc:
        foreign_keys[table_name] = options
      end

389
      # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
390 391 392
      # <tt>:updated_at</tt> to the table. See SchemaStatements#add_timestamps
      #
      #   t.timestamps null: false
393
      def timestamps(*args)
394
        options = args.extract_options!
395 396 397

        options[:null] = false if options[:null].nil?

398 399
        column(:created_at, :datetime, options)
        column(:updated_at, :datetime, options)
400 401
      end

R
Robin Dupret 已提交
402 403
      # Adds a reference. Optionally adds a +type+ column, if the
      # +:polymorphic+ option is provided. +references+ and +belongs_to+
404
      # are interchangeable. The reference column will be an +integer+ by default,
R
Robin Dupret 已提交
405 406
      # the +:type+ option can be used to specify a different type. A foreign
      # key will be created if the +:foreign_key+ option is passed.
407 408 409 410
      #
      #  t.references(:user)
      #  t.references(:user, type: "string")
      #  t.belongs_to(:supplier, polymorphic: true)
411
      #
412
      # See SchemaStatements#add_reference
413
      def references(*args, **options)
414
        args.each do |col|
415
          ReferenceDefinition.new(col, **options).add_to(self)
416 417 418 419
        end
      end
      alias :belongs_to :references

420
      def new_column_definition(name, type, options) # :nodoc:
421
        type = aliased_types(type.to_s, type)
422 423 424 425 426
        column = create_column_definition name, type
        limit = options.fetch(:limit) do
          native[type][:limit] if native[type].is_a?(Hash)
        end

427 428 429 430 431 432 433
        column.limit       = limit
        column.precision   = options[:precision]
        column.scale       = options[:scale]
        column.default     = options[:default]
        column.null        = options[:null]
        column.first       = options[:first]
        column.after       = options[:after]
434
        column.auto_increment = options[:auto_increment]
435
        column.primary_key = type == :primary_key || options[:primary_key]
436
        column
437 438
      end

439 440 441 442 443
      private
      def create_column_definition(name, type)
        ColumnDefinition.new name, type
      end

444
      def native
445
        @native
446
      end
S
Sean Griffin 已提交
447

448 449
      def aliased_types(name, fallback)
        'timestamp' == name ? :datetime : fallback
S
Sean Griffin 已提交
450
      end
451
    end
452

453
    class AlterTable # :nodoc:
A
Aaron Patterson 已提交
454
      attr_reader :adds
455 456
      attr_reader :foreign_key_adds
      attr_reader :foreign_key_drops
457 458

      def initialize(td)
A
Aaron Patterson 已提交
459 460
        @td   = td
        @adds = []
461 462
        @foreign_key_adds = []
        @foreign_key_drops = []
463 464 465 466
      end

      def name; @td.name; end

467 468 469 470 471 472 473 474
      def add_foreign_key(to_table, options)
        @foreign_key_adds << ForeignKeyDefinition.new(name, to_table, options)
      end

      def drop_foreign_key(name)
        @foreign_key_drops << name
      end

475 476 477
      def add_column(name, type, options)
        name = name.to_s
        type = type.to_sym
A
Aaron Patterson 已提交
478
        @adds << @td.new_column_definition(name, type, options)
479 480 481
      end
    end

482
    # Represents an SQL table in an abstract way for updating a table.
483 484 485 486 487
    # Also see TableDefinition and SchemaStatements#create_table
    #
    # Available transformations are:
    #
    #   change_table :table do |t|
488
    #     t.primary_key
489 490
    #     t.column
    #     t.index
J
Jarek Radosz 已提交
491
    #     t.rename_index
492 493 494 495 496 497 498 499 500
    #     t.timestamps
    #     t.change
    #     t.change_default
    #     t.rename
    #     t.references
    #     t.belongs_to
    #     t.string
    #     t.text
    #     t.integer
501
    #     t.bigint
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
    #     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
518 519
      include ColumnMethods

520 521
      attr_reader :name

522
      def initialize(table_name, base)
523
        @name = table_name
524 525 526 527
        @base = base
      end

      # Adds a new column to the named table.
528
      #
529
      #  t.column(:name, :string)
530 531
      #
      # See TableDefinition#column for details of the options you can use.
532
      def column(column_name, type, options = {})
533
        @base.add_column(name, column_name, type, options)
534 535
      end

536 537
      # Checks to see if a column exists.
      #
538 539
      # t.string(:name) unless t.column_exists?(:name, :string)
      #
540
      # See SchemaStatements#column_exists?
541
      def column_exists?(column_name, type = nil, options = {})
542
        @base.column_exists?(name, column_name, type, options)
543 544
      end

545
      # Adds a new index to the table. +column_name+ can be a single Symbol, or
546
      # an Array of Symbols.
547 548
      #
      #  t.index(:name)
A
AvnerCohen 已提交
549 550
      #  t.index([:branch_id, :party_id], unique: true)
      #  t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
551 552
      #
      # See SchemaStatements#add_index for details of the options you can use.
553
      def index(column_name, options = {})
554
        @base.add_index(name, column_name, options)
555 556
      end

557 558
      # Checks to see if an index exists.
      #
559 560 561 562
      # unless t.index_exists?(:branch_id)
      #   t.index(:branch_id)
      # end
      #
563
      # See SchemaStatements#index_exists?
564
      def index_exists?(column_name, options = {})
565
        @base.index_exists?(name, column_name, options)
566 567
      end

J
Jarek Radosz 已提交
568 569 570
      # Renames the given index on the table.
      #
      #  t.rename_index(:user_id, :account_id)
571 572
      #
      # See SchemaStatements#rename_index
J
Jarek Radosz 已提交
573
      def rename_index(index_name, new_index_name)
574
        @base.rename_index(name, index_name, new_index_name)
J
Jarek Radosz 已提交
575 576
      end

577 578 579
      # Adds timestamps (+created_at+ and +updated_at+) columns to the table.
      #
      #  t.timestamps(null: false)
580
      #
581
      # See SchemaStatements#add_timestamps
582
      def timestamps(options = {})
583
        @base.add_timestamps(name, options)
584 585 586
      end

      # Changes the column's definition according to the new options.
587
      #
A
AvnerCohen 已提交
588
      #  t.change(:name, :string, limit: 80)
589
      #  t.change(:description, :text)
590 591
      #
      # See TableDefinition#column for details of the options you can use.
592
      def change(column_name, type, options = {})
593
        @base.change_column(name, column_name, type, options)
594 595
      end

596
      # Sets a new default value for a column.
597
      #
598 599
      #  t.change_default(:qualification, 'new')
      #  t.change_default(:authorized, 1)
600 601
      #
      # See SchemaStatements#change_column_default
602
      def change_default(column_name, default)
603
        @base.change_column_default(name, column_name, default)
604 605 606
      end

      # Removes the column(s) from the table definition.
607
      #
608 609
      #  t.remove(:qualification)
      #  t.remove(:qualification, :experience)
610 611
      #
      # See SchemaStatements#remove_columns
612
      def remove(*column_names)
613
        @base.remove_columns(name, *column_names)
614 615
      end

616
      # Removes the given index from the table.
617
      #
618 619 620 621 622
      #   t.remove_index(:branch_id)
      #   t.remove_index(column: [:branch_id, :party_id])
      #   t.remove_index(name: :by_branch_party)
      #
      # See SchemaStatements#remove_index
623
      def remove_index(options = {})
624
        @base.remove_index(name, options)
625 626
      end

627
      # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
628
      #
629
      #  t.remove_timestamps
630 631
      #
      # See SchemaStatements#remove_timestamps
632 633
      def remove_timestamps(options = {})
        @base.remove_timestamps(name, options)
634 635 636
      end

      # Renames a column.
637
      #
638
      #  t.rename(:description, :name)
639 640
      #
      # See SchemaStatements#rename_column
641
      def rename(column_name, new_column_name)
642
        @base.rename_column(name, column_name, new_column_name)
643 644
      end

645
      # Adds a reference. Optionally adds a +type+ column, if
646
      # <tt>:polymorphic</tt> option is provided.
647
      #
648
      #  t.references(:user)
649
      #  t.references(:user, type: "string")
650
      #  t.belongs_to(:supplier, polymorphic: true)
651
      #  t.belongs_to(:supplier, foreign_key: true)
652
      #
653
      # See SchemaStatements#add_reference
654 655
      def references(*args)
        options = args.extract_options!
656
        args.each do |ref_name|
657
          @base.add_reference(name, ref_name, options)
658 659 660 661
        end
      end
      alias :belongs_to :references

662
      # Removes a reference. Optionally removes a +type+ column.
663
      #
664 665 666
      #  t.remove_references(:user)
      #  t.remove_belongs_to(:supplier, polymorphic: true)
      #
667
      # See SchemaStatements#remove_reference
668 669
      def remove_references(*args)
        options = args.extract_options!
670
        args.each do |ref_name|
671
          @base.remove_reference(name, ref_name, options)
672 673
        end
      end
674
      alias :remove_belongs_to :remove_references
675

676 677 678 679 680
      # Adds a foreign key.
      #
      # t.foreign_key(:authors)
      #
      # See SchemaStatements#add_foreign_key
681 682 683 684
      def foreign_key(*args) # :nodoc:
        @base.add_foreign_key(name, *args)
      end

685 686 687 688 689
      # Checks to see if a foreign key exists.
      #
      # t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
      #
      # See SchemaStatements#foreign_key_exists?
A
Anton 已提交
690 691 692
      def foreign_key_exists?(*args) # :nodoc:
        @base.foreign_key_exists?(name, *args)
      end
693

694 695 696 697 698
      private
        def native
          @base.native_database_types
        end
    end
699
  end
700
end