immigrant 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 083bc4d18b381bf62146a71c000495a4b108fed2
4
+ data.tar.gz: b096073f024d41aa6362c2d3db3a3014aa8016ba
5
+ SHA512:
6
+ metadata.gz: e1fe3e50d541c96400fbb476bcac1ac9176aa51e19b8d7e373398307aa34c0cabbea3a9353f932dd47d39439558fb367418b82eae651cac1fe7368c0d7d35e79
7
+ data.tar.gz: ce45456a29ebf673ea5a6b987990c70c784387db86804555edebe16812322d31534ff877aae37c071419dae0b26ba6052db2a51b31b5ebd1652f4282b8cbb7a8
@@ -3,7 +3,7 @@ require 'rails/generators/active_record'
3
3
  class ImmigrationGenerator < ActiveRecord::Generators::Base
4
4
  def create_immigration_file
5
5
  Rails.application.eager_load!
6
- @keys, warnings = Immigrant.infer_keys
6
+ @keys, warnings = Immigrant::KeyFinder.new.infer_keys
7
7
  warnings.values.each{ |warning| $stderr.puts "WARNING: #{warning}" }
8
8
  @keys.each do |key|
9
9
  next unless key.options[:dependent] == :delete
@@ -1,11 +1,12 @@
1
- module Immigrant
2
- ForeignKeyDefinition = ::Foreigner::ConnectionAdapters::ForeignKeyDefinition
1
+ require_relative 'foreigner'
3
2
 
3
+ module Immigrant
4
4
  TEMPLATE = 'immigration-pre-3.1.rb.erb'
5
5
  FOREIGN_KEY = :primary_key_name
6
- ON_DELETE = :dependent
7
6
 
8
- def self.qualified_reflection?(reflection, klass)
9
- reflection.options[:conditions].present?
7
+ class KeyFinder
8
+ def qualified_reflection?(reflection, klass)
9
+ reflection.options[:conditions].present?
10
+ end
10
11
  end
11
12
  end
@@ -1,12 +1,13 @@
1
- module Immigrant
2
- ForeignKeyDefinition = ::Foreigner::ConnectionAdapters::ForeignKeyDefinition
1
+ require_relative 'foreigner'
3
2
 
3
+ module Immigrant
4
4
  TEMPLATE = 'immigration.rb.erb'
5
5
  FOREIGN_KEY = :foreign_key
6
- ON_DELETE = :dependent
7
6
 
8
- def self.qualified_reflection?(reflection, klass)
9
- reflection.options[:conditions].present?
7
+ class KeyFinder
8
+ def qualified_reflection?(reflection, klass)
9
+ reflection.options[:conditions].present?
10
+ end
10
11
  end
11
12
  end
12
13
 
@@ -1,22 +1,21 @@
1
- module Immigrant
2
- ForeignKeyDefinition = ::Foreigner::ConnectionAdapters::ForeignKeyDefinition
1
+ require_relative 'foreigner'
3
2
 
3
+ module Immigrant
4
4
  TEMPLATE = 'immigration.rb.erb'
5
5
  FOREIGN_KEY = :foreign_key
6
- ON_DELETE = :dependent
7
6
 
8
- def self.qualified_reflection?(reflection, klass)
9
- scope = reflection.scope
10
- if scope.nil?
11
- false
12
- elsif scope.respond_to?(:options)
13
- scope.options[:where].present?
14
- else
15
- klass.instance_exec(*([nil]*scope.arity), &scope).where_values.present?
7
+ class KeyFinder
8
+ def qualified_reflection?(reflection, klass)
9
+ scope = reflection.scope
10
+ if scope.nil?
11
+ false
12
+ else
13
+ klass.instance_exec(*([nil]*scope.arity), &scope).where_values.present?
14
+ end
15
+ rescue
16
+ # if there's an error evaluating the scope block or whatever, just
17
+ # err on the side of caution and assume there are conditions
18
+ true
16
19
  end
17
- rescue
18
- # if there's an error evaluating the scope block or whatever, just
19
- # err on the side of caution and assume there are conditions
20
- true
21
20
  end
22
21
  end
@@ -1,60 +1,18 @@
1
- require "active_record/connection_adapters/abstract/schema_definitions"
1
+ require_relative 'active_record'
2
2
 
3
3
  module Immigrant
4
- ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
5
-
6
- TEMPLATE = 'immigration.rb.erb'
7
- FOREIGN_KEY = :foreign_key
8
- ON_DELETE = :on_delete
9
-
10
- def self.qualified_reflection?(reflection, klass)
11
- scope = reflection.scope
12
- if scope.nil?
13
- false
14
- elsif scope.respond_to?(:options)
15
- scope.options[:where].present?
16
- else
17
- klass.instance_exec(*([nil]*scope.arity), &scope).where_values.present?
18
- end
19
- rescue
20
- # if there's an error evaluating the scope block or whatever, just
21
- # err on the side of caution and assume there are conditions
22
- true
23
- end
24
-
25
- module ForeignKeyExtensions
26
- # DRY alert: copied from ActiveRecord::SchemaDumper#foreign_keys
27
- def dump_foreign_key(foreign_key)
28
- parts = [
29
- "add_foreign_key #{remove_prefix_and_suffix(foreign_key.from_table).inspect}",
30
- remove_prefix_and_suffix(foreign_key.to_table).inspect,
31
- ]
32
-
33
- if foreign_key.column != foreign_key_column_for(foreign_key.to_table)
34
- parts << "column: #{foreign_key.column.inspect}"
35
- end
36
-
37
- if foreign_key.custom_primary_key?
38
- parts << "primary_key: #{foreign_key.primary_key.inspect}"
4
+ class KeyFinder
5
+ def qualified_reflection?(reflection, klass)
6
+ scope = reflection.scope
7
+ if scope.nil?
8
+ false
9
+ else
10
+ klass.instance_exec(*([nil]*scope.arity), &scope).where_values.present?
39
11
  end
