immigrant 0.3.3 → 0.3.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: bdd0fcce996e63a9bbd79d5846a03508a5eb6f37
4
- data.tar.gz: 8223a67a2b04354b3d76a3914954e63f6497f69a
3
+ metadata.gz: 7ed3d771b38d02c5ff03b07c83d14e820703fe43
4
+ data.tar.gz: 8408b58635d65127dfcb28125bc23ff701abb442
5
5
  SHA512:
6
- metadata.gz: bde334922bc6b593d7746e2f1a722cb936ad46b5f6de00e5a8c616163a96e12664a79527ba18163f11b102910385ba96ad0bd4f2d697cb4bf71837d58477a566
7
- data.tar.gz: 76e6525a673b96efaa26506b4408f5db93010fac02d520ea03b0ce9606afd3f585f28bccbaa736b5494df5a531ac4d6013e4817bc25fa04bc9e150e0c193253e
6
+ metadata.gz: d81e14ec77a85039b8cd6fb9ca64b3bb25730ee4b232a220c37c1285340993b808d3ec82a2d721172fc2a5647ee934bf007774d76d32105761cd3279b8d98098
7
+ data.tar.gz: 29faf9f62a44d17984fd685600e38220a1e3cc355127c98fb810c4e76b1609ec8068eda4380e05a8738b38505c54fd2ab5435e855eba193bd019b0a9a602d42e
data/lib/immigrant.rb CHANGED
@@ -33,15 +33,23 @@ module Immigrant
33
33
  if current_key.to_table != foreign_key.to_table || current_key.options[:primary_key] != foreign_key.options[:primary_key]
34
34
  warnings[hash_key] = "Skipping #{foreign_key.from_table}.#{foreign_key.options[:column]}: its association references a different key/table than its current foreign key"
35
35
  end
36
- elsif !ignore_keys[hash_key]
37
- new_keys << foreign_key
36
+ next
38
37
  end
38
+
39
+ next if ignore_keys[hash_key]
40
+ next unless key_validator.valid?(foreign_key)
41
+
42
+ new_keys << foreign_key
39
43
  end
40
44
  [new_keys.sort_by{ |key| key.options[:name] }, warnings]
41
45
  end
42
46
 
43
47
  private
44
48
 
49
+ def key_validator
50
+ @key_validator ||= KeyValidator.new
51
+ end
52
+
45
53
  def tables
46
54
  @tables ||= ActiveRecord::Base.connection.tables
47
55
  end
@@ -129,8 +137,6 @@ module Immigrant
129
137
  column = reflection.send(FOREIGN_KEY).to_s
130
138
  primary_key = (reflection.options[:primary_key] || reflection.klass.primary_key).to_s
131
139
 
