Class: LegacyData::Schema

Inherits:
Object
  • Object
show all
Defined in:
lib/legacy_data/schema.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(table_name) ⇒ Schema

Returns a new instance of Schema.



66
67
68
# File 'lib/legacy_data/schema.rb', line 66

def initialize(table_name)
  @table_name = table_name
end

Instance Attribute Details

#table_nameObject (readonly)

Returns the value of attribute table_name.



3
4
5
# File 'lib/legacy_data/schema.rb', line 3

def table_name
  @table_name
end

Class Method Details

.add_pending_table(table_name) ⇒ Object



38
39
40
# File 'lib/legacy_data/schema.rb', line 38

def self.add_pending_table table_name
  table_definitions[table_name] = :pending if table_definitions[table_name].nil?
end

.analyze(options = {}) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'lib/legacy_data/schema.rb', line 5

def self.analyze(options={})
  initialize_tables(options[:table_name])

  while table_name = next_table_to_process
    table_definitions[table_name] = analyze_table(table_name)

    unless options[:skip_associated]
      [:has_many, :belongs_to].each do |relation_type| 
        associated_tables = table_definitions[table_name][:relations][relation_type].keys.map(&:to_s) 
        associated_tables.each {|associated_table| add_pending_table(associated_table) }
      end
    end
  end
  remove_join_tables
end

.analyze_table(table_name) ⇒ Object



21
22
23
# File 'lib/legacy_data/schema.rb', line 21

def self.analyze_table table_name
  new(table_name).analyze_table
end

.clear_table_definitionsObject



44
45
46
# File 'lib/legacy_data/schema.rb', line 44

def self.clear_table_definitions
  @tables = {}
end

.convert_to_habtm(join_table) ⇒ Object



60
61
62
63
64
# File 'lib/legacy_data/schema.rb', line 60

def self.convert_to_habtm join_table
  join_table.belongs_to_tables.each do |table|
    table_definitions[table].convert_has_many_to_habtm(join_table)
  end
end

.initialize_tables(table_name) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/legacy_data/schema.rb', line 26

def self.initialize_tables(table_name)
  clear_table_definitions
  if table_name
    if connection.table_exists? table_name
      add_pending_table(table_name)
    else
      log "Warning: Table '#{table_name}' does not exist"
    end
  else
    self.tables.each {|table| add_pending_table(table) }
  end
end

.log(msg) ⇒ Object



204
205
206
# File 'lib/legacy_data/schema.rb', line 204

def self.log msg
  puts msg
end

.next_join_tableObject



50
51
52
# File 'lib/legacy_data/schema.rb', line 50

def self.next_join_table
  table_definitions.keys.detect {|table_name| table_definitions[table_name].join_table? }
end

.next_table_to_processObject



41
42
43
# File 'lib/legacy_data/schema.rb', line 41

def self.next_table_to_process
  table_definitions.keys.map(&:to_s).sort.detect {|table_name| table_definitions[table_name] == :pending }
end

.remove_join_tablesObject



53
54
55
56
57
58
59
# File 'lib/legacy_data/schema.rb', line 53

def self.remove_join_tables
  join_tables, other_tables = table_definitions.values.partition &:join_table?

  join_tables.each { |join_table| convert_to_habtm(join_table) }

  other_tables
end

.table_definitionsObject



47
48
49
# File 'lib/legacy_data/schema.rb', line 47

def self.table_definitions
  @tables ||= {}
end

.tablesObject



80
81
82
# File 'lib/legacy_data/schema.rb', line 80

def self.tables 
  connection.tables.sort
end

Instance Method Details

#analyze_tableObject



70
71
72
73
74
75
76
77
78
# File 'lib/legacy_data/schema.rb', line 70

def analyze_table
  log "analyzing #{table_name} => #{class_name}"
  TableDefinition.new(:table_name   => table_name,
                      :columns      => columns,
                      :primary_key  => primary_key,
                      :relations    => relations,
                      :constraints  => constraints
                      )
end

#belongs_to_relationsObject



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/legacy_data/schema.rb', line 107

def belongs_to_relations
  return {} unless connection.respond_to? :foreign_keys

  belongs_to = {}
  connection.foreign_keys(table_name).each do |foreign_key|
    options = {:foreign_key=>foreign_key.options[:column].downcase.to_sym}
    options[:dependent] = :destroy if foreign_key.options[:dependent] == :delete
    belongs_to[foreign_key.to_table.downcase] = options
  end
  belongs_to
end

#class_nameObject



84
85
86
# File 'lib/legacy_data/schema.rb', line 84

def class_name
  TableClassNameMapper.class_name_for(self.table_name)
end

