kaspernj/baza

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

Summary

Maintainability
A
3 hrs
Test Coverage
# This class handels all the SQLite3-columns.
class Baza::Driver::Sqlite3::Column < Baza::Column
  attr_reader :args

  # Constructor. This should not be called manually.
  def initialize(args)
    @args = args
    @data = args.fetch(:data)
    @db = @args.fetch(:db)
  end

  # Returns the name of the column.
  def name
    @data.fetch(:name)
  end

  def table_name
    @args.fetch(:table_name)
  end

  # Returns the columns table-object.
  def table
    @db.tables[table_name]
  end

  # Returns the data of the column as a hash in knjdb-format.
  def data
    {
      type: type,
      name: name,
      null: null?,
      maxlength: maxlength,
      default: default,
      primarykey: primarykey?,
      autoincr: autoincr?
    }
  end

  # Returns the type of the column.
  def type
    unless @type
      if (match = @data.fetch(:type).match(/^([A-z]+)$/))
        @maxlength = false
        type = match[0].downcase.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]
        type = match[1].to_sym
      elsif @data.key?(:type) && @data.fetch(:type).to_s == ""
        return @data[:type] # A type can actually be empty in SQLite... Wtf?
      end

      if type == :integer
        @type = :int
      else
        @type = type
      end

      raise "Still not type? (#{@data})" if @type.to_s.strip.empty?
    end

    @type
  end

  # Returns true if the column allows null. Otherwise false.
  def null?
    return false if @data.fetch(:notnull).to_i == 1
    true
  end

  # Returns the maxlength of the column.
  def maxlength
    type unless @maxlength.nil?
    return @maxlength if @maxlength
    false
  end

  # Returns the default value of the column.
  def default
    def_val = @data.fetch(:dflt_value)

    if def_val && (match = def_val.match(/\A'(.*)'\Z/))
      return match[1]
    end

    return nil if @data.fetch(:dflt_value).to_s.empty?
    def_val
  end

  # Returns true if the column is the primary key.
  def primarykey?
    @data.fetch(:pk).to_i == 1
  end

  # Returns true if the column is auto-increasing.
  def autoincr?
    primarykey? && @data.fetch(:type).casecmp("integer").zero?
  end

  # Drops the column from the table.
  def drop
    table.copy(drops: name)
  end

  def reload
    @db.q("PRAGMA table_info(#{@db.quote_table(table_name)})") do |data|
      next unless data.fetch(:name) == name
      @data = data
      @type = nil
      return nil
    end

    raise Baza::Errors::ColumnNotFound, "Could not find data for column: #{table_name}.#{name}"
  end

  # Changes data on the column. Like the name, type, maxlength or whatever.
  def change(data)
    newdata = data.clone

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

    @type = nil
    @maxlength = nil

    table.copy(
      alter_columns: {
        name => newdata
      }
    )

    @data[:name] = newdata.fetch(:name).to_s
    reload
  end
end