40
-
41
- if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
42
- parts << "name: #{foreign_key.name.inspect}"
43
- end
44
-
45
- parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
46
- parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
47
-
48
- " #{parts.join(', ')}"
49
- end
50
-
51
-
52
- def remove_prefix_and_suffix(table)
53
- table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
54
- end
55
-
56
- def foreign_key_column_for(table_name)
57
- "#{table_name.to_s.singularize}_id"
12
+ rescue
13
+ # if there's an error evaluating the scope block or whatever, just
14
+ # err on the side of caution and assume there are conditions
15
+ true
58
16
  end
59
17
  end
60
18
  end
@@ -0,0 +1 @@
1
+ require_relative 'active_record'
@@ -0,0 +1,44 @@
1
+ require "active_record/connection_adapters/abstract/schema_definitions"
2
+
3
+ module Immigrant
4
+ ForeignKeyDefinition = ::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
5
+
6
+ TEMPLATE = 'immigration.rb.erb'
7
+ FOREIGN_KEY = :foreign_key
8
+
9
+ module ForeignKeyExtensions
10
+ # DRY alert: copied from ActiveRecord::SchemaDumper#foreign_keys
11
+ def dump_foreign_key(foreign_key)
12
+ parts = [
13
+ "add_foreign_key #{remove_prefix_and_suffix(foreign_key.from_table).inspect}",
14
+ remove_prefix_and_suffix(foreign_key.to_table).inspect,
15
+ ]
16
+
17
+ if foreign_key.column != foreign_key_column_for(foreign_key.to_table)
18
+ parts << "column: #{foreign_key.column.inspect}"
19
+ end
20
+
21
+ if foreign_key.custom_primary_key?
22
+ parts << "primary_key: #{foreign_key.primary_key.inspect}"
23
+ end
24
+
25
+ if foreign_key.name !~ /^fk_rails_[0-9a-f]{10}$/
26
+ parts << "name: #{foreign_key.name.inspect}"
27
+ end
28
+
29
+ parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
30
+ parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
31
+
32
+ parts.join(', ')
33
+ end
34
+
35
+
36
+ def remove_prefix_and_suffix(table)
37
+ table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, "\\2")
38
+ end
39
+
40
+ def foreign_key_column_for(table_name)
41
+ "#{table_name.to_s.singularize}_id"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ begin
2
+ require 'foreigner'
3
+ rescue LoadError
4
+ $stderr.puts <<-ERR.strip_heredoc
5
+
6
+ ERROR: immigrant requires the foreigner gem (unless you are on rails 4.2+)
7
+
8
+ To fix this, add the following to your Gemfile:
9
+
10
+ gem "foreigner", "~> 1.2"
11
+
12
+ Or just upgrade rails ;) ... lol, "just"
13
+
14
+ ERR
15
+ exit 1
16
+ end
17
+ Foreigner.load
18
+
19
+ module Immigrant
20
+ ForeignKeyDefinition = ::Foreigner::ConnectionAdapters::ForeignKeyDefinition
21
+
22
+ module ForeignKeyExtensions
23
+ include Foreigner::SchemaDumper::ClassMethods
24
+
25
+ def self.included(klass)
26
+ # ForeignKeyExtensions already overrides initialize; override it
27
+ # some more
28
+ klass.send(:include, Module.new{
29
+ def initialize(from_table, to_table, options)
30
+ options.delete(:on_update)
31
+ options[:dependent] = normalize_dependent(options.delete(:on_delete))
32
+ super
33
+ end
34
+ })
35
+ end
36
+
37
+ def normalize_dependent(value)
38
+ case value
39
+ when :cascade then :delete
40
+ else value
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,57 +1,13 @@
1
1
  version = ActiveRecord::VERSION::STRING
2
2
 
3
- if version >= '4.2.'
3
+ if version >= '5.0.'
4
+ require_relative 'compat/5.0'
5
+ elsif version >= '4.2.'
4
6
  require_relative 'compat/4.2'
7
+ elsif version >= '4.0'
8
+ require_relative 'compat/4.0'
9
+ elsif version >= '3.1'
10
+ require_relative 'compat/3.1'
5
11
  else
