class Sequel::Schema::Generator

the “Migrations and Schema Modification” guide.
For more information on Sequel’s support for schema modification, see
the column method, which makes for a nicer DSL.
allowing users to specify column type as a method instead of using
Schema::Generator has some methods but also includes method_missing,
create a table.
gives the Database a table description, which the database uses to
object and a block of column/index/constraint specifications, and
It is used to specify table creation parameters. It takes a Database
to instantiate directly. Instances are created by Database#create_table.
Schema::Generator is an internal class that the user is not expected

def self.add_type_method(*types)

as a constant/class.
be constants/classes or a capitalized string/symbol with the same name
with that type as a constant. Types given should either already
Add a method for each of the given types that creates a column
def self.add_type_method(*types)
  types.each do |type|
    class_eval("def #{type}(name, opts={}); column(name, #{type}, opts); end", __FILE__, __LINE__)
  end
end

def check(*args, &block)

check{num > 5} # CHECK num > 5
check(:num=>1..5) # CHECK num >= 1 AND num <= 5

or args:
Add an unnamed constraint to the DDL, specified by the given block
def check(*args, &block)
  constraint(nil, *args, &block)
end

def column(name, type, opts = {})

columns.
:unsigned :: Make the column type unsigned, only useful for integer
creating a unique index on the column.
:unique :: Mark the column as unique, generally has the same effect as
precision, respectively, of decimal columns.
An array of two integers can be provided to set the size and the
columns to specify the maximum number of characters the column will hold.
:size :: The size of the column, generally used with string
be used if you have a single, nonautoincrementing primary key column.
:primary_key :: Make the column as a single primary key column. This should only
(:restrict, cascade, :set_null, :set_default, :no_action).
:on_update :: Specify the behavior of this column when being updated
(:restrict, cascade, :set_null, :set_default, :no_action).
:on_delete :: Specify the behavior of this column when being deleted
to whatever the database default is.
or not allowing NULL values (if false). If unspecified, will default
:null :: Mark the column as allowing NULL values (if true),
using MySQL.
references the primary key of the associated table, except if you are
that this column references. Unnecessary if this column
:key :: For foreign key columns, the column in the associated table
:index :: Create an index on this column.
DEFERRABLE INITIALLY DEFERRED on key creation.
exists(yet) on referenced table. Basically it adds
reference table will use for its foreign key a value that does not
:deferrable :: This ensure Referential Integrity will work even if
:default :: The default value for the column.

The following options are supported:

integer :number
column :number, :integer

equivalent:
You can also create columns via method missing, so the following are

# ip inet
inet :ip

# name varchar(255) NOT NULL DEFAULT 'a'
column :name, String, :null=>false, :default=>'a'

# num INTEGER
column :num, :integer

Add a column with the given name, type, and opts to the DDL.
def column(name, type, opts = {})
  columns << {:name => name, :type => type}.merge(opts)
  index(name) if opts[:index]
end

def composite_foreign_key(columns, opts)

Add a composite foreign key constraint
def composite_foreign_key(columns, opts)
  constraints << {:type => :foreign_key, :columns => columns}.merge(opts)
end

def composite_primary_key(columns, *args)

Add a composite primary key constraint
def composite_primary_key(columns, *args)
  opts = args.pop || {}
  constraints << {:type => :primary_key, :columns => columns}.merge(opts)
end

def constraint(name, *args, &block)

check(:foo){num > 5} # CONSTRAINT foo CHECK num > 5
constraint(:blah, :num=>1..5) # CONSTRAINT blah CHECK num >= 1 AND num <= 5

with the given block or args.
Adds a named constraint (or unnamed if name is nil) to the DDL,
def constraint(name, *args, &block)
  constraints << {:name => name, :type => :check, :check => block || args}
end

def dump_columns

another instance to represent the same columns
Dump this generator's columns to a string that could be evaled inside
def dump_columns
  strings = []
  cols = columns.dup
  if pkn = primary_key_name
    cols.delete_if{|x| x[:name] == pkn}
    pk = @primary_key.dup
    pkname = pk.delete(:name)
    @db.serial_primary_key_options.each{|k,v| pk.delete(k) if v == pk[k]}
    strings << "primary_key #{pkname.inspect}#{opts_inspect(pk)}"
  end
  cols.each do |c|
    c = c.dup
    name = c.delete(:name)
    type = c.delete(:type)
    opts = opts_inspect(c)
    strings << if type.is_a?(Class)
      "#{type.name} #{name.inspect}#{opts}"
    else
      "column #{name.inspect}, #{type.inspect}#{opts}"
    end
  end
  strings.join("\n")
end

def dump_constraints

another instance to represent the same constraints
Dump this generator's constraints to a string that could be evaled inside
def dump_constraints
  cs = constraints.map do |c|
    c = c.dup
    type = c.delete(:type)
    case type
    when :check
      raise(Error, "can't dump check/constraint specified with Proc") if c[:check].is_a?(Proc)
      name = c.delete(:name)
      if !name and c[:check].length == 1 and c[:check].first.is_a?(Hash)
        "check #{c[:check].first.inspect[1...-1]}"
      else
        "#{name ? "constraint #{name.inspect}," : 'check'} #{c[:check].map{|x| x.inspect}.join(', ')}"
      end
    else
      cols = c.delete(:columns)
      "#{type} #{cols.inspect}#{opts_inspect(c)}"
    end
  end
  cs.join("\n")
end

def dump_indexes(options={})

