mini_record 0.4.3 → 0.4.4
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.
- checksums.yaml +4 -4
- data/README.md +14 -1
- data/lib/mini_record/auto_schema.rb +76 -37
- data/lib/mini_record/version.rb +1 -1
- data/test/helper.rb +7 -1
- data/test/test_mini_record.rb +98 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44eb9e5c3b23585ea142c23f9b79cc8783a06204
|
4
|
+
data.tar.gz: 78dcc1beff902922d33bfc660b819f22d73b8061
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
172
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
222
|
-
|
223
|
-
|
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
|
-
|
253
|
-
|
254
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
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
|
-
|
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
|
data/lib/mini_record/version.rb
CHANGED
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 }
|
data/test/test_mini_record.rb
CHANGED
@@ -2,13 +2,20 @@ require File.expand_path('../helper.rb', __FILE__)
|
|
2
2
|
|
3
3
|
describe MiniRecord do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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.
|
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-
|
11
|
+
date: 2014-11-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|