#column_by_name(name) ⇒ Object



164
165
166
# File 'lib/legacy_data/schema.rb', line 164

def column_by_name name
  columns.detect {|column| column.name == name }
end

#column_namesObject



175
176
177
# File 'lib/legacy_data/schema.rb', line 175

def column_names
  columns.map(&:name)
end

#columnsObject



172
173
174
# File 'lib/legacy_data/schema.rb', line 172

def columns
  @columns ||= connection.columns(table_name, "#{table_name} Columns")
end

#constraintsObject



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/legacy_data/schema.rb', line 128

def constraints
  if @constraints.nil?
    @constraints = {}
  
    @constraints[:unique],           @constraints[:multi_column_unique] = uniqueness_constraints
    boolean_presence_columns,        @constraints[:presence_of]         = presence_constraints
    @constraints[:numericality_of]                                      = numericality_constraints
    @constraints[:custom],           @constraints[:inclusion_of]        = custom_constraints
    
    boolean_presence_columns.each {|col| @constraints[:inclusion_of][col] = "true, false" }
  end
  @constraints
  ##### TO DO
  # presence_of schoolparentid => school_parent     - FOREIGN KEY
end

#custom_constraintsObject



187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/legacy_data/schema.rb', line 187

def custom_constraints
  return [[],[]] unless connection.respond_to? :constraints
  custom_constraints, inclusion_constraints = {}, {}
  connection.constraints(table_name).each do |constraint|
    constraint_sql = constraint.second
    if constraint_sql =~ /\s*\"*(\w*)\"*\s*IN\s*\((.*)\)/i
      inclusion_constraints[$1.downcase.to_sym] = $2
    else
      custom_constraints[constraint.first.underscore.to_sym] = constraint_sql
    end
  end
  [custom_constraints, inclusion_constraints]
end

#has_some_relationsObject



118
119
120
121
122
123
124
125
126
# File 'lib/legacy_data/schema.rb', line 118

def has_some_relations
  return {} unless connection.respond_to? :foreign_keys_of

  has_some = {}
  connection.foreign_keys_of(table_name).each do |relation|
    has_some[relation.delete(:to_table).downcase] = relation
  end
  has_some
end

#integer_columnsObject



168
169
170
# File 'lib/legacy_data/schema.rb', line 168

def integer_columns
  columns.select {|column| column.type == :integer }.reject {|column| column.name == primary_key}
end

#log(msg) ⇒ Object



201
202
203
# File 'lib/legacy_data/schema.rb', line 201

def log msg
  self.class.log msg
end

#non_nullable_constraintsObject



178
179
180
181
# File 'lib/legacy_data/schema.rb', line 178

def non_nullable_constraints
  non_nullable_constraints = columns.reject(&:null).map(&:name)
  non_nullable_constraints.reject {|col| col == primary_key}
end

#numericality_constraintsObject



144
145
146
147
148
149
# File 'lib/legacy_data/schema.rb', line 144

def numericality_constraints
  allow_nil, do_not_allow_nil = integer_columns.partition do |column| 
    column.null
  end
  {:allow_nil=>allow_nil.map(&:name), :do_not_allow_nil=>do_not_allow_nil.map(&:name)}
end

#presence_constraintsObject



158
159
160
161
162
# File 'lib/legacy_data/schema.rb', line 158

def presence_constraints
  boolean_presence, presence_of = non_nullable_constraints.partition do |column_name| 
    column_by_name(column_name).type == :boolean 
  end
end

#primary_keyObject



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/legacy_data/schema.rb', line 88

def primary_key
  if @pk.nil?
    if connection.respond_to?(:pk_and_sequence_for)
      @pk, seq = connection.pk_and_sequence_for(table_name)
    elsif connection.respond_to?(:primary_key)
      @pk = connection.primary_key(table_name)
    end
    @pk = 'no_primary_key' if @pk.nil?
  end
  @pk
end

#relationsObject



100
101
102
103
104
105
# File 'lib/legacy_data/schema.rb', line 100

def relations
  { :belongs_to               => belongs_to_relations,
    :has_many                 => has_some_relations,
    :has_and_belongs_to_many  => {}
  }
end

#unique_constraintsObject



183
184
185
# File 'lib/legacy_data/schema.rb', line 183

def unique_constraints
  connection.indexes(table_name).select(&:unique).map(&:columns)
end

#uniqueness_constraintsObject



151
152
153
154
155
156
# File 'lib/legacy_data/schema.rb', line 151

def uniqueness_constraints
  unique, multi_column_unique = unique_constraints.partition do |columns| 
    columns.size == 1
  end
  [unique.map(&:first), multi_column_unique] 
end