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 +4 -4
- data/lib/immigrant.rb +21 -29
- data/lib/immigrant/key_validator.rb +32 -0
- data/test/immigrant_test.rb +27 -2
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ed3d771b38d02c5ff03b07c83d14e820703fe43
|
4
|
+
data.tar.gz: 8408b58635d65127dfcb28125bc23ff701abb442
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
192
|
-
|
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
|
-
|
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
|
data/test/immigrant_test.rb
CHANGED
@@ -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
|
-
|
44
|
+
AnyCollection.new
|
45
|
+
end
|
46
|
+
def indexes(table_name)
|
47
|
+
AnyCollection.new
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
48
|
-
class
|
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.
|
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
|