mini_record 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cfb798464fea4709be8710a161550d3f4cdf1371
4
- data.tar.gz: d2bd9f1fa0fbe58af774dd5a7b66812603a9e358
3
+ metadata.gz: 44eb9e5c3b23585ea142c23f9b79cc8783a06204
4
+ data.tar.gz: 78dcc1beff902922d33bfc660b819f22d73b8061
5
5
  SHA512:
6
- metadata.gz: 3d143593162f47be6b2824ce36e47d1b9b2b46b7a84225ffd2bc4e6628f443407866cde9a3d8a1b04a36638ce871c2059141f2899ab61d4f763171ccfb9ad353
7
- data.tar.gz: 855af276975d4b394fd9563c6b219fbe61b860e9b1e4aca57b8fe615158df45274ac48171e95f4c7aea01a73c5ded63bbe4e8397f8ddf88d753059b07cb54fc1
6
+ metadata.gz: 1436a23b6d6fa2327ee7545258f3059b068cc0c85dd9964ff8d8ccc1b634fcd277c5a82d5644c6c9092e433a993e2e681f053f3bd7b70e8426bdc8e8e2ee91bd
7
+ data.tar.gz: 662eeecaa4f45ff27854ec646e381b71959ac143766731ee585394c3b3f1b110778171878d27f684cc5cf7971332d22ea187fba58eaada58437f02ff55df1274
data/README.md CHANGED
@@ -260,6 +260,19 @@ class Fox < ActiveRecord::Base
260
260
  end
