magoosh/motion_record

View on GitHub
lib/motion_record/schema/column_definition.rb

Summary

Maintainability
A
1 hr
Test Coverage
module MotionRecord
  module Schema
    class ColumnDefinition
      TYPE_MAP = {
        :integer => "INTEGER",
        :text    => "TEXT",
        :float   => "REAL"
      }
      INVERSE_TYPE_MAP = {
        "INTEGER" => :integer,
        "TEXT"    => :text,
        "REAL"    => :float
      }

      attr_reader :type
      attr_reader :name
      attr_reader :options
      
      # name    - name of the column
      # type    - a Symbol representing the column type
      # options - Hash of constraints for the column:
      #           :primary - set to true to configure as the primary auto-incrementing key
      #           :null - set to false to add a "NOT NULL" constraint
      #           :default - TODO
      def initialize(type, name, options)
        @type = type.to_sym
        @name = name.to_sym
        @options = options
      end

      def to_sql_definition
        [@name, sql_type, sql_options].compact.join(" ")
      end

      def default
        @options[:default]
      end

      # Build a new ColumnDefinition from the result of a "PRAGMA table_info()"
      # query
      #
      # pragma - Hash representing a row of the query's result:
      #          :cid - column index
      #          :name - column name
      #          :type - column type
      #          :notnull - integer flag for "NOT NULL"
      #          :dflt_value - default value
      #          :pk - integer flag for primary key
      #
      # Returns the new ColumnDefinition
      def self.from_pragma(pragma)
        type = INVERSE_TYPE_MAP[pragma[:type]]
        options = {
          :null    => (pragma[:notnull] != 1),
          :primary => (pragma[:pk] == 1),
          :default => (pragma[:dflt_value])
        }

        if options[:default]
          case type
          when :integer
            options[:default] = options[:default].to_i
          when :float
            options[:default] = options[:default].to_f
          end
        end

        self.new(type, pragma[:name], options)
      end

      protected

      def sql_type
        if TYPE_MAP[@type]
          TYPE_MAP[@type]
        else
          raise "Unrecognized column type: #{@type.inspect}"
        end
      end

      def sql_options
        sql_options = []

        @options.each do |key, value|
          case key
          when :primary
            if value
              sql_options << "PRIMARY KEY ASC AUTOINCREMENT"
            end
          when :null
            if !value
              sql_options << "NOT NULL"
            end
          when :default
            if value
              sql_options << "DEFAULT #{value.inspect}"
            end
          else
            raise "Unrecognized column option: #{key.inspect}"
          end
        end

        if sql_options.any?
          sql_options.join(" ")
        else
          nil
        end
      end
    end
  end
end