6
- begin
7
- require 'foreigner'
8
- rescue LoadError
9
- $stderr.puts <<-ERR.strip_heredoc
10
-
11
- ERROR: immigrant requires the foreigner gem (unless you are on rails 4.2+)
12
-
13
- To fix this, add the following to your Gemfile:
14
-
15
- gem "foreigner", "~> 1.2"
16
-
17
- Or just upgrade rails ;) ... lol, "just"
18
-
19
- ERR
20
- exit 1
21
- end
22
- Foreigner.load
23
-
24
- require_relative 'compat/foreigner_extensions'
25
-
26
- if version >= '4.0'
27
- require_relative 'compat/4.0'
28
- elsif version >= '3.1'
29
- require_relative 'compat/3.1'
30
- else
31
- require_relative 'compat/3.0'
32
- end
33
- end
34
-
35
- # add some useful things for querying/comparing/dumping foreign keys
36
- module Immigrant
37
- module ForeignKeyExtensions
38
- def initialize(from_table, to_table, options, *args)
39
- options ||= {}
40
- options[:name] ||= "#{from_table}_#{options[:column]}_fk"
41
- super(from_table, to_table, options, *args)
42
- end
43
-
44
- def hash_key
45
- [from_table, options[:column]]
46
- end
47
-
48
- def to_ruby(action = :add)
49
- if action == :add
50
- dump_foreign_key(self)
51
- else
52
- "remove_foreign_key #{from_table.inspect}, " \
53
- ":name => #{options[:name].inspect}"
54
- end
55
- end
56
- end
12
+ require_relative 'compat/3.0'
57
13
  end
@@ -0,0 +1,23 @@
1
+ # add some useful things for querying/comparing/dumping foreign keys
2
+ module Immigrant
3
+ module ForeignKeyExtensions
4
+ def initialize(from_table, to_table, options, *args)
5
+ options ||= {}
6
+ options[:name] ||= "#{from_table}_#{options[:column]}_fk"
7
+ super(from_table, to_table, options, *args)
8
+ end
9
+
10
+ def hash_key
11
+ [from_table, options[:column]]
12
+ end
13
+
14
+ def to_ruby(action = :add)
15
+ if action == :add
16
+ dump_foreign_key(self)
17
+ else
18
+ "remove_foreign_key #{from_table.inspect}, " \
19
+ ":name => #{options[:name].inspect}"
20
+ end
21
+ end
22
+ end
23
+ end
data/lib/immigrant.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'active_support/all'
2
2
 
3
3
  module Immigrant
4
- class << self
4
+ class KeyFinder
5
5
  def infer_keys(db_keys = current_foreign_keys, classes = model_classes)
