schema_definitions.rb 21.9 KB
Newer Older
1 2
module ActiveRecord
  module ConnectionAdapters #:nodoc:
3 4 5
    # 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
6
    class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using) #:nodoc:
7 8
    end

P
Pratik Naik 已提交
9 10 11 12
    # 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.
13
    class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :auto_increment, :primary_key, :collation, :sql_type) #:nodoc:
14

A
Aaron Patterson 已提交
15
      def primary_key?
16
        primary_key || type.to_sym == :primary_key
A
Aaron Patterson 已提交
17
      end
18 19
    end

20 21 22
    class AddColumnDefinition < Struct.new(:column) # :nodoc:
    end

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

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

      def column
        options[:column]
      end

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

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

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

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

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

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

65 66 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
    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
139
        Base.pluralize_table_names ? name.to_s.pluralize : name
140 141 142
      end
    end

143 144 145 146 147 148
    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
149 150 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

      # 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
176 177
    end

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

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

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

217 218
      def columns; @columns_hash.values; end

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

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

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

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

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

376 377
      # 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
378
      #
A
AvnerCohen 已提交
379
      #   index(:account_id, name: 'index_projects_on_account_id')
380 381 382
      def index(column_name, options = {})
        indexes[column_name] = options
      end
383

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

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

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

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

401
      # Adds a reference.
402 403
      #
      #  t.references(:user)
404
      #  t.belongs_to(:supplier, foreign_key: true)
405
      #
406
      # See SchemaStatements#add_reference for details of the options you can use.
407
      def references(*args, **options)
408
        args.each do |col|
409
          ReferenceDefinition.new(col, **options).add_to(self)
410 411 412 413
        end
      end
      alias :belongs_to :references

414
      def new_column_definition(name, type, options) # :nodoc:
415
        type = aliased_types(type.to_s, type)
416 417 418 419 420
        column = create_column_definition name, type
        limit = options.fetch(:limit) do
          native[type][:limit] if native[type].is_a?(Hash)
        end

421 422 423 424 425 426 427
        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]
428
        column.auto_increment = options[:auto_increment]
429
        column.primary_key = type == :primary_key || options[:primary_key]
430
        column.collation   = options[:collation]
431
        column
432 433
      end

434 435 436 437 438
      private
      def create_column_definition(name, type)
        ColumnDefinition.new name, type
      end

439
      def native
440
        @native
441
      end
S
Sean Griffin 已提交
442

443 444
      def aliased_types(name, fallback)
        'timestamp' == name ? :datetime : fallback
S
Sean Griffin 已提交
445
      end
446
    end
447

448
    class AlterTable # :nodoc:
A
Aaron Patterson 已提交
449
      attr_reader :adds
450 451
      attr_reader :foreign_key_adds
      attr_reader :foreign_key_drops
452 453

      def initialize(td)
A
Aaron Patterson 已提交
454 455
        @td   = td
        @adds = []
456 457
        @foreign_key_adds = []
        @foreign_key_drops = []
458 459 460 461
      end

      def name; @td.name; end

462 463 464 465 466 467 468 469
      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

470 471 472
      def add_column(name, type, options)
        name = name.to_s
        type = type.to_sym
473
        @adds << AddColumnDefinition.new(@td.new_column_definition(name, type, options))
474 475 476
      end
    end

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

515 516
      attr_reader :name

517
      def initialize(table_name, base)
518
        @name = table_name
519 520 521 522
        @base = base
      end

      # Adds a new column to the named table.
523
      #
524
      #  t.column(:name, :string)
525 526
      #
      # See TableDefinition#column for details of the options you can use.
527
      def column(column_name, type, options = {})
528
        @base.add_column(name, column_name, type, options)
529 530
      end

531 532
      # Checks to see if a column exists.
      #
533 534
      # t.string(:name) unless t.column_exists?(:name, :string)
      #
535
      # See SchemaStatements#column_exists?
536
      def column_exists?(column_name, type = nil, options = {})
537
        @base.column_exists?(name, column_name, type, options)
538 539
      end

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

552 553
      # Checks to see if an index exists.
      #
554 555 556 557
      # unless t.index_exists?(:branch_id)
      #   t.index(:branch_id)
      # end
      #
558
      # See SchemaStatements#index_exists?
559
      def index_exists?(column_name, options = {})
560
        @base.index_exists?(name, column_name, options)
561 562
      end

J
Jarek Radosz 已提交
563 564 565
      # Renames the given index on the table.
      #
      #  t.rename_index(:user_id, :account_id)
566 567
      #
      # See SchemaStatements#rename_index
J
Jarek Radosz 已提交
568
      def rename_index(index_name, new_index_name)
569
        @base.rename_index(name, index_name, new_index_name)
J
Jarek Radosz 已提交
570 571
      end

572 573 574
      # Adds timestamps (+created_at+ and +updated_at+) columns to the table.
      #
      #  t.timestamps(null: false)
575
      #
576
      # See SchemaStatements#add_timestamps
577
      def timestamps(options = {})
578
        @base.add_timestamps(name, options)
579 580 581
      end

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

591
      # Sets a new default value for a column.
592
      #
593 594
      #  t.change_default(:qualification, 'new')
      #  t.change_default(:authorized, 1)
595
      #  t.change_default(:status, from: nil, to: "draft")
596 597
      #
      # See SchemaStatements#change_column_default
598 599
      def change_default(column_name, default_or_changes)
        @base.change_column_default(name, column_name, default_or_changes)
600 601 602
      end

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

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

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

      # Renames a column.
633
      #
634
      #  t.rename(:description, :name)
635 636
      #
      # See SchemaStatements#rename_column
637
      def rename(column_name, new_column_name)
638
        @base.rename_column(name, column_name, new_column_name)
639 640
      end

641
      # Adds a reference.
642
      #
643
      #  t.references(:user)
644
      #  t.belongs_to(:supplier, foreign_key: true)
645
      #
646
      # See SchemaStatements#add_reference for details of the options you can use.
647 648
      def references(*args)
        options = args.extract_options!
649
        args.each do |ref_name|
650
          @base.add_reference(name, ref_name, options)
651 652 653 654
        end
      end
      alias :belongs_to :references

655
      # Removes a reference. Optionally removes a +type+ column.
656
      #
657 658 659
      #  t.remove_references(:user)
      #  t.remove_belongs_to(:supplier, polymorphic: true)
      #
660
      # See SchemaStatements#remove_reference
661 662
      def remove_references(*args)
        options = args.extract_options!
663
        args.each do |ref_name|
664
          @base.remove_reference(name, ref_name, options)
665 666
        end
      end
667
      alias :remove_belongs_to :remove_references
668

669 670 671 672 673
      # Adds a foreign key.
      #
      # t.foreign_key(:authors)
      #
      # See SchemaStatements#add_foreign_key
674 675 676 677
      def foreign_key(*args) # :nodoc:
        @base.add_foreign_key(name, *args)
      end

678 679 680 681 682
      # 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 已提交
683 684 685
      def foreign_key_exists?(*args) # :nodoc:
        @base.foreign_key_exists?(name, *args)
      end
686

687 688 689 690 691
      private
        def native
          @base.native_database_types
        end
    end
692
  end
693
end