immigrant 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/immigrant.rb +80 -44
  2. data/test/immigrant_test.rb +19 -0
  3. metadata +3 -3
data/lib/immigrant.rb CHANGED
@@ -50,16 +50,14 @@ module Immigrant
50
50
  # see what the models say there should be
51
51
  foreign_keys = {}
52
52
  warnings = {}
53
- classes.map{ |klass|
54
- foreign_keys_for(klass)
55
- }.flatten.uniq.each do |foreign_key|
53
+
54
+ candidate_model_keys(classes).each do |foreign_key|
56
55
  # we may have inferred it from several different places, e.g.
57
56
  # Bar.belongs_to :foo
58
57
  # Foo.has_many :bars
59
58
  # Foo.has_many :bazzes, :class_name => Bar
60
59
  # we need to make sure everything is legit and see if any of them
61
60
  # specify :dependent => :delete
62
- next if foreign_key.nil?
63
61
  if current_key = foreign_keys[foreign_key.hash_key]
64
62
  if current_key.to_table != foreign_key.to_table || current_key.options[:primary_key] != foreign_key.options[:primary_key]
65
63
  warnings[foreign_key.hash_key] ||= "Skipping #{foreign_key.from_table}.#{foreign_key.options[:column]}: it has multiple associations referencing different keys/tables."
@@ -74,56 +72,94 @@ module Immigrant
74
72
  [foreign_keys, warnings]
75
73
  end
76
74
 
77
- def foreign_keys_for(klass)
78
- fk_method = ActiveRecord::VERSION::STRING < '3.1.' ? :primary_key_name : :foreign_key
75
+ def candidate_model_keys(classes)
76
+ classes.inject([]) do |result, klass|
77
+ result.concat foreign_keys_for(klass)
78
+ end.uniq
79
+ end
79
80
 
80
- klass.reflections.values.reject{ |reflection|
81
+ def candidate_reflections_for(klass)
82
+ klass.reflections.values.reject do |reflection|
81
83
  # some associations can just be ignored, since:
82
84
  # 1. we aren't going to parse SQL
83
85
  # 2. foreign keys for :through associations will be handled by their
84
86
  # component has_one/has_many/belongs_to associations
85
87
  # 3. :polymorphic(/:as) associations can't have foreign keys
86
88
  (reflection.options.keys & [:finder_sql, :through, :polymorphic, :as]).present?
87
- }.map { |reflection|
89
+ end
90
+ end
91
+
92
+ def foreign_keys_for(klass)
93
+ candidate_reflections_for(klass).inject([]) do |result, reflection|
88
94
  begin
89
- case reflection.macro
90
- when :belongs_to
91
- Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
92
- klass.table_name, reflection.klass.table_name,
93
- :column => reflection.send(fk_method).to_s,
94
- :primary_key => reflection.klass.primary_key.to_s,
95
- # although belongs_to can specify :dependent, it doesn't make
96
- # sense from a foreign key perspective
97
- :dependent => nil
98
- )
99
- when :has_one, :has_many
100
- Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
101
- reflection.klass.table_name, klass.table_name,
102
- :column => reflection.send(fk_method).to_s,
103
- :primary_key => klass.primary_key.to_s,
104
- :dependent => [:delete, :delete_all].include?(reflection.options[:dependent]) && !qualified_reflection?(reflection, klass) ? :delete : nil
105
- )
106
- when :has_and_belongs_to_many
107
- join_table = (reflection.respond_to?(:join_table) ? reflection.join_table : reflection.options[:join_table]).to_s
108
- [
109
- Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
110
- join_table, klass.table_name,
111
- :column => reflection.send(fk_method).to_s,
112
- :primary_key => klass.primary_key.to_s,
113
- :dependent => nil
114
- ),
115
- Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
116
- join_table, reflection.klass.table_name,
117
- :column => reflection.association_foreign_key.to_s,
118
- :primary_key => reflection.klass.primary_key.to_s,
119
- :dependent => nil
120
- )
121
- ]
122
- end
95
+ result.concat foreign_key_for(klass, reflection)
123
96
  rescue NameError # e.g. belongs_to :oops_this_is_not_a_table