6
6
  database_keys = db_keys.inject({}) { |hash, foreign_key|
7
7
  hash[foreign_key.hash_key] = foreign_key
@@ -27,8 +27,12 @@ module Immigrant
27
27
 
28
28
  private
29
29
 
30
+ def tables
31
+ @tables ||= ActiveRecord::Base.connection.tables
32
+ end
33
+
30
34
  def current_foreign_keys
31
- ActiveRecord::Base.connection.tables.map{ |table|
35
+ tables.map{ |table|
32
36
  ActiveRecord::Base.connection.foreign_keys(table)
33
37
  }.flatten
34
38
  end
@@ -81,16 +85,17 @@ module Immigrant
81
85
  end
82
86
 
83
87
  def foreign_keys_for(klass)
88
+ return [] if klass.abstract_class? || !tables.include?(klass.table_name)
84
89
  candidate_reflections_for(klass).inject([]) do |result, reflection|
85
90
  begin
86
- result.concat foreign_key_for(klass, reflection)
91
+ result.concat foreign_keys_for_reflection(klass, reflection)
87
92
  rescue NameError # e.g. belongs_to :oops_this_is_not_a_table
88
93
  result
89
94
  end
90
95
  end
91
96
  end
92
97
 
93
- def foreign_key_for(klass, reflection)
98
+ def foreign_keys_for_reflection(klass, reflection)
94
99
  case reflection.macro
95
100
  when :belongs_to
96
101
  infer_belongs_to_keys(klass, reflection)
@@ -98,59 +103,112 @@ module Immigrant
98
103
  infer_has_n_keys(klass, reflection)
99
104
  when :has_and_belongs_to_many
100
105
  infer_habtm_keys(klass, reflection)
101
- else
102
- []
103
- end
106
+ end || []
104
107
  end
105
108
 
106
109
  def infer_belongs_to_keys(klass, reflection)
107
- return [] if reflection.name == :left_side # redundant and unusable reflection automagically created by HABTM
110
+ return if reflection.name == :left_side # redundant and unusable reflection automagically created by HABTM
111
+
112
+ from_table = klass.table_name
113
+ to_table = reflection.klass.table_name
114
+ column = reflection.send(FOREIGN_KEY).to_s
115
+ primary_key = (reflection.options[:primary_key] || reflection.klass.primary_key).to_s
116
+
117
+ return unless column_exists?(from_table, column)
118
+
108
119
  [
109
120
  ForeignKeyDefinition.new(
110
- klass.table_name,
111
- reflection.klass.table_name,
112
- :column => reflection.send(FOREIGN_KEY).to_s,
113
- :primary_key => (reflection.options[:primary_key] || reflection.klass.primary_key).to_s,
121
+ from_table,
122
+ to_table,
123
+ :column => column,
124
+ :primary_key => primary_key
114
125
  # although belongs_to can specify :dependent, it doesn't make
115
- # sense from a foreign key perspective
116
- ON_DELETE => nil
126
+ # sense from a foreign key perspective, so no :on_delete
117
127
  )
118
128
  ]
119
129
  end
120
130
 
121
131
  def infer_has_n_keys(klass, reflection)
132
+ from_table = reflection.klass.table_name
133
+ to_table = klass.table_name
134
+ column = reflection.send(FOREIGN_KEY).to_s
135
+ primary_key = (reflection.options[:primary_key] || klass.primary_key).to_s
136
+
137
+ actions = {}
138
+ if [:delete, :delete_all].include?(reflection.options[:dependent]) && !qualified_reflection?(reflection, klass)
139
+ actions = {:on_delete => :cascade, :on_update => :cascade}
140
+ end
141
+
142
+ return unless column_exists?(from_table, column)
143
+
122
144
  [
123
145
  ForeignKeyDefinition.new(
124
- reflection.klass.table_name,
125
- klass.table_name,
126
- :column => reflection.send(FOREIGN_KEY).to_s,
127
- :primary_key => (reflection.options[:primary_key] || klass.primary_key).to_s,
128
- ON_DELETE => [:delete, :delete_all].include?(reflection.options[:dependent]) && !qualified_reflection?(reflection, klass) ? :delete : nil
146
+ from_table,
147
+ to_table,
148
+ {
149
+ :column => column,
150
+ :primary_key => primary_key
151
+ }.merge(actions)
129
152
  )
130
153
  ]
131
154
  end
132
155
 
133
156
  def infer_habtm_keys(klass, reflection)
157
+ keys = []
158
+
134
159
  join_table = (reflection.respond_to?(:join_table) ? reflection.join_table : reflection.options[:join_table]).to_s
135
- [
136
- ForeignKeyDefinition.new(
160
+
161
+ left_to_table = klass.table_name
162
+ left_column = reflection.send(FOREIGN_KEY).to_s
163
+ left_primary_key = klass.primary_key.to_s
164
+ if column_exists?(join_table, left_column)
165
+ keys << ForeignKeyDefinition.new(
137
166
  join_table,
138
- klass.table_name,
139
- :column => reflection.send(FOREIGN_KEY).to_s,
140
- :primary_key => klass.primary_key.to_s,
141
- ON_DELETE => nil
142
- ),
143
- ForeignKeyDefinition.new(
167
+ left_to_table,
168
+ :column => left_column,
169
+ :primary_key => left_primary_key
170
+ )
171
+ end
172
+
173
+ right_to_table = reflection.klass.table_name
174
+ right_column = reflection.association_foreign_key.to_s
175
+ right_primary_key = reflection.klass.primary_key.to_s
176
+ if column_exists?(join_table, left_column)
177
+ keys << ForeignKeyDefinition.new(
144
178
  join_table,
145
- reflection.klass.table_name,
146
- :column => reflection.association_foreign_key.to_s,
147
- :primary_key => reflection.klass.primary_key.to_s,
148
- ON_DELETE => nil
179
+ right_to_table,
180
+ :column => right_column,
181
+ :primary_key => right_primary_key
149
182
  )
150
- ]
183
+ end
184
+
185
+ keys
186
+ end
187
+
188
+ def column_exists?(table_name, column_name)
189
+ columns_for(table_name).any? { |column| column.name == column_name }
190
+ end
191
+
192
+ def columns_for(table_name)
193
+ @columns ||= {}
194
+ @columns[table_name] ||= ActiveRecord::Base.connection.columns(table_name)
195
+ end
196
+
197
+ def qualified_reflection?(reflection, klass)
198
+ scope = reflection.scope
199
+ if scope.nil?
200
+ false
201
+ else
202
+ klass.instance_exec(*([nil]*scope.arity), &scope).where_clause.any?
203
+ end
204
+ rescue
205
+ # if there's an error evaluating the scope block or whatever, just
206
+ # err on the side of caution and assume there are conditions
207
+ true
151
208
  end
152
209
  end
153
210
  end
154
211
 
155
212
  require 'immigrant/loader'
213
+ require 'immigrant/foreign_key_extensions'
156
214
  require 'immigrant/railtie' if defined?(Rails)
data/test/helper.rb CHANGED
@@ -3,6 +3,7 @@ require 'bundler/setup'
3
3
  Bundler.require(:default)
4
4
 
5
5
  require 'minitest/autorun'
6
+ require 'minitest/stub_any_instance'
6
7
 
7
8
  require 'active_record'
8
9
  require_relative "compat"
@@ -3,22 +3,19 @@ require 'helper'
3
3
  class ImmigrantTest < ActiveSupport::TestCase
4
4
  include TestMethods
5
5
 
6
- class MockModel < ActiveRecord::Base
7
- self.abstract_class = true
8
- class << self
9
- def primary_key
10
- connection.primary_key(table_name)
11
- end
12
- def connection
13
- @connection ||= MockConnection.new
14
- end
6
+ ActiveRecord::Base.instance_eval do
7
+ def primary_key
8
+ connection.primary_key(table_name)
9
+ end
10
+ def connection
11
+ @connection ||= MockConnection.new
15
12
  end
16
13
 
17
14
  if ActiveRecord::VERSION::STRING >= '4.'
18
15
  # support old 3.x syntax for the sake of concise tests
19
- [:belongs_to, :has_one, :has_many, :has_and_belongs_to_many].each do |method|
20
- instance_eval <<-CODE, __FILE__, __LINE__ + 1
21
- def self.#{method}(assoc, scope = nil, options = {})
16
+ extend(Module.new{
17
+ [:belongs_to, :has_one, :has_many, :has_and_belongs_to_many].each do |method|
18
+ define_method method do |assoc, scope = nil, options = {}|
22
19
  if scope.is_a?(Hash)
23
20
  options = scope
24
21
  scope_opts = options.extract!(:conditions, :order)
@@ -28,8 +25,8 @@ class ImmigrantTest < ActiveSupport::TestCase
28
25
  end
29
26
  super assoc, scope, options
30
27
  end
31
- CODE
32
- end
28
+ end
29
+ })
33
30
  end
34
31
  end
35
32
 
@@ -40,18 +37,27 @@ class ImmigrantTest < ActiveSupport::TestCase
40
37
  def primary_key(table)
41
38
  table.to_s !~ /s_.*s\z/ ? 'id' : nil
42
39
  end
40
+ def tables
41
+ ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base).map(&:table_name)
42
+ end
43
+ def columns(table_name)
44
+ AnyColumn.new
45
+ end
46
+ end
47
+
48
+ class AnyColumn
49
+ def any?
50
+ true
51
+ end
43
52
  end
44
53
 
45
54
  def teardown
46
- subclasses = ActiveSupport::DescendantsTracker.direct_descendants(MockModel)
55
+ subclasses = ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base)
47
56
  subclasses.each do |subclass|
48
- Object.send(:remove_const, subclass.to_s)
57
+ subclass = subclass.to_s
58
+ Object.send(:remove_const, subclass) if subclass =~ /\A[A-Z]/ && Object.const_defined?(subclass)
49
59
  end
50
60
  subclasses.replace([])
51
- # also need to clear out other things under AR::Base, because as of
52
- # 4.1 there are automagical anonymous classes due to HABTM
53
- subclasses = ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base)
54
- subclasses.replace([MockModel])
55
61
  end
