Class: DeclareSchema::Model::Column

Inherits:
Object
  • Object
show all
Defined in:
lib/declare_schema/model/column.rb

Overview

This class is a wrapper for the ActiveRecord::…::Column class

Constant Summary collapse

SCHEMA_KEYS =
[:type, :limit, :precision, :scale, :null, :default].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, current_table_name, column) ⇒ Column

Returns a new instance of Column.



108
109
110
111
112
113
# File 'lib/declare_schema/model/column.rb', line 108

def initialize(model, current_table_name, column)
  @model = model or raise ArgumentError, "must pass model"
  @current_table_name = current_table_name or raise ArgumentError, "must pass current_table_name"
  @column = column or raise ArgumentError, "must pass column"
  @sql_type = self.class.sql_type(@column.type)
end

Instance Attribute Details

#sql_typeObject (readonly)

Returns the value of attribute sql_type.



106
107
108
# File 'lib/declare_schema/model/column.rb', line 106

def sql_type
  @sql_type
end

Class Method Details

.deserialize_default_value(column, sql_type, default_value) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/declare_schema/model/column.rb', line 61

def deserialize_default_value(column, sql_type, default_value)
  sql_type or raise ArgumentError, "must pass sql_type; got #{sql_type.inspect}"

  case Rails::VERSION::MAJOR
  when 4
    # TODO: Delete this Rails 4 support ASAP! This could be wrong, since it's using the type of the old column...which
    # might be getting migrated to a new type. We should be using just sql_type as below. -Colin
    column.type_cast_from_database(default_value)
  else
    cast_type = ActiveRecord::Base.connection.send(:lookup_cast_type, sql_type) or
      raise "cast_type not found for #{sql_type}"
    cast_type.deserialize(default_value)
  end
end

.equivalent_schema_attributes?(schema_attributes_lhs, schema_attributes_rhs) ⇒ Boolean

Returns:



97
98
99
100
101
102
103
# File 'lib/declare_schema/model/column.rb', line 97

def equivalent_schema_attributes?(schema_attributes_lhs, schema_attributes_rhs)
  db_adapter_name = ActiveRecord::Base.connection.class.name
  normalized_lhs = normalize_schema_attributes(schema_attributes_lhs, db_adapter_name)
  normalized_rhs = normalize_schema_attributes(schema_attributes_rhs, db_adapter_name)

  normalized_lhs == normalized_rhs
end

.native_type?(type) ⇒ Boolean

Returns:



10
11
12
# File 'lib/declare_schema/model/column.rb', line 10

def native_type?(type)
  type != :primary_key && native_types.has_key?(type)
end

.native_typesObject

MySQL example: { primary_key: “bigint auto_increment PRIMARY KEY”,

string: { name: "varchar", limit: 255 },
text: { name: "text", limit: 65535},
integer: {name: "int", limit: 4 },
float: {name: "float", limit: 24 },
decimal: { name: "decimal" },
datetime: { name: "datetime" },
timestamp: { name: "timestamp" },
time: { name: "time" },
date: { name: "date" },
binary: { name>: "blob", limit: 65535 },
boolean: { name: "tinyint", limit: 1 },
json: { name: "json" } }

SQLite example: { primary_key: “integer PRIMARY KEY AUTOINCREMENT NOT NULL”,

string: { name: "varchar" },
text: { name: "text"},
integer: { name: "integer" },
float: { name: "float" },
decimal: { name: "decimal" },
datetime: { name: "datetime" },
time: { name: "time" },
date: { name: "date" },
binary: { name: "blob" },
boolean: { name: "boolean" },
json: { name: "json" } }


42
43
44
45
46
47
48
49
# File 'lib/declare_schema/model/column.rb', line 42

def native_types
  @native_types ||= ActiveRecord::Base.connection.native_database_types.tap do |types|
    if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
      types[:text][:limit]    ||= 0xffff
      types[:binary][:limit]  ||= 0xffff
    end
  end
end

.normalize_schema_attributes(schema_attributes, db_adapter_name) ⇒ Object

Normalizes schema attributes for the given database adapter name. Note that the un-normalized attributes are still useful for generating migrations because those may be run with a different adapter. This method never mutates its argument.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/declare_schema/model/column.rb', line 80

def normalize_schema_attributes(schema_attributes, db_adapter_name)
  case schema_attributes[:type]
  when :boolean
    schema_attributes.reverse_merge(limit: 1)
  when :integer
    schema_attributes.reverse_merge(limit: 8) if db_adapter_name.match?(/sqlite/i)
  when :float
    schema_attributes.except(:limit)
  when :text
    schema_attributes.except(:limit)          if db_adapter_name.match?(/sqlite/i)
  when :datetime
    schema_attributes.reverse_merge(precision: 0)
  when NilClass
    raise ArgumentError, ":type key not found; keys: #{schema_attributes.keys.inspect}"
  end || schema_attributes
end

.sql_type(type) ⇒ Object



51
52
53
54
55
56
57
58
59
# File 'lib/declare_schema/model/column.rb', line 51

def sql_type(type)
  if native_type?(type)
    type
  else
    if (field_class = DeclareSchema.to_class(type))
      field_class::COLUMN_TYPE
    end or raise UnknownSqlTypeError, "#{type.inspect} for type #{type.inspect}"
  end
end

Instance Method Details

#schema_attributesObject

omits keys with nil values



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/declare_schema/model/column.rb', line 118

def schema_attributes
  SCHEMA_KEYS.each_with_object({}) do |key, result|
    value =
      case key
      when :default
        self.class.deserialize_default_value(@column, @sql_type, @column.default)
      else
        col_value = @column.send(key)
        if col_value.nil? && (native_type = self.class.native_types[@column.type])
          native_type[key]
        else
          col_value
        end
      end

    result[key] = value unless value.nil?
  end.tap do |result|
    if ActiveRecord::Base.connection.class.name.match?(/mysql/i) && @column.type.in?([:string, :text])
      result.merge!(collation_and_charset_for_column(@current_table_name, @column.name))
    end
  end
end