124
- []
97
+ result
125
98
  end
126
- }.flatten
99
+ end
100
+ end
101
+
102
+ def foreign_key_for(klass, reflection)
103
+ case reflection.macro
104
+ when :belongs_to
105
+ infer_belongs_to_keys(klass, reflection)
106
+ when :has_one, :has_many
107
+ infer_has_n_keys(klass, reflection)
108
+ when :has_and_belongs_to_many
109
+ infer_habtm_keys(klass, reflection)
110
+ else
111
+ []
112
+ end
113
+ end
114
+
115
+ def infer_belongs_to_keys(klass, reflection)
116
+ [
117
+ Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
118
+ klass.table_name,
119
+ reflection.klass.table_name,
120
+ :column => reflection.send(fk_method).to_s,
121
+ :primary_key => (reflection.options[:primary_key] || reflection.klass.primary_key).to_s,
122
+ # although belongs_to can specify :dependent, it doesn't make
123
+ # sense from a foreign key perspective
124
+ :dependent => nil
125
+ )
126
+ ]
127
+ end
128
+
129
+ def infer_has_n_keys(klass, reflection)
130
+ [
131
+ Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
132
+ reflection.klass.table_name,
133
+ klass.table_name,
134
+ :column => reflection.send(fk_method).to_s,
135
+ :primary_key => (reflection.options[:primary_key] || klass.primary_key).to_s,
136
+ :dependent => [:delete, :delete_all].include?(reflection.options[:dependent]) && !qualified_reflection?(reflection, klass) ? :delete : nil
137
+ )
138
+ ]
139
+ end
140
+
141
+ def infer_habtm_keys(klass, reflection)
142
+ join_table = (reflection.respond_to?(:join_table) ? reflection.join_table : reflection.options[:join_table]).to_s
143
+ [
144
+ Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
145
+ join_table,
146
+ klass.table_name,
147
+ :column => reflection.send(fk_method).to_s,
148
+ :primary_key => klass.primary_key.to_s,
149
+ :dependent => nil
150
+ ),
151
+ Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
152
+ join_table,
153
+ reflection.klass.table_name,
154
+ :column => reflection.association_foreign_key.to_s,
155
+ :primary_key => reflection.klass.primary_key.to_s,
156
+ :dependent => nil
157
+ )
158
+ ]
159
+ end
160
+
161
+ def fk_method
162
+ ActiveRecord::VERSION::STRING < '3.1.' ? :primary_key_name : :foreign_key
127
163
  end
128
164
 
129
165
  def qualified_reflection?(reflection, klass)
@@ -202,6 +202,25 @@ class ImmigrantTest < ActiveSupport::TestCase
202
202
  )
203
203
  end
204
204
 
205
+ test 'primary_key should be respected' do
206
+ class User < MockModel
207
+ has_many :emails, :primary_key => :email, :foreign_key => :to,
208
+ :dependent => :destroy
209
+ end
210
+ class Email < MockModel
211
+ belongs_to :user, :primary_key => :email, :foreign_key => :to
212
+ end
213
+
214
+ keys = Immigrant.infer_keys([]).first
215
+ assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
216
+ assert_equal(
217
+ [foreign_key_definition(
218
+ 'emails', 'users',
219
+ :column => 'to', :primary_key => 'email', :dependent => nil
220
+ )],
221
+ keys
222
+ )
223
+ end
205
224
 
206
225
  # (no) duplication
207
226
 
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.1.5
4
+ version: 0.1.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-08 00:00:00.000000000 Z
12
+ date: 2014-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  version: 1.3.5
85
85
  requirements: []
86
86
  rubyforge_project:
87
- rubygems_version: 1.8.25
87
+ rubygems_version: 1.8.23
88
88
  signing_key:
89
89
  specification_version: 3
90
90
  summary: Migration generator for Foreigner