56
62
 
57
63
  def given(code)
@@ -60,194 +66,183 @@ class ImmigrantTest < ActiveSupport::TestCase
60
66
  Object.class_eval code
61
67
  end
62
68
 
69
+ def infer_keys(db_keys = [])
70
+ keys = Immigrant::KeyFinder.new.infer_keys(db_keys).first
71
+ # ensure each key generates correctly
72
+ keys.each { |key| key.to_ruby(:add) }
73
+ keys.sort_by { |key| [key.from_table, key.to_table] }
74
+ end
75
+
63
76
  # basic scenarios
64
77
 
65
78
  test 'belongs_to should generate a foreign key' do
66
79
  given <<-CODE
67
- class Author < MockModel; end
68
- class Book < MockModel
80
+ class Author < ActiveRecord::Base; end
81
+ class Book < ActiveRecord::Base
69
82
  belongs_to :guy, :class_name => 'Author', :foreign_key => 'author_id'
70
83
  end
71
84
  CODE
72
85
 
73
- keys = Immigrant.infer_keys([]).first
74
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
75
86
  assert_equal(
76
87
  [foreign_key_definition(
77
88
  'books', 'authors',
78
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
89
+ :column => 'author_id', :primary_key => 'id'
79
90
  )],
80
- keys
91
+ infer_keys
81
92
  )
82
93
  end
83
94
 
84
95
  test 'has_one should generate a foreign key' do
85
96
  given <<-CODE
86
- class Author < MockModel
97
+ class Author < ActiveRecord::Base
87
98
  has_one :piece_de_resistance, :class_name => 'Book', :order => "id DESC"
88
99
  end
89
- class Book < MockModel; end
100
+ class Book < ActiveRecord::Base; end
90
101
  CODE
91
102
 
92
- keys = Immigrant.infer_keys([]).first
93
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
94
103
  assert_equal(
95
104
  [foreign_key_definition(
96
105
  'books', 'authors',
97
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
106
+ :column => 'author_id', :primary_key => 'id'
98
107
  )],
99
- keys
108
+ infer_keys
100
109
  )
101
110
  end
102
111
 
103
- test 'has_one :dependent => :delete should generate a foreign key with :on_delete => :delete' do
112
+ test 'has_one :dependent => :delete should generate a foreign key with :on_delete => :cascade' do
104
113
  given <<-CODE
105
- class Author < MockModel
114
+ class Author < ActiveRecord::Base
106
115
  has_one :book, :order => "id DESC", :dependent => :delete
107
116
  end
108
- class Book < MockModel; end
117
+ class Book < ActiveRecord::Base; end
109
118
  CODE
110
119
 
111
- keys = Immigrant.infer_keys([]).first
112
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
113
120
  assert_equal(
114
121
  [foreign_key_definition(
115
122
  'books', 'authors',
116
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => :delete
123
+ :column => 'author_id', :primary_key => 'id', :on_delete => :cascade, :on_update => :cascade
117
124
  )],
118
- keys
125
+ infer_keys
119
126
  )
120
127
  end
121
128
 
122
129
  test 'has_many should generate a foreign key' do
123
130
  given <<-CODE
124
- class Author < MockModel
131
+ class Author < ActiveRecord::Base
125
132
  has_many :babies, :class_name => 'Book'
126
133
  end
127
- class Book < MockModel; end
134
+ class Book < ActiveRecord::Base; end
128
135
  CODE
129
136
 
130
- keys = Immigrant.infer_keys([]).first
131
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
132
137
  assert_equal(
133
138
  [foreign_key_definition(
134
139
  'books', 'authors',
135
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
140
+ :column => 'author_id', :primary_key => 'id'
136
141
  )],
137
- keys
142
+ infer_keys
138
143
  )
139
144
  end
140
145
 
141
- test 'has_many :dependent => :delete_all should generate a foreign key with :on_delete => :delete' do
146
+ test 'has_many :dependent => :delete_all should generate a foreign key with :on_delete => :cascade' do
142
147
  given <<-CODE
143
- class Author < MockModel
148
+ class Author < ActiveRecord::Base
144
149
  has_many :books, :dependent => :delete_all
145
150
  end
