mini_record-cj 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 27896303273b7579110fcaca700f5ad8573606f6
4
+ data.tar.gz: 411456a93af4970469f7f7d7d4f5d9012518016a
5
+ SHA512:
6
+ metadata.gz: 6d6ae3f5c75e2041ad1787ca7ff2a4b0d69b46133c46c3a12b7fee9608f05a9c6e6f6bffb298adc29ce85abd4e8f5b7a16a395d21f7c42d77e7ee52e7c29034b
7
+ data.tar.gz: 4ee3159eee1475baa6764fc7e4f9781208222b94ca1f05a384255f40735a9e3d0542b690876d062f1346281217590a0051c46fc4b0a02c3814e3d1bb679ab9e8
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ *.swp
7
+ *.swo
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ before_install: 'gem update --system'
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
7
+ - rbx-18mode
8
+ - rbx
9
+ - ree
10
+ notifications:
11
+ recipients:
12
+ - info@daddye.it
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mini_record.gemspec
4
+ gem 'rake'
5
+ gem 'minitest'
6
+ gem 'sqlite3'
7
+ gem 'mysql2'
8
+ gem 'mysql'
9
+ gem 'pg'
10
+ gem 'activerecord', '<= 3.2'
11
+
12
+ group :test do
13
+ gem 'foreigner', '>= 1.4.2'
14
+ end
15
+
16
+ gemspec
@@ -0,0 +1,198 @@
1
+ [![Build Status](https://secure.travis-ci.org/DAddYE/mini_record.png)](http://travis-ci.org/DAddYE/mini_record)
2
+
3
+
4
+ MiniRecord is a micro extension for our `ActiveRecord` gem.
5
+ With MiniRecord you can add the ability to create columns outside the default `schema.rb`, directly
6
+ in your **model** in a similar way that should know in others projects
7
+ like DataMapper, MongoMapper or MongoID.
8
+
9
+ My inspiration come from this handy [project](https://github.com/pjhyett/auto_migrations).
10
+
11
+ ## Features
12
+
13
+ * Define columns/properties inside your model
14
+ * Perform migrations automatically
15
+ * Auto upgrade your schema, so if you know what you are doing you don't lose your existing data!
16
+ * Add, Remove, Change Columns; Add, Remove, Change indexes
17
+
18
+ ## Instructions
19
+
20
+ What you need is to move/remove your `db/schema.rb`.
21
+ This avoid conflicts.
22
+
23
+ Add to your `Gemfile`:
24
+
25
+ ``` rb
26
+ gem 'mini_record'
27
+ ```
28
+
29
+ That's all!
30
+
31
+ ## Examples
32
+
33
+ Remember that inside properties you can use all migrations methods,
34
+ see [documentation](http://api.rubyonrails.org/classes/ActiveRecord/Migration.html)
35
+
36
+ ``` rb
37
+ class Post < ActiveRecord::Base
38
+ col :title_en, :title_jp
39
+ col :description_en, :description_jp, :as => :text
40
+ col :permalink, :index => true, :limit => 50
41
+ col :comments_count, :as => :integer
42
+ col :category, :as => :references, :index => true
43
+ end
44
+ Post.auto_upgrade!
45
+ ```
46
+
47
+ If you don't like `col` there are also few aliases: `key, field, property, attribute`
48
+
49
+ Instead of `:as => :my_type` you can use `:type => :my_type`
50
+
51
+ Option `:as` or `:type` if not provided is `:string` by default, you can use all ActiveRecord types:
52
+
53
+ ``` rb
54
+ :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time,
55
+ :date, :binary, :boolean, :references, :belongs_to, :timestamp
56
+ ```
57
+
58
+ You can provide others ActiveRecord options like:
59
+
60
+ ``` rb
61
+ :limit, :default, :null, :precision, :scale
62
+
63
+ # example
64
+ class Foo < ActiveRecord::Base
65
+ col :title, :default => "MyTitle" # :as => :string is by default
66
+ col :price, :as => :decimal, :scale => 8, :precision => 2
67
+ end
68
+ ```
69
+
70
+ See [ActiveRecord::TableDefinition](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html)
71
+ for more details.
72
+
73
+ Finally, when you execute `MyModel.auto_upgrade!`, missing columns, indexes and tables will be created on the fly.
74
+ Indexes and columns present in the db but **not** in your model schema will be **deleted*** also in your db.
75
+
76
+ ### Single Table Inheritance
77
+
78
+ MiniRecord as ActiveRecord support STI plus some goodness, see our specs for more details.
79
+
80
+ ### ActiveRecord Relations
81
+
82
+ MiniRecord has built-in support of belongs_to, belongs_to polymorphic and habtm relations. Just declaring these in your model will generate the necessary id columns, indexes and join tables
83
+
84
+ #### belongs_to
85
+ ```ruby
86
+ class Address < ActiveRecord::Base
87
+ belongs_to :person
88
+ end
89
+ ```
90
+ Will result in a person_id column (you can override with the `foreign_key` option) which is indexed
91
+
92
+ #### belongs_to with foreign key in database
93
+ ```ruby
94
+ class Address < ActiveRecord::Base
95
+ belongs_to :person
96
+ index :person_id, :foreign => true
97
+ end
98
+ ```
99
+ The same as in the previous case, but foreign key will be added to the database with help of [foreigner](https://github.com/matthuhiggins/foreigner) gem.
100
+
101
+ To remove the key please use :foreign => false
102
+ If you simple remove the index, the foreign key will not be removed.
103
+
104
+ #### belongs_to (polymorphic)
105
+ ```ruby
106
+ class Address < ActiveRecord::Base
107
+ belongs_to :addressable, :polymorphic => true
108
+ end
109
+ ```
110
+ Will result in addressable id and type columns with composite indexes `add_index(:addresses), [:addressable_id, :addressable_type]`
111
+
112
+ #### habtm
113
+ ```ruby
114
+ class Address < ActiveRecord::Base
115
+ has_and_belongs_to_many :people
116
+ end
117
+ ```
118
+ Will generate a "addresses_people" join table and index the id columns
119
+
120
+ ### Adding a new column
121
+
122
+ Super easy, open your model and just add it:
123
+
124
+ ``` rb
125
+ class Post < ActiveRecord::Base
126
+ col :title
127
+ col :body, :as => :text # <<- this
128
+ col :permalink, :index => true
129
+ col :comments_count, :as => :integer
130
+ col :category, :as => :references, :index => true
131
+ end
132
+ Post.auto_upgrade!
133
+ ```
134
+
135
+ So now when you invoke `MyModel.auto_upgrade!` you should see a SQL query like `ALTER TABLE` that mean that your existing
136
+ records are happy and safe.
137
+
138
+ ### Removing a column
139
+
140
+ It's exactly the same, but the column will be _really_ deleted without affect other columns.
141
+
142
+ ### Change columns
143
+
144
+ It's not possible for us know when/what column you have renamed, but we can know if you changed the `type` so
145
+ if you change `t.string :name` to `t.text :name` we are be able to perform an `ALTER TABLE`
146
+
147
+ ### Add/Remove indexes
148
+
149
+ In the same ways we manage columns MiniRecord will detect new indexes and indexes that needs to be removed.
150
+ So when you perform `MyModel.auto_upgrade!` a SQL command like:
151
+
152
+ ``` SQL
153
+ PRAGMA index_info('index_people_on_name')
154
+ CREATE INDEX "index_people_on_surname" ON "people" ("surname")
155
+ ```
156
+
157
+ Note that writing it in DSL way you have same options as `add_index` so you are be able to write:
158
+
159
+ ``` rb
160
+ class Fox < ActiveRecord::Base
161
+ col :foo, :index => true
162
+ col :foo, :index => :custom_name
163
+ col :foo, :index => [:foo, :bar]
164
+ col :foo, :index => { :column => [:branch_id, :party_id], :unique => true, :name => 'by_branch_party' }
165
+ end
166
+ ```
167
+
168
+ That is the same of:
169
+
170
+ ``` rb
171
+ class Fox < ActiveRecord::Base
172
+ col :foo
173
+ add_index :foo
174
+ add_index :custom_name
175
+ add_index [:foo, :bar]
176
+ add_index [:branch_id, :party_id], :unique => true, :name => 'by_branch_party'
177
+ end
178
+ ```
179
+
180
+ ## Author
181
+
182
+ DAddYE, you can follow me on twitter [@daddye](http://twitter.com/daddye) or take a look at my site [daddye.it](http://www.daddye.it)
183
+
184
+ ## Copyright
185
+
186
+ Copyright (C) 2011 Davide D'Agostino - [@daddye](http://twitter.com/daddye)
187
+
188
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
189
+ associated documentation files (the “Software”), to deal in the Software without restriction, including without
190
+ limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
191
+ and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
192
+
193
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
194
+
195
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
196
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM,
197
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
198
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'bundler/gem_tasks'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+
6
+ %w(install release).each do |task|
7
+ Rake::Task[task].enhance do
8
+ sh "rm -rf pkg"
9
+ end
10
+ end
11
+
12
+ desc "Bump version on github"
13
+ task :bump do
14
+ if `git status -s`.strip == ""
15
+ puts "\e[31mNothing to commit (working directory clean)\e[0m"
16
+ else
17
+ version = Bundler.load_gemspec(Dir[File.expand_path('../*.gemspec', __FILE__)].first).version
18
+ sh "git add .; git commit -a -m \"Bump to version #{version}\""
19
+ end
20
+ end
21
+
22
+ task :release => :bump
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'test'
25
+ test.test_files = Dir['test/**/test_*.rb']
26
+ test.verbose = true
27
+ end
28
+
29
+ task :default => :test
30
+ task :spec => :test
@@ -0,0 +1,5 @@
1
+ require 'rubygems' unless defined?(Gem)
2
+ require 'active_record'
3
+ require 'mini_record/auto_schema'
4
+
5
+ ActiveRecord::Base.send(:include, MiniRecord::AutoSchema)
@@ -0,0 +1,364 @@
1
+ module MiniRecord
2
+ module AutoSchema
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+
9
+ def init_table_definition(connection)
10
+ #connection.create_table(table_name) unless connection.table_exists?(table_name)
11
+
12
+ case ActiveRecord::ConnectionAdapters::TableDefinition.instance_method(:initialize).arity
13
+ when 1
14
+ # Rails 3.2 and earlier
15
+ ActiveRecord::ConnectionAdapters::TableDefinition.new(connection)
16
+ when 4, -5
17
+ # Rails 4
18
+ ActiveRecord::ConnectionAdapters::TableDefinition.new(connection.native_database_types, table_name, false, {})
19
+ else
20
+ raise ArgumentError,
21
+ "Unsupported number of args for ActiveRecord::ConnectionAdapters::TableDefinition.new()"
22
+ end
23
+
24
+ end
25
+
26
+ def schema_tables
27
+ @@_schema_tables ||= []
28
+ end
29
+
30
+ def table_definition
31
+ return superclass.table_definition unless (superclass == ActiveRecord::Base) || (superclass.respond_to?(:abstract_class?) && superclass.abstract_class?)
32
+
33
+ @_table_definition ||= begin
34
+ tb = init_table_definition(connection)
35
+ tb.primary_key(primary_key)
36
+ tb
37
+ end
38
+ end
39
+
40
+ def indexes
41
+ return superclass.indexes unless (superclass == ActiveRecord::Base) || (superclass.respond_to?(:abstract_class?) && superclass.abstract_class?)
42
+
43
+ @_indexes ||= {}
44
+ end
45
+
46
+ def indexes_in_db
47
+ connection.indexes(table_name).inject({}) do |hash, index|
48
+ hash[index.name] = index
49
+ hash
50
+ end
51
+ end
52
+
53
+ def get_sql_field_type(field)
54
+ if field.respond_to?(:sql_type)
55
+ # Rails 3.2 and earlier
56
+ field.sql_type.to_s.downcase
57
+ else
58
+ # Rails 4
59
+ connection.type_to_sql(field.type.to_sym, field.limit, field.precision, field.scale)
60
+ end
61
+ end
62
+
63
+ def fields
64
+ table_definition.columns.inject({}) do |hash, column|
65
+ hash[column.name] = column
66
+ hash
67
+ end
68
+ end
69
+
70
+ def fields_in_db
71
+ connection.columns(table_name).inject({}) do |hash, column|
72
+ hash[column.name] = column
73
+ hash
74
+ end
75
+ end
76
+
77
+ def columns_hash
78
+ if mini_record_fake_columns
79
+ super.merge mini_record_fake_columns
80
+ else
81
+ super
82
+ end
83
+ end
84
+
85
+ def mini_record_columns
86
+ @@_mr_columns ||= {}
87
+ @@_mr_columns[table_name] ||= {}
88
+ end
89
+
90
+ def mini_record_fake_columns
91
+ @@_mr_fake_columns ||= {}
92
+ @@_mr_fake_columns[table_name] ||= {}
93
+ end
94
+
95
+ def field(*args)
96
+ return unless connection?
97
+
98
+ options = args.extract_options!
99
+ type = options.delete(:as) || options.delete(:type) || :string
100
+ index = options.delete(:index)
101
+ fake = options.delete(:fake) || false
102
+
103
+ args.each do |column_name|
104
+ # add it it the mini record columns for this table so we can access
105
+ # special fields like input_as, used by form builders
106
+ mini_record_columns[column_name] = options
107
+
108
+ if fake
109
+ # allow you to access the field on the instance object
110
+ attr_accessor column_name
111
+ # create a column that column_hashes will understand (a fake row)
112
+ fake_column = ActiveRecord::ConnectionAdapters::Column.new(
113
+ column_name.to_s, nil, type, true
114
+ )
115
+ # add it to the list of fake columns for this table
116
+ mini_record_fake_columns[column_name.to_s] = fake_column
117
+ # skip everything else as it's a fake column and don't want it in the db
118
+ next
119
+ end
120
+
121
+ # Allow custom types like:
122
+ # t.column :type, "ENUM('EMPLOYEE','CLIENT','SUPERUSER','DEVELOPER')"
123
+ if type.is_a?(String)
124
+ # will be converted in: t.column :type, "ENUM('EMPLOYEE','CLIENT')"
125
+ table_definition.column(column_name, type, options.reverse_merge(:limit => 0))
126
+ else
127
+ # wil be converted in: t.string :name
128
+ table_definition.send(type, column_name, options)
129
+ end
130
+
131
+ # Get the correct column_name i.e. in field :category, :as => :references
132
+ column_name = table_definition.columns[-1].name
133
+
134
+ # Parse indexes
135
+ case index
136
+ when Hash
137
+ add_index(options.delete(:column) || column_name, index)
138
+ when TrueClass
139
+ add_index(column_name)
140
+ when String, Symbol, Array
141
+ add_index(index)
142
+ end
143
+ end
144
+ end
145
+ alias :key :field
146
+ alias :property :field
147
+ alias :col :field
148
+
149
+ def timestamps
150
+ field :created_at, :updated_at, :as => :datetime, :null => false
151
+ end
152
+
153
+ def reset_table_definition!
154
+ @_table_definition = nil
155
+ end
156
+ alias :reset_schema! :reset_table_definition!
157
+
158
+ def schema
159
+ reset_table_definition!
160
+ yield table_definition
161
+ table_definition
162
+ end
163
+
164
+ def add_index(column_name, options={})
165
+ index_name = connection.index_name(table_name, :column => column_name)
166
+ indexes[index_name] = options.merge(:column => column_name) unless indexes.key?(index_name)
167
+ index_name
168
+ end
169
+ alias :index :add_index
170
+
171
+ def connection?
172
+ !!connection
173
+ rescue Exception => e
174
+ puts "\e[31m%s\e[0m" % e.message.strip
175
+ false
176
+ end
177
+
178
+ def clear_tables!
179
+ (connection.tables - schema_tables).each do |name|
180
+ connection.drop_table(name)
181
+ schema_tables.delete(name)
182
+ end
183
+ end
184
+
185
+ def foreign_keys
186
+ # fk cache to minimize quantity of sql queries
187
+ @foreign_keys ||= {}
188
+ @foreign_keys[:table_name] ||= connection.foreign_keys(table_name)
189
+ end
190
+
191
+ # Remove foreign keys for indexes with :foreign=>false option
192
+ def remove_foreign_keys
193
+ indexes.each do |name, options|
194
+ if options[:foreign]==false
195
+ foreign_key = foreign_keys.detect { |fk| fk.options[:column] == options[:column].to_s }
196
+ if foreign_key
197
+ connection.remove_foreign_key(table_name, :name => foreign_key.options[:name])
198
+ foreign_keys.delete(foreign_key)
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ # Add foreign keys for indexes with :foreign=>true option, if the key doesn't exists
205
+ def add_foreign_keys
206
+ indexes.each do |name, options|
207
+ if options[:foreign]
208
+ column = options[:column].to_s
209
+ unless foreign_keys.detect { |fk| fk[:options][:column] == column }
210
+ to_table = reflect_on_all_associations.detect { |a| a.foreign_key.to_s==column }.table_name
211
+ connection.add_foreign_key(table_name, to_table, options)
212
+ foreign_keys << { :options=> { :column=>column } }
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ def auto_upgrade!
219
+ return unless connection?
220
+ return if respond_to?(:abstract_class?) && abstract_class?
221
+
222
+ if self == ActiveRecord::Base
223
+ descendants.each(&:auto_upgrade!)
224
+ clear_tables!
225
+ else
226
+ # If table doesn't exist, create it
227
+ unless connection.tables.include?(table_name)
228
+ # TODO: create_table options
229
+ class << connection; attr_accessor :table_definition; end unless connection.respond_to?(:table_definition=)
230
+ connection.table_definition = table_definition
231
+ connection.create_table(table_name)
232
+ connection.table_definition = init_table_definition(connection)
233
+ end
234
+
235
+ # Add this to our schema tables
236
+ schema_tables << table_name unless schema_tables.include?(table_name)
237
+
238
+ # Generate fields from associations
239
+ if reflect_on_all_associations.any?
240
+ reflect_on_all_associations.each do |association|
241
+ foreign_key = association.options[:foreign_key] || "#{association.name}_id"
242
+ type_key = "#{association.name.to_s}_type"
243
+ case association.macro
244
+ when :belongs_to
245
+ field foreign_key, :as => :integer unless fields.key?(foreign_key.to_s)
246
+ if association.options[:polymorphic]
247
+ field type_key, :as => :string unless fields.key?(type_key.to_s)
248
+ index [foreign_key, type_key]
249
+ else
250
+ index foreign_key
251
+ end
252
+ when :has_and_belongs_to_many
253
+ table = if name = association.options[:join_table]
254
+ name.to_s
255
+ else
256
+ [table_name, association.name.to_s].sort.join("_")
257
+ end
258
+ unless connection.tables.include?(table.to_s)
259
+ foreign_key = association.options[:foreign_key] || association.foreign_key
260
+ association_foreign_key = association.options[:association_foreign_key] || association.association_foreign_key
261
+ connection.create_table(table, :id => false) do |t|
262
+ t.integer foreign_key
263
+ t.integer association_foreign_key
264
+ end
265
+ index_name = connection.index_name(table, :column => [foreign_key, association_foreign_key])
266
+ index_name = index_name[0...connection.index_name_length] if index_name.length > connection.index_name_length
267
+ connection.add_index table, [foreign_key, association_foreign_key], :name => index_name, :unique => true
268
+ end
269
+ # Add join table to our schema tables
270
+ schema_tables << table unless schema_tables.include?(table)
271
+ end
272
+ end
273
+ end
274
+
275
+ # Add to schema inheritance column if necessary
276
+ if descendants.present?
277
+ field inheritance_column, :as => :string unless fields.key?(inheritance_column.to_s)
278
+ index inheritance_column
279
+ end
280
+
281
+ # Remove fields from db no longer in schema
282
+ (fields_in_db.keys - fields.keys & fields_in_db.keys).each do |field|
283
+ column = fields_in_db[field]
284
+ connection.remove_column table_name, column.name
285
+ end
286
+
287
+ # Add fields to db new to schema
288
+ (fields.keys - fields_in_db.keys).each do |field|
289
+ column = fields[field]
290
+ options = {:limit => column.limit, :precision => column.precision, :scale => column.scale}
291
+ options[:default] = column.default unless column.default.nil?
292
+ options[:null] = column.null unless column.null.nil?
293
+ connection.add_column table_name, column.name, column.type.to_sym, options
294
+ end
295
+
296
+ # Change attributes of existent columns
297
+ (fields.keys & fields_in_db.keys).each do |field|
298
+ if field != primary_key #ActiveRecord::Base.get_primary_key(table_name)
299
+ changed = false # flag
300
+ new_type = fields[field].type.to_sym
301
+ new_attr = {}
302
+
303
+ # First, check if the field type changed
304
+ old_sql_type = get_sql_field_type(fields_in_db[field])
305
+ new_sql_type = get_sql_field_type(fields[field])
306
+
307
+ if old_sql_type != new_sql_type
308
+ logger.debug "[MiniRecord] Detected schema change for #{table_name}.#{field}#type " +
309
+ " from #{old_sql_type.inspect} to #{new_sql_type.inspect}" if logger
310
+ changed = true
311
+ end
312
+
313
+ # Special catch for precision/scale, since *both* must be specified together
314
+ # Always include them in the attr struct, but they'll only get applied if changed = true
315
+ new_attr[:precision] = fields[field][:precision]
316
+ new_attr[:scale] = fields[field][:scale]
317
+
318
+ # If we have precision this is also the limit
319
+ fields[field][:limit] ||= fields[field][:precision]
320
+
321
+ # Next, iterate through our extended attributes, looking for any differences
322
+ # This catches stuff like :null, :precision, etc
323
+ # Ignore junk attributes that different versions of Rails include
324
+ fields[field].each_pair do |att,value|
325
+ next unless [:name, :limit, :precision, :scale, :default, :null].include?(att)
326
+ value = true if att == :null && value.nil?
327
+ old_value = fields_in_db[field].send(att)
328
+ if value != old_value
329
+ logger.debug "[MiniRecord] Detected schema change for #{table_name}.#{field}##{att} " +
330
+ "from #{old_value.inspect} to #{value.inspect}" if logger
331
+ new_attr[att] = value
332
+ changed = true
333
+ end
334
+ end
335
+
336
+ # Change the column if applicable
337
+ connection.change_column table_name, field, new_type, new_attr if changed
338
+ end
339
+ end
340
+
341
+ remove_foreign_keys if connection.respond_to?(:foreign_keys)
342
+
343
+ # Remove old index
344
+ (indexes_in_db.keys - indexes.keys).each do |name|
345
+ connection.remove_index(table_name, :name => name)
346
+ end
347
+
348
+ # Add indexes
349
+ indexes.each do |name, options|
350
+ options = options.dup
351
+ unless connection.indexes(table_name).detect { |i| i.name == name }
352
+ connection.add_index(table_name, options.delete(:column), options)
353
+ end
354
+ end
355
+
356
+ add_foreign_keys if connection.respond_to?(:foreign_keys)
357
+
358
+ # Reload column information
359
+ reset_column_information
360
+ end
361
+ end
362
+ end # ClassMethods
363
+ end # AutoSchema
364
+ end # MiniRecord