261
261
  ```
262
262
 
263
+ ### Suppress default indexes for associations
264
+
265
+ If you do not need the default index for a `belongs_to` or `has_and_belongs_to_many` relationship, such as if you are using a composite index instead, you can suppress it from being created (or remove it) using `suppress_index` on the association:
266
+
267
+ ```ruby
268
+ class PhoneNumber < ActiveRecord::Base
269
+ field :position
270
+ belongs_to :person
271
+ suppress_index :person
272
+ add_index [:person_id, :position]
273
+ end
274
+ ```
275
+
263
276
  ### Passing options to Create Table
264
277
 
265
278
  If you need to pass particular options to your `CREATE TABLE` statement, you can do so with `create_table` in the Model:
@@ -305,4 +318,4 @@ The above copyright notice and this permission notice shall be included in all c
305
318
  THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
306
319
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM,
307
320
  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
308
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
321
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -44,6 +44,12 @@ module MiniRecord
44
44
  @_indexes ||= {}
45
45
  end
46
46
 
47
+ def suppressed_indexes
48
+ return superclass.suppressed_indexes unless (superclass == ActiveRecord::Base) || (superclass.respond_to?(:abstract_class?) && superclass.abstract_class?)
49
+
50
+ @_suppressed_indexes ||= {}
51
+ end
52
+
47
53
  def indexes_in_db
48
54
  connection.indexes(table_name).inject({}) do |hash, index|
49
55
  hash[index.name] = index
@@ -158,6 +164,12 @@ module MiniRecord
158
164
  end
159
165
  alias :index :add_index
160
166
 
167
+ def suppress_index(*associations)
168
+ associations.each do |association|
169
+ suppressed_indexes[association] = true
170
+ end
171
+ end
172
+
161
173
  def connection?
162
174
  !!connection
163
175
  rescue Exception => e
@@ -165,11 +177,14 @@ module MiniRecord
165
177
  false
166
178
  end
167
179
 
168
- def clear_tables!
180
+ def clear_tables!(dry_run = false)
169
181
  return unless MiniRecord.configuration.destructive == true
170
182
  (connection.tables - schema_tables).each do |name|
171
- connection.drop_table(name)
172
- schema_tables.delete(name)
183
+ logger.debug "[MiniRecord] Dropping table #{name}"
184
+ unless dry_run
185
+ connection.drop_table(name)
186
+ schema_tables.delete(name)
187
+ end
173
188
  end
174
189
  end
175
190
 
@@ -180,13 +195,14 @@ module MiniRecord
180
195
  end
181
196
 
182
197
  # Remove foreign keys for indexes with :foreign=>false option
183
- def remove_foreign_keys
198
+ def remove_foreign_keys(dry_run)
184
199
  return unless MiniRecord.configuration.destructive == true
185
200
  indexes.each do |name, options|
186
201
  if options[:foreign]==false
187
202
  foreign_key = foreign_keys.detect { |fk| fk.options[:column] == options[:column].to_s }
188
203
  if foreign_key
189
- connection.remove_foreign_key(table_name, :name => foreign_key.options[:name])
204
+ logger.debug "[MiniRecord] Removing Foreign Key #{foreign_key.options[:name]} on table #{table_name}"
205
+ connection.remove_foreign_key(table_name, :name => foreign_key.options[:name]) unless dry_run
190
206
  foreign_keys.delete(foreign_key)
191
207
  end
192
208
  end
@@ -194,33 +210,42 @@ module MiniRecord
194
210
  end
195
211
 
196
212
  # Add foreign keys for indexes with :foreign=>true option, if the key doesn't exists
197
- def add_foreign_keys
213
+ def add_foreign_keys(dry_run)
198
214
  indexes.each do |name, options|
199
215
  if options[:foreign]
200
216
  column = options[:column].to_s
201
217
  unless foreign_keys.detect { |fk| fk[:options][:column] == column }
202
218
  to_table = reflect_on_all_associations.detect { |a| a.foreign_key.to_s==column }.table_name
203
- connection.add_foreign_key(table_name, to_table, options)
219
+ logger.debug "[MiniRecord] Adding Foreign Key on #{table_name} to #{to_table}"
220
+ connection.add_foreign_key(table_name, to_table, options) unless dry_run
204
221
  foreign_keys << { :options=> { :column=>column } }
205
222
  end
206
223
  end
207
224
  end
208
225
  end
209
226
 
210
- def auto_upgrade!
227
+ # dry-run
228
+ def auto_upgrade_dry
229
+ auto_upgrade!(true)
230
+ end
231
+
232
+ def auto_upgrade!(dry_run = false)
211
233
  return unless connection?
212
234
  return if respond_to?(:abstract_class?) && abstract_class?
213
235
 
214
236
  if self == ActiveRecord::Base
215
- descendants.each(&:auto_upgrade!)
216
- clear_tables!
237
+ descendants.each { |model| model.auto_upgrade!(dry_run) }
238
+ clear_tables!(dry_run)
217
239
  else
218
240
  # If table doesn't exist, create it
219
241
  unless connection.tables.include?(table_name)
220
242
  class << connection; attr_accessor :table_definition; end unless connection.respond_to?(:table_definition=)
221
- connection.table_definition = table_definition
222
- connection.create_table(table_name, *create_table_options)
223
- connection.table_definition = init_table_definition(connection)
243
+ logger.debug "[MiniRecord] Creating Table #{table_name}"
244
+ unless dry_run
245
+ connection.table_definition = table_definition
246
+ connection.create_table(table_name, *create_table_options)
247
+ connection.table_definition = init_table_definition(connection)
248
+ end
224
249
  end
225
250
 
226
251
  # Add this to our schema tables
@@ -236,9 +261,9 @@ module MiniRecord
236
261
  field foreign_key, :as => :integer unless fields.key?(foreign_key.to_s)
237
262
  if association.options[:polymorphic]
238
263
  field type_key, :as => :string unless fields.key?(type_key.to_s)
239
- index [foreign_key, type_key]
264
+ index [foreign_key, type_key] unless suppressed_indexes[association.name]
240
265
  else
241
- index foreign_key
266
+ index foreign_key unless suppressed_indexes[association.name]
242
267
  end
243
268
  when :has_and_belongs_to_many
244
269
  table = if name = association.options[:join_table]
@@ -249,13 +274,17 @@ module MiniRecord
249
274
  unless connection.tables.include?(table.to_s)
250
275
  foreign_key = association.options[:foreign_key] || association.foreign_key
251
276
  association_foreign_key = association.options[:association_foreign_key] || association.association_foreign_key
252
- connection.create_table(table, :id => false) do |t|
253
- t.integer foreign_key
254
- t.integer association_foreign_key
277
+ logger.debug "[MiniRecord] Creating Join Table #{table} with keys #{foreign_key} and #{association_foreign_key}"
278
+ unless dry_run
279
+ connection.create_table(table, :id => false) do |t|
280
+ t.integer foreign_key
281
+ t.integer association_foreign_key
282
+ end
255
283
  end
256
284
  index_name = connection.index_name(table, :column => [foreign_key, association_foreign_key])
257
285
  index_name = index_name[0...connection.index_name_length] if index_name.length > connection.index_name_length
258
- connection.add_index table, [foreign_key, association_foreign_key], :name => index_name, :unique => true
286
+ logger.debug "[MiniRecord] Creating Join Table Index #{index_name} (#{foreign_key}, #{association_foreign_key}) on #{table}"
287
+ connection.add_index table, [foreign_key, association_foreign_key], :name => index_name, :unique => true unless dry_run or suppressed_indexes[association.name]
259
288
  end
260
289
  # Add join table to our schema tables
261
290
  schema_tables << table unless schema_tables.include?(table)
@@ -270,14 +299,15 @@ module MiniRecord
270
299
  end
271
300
 
272
301
  # Group Destructive Actions
273
- if MiniRecord.configuration.destructive == true
302
+ if MiniRecord.configuration.destructive == true and connection.tables.include?(table_name)
274
303
 
275
304
  # Rename fields
276
305
  rename_fields.each do |old_name, new_name|
277
306
  old_column = fields_in_db[old_name.to_s]
278
307
  new_column = fields_in_db[new_name.to_s]
279
308
  if old_column && !new_column
280
- connection.rename_column(table_name, old_column.name, new_name)
309
+ logger.debug "[MiniRecord] Renaming column #{table_name}.#{old_column.name} to #{new_name}"
310
+ connection.rename_column(table_name, old_column.name, new_name) unless dry_run
281
311
  end
282
312
  end
283
313
 
@@ -285,7 +315,8 @@ module MiniRecord
285
315
  columns_to_delete = fields_in_db.keys - fields.keys & fields_in_db.keys
286
316
  columns_to_delete.each do |field|
287
317
  column = fields_in_db[field]
288
- connection.remove_column table_name, column.name
318
+ logger.debug "[MiniRecord] Removing column #{table_name}.#{column.name}"
319
+ connection.remove_column table_name, column.name unless dry_run
289
320
  end
290
321
 
291
322
  # Change attributes of existent columns
@@ -324,40 +355,48 @@ module MiniRecord
324
355
 
325
356
  # Change the column if applicable
326
357
  new_type = fields[field].type.to_sym
327
- connection.change_column table_name, field, new_type, new_attr if changed
358
+ if changed
359
+ logger.debug "[MiniRecord] Changing column #{table_name}.#{field} to new type #{new_type}"
360
+ connection.change_column table_name, field, new_type, new_attr unless dry_run
361
+ end
328
362
  end
329
363
  end
330
364
 
331
- remove_foreign_keys if connection.respond_to?(:foreign_keys)
365
+ remove_foreign_keys(dry_run) if connection.respond_to?(:foreign_keys)
332
366
 
333
367
  # Remove old index
334
- index_names = indexes.collect{|name,opts| opts[:name] || name }
368
+ index_names = indexes.collect{ |name, opts| (opts[:name] || name).to_s }
335
369
  (indexes_in_db.keys - index_names).each do |name|
336
- connection.remove_index(table_name, :name => name)
370
+ logger.debug "[MiniRecord] Removing index #{name} on #{table_name}"
371
+ connection.remove_index(table_name, :name => name) unless dry_run
337
372
  end
338
373
 
339
374
  end
340
375
 
341
- # Add fields to db new to schema
342
- columns_to_add = fields.keys - fields_in_db.keys
343
- columns_to_add.each do |field|
344
- column = fields[field]
345
- options = {:limit => column.limit, :precision => column.precision, :scale => column.scale}
346
- options[:default] = column.default unless column.default.nil?
347
- options[:null] = column.null unless column.null.nil?
348
- connection.add_column table_name, column.name, column.type.to_sym, options
376
+ if connection.tables.include?(table_name)
377
+ # Add fields to db new to schema
378
+ columns_to_add = fields.keys - fields_in_db.keys
379
+ columns_to_add.each do |field|
380
+ column = fields[field]
381
+ options = {:limit => column.limit, :precision => column.precision, :scale => column.scale}
382
+ options[:default] = column.default unless column.default.nil?
383
+ options[:null] = column.null unless column.null.nil?
384
+ logger.debug "[MiniRecord] Adding column #{table_name}.#{column.name}"
385
+ connection.add_column table_name, column.name, column.type.to_sym, options unless dry_run
386
+ end
349
387
  end
350
388
 
351
389
  # Add indexes
352
390
  indexes.each do |name, options|
353
391
  options = options.dup
354
- index_name = options[:name] || name
392
+ index_name = (options[:name] || name).to_s
355
393
  unless connection.indexes(table_name).detect { |i| i.name == index_name }
356
- connection.add_index(table_name, options.delete(:column), options)
394
+ logger.debug "[MiniRecord] Adding index #{index_name} #{options[:column].inspect} on #{table_name}"
395
+ connection.add_index(table_name, options.delete(:column), options) unless dry_run
357
396
  end
358
397
  end
359
398
 
360
- add_foreign_keys if connection.respond_to?(:foreign_keys)
399
+ add_foreign_keys(dry_run) if connection.respond_to?(:foreign_keys)
361
400
 
362
401
  # Reload column information
363
402
  reset_column_information
@@ -1,3 +1,3 @@
1
1
  module MiniRecord
2
- VERSION = "0.4.3"
2
+ VERSION = "0.4.4"
3
3
  end
data/test/helper.rb CHANGED
@@ -37,7 +37,13 @@ class ActiveRecord::Base
37
37
  ActiveRecord::Base.logs.string.gsub(/\e\[[\d;]+m/, '').lines.reject { |l| !pragma && l =~ /pragma/i }.join("\n")
38
38
  end
39
39
 
40
- def auto_upgrade!
40
+ def auto_upgrade!(*args)
41
+ ActiveRecord::Base.logs = StringIO.new
42
+ ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(ActiveRecord::Base.logs)
43
+ silence_stream(STDERR) { super }
44
+ end
45
+
46
+ def auto_upgrade_dry
41
47
  ActiveRecord::Base.logs = StringIO.new
42
48
  ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(ActiveRecord::Base.logs)
43
49
  silence_stream(STDERR) { super }
@@ -2,13 +2,20 @@ require File.expand_path('../helper.rb', __FILE__)
2
2
 
3
3
  describe MiniRecord do
4
4
 
5
- before do
6
- ActiveRecord::Base.clear_reloadable_connections!
7
- ActiveRecord::Base.clear_cache!
8
- ActiveRecord::Base.clear_active_connections!
9
- conn.tables.each { |table| silence_stream(STDERR) { conn.execute "DROP TABLE IF EXISTS #{table}" } }
5
+ def clear_active_record!(options = {})
6
+ unless options[:keep_tables]
7
+ ActiveRecord::Base.clear_reloadable_connections!
8
+ ActiveRecord::Base.clear_cache!
9
+ ActiveRecord::Base.clear_active_connections!
10
+ conn.tables.each { |table| silence_stream(STDERR) { conn.execute "DROP TABLE IF EXISTS #{table}" } }
11
+ end
12
+
10
13
  ActiveRecord::Base.descendants.each { |klass| Object.send(:remove_const, klass.to_s) if Object.const_defined?(klass.to_s) }
11
14
  ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base).clear
15
+ end
16
+
17
+ before do
18
+ clear_active_record!
12
19
  load File.expand_path('../models.rb', __FILE__)
13
20
  ActiveRecord::Base.auto_upgrade!
14
21
  MiniRecord.reset_configuration!
@@ -128,9 +135,41 @@ describe MiniRecord do
128
135
  index :customer_id, :unique => true, :name => 'by_customer'
129
136
  belongs_to :customer
130
137
  end
138
+ # Run auto_upgrade! once to create table and index.
131
139
  Foo.auto_upgrade!
132
140
  assert_equal 1, Foo.db_indexes.size
133
141
  assert_includes Foo.db_indexes, 'by_customer'
142
+ # Run auto_upgrade! again and ensure no statements issued.
143
+ Foo.auto_upgrade!
144
+ assert_empty Foo.queries
145
+ end
146
+
147
+ it 'does not add already defined composite indexes' do
148
+ class Foo < ActiveRecord::Base
149
+ belongs_to :region
150
+ belongs_to :customer
151
+ add_index [:region_id, :customer_id], :unique => true, :name => 'by_region_and_customer'
152
+ end
153
+ # Run auto_upgrade! once to create table and index.
154
+ Foo.auto_upgrade!
155
+ assert_equal 3, Foo.db_indexes.size
156
+ assert_includes Foo.db_indexes, 'by_region_and_customer'
157
+ # Run auto_upgrade! again and ensure no statements issued.
158
+ Foo.auto_upgrade!
159
+ assert_empty Foo.queries
160
+ end
161
+
162
+ it 'supports indexes with symbols for names' do
163
+ class Foo < ActiveRecord::Base
164
+ col :some_field, :index => {:name => :idx_for_some_field}
165
+ end
166
+ # Run auto_upgrade! once to create table and index.
167
+ Foo.auto_upgrade!
168
+ assert_equal 1, Foo.db_indexes.size
169
+ assert_includes Foo.db_indexes, 'idx_for_some_field'
170
+ # Run auto_upgrade! again and ensure no statements issued.
171
+ Foo.auto_upgrade!
172
+ assert_empty Foo.queries
134
173
  end
135
174
 
136
175
  it 'works with STI' do
@@ -518,6 +557,24 @@ describe MiniRecord do
518
557
  assert_includes Book.db_indexes, 'index_books_on_second_publisher_id'
519
558
  end
520
559
 
560
+ it "does not add suppressed index" do
561
+ class Foo < ActiveRecord::Base
562
+ belongs_to :customer
563
+ suppress_index :customer
564
+ end
565
+ Foo.auto_upgrade!
566
+ assert_equal 0, Foo.db_indexes.size
567
+ end
568
+
569
+ it "does not add suppressed index from polymorphic relation" do
570
+ class Foo < ActiveRecord::Base
571
+ belongs_to :customer, :polymorphic => true
572
+ suppress_index :customer
573
+ end
574
+ Foo.auto_upgrade!
575
+ assert_equal 0, Foo.db_indexes.size
576
+ end
577
+
521
578
  end
522
579
 
523
580
  describe 'relation #habtm' do
@@ -580,6 +637,16 @@ describe MiniRecord do
580
637
  assert_includes conn.indexes(:long_people).map(&:name), index_name
581
638
  end
582
639
 
640
+ it 'creates a join table without an index when suppressed for has_and_belongs_to_many relations' do
641
+ class Foo < ActiveRecord::Base
642
+ has_and_belongs_to_many :bars
643
+ suppress_index :bars
644
+ end
645
+ Foo.auto_upgrade!
646
+ assert_includes conn.tables, 'bars_foos'
647
+ assert_equal 0, conn.indexes(:bars_foos).size
648
+ end
649
+
583
650
  it 'adds unique index' do
584
651
  page = Page.create(:title => 'Foo')
585
652
  photogallery = Photogallery.create(:title => 'Bar')
@@ -895,4 +962,30 @@ describe MiniRecord do
895
962
  Foo.auto_upgrade! rescue nil # eat the exception from invalid options
896
963
  assert_match /CREATE TABLE.* extra options\Z/, Foo.queries
897
964
  end
965
+
966
+ it 'can do a dry run' do
967
+ class Foo < ActiveRecord::Base
968
+ end
969
+
970
+ ActiveRecord::Base.auto_upgrade_dry
971
+ refute_match /\bcreate\b/i, Foo.queries
972
+ refute_match /\balter\b/i, Foo.queries
973
+
974
+ ActiveRecord::Base.auto_upgrade!
975
+ assert_match /\bcreate\b/i, Foo.queries
976
+ refute_match /\balter\b/i, Foo.queries
977
+
978
+ clear_active_record!(:keep_tables => true)
979
+ class Foo < ActiveRecord::Base
980
+ property :new_field, :index => true
981
+ end
982
+
983
+ ActiveRecord::Base.auto_upgrade_dry
984
+ refute_match /\bcreate\b/i, Foo.queries
985
+ refute_match /\balter\b/i, Foo.queries
986
+
987
+ ActiveRecord::Base.auto_upgrade!
988
+ assert_match /\bcreate\b/i, Foo.queries
989
+ assert_match /\balter\b/i, Foo.queries
990
+ end
898
991
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Davide D'Agostino
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-10 00:00:00.000000000 Z
11
+ date: 2014-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord