kaspernj/baza

View on GitHub
lib/baza/driver/mysql/column.rb

Summary

Maintainability
B
4 hrs
Test Coverage
# This class handels every MySQL-column, that can be returned from a table-object.
class Baza::Driver::Mysql::Column < Baza::Column
  attr_reader :args, :name

  # Constructor. Should not be called manually.
  def initialize(args)
    @args = args
    @data = @args.delete(:data)
    @name = @data.fetch(:Field)
    @db = @args.fetch(:db)
  end

  # Used to validate in Wref::Map.
  def __object_unique_id__
    @name
  end

  def create_foreign_key(args)
    fk_name = args[:name]
    fk_name ||= "fk_#{table_name}_#{name}"

    other_column = args.fetch(:column)
    other_table = other_column.table

    sql = "
      ALTER TABLE #{@db.quote_table(table_name)}
      ADD CONSTRAINT #{@db.escape_table(fk_name)}
      FOREIGN KEY (#{@db.escape_table(name)})
      REFERENCES #{@db.escape_table(other_table.name)} (#{@db.escape_column(other_column.name)})
    "

    @db.query(sql)

    true
  end

  def table_name
    @args.fetch(:table_name)
  end

  def reload
    data = @db.query("SHOW FULL COLUMNS FROM #{@db.quote_table(table_name)} WHERE #{@db.quote_column("Field")} = #{@db.quote_value(name)}").fetch
    raise Baza::Errors::ColumnNotFound unless data
    @data = data
    @type = nil
  end

  # Returns the type of the column (integer, varchar etc.).
  def type
    unless @type
      if (match = @data.fetch(:Type).match(/^([A-z]+)$/))
        @maxlength = false
        @type = match[0].to_sym
      elsif (match = @data.fetch(:Type).match(/^decimal\((\d+),(\d+)\)$/))
        @maxlength = "#{match[1]},#{match[2]}"
        @type = :decimal
      elsif (match = @data.fetch(:Type).match(/^enum\((.+)\)$/))
        @maxlength = match[1]
        @type = :enum
      elsif (match = @data.fetch(:Type).match(/^(.+)\((\d+)\)/))
        @maxlength = match[2].to_i
        @type = match[1].to_sym
      end

      raise "Still no type from: '#{@data.fetch(:Type)}'" if @type.to_s.strip.empty?
    end

    @type
  end

  # Return true if the columns allows null. Otherwise false.
  def null?
    @data[:Null] != "NO"
  end

  # Returns the maxlength.
  def maxlength
    type unless @maxlength
    return @maxlength if @maxlength
    false
  end

  # Returns the default value for the column.
  def default
    return nil if (type == :datetime || type == :date) && @data[:Default].to_s.strip.empty?
    return nil if (type == :int || type == :bigint) && @data[:Default].to_s.strip.empty?
    return nil unless @data[:Default]
    @data.fetch(:Default)
  end

  # Returns true if the column is the primary key. Otherwise false.
  def primarykey?
    @data.fetch(:Key) == "PRI"
  end

  # Returns true if the column is auto-increasing. Otherwise false.
  def autoincr?
    @data.fetch(:Extra).include?("auto_increment")
  end

  # Returns the comment for the column.
  def comment
    @data.fetch(:Comment)
  end

  # Drops the column from the table.
  def drop
    @db.query("ALTER TABLE #{@db.quote_table(table_name)} DROP COLUMN #{@db.quote_column(name)}")
    table.__send__(:remove_column_from_list, self)
    nil
  end

  # Changes the column properties by the given hash.
  def change(data)
    newdata = data.clone

    newdata[:name] = name unless newdata.key?(:name)
    newdata[:type] = type unless newdata.key?(:type)
    newdata[:maxlength] = maxlength if !newdata.key?(:maxlength) && maxlength
    newdata[:null] = null? unless newdata.key?(:null)
    newdata[:default] = default if !newdata.key?(:default) && default
    newdata.delete(:primarykey) if newdata.key?(:primarykey)

    drop_add = true if name.to_s != newdata[:name].to_s

    table.__send__(:remove_column_from_list, self) if drop_add
    @db.query("ALTER TABLE #{@db.quote_table(table_name)} CHANGE #{@db.quote_column(name)} #{@db.columns.data_sql(newdata)}")
    @name = newdata[:name].to_s
    reload
    table.__send__(:add_column_to_list, self) if drop_add
  end
end