Class: DeclareSchema::Model::FieldSpec

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

Defined Under Namespace

Classes: UnknownSqlTypeError

Constant Summary collapse

MYSQL_TINYTEXT_LIMIT =
0xff
MYSQL_TEXT_LIMIT =
0xffff
MYSQL_MEDIUMTEXT_LIMIT =
0xff_ffff
MYSQL_LONGTEXT_LIMIT =
0xffff_ffff
MYSQL_TEXT_LIMITS_ASCENDING =
[MYSQL_TINYTEXT_LIMIT, MYSQL_TEXT_LIMIT, MYSQL_MEDIUMTEXT_LIMIT, MYSQL_LONGTEXT_LIMIT].freeze
TYPE_SYNONYMS =
{ timestamp: :datetime }.freeze
SQLITE_COLUMN_CLASS =
begin
  ActiveRecord::ConnectionAdapters::SQLiteColumn
rescue NameError
  NilClass
end

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, name, type, options = {}) ⇒ FieldSpec

Returns a new instance of FieldSpec.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/declare_schema/model/field_spec.rb', line 36

def initialize(model, name, type, options = {})
  # Invoca change - searching for the primary key was causing an additional database read on every model load.  Assume
  # "id" which works for invoca.
  # raise ArgumentError, "you cannot provide a field spec for the primary key" if name == model.primary_key
  name == "id" and raise ArgumentError, "you cannot provide a field spec for the primary key"

  @model = model
  @name = name.to_sym
  type.is_a?(Symbol) or raise ArgumentError, "type must be a Symbol; got #{type.inspect}"
  @type = type
  position_option = options.delete(:position)
  @options = options

  case type
  when :text
    @options[:default] and raise "default may not be given for :text field #{model}##{@name}"
    if self.class.mysql_text_limits?
      @options[:limit] = self.class.round_up_mysql_text_limit(@options[:limit] || MYSQL_LONGTEXT_LIMIT)
    end
  when :string
    @options[:limit] or raise "limit must be given for :string field #{model}##{@name}: #{@options.inspect}; do you want `limit: 255`?"
  else
    @options[:collation] and raise "collation may only given for :string and :text fields"
    @options[:charset]   and raise "charset may only given for :string and :text fields"
  end
  @position = position_option || model.field_specs.length
end

Instance Attribute Details

#modelObject (readonly)

Returns the value of attribute model.



34
35
36
# File 'lib/declare_schema/model/field_spec.rb', line 34

def model
  @model
end

#nameObject (readonly)

Returns the value of attribute name.



34
35
36
# File 'lib/declare_schema/model/field_spec.rb', line 34

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



34
35
36
# File 'lib/declare_schema/model/field_spec.rb', line 34

def options
  @options
end

#positionObject (readonly)

Returns the value of attribute position.



34
35
36
# File 'lib/declare_schema/model/field_spec.rb', line 34

def position
  @position
end

#typeObject (readonly)

Returns the value of attribute type.



34
35
36
# File 'lib/declare_schema/model/field_spec.rb', line 34

def type
  @type
end

Class Method Details

.mysql_text_limits?Boolean

method for easy stubbing in tests

Returns:



17
18
19
20
21
22
23
# File 'lib/declare_schema/model/field_spec.rb', line 17

def mysql_text_limits?
  if defined?(@mysql_text_limits)
    @mysql_text_limits
  else
    @mysql_text_limits = ActiveRecord::Base.connection.class.name.match?(/mysql/i)
  end
end

.round_up_mysql_text_limit(limit) ⇒ Object



25
26
27
28
29
30
31
# File 'lib/declare_schema/model/field_spec.rb', line 25

def round_up_mysql_text_limit(limit)
  MYSQL_TEXT_LIMITS_ASCENDING.find do |mysql_supported_text_limit|
    if limit <= mysql_supported_text_limit
      mysql_supported_text_limit
    end
  end or raise ArgumentError, "limit of #{limit} is too large for MySQL"
end

Instance Method Details

#charsetObject



114
115
116
117
118
# File 'lib/declare_schema/model/field_spec.rb', line 114

def charset
  if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
    (@options[:charset] || model.table_options[:charset] || Generators::DeclareSchema::Migration::Migrator.default_charset).to_s
  end
end

#collationObject



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

def collation
  if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
    (@options[:collation] || model.table_options[:collation] || Generators::DeclareSchema::Migration::Migrator.default_collation).to_s
  end
end

#defaultObject



104
105
106
# File 'lib/declare_schema/model/field_spec.rb', line 104

def default
  @options[:default]
end

#different_to?(table_name, col_spec) ⇒ Boolean

Returns:



127
128
129
# File 'lib/declare_schema/model/field_spec.rb', line 127

def different_to?(table_name, col_spec)
  !same_as(table_name, col_spec)
end

#limitObject



88
89
90
# File 'lib/declare_schema/model/field_spec.rb', line 88

def limit
  @options[:limit] || native_types[sql_type][:limit]
end

#nullObject



100
101
102
# File 'lib/declare_schema/model/field_spec.rb', line 100

def null
  !:null.in?(@options) || @options[:null]
end

#precisionObject



92
93
94
# File 'lib/declare_schema/model/field_spec.rb', line 92

def precision
  @options[:precision]
end

#same_as(table_name, col_spec) ⇒ Object



131
132
133
134
135
# File 'lib/declare_schema/model/field_spec.rb', line 131

def same_as(table_name, col_spec)
  same_type?(col_spec) &&
    same_attributes?(col_spec) &&
    (!type.in?([:text, :string]) || same_charset_and_collation?(table_name, col_spec))
end

#same_type?(col_spec) ⇒ Boolean

Returns:



120
121
122
123
124
125
# File 'lib/declare_schema/model/field_spec.rb', line 120

def same_type?(col_spec)
  type = sql_type
  normalized_type           = TYPE_SYNONYMS[type] || type
  normalized_col_spec_type  = TYPE_SYNONYMS[col_spec.type] || col_spec.type
  normalized_type == normalized_col_spec_type
end

#scaleObject



96
97
98
# File 'lib/declare_schema/model/field_spec.rb', line 96

def scale
  @options[:scale]
end

#sql_optionsObject



84
85
86
# File 'lib/declare_schema/model/field_spec.rb', line 84

def sql_options
  @options.except(:ruby_default, :validates)
end

#sql_typeObject



73
74
75
76
77
78
79
80
81
82
# File 'lib/declare_schema/model/field_spec.rb', line 73

def sql_type
  @options[:sql_type] || begin
                          if native_type?(type)
                            type
                          else
                            field_class = DeclareSchema.to_class(type)
                            field_class && field_class::COLUMN_TYPE or raise UnknownSqlTypeError, "#{type.inspect} for #{model}##{@name}"
                          end
                        end
end