* :ignore_errors - Add the ignore_errors option to the outputted indexes
* :drop_index - Same as add_index, but create drop_index statements.
The value of this option should be the table name to use.
can be called outside of a generator but inside a migration.
* :add_index - Use add_index instead of index, so the methods
another instance to represent the same indexes. Options:
Dump this generator's indexes to a string that could be evaled inside
def dump_indexes(options={})
  is = indexes.map do |c|
    c = c.dup
    cols = c.delete(:columns)
    if table = options[:add_index] || options[:drop_index]
      "#{options[:drop_index] ? 'drop' : 'add'}_index #{table.inspect}, #{cols.inspect}#{', :ignore_errors=>true' if options[:ignore_errors]}#{opts_inspect(c)}"
    else
      "index #{cols.inspect}#{opts_inspect(c)}"
    end
  end
  is.join("\n")
end

def foreign_key(name, table=nil, opts = {})

# ADD CONSTRAINT artist_fk FOREIGN KEY (artist_name, artist_location) REFERENCES artists
foreign_key([:artist_name, :artist_location], :artists, :name=>:artist_fk)

you can provide the :name option to name the constraint:
composite foreign key), you can provide an array of columns as the first argument, and
If you want a foreign key constraint without adding a column (usually because it is a

foreign_key(:artist_id, :artists, :key=>:id) # artist_id INTEGER REFERENCES artists(id)
foreign_key(:artist_id, :artists) # artist_id INTEGER REFERENCES artists
foreign_key(:artist_id) # artist_id INTEGER

for available options.
Add a foreign key in the table that references another table to the DDL. See column
def foreign_key(name, table=nil, opts = {})
  opts = case table
  when Hash
    table.merge(opts)
  when Symbol
    opts.merge(:table=>table)
  when NilClass
    opts
  else
    raise(Error, "The second argument to foreign_key should be a Hash, Symbol, or nil")
  end
  return composite_foreign_key(name, opts) if name.is_a?(Array)
  column(name, Integer, opts)
end

def full_text_index(columns, opts = {})

Add a full text index on the given columns to the DDL.
def full_text_index(columns, opts = {})
  index(columns, opts.merge(:type => :full_text))
end

def has_column?(name)

True if the DDL includes the creation of a column with the given name.
def has_column?(name)
  columns.any?{|c| c[:name] == name}
end

def index(columns, opts = {})

# CREATE INDEX table_artist_id_name_index ON table (artist_id, name)
index [:artist_id, :name]

# CREATE INDEX table_name_index ON table (name)
index :name

:where :: Create a partial index (only supported by some databases)
:unique :: Make the index unique, so duplicate values are not allowed.
:type :: The type of index to use (only supported by some databases)

The available options are:
Add an index on the given column(s) with the given options to the DDL.
def index(columns, opts = {})
  indexes << {:columns => Array(columns)}.merge(opts)
end

def initialize(db, &block)

in the context of this object.
Set the database in which to create the table, and evaluate the block
def initialize(db, &block)
  @db = db
  @columns = []
  @indexes = []
  @constraints = []
  @primary_key = nil
  instance_eval(&block) if block
  @columns.unshift(@primary_key) if @primary_key && !has_column?(primary_key_name)
end

def method_missing(type, name = nil, opts = {})

options.
Add a column with the given type, name, and opts to the DDL. See +column+ for available
def method_missing(type, name = nil, opts = {})
  name ? column(name, type, opts) : super
end

def opts_inspect(opts)

def opts_inspect(opts)
  if opts[:default]
    opts = opts.dup
    de = case d = opts.delete(:default)
    when BigDecimal, Sequel::SQL::Blob
      "#{d.class.name}.new(#{d.to_s.inspect})"
    when DateTime, Date
      "#{d.class.name}.parse(#{d.to_s.inspect})"
    when Time
      "#{d.class.name}.parse(#{d.strftime('%H:%M:%S').inspect})"
    else
      d.inspect
    end
    ", :default=>#{de}#{", #{opts.inspect[1...-1]}" if opts.length > 0}"
  else
    ", #{opts.inspect[1...-1]}" if opts.length > 0
  end
end

def primary_key(name, *args)

primary_key([:street_number, :house_number])
primary_key(:id)
Examples:

with a :primary_key=>true option.
should not use this method. Instead, you should use the regular +column+ method
If you want to create a primary key column that is not autoincrementing, you

as the second argument.
column, a single symbol can be used. In both cases, an options hash can be used
specifying the primary key columns. To create an autoincrementing primary key
To create a constraint, the first argument should be an array of column symbols
Adds an autoincrementing primary key column or a primary key constraint to the DDL.
def primary_key(name, *args)
  return composite_primary_key(name, *args) if name.is_a?(Array)
  @primary_key = @db.serial_primary_key_options.merge({:name => name})
  
  if opts = args.pop
    opts = {:type => opts} unless opts.is_a?(Hash)
    if type = args.pop
      opts.merge!(:type => type)
    end
    @primary_key.merge!(opts)
  end
  @primary_key
end

def primary_key_name

The name of the primary key for this generator, if it has a primary key.
def primary_key_name
  @primary_key[:name] if @primary_key
end

def spatial_index(columns, opts = {})

Add a spatial index on the given columns to the DDL.
def spatial_index(columns, opts = {})
  index(columns, opts.merge(:type => :spatial))
end

def unique(columns, opts = {})

unique(:name) # UNIQUE (name)

Add a unique constraint on the given columns to the DDL.
def unique(columns, opts = {})
  constraints << {:type => :unique, :columns => Array(columns)}.merge(opts)
end