132
- return unless column_exists?(from_table, column)
133
-
134
140
  [
135
141
  ForeignKeyDefinition.new(
136
142
  from_table,
@@ -154,8 +160,6 @@ module Immigrant
154
160
  actions = {:on_delete => :cascade, :on_update => :cascade}
155
161
  end
156
162
 
157
- return unless column_exists?(from_table, column)
158
-
159
163
  [
160
164
  ForeignKeyDefinition.new(
161
165
  from_table,
@@ -169,45 +173,32 @@ module Immigrant
169
173
  end
170
174
 
171
175
  def infer_habtm_keys(klass, reflection)
172
- keys = []
173
-
174
176
  join_table = (reflection.respond_to?(:join_table) ? reflection.join_table : reflection.options[:join_table]).to_s
175
177
 
176
178
  left_to_table = klass.table_name
177
179
  left_column = reflection.send(FOREIGN_KEY).to_s
178
180
  left_primary_key = klass.primary_key.to_s
179
- if column_exists?(join_table, left_column)
180
- keys << ForeignKeyDefinition.new(
181
- join_table,
182
- left_to_table,
183
- :column => left_column,
184
- :primary_key => left_primary_key
185
- )
186
- end
187
181
 
188
182
  right_to_table = reflection.klass.table_name
189
183
  right_column = reflection.association_foreign_key.to_s
190
184
  right_primary_key = reflection.klass.primary_key.to_s
191
- if column_exists?(join_table, left_column)
192
- keys << ForeignKeyDefinition.new(
185
+
186
+ [
187
+ ForeignKeyDefinition.new(
188
+ join_table,
189
+ left_to_table,
190
+ :column => left_column,
191
+ :primary_key => left_primary_key
192
+ ),
193
+ ForeignKeyDefinition.new(
193
194
  join_table,
194
195
  right_to_table,
195
196
  :column => right_column,
196
197
  :primary_key => right_primary_key
197
198
  )
198
- end
199
-
200
- keys
201
- end
202
-
203
- def column_exists?(table_name, column_name)
204
- columns_for(table_name).any? { |column| column.name == column_name }
199
+ ]
205
200
  end
206
201
 
207
- def columns_for(table_name)
208
- @columns ||= {}
209
- @columns[table_name] ||= ActiveRecord::Base.connection.columns(table_name)
210
- end
211
202
 
212
203
  def qualified_reflection?(reflection, klass)
213
204
  scope = reflection.scope
@@ -225,5 +216,6 @@ module Immigrant
225
216
  end
226
217
 
227
218
  require 'immigrant/loader'
219
+ require 'immigrant/key_validator'
228
220
  require 'immigrant/foreign_key_extensions'
229
221
  require 'immigrant/railtie' if defined?(Rails)
@@ -0,0 +1,32 @@
1
+ module Immigrant
2
+ class KeyValidator
3
+ def valid?(key)
4
+ tables = connection.tables
5
+ return false unless tables.include?(key.from_table)
6
+ return false unless tables.include?(key.to_table)
7
+ return false unless column_exists?(key.from_table, key.options[:column])
8
+ return false unless column_exists?(key.to_table, key.options[:primary_key])
9
+ return false unless key.options[:primary_key] == "id" || has_unique_index?(key.to_table, key.options[:primary_key])
10
+ true
11
+ end
12
+
13
+ private
14
+
15
+ def has_unique_index?(table_name, column_name)
16
+ connection.indexes(table_name).any? { |index| index.columns == [column_name] && index.unique && index.where.nil? }
17
+ end
18
+
19
+ def column_exists?(table_name, column_name)
20
+ columns_for(table_name).any? { |column| column.name == column_name }
21
+ end
22
+
23
+ def columns_for(table_name)
24
+ @columns ||= {}
25
+ @columns[table_name] ||= connection.columns(table_name)
26
+ end
27
+
28
+ def connection
29
+ @connection ||= ActiveRecord::Base.connection
30
+ end
31
+ end
32
+ end
@@ -41,16 +41,21 @@ class ImmigrantTest < ActiveSupport::TestCase
41
41
  ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base).map(&:table_name)
42
42
  end
43
43
  def columns(table_name)
44
- AnyColumn.new
44
+ AnyCollection.new
45
+ end
46
+ def indexes(table_name)
47
+ AnyCollection.new
45
48
  end
46
49
  end
47
50
 
48
- class AnyColumn
51
+ class AnyCollection
49
52
  def any?
50
53
  true
51
54
  end
52
55
  end
53
56
 
57
+ Index = ActiveRecord::ConnectionAdapters::IndexDefinition
58
+
54
59
  def teardown
55
60
  subclasses = ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base)
56
61
  subclasses.each do |subclass|
@@ -455,6 +460,26 @@ class ImmigrantTest < ActiveSupport::TestCase
455
460
  end
456
461
  end
457
462
 
463
+ test 'insufficiently unique "primary" keys should not generate a foreign key' do
464
+ given <<-CODE
465
+ class Setting < ActiveRecord::Base; end
466
+
467
+ class SettingValue < ActiveRecord::Base
468
+ belongs_to :setting,
469
+ :conditions => { :deleted_at => nil },
470
+ foreign_key: :name, primary_key: :name
471
+ end
472
+ CODE
473
+
474
+ # emulate `"index_settings_on_name" UNIQUE, btree (name) WHERE deleted_at IS NULL`
475
+ # it's unique, but not enough for a foreign key just on name
476
+ indexes = [Index.new("settings", ["name"], true, "deleted_at IS NULL")]
477
+
478
+ MockConnection.stub_any_instance(:indexes, indexes) do
479
+ assert_equal([], infer_keys)
480
+ end
481
+ end
482
+
458
483
  test 'ignore_keys should be respected' do
459
484
  given <<-CODE
460
485
  class User < ActiveRecord::Base; end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immigrant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Jensen
@@ -48,6 +48,7 @@ files:
48
48
  - lib/immigrant/compat/active_record.rb
49
49
  - lib/immigrant/compat/foreigner.rb
50
50
  - lib/immigrant/foreign_key_extensions.rb
51
+ - lib/immigrant/key_validator.rb
51
52
  - lib/immigrant/loader.rb
52
53
  - lib/immigrant/railtie.rb
53
54
  - lib/immigrant/task.rb