Class: DeclareSchema::Model::IndexSpec

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/declare_schema/model/index_spec.rb

Defined Under Namespace

Classes: IndexNameTooLongError

Constant Summary collapse

PRIMARY_KEY_NAME =
"PRIMARY_KEY"
MYSQL_INDEX_NAME_MAX_LENGTH =
64

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, fields, options = {}) ⇒ IndexSpec

Returns a new instance of IndexSpec.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/declare_schema/model/index_spec.rb', line 15

def initialize(model, fields, options = {})
  @model = model
  @table = options.delete(:table_name) || model.table_name
  @fields = Array.wrap(fields).map(&:to_s)
  @explicit_name = options[:name] unless options.delete(:allow_equivalent)
  @name = options.delete(:name) || model.connection.index_name(table, column: @fields).gsub(/index.*_on_/, 'on_')
  @unique = options.delete(:unique) || name == PRIMARY_KEY_NAME || false

  if @name.length > MYSQL_INDEX_NAME_MAX_LENGTH
    raise IndexNameTooLongError, "Index '#{@name}' exceeds MySQL limit of #{MYSQL_INDEX_NAME_MAX_LENGTH} characters. Give it a shorter name."
  end

  if (where = options[:where])
    @where = where.start_with?('(') ? where : "(#{where})"
  end
end

Instance Attribute Details

#explicit_name ⇒ Object (readonly)

Returns the value of attribute explicit_name.



8
9
10
# File 'lib/declare_schema/model/index_spec.rb', line 8

def explicit_name
  @explicit_name
end

#fields ⇒ Object (readonly)

Returns the value of attribute fields.



8
9
10
# File 'lib/declare_schema/model/index_spec.rb', line 8

def fields
  @fields
end

#name ⇒ Object (readonly)

Returns the value of attribute name.



8
9
10
# File 'lib/declare_schema/model/index_spec.rb', line 8

def name
  @name
end

#table ⇒ Object (readonly)

Returns the value of attribute table.



8
9
10
# File 'lib/declare_schema/model/index_spec.rb', line 8

def table
  @table
end

#unique ⇒ Object (readonly)

Returns the value of attribute unique.



8
9
10
# File 'lib/declare_schema/model/index_spec.rb', line 8

def unique
  @unique
end

#where ⇒ Object (readonly)

Returns the value of attribute where.



8
9
10
# File 'lib/declare_schema/model/index_spec.rb', line 8

def where
  @where
end

Class Method Details

.for_model(model, old_table_name = nil) ⇒ Object

extract IndexSpecs from an existing table



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/declare_schema/model/index_spec.rb', line 34

def for_model(model, old_table_name = nil)
  t = old_table_name || model.table_name
  connection = model.connection.dup
  # TODO: Change below to use prepend
  class << connection              # defeat Rails code that skips the primary keys by changing their name to PRIMARY_KEY_NAME
    def each_hash(result)
      super do |hash|
        if hash[:Key_name] == "PRIMARY"
          hash[:Key_name] = PRIMARY_KEY_NAME
        end
        yield hash
      end
    end
  end
  connection.indexes(t).map do |i|
    new(model, i.columns, name: i.name, unique: i.unique, where: i.where, table_name: old_table_name) unless model.ignore_indexes.include?(i.name)
  end.compact
end

Instance Method Details

#<=>(rhs) ⇒ Object



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

def <=>(rhs)
  to_key <=> rhs.to_key
end

#equivalent?(rhs) ⇒ Boolean

Returns:



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

def equivalent?(rhs)
  settings == rhs.settings
end

#hash ⇒ Object



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

def hash
  to_key.hash
end

#primary_key? ⇒ Boolean

Returns:



54
55
56
# File 'lib/declare_schema/model/index_spec.rb', line 54

def primary_key?
  name == PRIMARY_KEY_NAME
end

#settings ⇒ Object



80
81
82
# File 'lib/declare_schema/model/index_spec.rb', line 80

def settings
  @settings ||= [table, fields, unique].map(&:to_s)
end

#to_add_primary_key_statement(new_table_name, existing_primary_key) ⇒ Object



70
71
72
73
74
# File 'lib/declare_schema/model/index_spec.rb', line 70

def to_add_primary_key_statement(new_table_name, existing_primary_key)
  drop = "DROP PRIMARY KEY, " if existing_primary_key
  statement = "ALTER TABLE #{new_table_name} #{drop}ADD PRIMARY KEY (#{fields.join(', ')})"
  "execute #{statement.inspect}"
end

#to_add_statement(new_table_name, existing_primary_key = nil) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/declare_schema/model/index_spec.rb', line 58

def to_add_statement(new_table_name, existing_primary_key = nil)
  if primary_key? && !ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/)
    to_add_primary_key_statement(new_table_name, existing_primary_key)
  else
    r = +"add_index #{new_table_name.to_sym.inspect}, #{fields.map(&:to_sym).inspect}"
    r += ", unique: true"      if unique
    r += ", where: '#{where}'" if where.present?
    r += ", name: '#{name}'"
    r
  end
end

#to_key ⇒ Object



76
77
78
# File 'lib/declare_schema/model/index_spec.rb', line 76

def to_key
  @key ||= [table, fields, name, unique, where].map(&:to_s)
end

#with_name(new_name) ⇒ Object



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

def with_name(new_name)
  self.class.new(@model, @fields, table_name: @table_name, index_name: @index_name, unique: @unique, name: new_name)
end