146
- class Book < MockModel; end
151
+ class Book < ActiveRecord::Base; end
147
152
  CODE
148
153
 
149
- keys = Immigrant.infer_keys([]).first
150
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
151
154
  assert_equal(
152
155
  [foreign_key_definition(
153
156
  'books', 'authors',
154
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => :delete
157
+ :column => 'author_id', :primary_key => 'id', :on_delete => :cascade, :on_update => :cascade
155
158
  )],
156
- keys
159
+ infer_keys
157
160
  )
158
161
  end
159
162
 
160
163
  test 'has_and_belongs_to_many should generate two foreign keys' do
161
164
  given <<-CODE
162
- class Author < MockModel
165
+ class Author < ActiveRecord::Base
163
166
  has_and_belongs_to_many :fans
164
167
  end
165
- class Fan < MockModel; end
168
+ class Fan < ActiveRecord::Base; end
166
169
  CODE
167
170
 
168
- keys = Immigrant.infer_keys([]).first
169
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
170
171
  assert_equal(
171
172
  [foreign_key_definition(
172
173
  'authors_fans', 'authors',
173
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
174
+ :column => 'author_id', :primary_key => 'id'
174
175
  ),
175
176
  foreign_key_definition(
176
177
  'authors_fans', 'fans',
177
- :column => 'fan_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
178
+ :column => 'fan_id', :primary_key => 'id'
178
179
  )],
179
- keys
180
+ infer_keys
180
181
  )
181
182
  end
182
183
 
183
184
  test 'has_and_belongs_to_many should respect the join_table' do
184
185
  given <<-CODE
185
- class Author < MockModel
186
+ class Author < ActiveRecord::Base
186
187
  has_and_belongs_to_many :fans, :join_table => :lols_wuts
187
188
  end
188
- class Fan < MockModel; end
189
+ class Fan < ActiveRecord::Base; end
189
190
  CODE
190
191
 
191
- keys = Immigrant.infer_keys([]).first
192
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
193
192
  assert_equal(
194
193
  [foreign_key_definition(
195
194
  'lols_wuts', 'authors',
196
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
195
+ :column => 'author_id', :primary_key => 'id'
197
196
  ),
198
197
  foreign_key_definition(
199
198
  'lols_wuts', 'fans',
200
- :column => 'fan_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
199
+ :column => 'fan_id', :primary_key => 'id'
201
200
  )],
202
- keys
201
+ infer_keys
203
202
  )
204
203
  end
205
204
 
206
205
  test 'conditional has_one/has_many associations should ignore :dependent' do
207
206
  given <<-CODE
208
- class Author < MockModel
207
+ class Author < ActiveRecord::Base
209
208
  has_many :articles, :conditions => "published", :dependent => :delete_all
210
209
  has_one :favorite_book, :class_name => 'Book',
211
210
  :conditions => "most_awesome", :dependent => :delete
212
211
  end
213
- class Book < MockModel; end
214
- class Article < MockModel; end
212
+ class Book < ActiveRecord::Base; end
213
+ class Article < ActiveRecord::Base; end
215
214
  CODE
216
215
 
217
- keys = Immigrant.infer_keys([]).first
218
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
219
216
  assert_equal(
220
217
  [foreign_key_definition(
221
218
  'articles', 'authors',
222
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
219
+ :column => 'author_id', :primary_key => 'id'
223
220
  ),
224
221
  foreign_key_definition(
225
222
  'books', 'authors',
226
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
223
+ :column => 'author_id', :primary_key => 'id'
227
224
  )],
228
- keys
225
+ infer_keys
229
226
  )
230
227
  end
231
228
 
232
229
  test 'primary_key should be respected' do
233
230
  given <<-CODE
234
- class User < MockModel
231
+ class User < ActiveRecord::Base
235
232
  has_many :emails, :primary_key => :email, :foreign_key => :to,
236
233
  :dependent => :destroy
237
234
  end
238
- class Email < MockModel
235
+ class Email < ActiveRecord::Base
239
236
  belongs_to :user, :primary_key => :email, :foreign_key => :to
240
237
  end
241
238
  CODE
242
239
 
243
- keys = Immigrant.infer_keys([]).first
244
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
245
240
  assert_equal(
246
241
  [foreign_key_definition(
247
242
  'emails', 'users',
248
- :column => 'to', :primary_key => 'email', Immigrant::ON_DELETE => nil
243
+ :column => 'to', :primary_key => 'email'
249
244
  )],
250
- keys
245
+ infer_keys
251
246
  )
252
247
  end
253
248
 
@@ -255,64 +250,58 @@ class ImmigrantTest < ActiveSupport::TestCase
255
250
 
256
251
  test 'STI should not generate duplicate foreign keys' do
257
252
  given <<-CODE
258
- class Company < MockModel; end
259
- class Employee < MockModel
253
+ class Company < ActiveRecord::Base; end
254
+ class Employee < ActiveRecord::Base
260
255
  belongs_to :company
261
256
  end
262
257
  class Manager < Employee; end
263
258
  CODE
264
259
 
265
260
  assert(Manager.reflections.present?)
266
- keys = Immigrant.infer_keys([]).first
267
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
268
261
  assert_equal(
269
262
  [foreign_key_definition(
270
263
  'employees', 'companies',
271
- :column => 'company_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
264
+ :column => 'company_id', :primary_key => 'id'
272
265
  )],
273
- keys
266
+ infer_keys
274
267
  )
275
268
  end
276
269
 
