immigrant 0.3.3 → 0.3.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 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