277
270
  test 'complementary associations should not generate duplicate foreign keys' do
278
271
  given <<-CODE
279
- class Author < MockModel
272
+ class Author < ActiveRecord::Base
280
273
  has_many :books
281
274
  end
282
- class Book < MockModel
275
+ class Book < ActiveRecord::Base
283
276
  belongs_to :author
284
277
  end
285
278
  CODE
286
279
 
287
- keys = Immigrant.infer_keys([]).first
288
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
289
280
  assert_equal(
290
281
  [foreign_key_definition(
291
282
  'books', 'authors',
292
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
283
+ :column => 'author_id', :primary_key => 'id'
293
284
  )],
294
- keys
285
+ infer_keys
295
286
  )
296
287
  end
297
288
 
298
289
  test 'redundant associations should not generate duplicate foreign keys' do
299
290
  given <<-CODE
300
- class Author < MockModel
291
+ class Author < ActiveRecord::Base
301
292
  has_many :books
302
293
  has_many :favorite_books, :class_name => 'Book', :conditions => "awesome"
303
294
  has_many :bad_books, :class_name => 'Book', :conditions => "amateur_hour"
304
295
  end
305
- class Book < MockModel; end
296
+ class Book < ActiveRecord::Base; end
306
297
  CODE
307
298
 
308
- keys = Immigrant.infer_keys([]).first
309
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
310
299
  assert_equal(
311
300
  [foreign_key_definition(
312
301
  'books', 'authors',
313
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
302
+ :column => 'author_id', :primary_key => 'id'
314
303
  )],
315
- keys
304
+ infer_keys
316
305
  )
317
306
  end
318
307
 
@@ -323,33 +312,32 @@ class ImmigrantTest < ActiveSupport::TestCase
323
312
  database_keys = [
324
313
  foreign_key_definition(
325
314
  'articles', 'authors',
326
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil,
315
+ :column => 'author_id', :primary_key => 'id',
327
316
  :name => "doesn't_matter"
328
317
  ),
329
318
  foreign_key_definition(
330
319
  'books', 'authors', :column => 'author_id', :primary_key => 'id',
331
- Immigrant::ON_DELETE => :delete
320
+ :on_delete => :restrict, :on_update => :nullify
332
321
  )
333
322
  ]
334
323
 
335
324
  given <<-CODE
336
- class Author < MockModel
325
+ class Author < ActiveRecord::Base
337
326
  has_many :articles
338
327
  has_one :favorite_book, :class_name => 'Book',
339
328
  :conditions => "most_awesome"
340
329
  end
341
- class Book < MockModel; end
342
- class Article < MockModel; end
330
+ class Book < ActiveRecord::Base; end
331
+ class Article < ActiveRecord::Base; end
343
332
  CODE
344
333
 
345
- keys = Immigrant.infer_keys(database_keys).first
346
- assert_equal([], keys)
334
+ assert_equal([], infer_keys(database_keys))
347
335
  end
348
336
 
349
337
  if ActiveRecord::VERSION::STRING < '4.'
350
338
  test 'finder_sql associations should not generate foreign keys' do
351
339
  given <<-CODE
352
- class Author < MockModel
340
+ class Author < ActiveRecord::Base
353
341
  has_many :books, :finder_sql => <<-SQL
354
342
  SELECT *
355
343
  FROM books
@@ -357,79 +345,113 @@ class ImmigrantTest < ActiveSupport::TestCase
357
345
  ORDER BY RANDOM() LIMIT 5'
358
346
  SQL
359
347
  end
360
- class Book < MockModel; end
348
+ class Book < ActiveRecord::Base; end
361
349
  CODE
362
350
 
363
- keys = Immigrant.infer_keys([]).first
364
- assert_equal([], keys)
351
+ assert_equal([], infer_keys)
365
352
  end
366
353
  end
367
354
 
368
355
  test 'polymorphic associations should not generate foreign keys' do
369
356
  given <<-CODE
370
- class Property < MockModel
357
+ class Property < ActiveRecord::Base
371
358
  belongs_to :owner, :polymorphic => true
372
359
  end
373
- class Person < MockModel
360
+ class Person < ActiveRecord::Base
374
361
  has_many :properties, :as => :owner
375
362
  end
376
- class Corporation < MockModel
363
+ class Corporation < ActiveRecord::Base
377
364
  has_many :properties, :as => :owner
378
365
  end
379
366
  CODE
380
367
 
381
- keys = Immigrant.infer_keys([]).first
382
- assert_equal([], keys)
368
+ assert_equal([], infer_keys)
383
369
  end
384
370
 
385
371
  test 'has_many :through should not generate foreign keys' do
386
372
  given <<-CODE
387
- class Author < MockModel
373
+ class Author < ActiveRecord::Base
388
374
  has_many :authors_fans
389
375
  has_many :fans, :through => :authors_fans
390
376
  end
391
- class AuthorsFan < MockModel
377
+ class AuthorsFan < ActiveRecord::Base
392
378
  belongs_to :author
393
379
  belongs_to :fan
394
380
  end
395
- class Fan < MockModel
381
+ class Fan < ActiveRecord::Base
396
382
  has_many :authors_fans
397
383
  has_many :authors, :through => :authors_fans
398
384
  end
399
385
  CODE
400
386
 
401
- keys = Immigrant.infer_keys([]).first
402
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
403
387
  assert_equal(
404
388
  [foreign_key_definition(
405
389
  'authors_fans', 'authors',
406
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
390
+ :column => 'author_id', :primary_key => 'id'
407
391
  ),
408
392
  foreign_key_definition(
409
393
  'authors_fans', 'fans',
410
- :column => 'fan_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
394
+ :column => 'fan_id', :primary_key => 'id'
411
395
  )],
412
- keys
396
+ infer_keys
413
397
  )
414
398
  end
415
399
 
416
400
  test 'broken associations should not cause errors' do
417
401
  given <<-CODE
418
- class Author < MockModel; end
419
- class Book < MockModel
402
+ class Author < ActiveRecord::Base; end
403
+ class Book < ActiveRecord::Base
420
404
  belongs_to :author
421
405
  belongs_to :invalid
422
406
  end
423
407
  CODE
424
408
 
425
- keys = Immigrant.infer_keys([]).first
426
- assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
427
409
  assert_equal(
428
410
  [foreign_key_definition(
429
411
  'books', 'authors',
430
- :column => 'author_id', :primary_key => 'id', Immigrant::ON_DELETE => nil
412
+ :column => 'author_id', :primary_key => 'id'
431
413
  )],
432
- keys
414
+ infer_keys
433
415
  )
434
416
  end
417
+
418
+ test 'abstract classes should not generate a foreign key' do
419
+ given <<-CODE
420
+ class User < ActiveRecord::Base; end
421
+ class Widget < ActiveRecord::Base
422
+ self.abstract_class = true
423
+
424
+ belongs_to :user
425
+ end
426
+ CODE
427
+
428
+ assert_equal([], infer_keys)
429
+ end
430
+
431
+ test 'missing tables should not generate a foreign key' do
432
+ given <<-CODE
433
+ class User < ActiveRecord::Base; end
434
+ class Widget < ActiveRecord::Base
435
+ self.table_name = :wiiiidgets
436
+ belongs_to :user
437
+ end
438
+ CODE
439
+
440
+ MockConnection.stub_any_instance(:tables, ["users"]) do
441
+ assert_equal([], infer_keys)
442
+ end
443
+ end
444
+
445
+ test 'invalid columns should not generate a foreign key' do
446
+ given <<-CODE
447
+ class User < ActiveRecord::Base; end
448
+ class Widget < ActiveRecord::Base
449
+ belongs_to :user
450
+ end
451
+ CODE
452
+
453
+ MockConnection.stub_any_instance(:columns, []) do
454
+ assert_equal([], infer_keys)
455
+ end
456
+ end
435
457
  end
metadata CHANGED
@@ -1,30 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immigrant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
5
- prerelease:
4
+ version: 0.3.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jon Jensen
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-12-11 00:00:00.000000000 Z
11
+ date: 2015-02-24 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activerecord
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '3.0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '3.0'
30
27
  description: Adds a generator for creating a foreign key migration based on your current
@@ -35,47 +32,48 @@ extensions: []
35
32
  extra_rdoc_files: []
36
33
  files:
37
34
  - LICENSE.txt
38
- - Rakefile
39
35
  - README.md
36
+ - Rakefile
40
37
  - lib/generators/USAGE
41
38
  - lib/generators/immigration_generator.rb
42
39
  - lib/generators/templates/immigration-pre-3.1.rb.erb
43
40
  - lib/generators/templates/immigration.rb.erb
41
+ - lib/immigrant.rb
42
+ - lib/immigrant/compat.rb
44
43
  - lib/immigrant/compat/3.0.rb
45
44
  - lib/immigrant/compat/3.1.rb
46
45
  - lib/immigrant/compat/4.0.rb
47
46
  - lib/immigrant/compat/4.2.rb
48
- - lib/immigrant/compat/foreigner_extensions.rb
49
- - lib/immigrant/compat.rb
47
+ - lib/immigrant/compat/5.0.rb
48
+ - lib/immigrant/compat/active_record.rb
49
+ - lib/immigrant/compat/foreigner.rb
50
+ - lib/immigrant/foreign_key_extensions.rb
50
51
  - lib/immigrant/loader.rb
51
52
  - lib/immigrant/railtie.rb
52
- - lib/immigrant.rb
53
53
  - test/compat.rb
54
54
  - test/helper.rb
55
55
  - test/immigrant_test.rb
56
56
  homepage: http://github.com/jenseng/immigrant
57
57
  licenses: []
58
+ metadata: {}
58
59
  post_install_message:
59
60
  rdoc_options: []
60
61
  require_paths:
61
62
  - lib
62
63
  required_ruby_version: !ruby/object:Gem::Requirement
63
- none: false
64
64
  requirements:
65
- - - ! '>='
65
+ - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: 1.8.7
68
68
  required_rubygems_version: !ruby/object:Gem::Requirement
69
- none: false
70
69
  requirements:
71
- - - ! '>='
70
+ - - ">="
72
71
  - !ruby/object:Gem::Version
73
72
  version: 1.3.5
74
73
  requirements: []
75
74
  rubyforge_project:
76
- rubygems_version: 1.8.23.2
75
+ rubygems_version: 2.2.2
77
76
  signing_key:
78
- specification_version: 3
77
+ specification_version: 4
79
78
  summary: Foreign key migration generator for Rails
80
79
  test_files: []
81
- has_rdoc:
@@ -1,5 +0,0 @@
1
- module Immigrant
2
- module ForeignKeyExtensions
3
- include Foreigner::SchemaDumper::ClassMethods
4
- end
5
- end