activerecord-import 0.12.0 → 0.13.0

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +49 -0
  3. data/.rubocop_todo.yml +36 -0
  4. data/.travis.yml +31 -7
  5. data/CHANGELOG.md +19 -0
  6. data/Gemfile +5 -2
  7. data/README.markdown +6 -1
  8. data/Rakefile +5 -2
  9. data/activerecord-import.gemspec +1 -1
  10. data/benchmarks/benchmark.rb +67 -68
  11. data/benchmarks/lib/base.rb +136 -137
  12. data/benchmarks/lib/cli_parser.rb +106 -107
  13. data/benchmarks/lib/mysql2_benchmark.rb +19 -21
  14. data/benchmarks/lib/output_to_csv.rb +2 -1
  15. data/benchmarks/lib/output_to_html.rb +8 -13
  16. data/benchmarks/schema/mysql_schema.rb +8 -8
  17. data/gemfiles/4.0.gemfile +1 -1
  18. data/gemfiles/4.1.gemfile +1 -1
  19. data/gemfiles/4.2.gemfile +1 -1
  20. data/gemfiles/5.0.gemfile +1 -1
  21. data/lib/activerecord-import.rb +2 -0
  22. data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +0 -1
  23. data/lib/activerecord-import/adapters/abstract_adapter.rb +9 -9
  24. data/lib/activerecord-import/adapters/mysql_adapter.rb +17 -17
  25. data/lib/activerecord-import/adapters/postgresql_adapter.rb +20 -22
  26. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +9 -9
  27. data/lib/activerecord-import/base.rb +3 -3
  28. data/lib/activerecord-import/import.rb +152 -131
  29. data/lib/activerecord-import/synchronize.rb +20 -20
  30. data/lib/activerecord-import/value_sets_parser.rb +7 -6
  31. data/lib/activerecord-import/version.rb +1 -1
  32. data/test/adapters/mysql2spatial.rb +1 -1
  33. data/test/adapters/postgis.rb +1 -1
  34. data/test/adapters/postgresql.rb +1 -1
  35. data/test/adapters/spatialite.rb +1 -1
  36. data/test/adapters/sqlite3.rb +1 -1
  37. data/test/import_test.rb +121 -70
  38. data/test/models/book.rb +5 -6
  39. data/test/models/chapter.rb +2 -2
  40. data/test/models/discount.rb +3 -0
  41. data/test/models/end_note.rb +2 -2
  42. data/test/models/promotion.rb +1 -1
  43. data/test/models/question.rb +1 -1
  44. data/test/models/rule.rb +2 -2
  45. data/test/models/topic.rb +3 -3
  46. data/test/models/widget.rb +1 -1
  47. data/test/postgis/import_test.rb +1 -1
  48. data/test/schema/generic_schema.rb +100 -96
  49. data/test/schema/mysql_schema.rb +5 -7
  50. data/test/sqlite3/import_test.rb +0 -2
  51. data/test/support/active_support/test_case_extensions.rb +12 -15
  52. data/test/support/assertions.rb +1 -1
  53. data/test/support/factories.rb +15 -16
  54. data/test/support/generate.rb +4 -4
  55. data/test/support/mysql/import_examples.rb +21 -21
  56. data/test/support/postgresql/import_examples.rb +83 -55
  57. data/test/support/shared_examples/on_duplicate_key_update.rb +23 -23
  58. data/test/synchronize_test.rb +2 -2
  59. data/test/test_helper.rb +6 -8
  60. data/test/value_sets_bytes_parser_test.rb +14 -17
  61. data/test/value_sets_records_parser_test.rb +6 -6
  62. metadata +7 -4
  63. data/test/travis/build.sh +0 -34
@@ -1,11 +1,11 @@
1
1
  class ActiveSupport::TestCase
2
- def Build(*args)
2
+ def Build(*args) # rubocop:disable Style/MethodName
3
3
  n = args.shift if args.first.is_a?(Numeric)
4
4
  factory = args.shift
5
5
  factory_girl_args = args.shift || {}
6
6
 
7
7
  if n
8
- Array.new.tap do |collection|
8
+ [].tap do |collection|
9
9
  n.times.each { collection << FactoryGirl.build(factory.to_s.singularize.to_sym, factory_girl_args) }
10
10
  end
11
11
  else
@@ -13,13 +13,13 @@ class ActiveSupport::TestCase
13
13
  end
14
14
  end
15
15
 
16
- def Generate(*args)
16
+ def Generate(*args) # rubocop:disable Style/MethodName
17
17
  n = args.shift if args.first.is_a?(Numeric)
18
18
  factory = args.shift
19
19
  factory_girl_args = args.shift || {}
20
20
 
21
21
  if n
22
- Array.new.tap do |collection|
22
+ [].tap do |collection|
23
23
  n.times.each { collection << FactoryGirl.create(factory.to_s.singularize.to_sym, factory_girl_args) }
24
24
  end
25
25
  else
@@ -16,68 +16,68 @@ def should_support_mysql_import_functionality
16
16
  should_update_updated_at_on_timestamp_columns
17
17
  end
18
18
 
19
- macro(:perform_import){ raise "supply your own #perform_import in a context below" }
20
- macro(:updated_topic){ Topic.find(@topic.id) }
19
+ macro(:perform_import) { raise "supply your own #perform_import in a context below" }
20
+ macro(:updated_topic) { Topic.find(@topic.id) }
21
21
 
22
- let(:columns){ %w( id title author_name author_email_address parent_id ) }
23
- let(:values){ [ [ 99, "Book", "John Doe", "john@doe.com", 17 ] ] }
24
- let(:updated_values){ [ [ 99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57 ] ] }
22
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
23
+ let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
24
+ let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
25
25
 
26
26
  macro(:perform_import) do |*opts|
27
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => update_columns, :validate => false)
27
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: update_columns, validate: false)
28
28
  end
29
29
 
30
30
  setup do
31
- Topic.import columns, values, :validate => false
31
+ Topic.import columns, values, validate: false
32
32
  @topic = Topic.find 99
33
33
  end
34
34
 
35
35
  context "using string hash map" do
36
- let(:update_columns){ { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
36
+ let(:update_columns) { { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
37
37
  should_support_on_duplicate_key_update
38
38
  should_update_fields_mentioned
39
39
  end
40
40
 
41
41
  context "using string hash map, but specifying column mismatches" do
42
- let(:update_columns){ { "title" => "author_email_address", "author_email_address" => "title", "parent_id" => "parent_id" } }
42
+ let(:update_columns) { { "title" => "author_email_address", "author_email_address" => "title", "parent_id" => "parent_id" } }
43
43
  should_support_on_duplicate_key_update
44
44
  should_update_fields_mentioned_with_hash_mappings
45
45
  end
46
46
 
47
47
  context "using symbol hash map" do
48
- let(:update_columns){ { :title => :title, :author_email_address => :author_email_address, :parent_id => :parent_id } }
48
+ let(:update_columns) { { title: :title, author_email_address: :author_email_address, parent_id: :parent_id } }
49
49
  should_support_on_duplicate_key_update
50
50
  should_update_fields_mentioned
51
51
  end
52
52
 
53
53
  context "using symbol hash map, but specifying column mismatches" do
54
- let(:update_columns){ { :title => :author_email_address, :author_email_address => :title, :parent_id => :parent_id } }
54
+ let(:update_columns) { { title: :author_email_address, author_email_address: :title, parent_id: :parent_id } }
55
55
  should_support_on_duplicate_key_update
56
56
  should_update_fields_mentioned_with_hash_mappings
57
57
  end
58
58
  end
59
59
 
60
60
  context "with :synchronization option" do
61
- let(:topics){ Array.new }
62
- let(:values){ [ [topics.first.id, "Jerry Carter", "title1"], [topics.last.id, "Chad Fowler", "title2"] ]}
63
- let(:columns){ %W(id author_name title) }
61
+ let(:topics) { [] }
62
+ let(:values) { [[topics.first.id, "Jerry Carter", "title1"], [topics.last.id, "Chad Fowler", "title2"]] }
63
+ let(:columns) { %w(id author_name title) }
64
64
 
65
65
  setup do
66
- topics << Topic.create!(:title=>"LDAP", :author_name=>"Big Bird")
67
- topics << Topic.create!(:title=>"Rails Recipes", :author_name=>"Elmo")
66
+ topics << Topic.create!(title: "LDAP", author_name: "Big Bird")
67
+ topics << Topic.create!(title: "Rails Recipes", author_name: "Elmo")
68
68
  end
69
69
 
70
70
  it "synchronizes passed in ActiveRecord model instances with the data just imported" do
71
- columns2update = [ 'author_name' ]
71
+ columns2update = ['author_name']
72
72
 
73
73
  expected_count = Topic.count
74
74
  Topic.import( columns, values,
75
- :validate=>false,
76
- :on_duplicate_key_update=>columns2update,
77
- :synchronize=>topics )
75
+ validate: false,
76
+ on_duplicate_key_update: columns2update,
77
+ synchronize: topics )
78
78
 
79
79
  assert_equal expected_count, Topic.count, "no new records should have been created!"
80
- assert_equal "Jerry Carter", topics.first.author_name, "wrong author!"
80
+ assert_equal "Jerry Carter", topics.first.author_name, "wrong author!"
81
81
  assert_equal "Chad Fowler", topics.last.author_name, "wrong author!"
82
82
  end
83
83
  end
@@ -20,21 +20,21 @@ def should_support_postgresql_import_functionality
20
20
 
21
21
  describe "importing objects with associations" do
22
22
  let(:new_topics) { Build(num_topics, :topic_with_book) }
23
- let(:new_topics_with_invalid_chapter) {
24
- chapter = new_topics.first.books.first.chapters.first
25
- chapter.title = nil
26
- new_topics
27
- }
28
- let(:num_topics) {3}
29
- let(:num_books) {6}
30
- let(:num_chapters) {18}
31
- let(:num_endnotes) {24}
23
+ let(:new_topics_with_invalid_chapter) do
24
+ chapter = new_topics.first.books.first.chapters.first
25
+ chapter.title = nil
26
+ new_topics
27
+ end
28
+ let(:num_topics) { 3 }
29
+ let(:num_books) { 6 }
30
+ let(:num_chapters) { 18 }
31
+ let(:num_endnotes) { 24 }
32
32
 
33
33
  let(:new_question_with_rule) { FactoryGirl.build :question, :with_rule }
34
34
 
35
35
  it 'imports top level' do
36
36
  assert_difference "Topic.count", +num_topics do
37
- Topic.import new_topics, :recursive => true
37
+ Topic.import new_topics, recursive: true
38
38
  new_topics.each do |topic|
39
39
  assert_not_nil topic.id
40
40
  end
@@ -43,7 +43,7 @@ def should_support_postgresql_import_functionality
43
43
 
44
44
  it 'imports first level associations' do
45
45
  assert_difference "Book.count", +num_books do
46
- Topic.import new_topics, :recursive => true
46
+ Topic.import new_topics, recursive: true
47
47
  new_topics.each do |topic|
48
48
  topic.books.each do |book|
49
49
  assert_equal topic.id, book.topic_id
@@ -52,8 +52,23 @@ def should_support_postgresql_import_functionality
52
52
  end
53
53
  end
54
54
 
55
- [{:recursive => false}, {}].each do |import_options|
56
- it "skips recursion for #{import_options.to_s}" do
55
+ it 'imports polymorphic associations' do
56
+ discounts = Array.new(1) { |i| Discount.new(amount: i) }
57
+ books = Array.new(1) { |i| Book.new(author_name: "Author ##{i}", title: "Book ##{i}") }
58
+ books.each do |book|
59
+ book.discounts << discounts
60
+ end
61
+ Book.import books, recursive: true
62
+ books.each do |book|
63
+ book.discounts.each do |discount|
64
+ assert_not_nil discount.discountable_id
65
+ assert_equal 'Book', discount.discountable_type
66
+ end
67
+ end
68
+ end
69
+
70
+ [{ recursive: false }, {}].each do |import_options|
71
+ it "skips recursion for #{import_options}" do
57
72
  assert_difference "Book.count", 0 do
58
73
  Topic.import new_topics, import_options
59
74
  end
@@ -63,7 +78,7 @@ def should_support_postgresql_import_functionality
63
78
  it 'imports deeper nested associations' do
64
79
  assert_difference "Chapter.count", +num_chapters do
65
80
  assert_difference "EndNote.count", +num_endnotes do
66
- Topic.import new_topics, :recursive => true
81
+ Topic.import new_topics, recursive: true
67
82
  new_topics.each do |topic|
68
83
  topic.books.each do |book|
69
84
  book.chapters.each do |chapter|
@@ -80,7 +95,7 @@ def should_support_postgresql_import_functionality
80
95
 
81
96
  it "skips validation of the associations if requested" do
82
97
  assert_difference "Chapter.count", +num_chapters do
83
- Topic.import new_topics_with_invalid_chapter, :validate => false, :recursive => true
98
+ Topic.import new_topics_with_invalid_chapter, validate: false, recursive: true
84
99
  end
85
100
  end
86
101
 
@@ -95,15 +110,15 @@ def should_support_postgresql_import_functionality
95
110
  # being created, you would need to have validates_associated in your models and insert with validation
96
111
  describe "all_or_none" do
97
112
  [Book, Topic, EndNote].each do |type|
98
- it "creates #{type.to_s}" do
99
- assert_difference "#{type.to_s}.count", send("num_#{type.to_s.downcase}s") do
100
- Topic.import new_topics_with_invalid_chapter, :all_or_none => true, :recursive => true
113
+ it "creates #{type}" do
114
+ assert_difference "#{type}.count", send("num_#{type.to_s.downcase}s") do
115
+ Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true
101
116
  end
102
117
  end
103
118
  end
104
119
  it "doesn't create chapters" do
105
120
  assert_difference "Chapter.count", 0 do
106
- Topic.import new_topics_with_invalid_chapter, :all_or_none => true, :recursive => true
121
+ Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true
107
122
  end
108
123
  end
109
124
  end
@@ -141,35 +156,35 @@ def should_support_postgresql_upsert_functionality
141
156
  describe "#import" do
142
157
  extend ActiveSupport::TestCase::ImportAssertions
143
158
 
144
- macro(:perform_import){ raise "supply your own #perform_import in a context below" }
145
- macro(:updated_topic){ Topic.find(@topic.id) }
159
+ macro(:perform_import) { raise "supply your own #perform_import in a context below" }
160
+ macro(:updated_topic) { Topic.find(@topic.id) }
146
161
 
147
162
  context "with :on_duplicate_key_ignore and validation checks turned off" do
148
- let(:columns){ %w( id title author_name author_email_address parent_id ) }
149
- let(:values){ [ [ 99, "Book", "John Doe", "john@doe.com", 17 ] ] }
150
- let(:updated_values){ [ [ 99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57 ] ] }
163
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
164
+ let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
165
+ let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
151
166
 
152
167
  macro(:perform_import) do |*opts|
153
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_ignore => value, :validate => false)
168
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_ignore: value, validate: false)
154
169
  end
155
170
 
156
171
  setup do
157
- Topic.import columns, values, :validate => false
172
+ Topic.import columns, values, validate: false
158
173
  @topic = Topic.find 99
159
174
  end
160
175
 
161
176
  context "using true" do
162
- let(:value){ true }
177
+ let(:value) { true }
163
178
  should_not_update_updated_at_on_timestamp_columns
164
179
  end
165
180
 
166
181
  context "using hash with :conflict_target" do
167
- let(:value){ { conflict_target: :id } }
182
+ let(:value) { { conflict_target: :id } }
168
183
  should_not_update_updated_at_on_timestamp_columns
169
184
  end
170
185
 
171
186
  context "using hash with :constraint_target" do
172
- let(:value){ { constraint_name: :topics_pkey } }
187
+ let(:value) { { constraint_name: :topics_pkey } }
173
188
  should_not_update_updated_at_on_timestamp_columns
174
189
  end
175
190
  end
@@ -184,101 +199,114 @@ def should_support_postgresql_upsert_functionality
184
199
 
185
200
  context "using a hash" do
186
201
  context "with :columns a hash" do
187
- let(:columns){ %w( id title author_name author_email_address parent_id ) }
188
- let(:values){ [ [ 99, "Book", "John Doe", "john@doe.com", 17 ] ] }
189
- let(:updated_values){ [ [ 99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57 ] ] }
202
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
203
+ let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
204
+ let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
190
205
 
191
206
  macro(:perform_import) do |*opts|
192
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => { :conflict_target => :id, :columns => update_columns }, :validate => false)
207
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: { conflict_target: :id, columns: update_columns }, validate: false)
193
208
  end
194
209
 
195
210
  setup do
196
- Topic.import columns, values, :validate => false
211
+ Topic.import columns, values, validate: false
197
212
  @topic = Topic.find 99
198
213
  end
199
214
 
200
215
  context "using string hash map" do
201
- let(:update_columns){ { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
216
+ let(:update_columns) { { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
202
217
  should_support_on_duplicate_key_update
203
218
  should_update_fields_mentioned
204
219
  end
205
220
 
206
221
  context "using string hash map, but specifying column mismatches" do
207
- let(:update_columns){ { "title" => "author_email_address", "author_email_address" => "title", "parent_id" => "parent_id" } }
222
+ let(:update_columns) { { "title" => "author_email_address", "author_email_address" => "title", "parent_id" => "parent_id" } }
208
223
  should_support_on_duplicate_key_update
209
224
  should_update_fields_mentioned_with_hash_mappings
210
225
  end
211
226
 
212
227
  context "using symbol hash map" do
213
- let(:update_columns){ { :title => :title, :author_email_address => :author_email_address, :parent_id => :parent_id } }
228
+ let(:update_columns) { { title: :title, author_email_address: :author_email_address, parent_id: :parent_id } }
214
229
  should_support_on_duplicate_key_update
215
230
  should_update_fields_mentioned
216
231
  end
217
232
 
218
233
  context "using symbol hash map, but specifying column mismatches" do
219
- let(:update_columns){ { :title => :author_email_address, :author_email_address => :title, :parent_id => :parent_id } }
234
+ let(:update_columns) { { title: :author_email_address, author_email_address: :title, parent_id: :parent_id } }
220
235
  should_support_on_duplicate_key_update
221
236
  should_update_fields_mentioned_with_hash_mappings
222
237
  end
223
238
  end
224
239
 
225
240
  context "with :constraint_name" do
226
- let(:columns){ %w( id title author_name author_email_address parent_id ) }
227
- let(:values){ [ [ 100, "Book", "John Doe", "john@doe.com", 17 ] ] }
228
- let(:updated_values){ [ [ 100, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57 ] ] }
241
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
242
+ let(:values) { [[100, "Book", "John Doe", "john@doe.com", 17]] }
243
+ let(:updated_values) { [[100, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
229
244
 
230
245
  macro(:perform_import) do |*opts|
231
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => { :constraint_name => :topics_pkey, :columns => update_columns }, :validate => false)
246
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: { constraint_name: :topics_pkey, columns: update_columns }, validate: false)
232
247
  end
233
248
 
234
249
  setup do
235
- Topic.import columns, values, :validate => false
250
+ Topic.import columns, values, validate: false
236
251
  @topic = Topic.find 100
237
252
  end
238
253
 
239
- let(:update_columns){ [ :title, :author_email_address, :parent_id ] }
254
+ let(:update_columns) { [:title, :author_email_address, :parent_id] }
240
255
  should_support_on_duplicate_key_update
241
256
  should_update_fields_mentioned
242
257
  end
243
258
 
244
259
  context "with no :conflict_target or :constraint_name" do
245
- let(:columns){ %w( id title author_name author_email_address parent_id ) }
246
- let(:values){ [ [ 100, "Book", "John Doe", "john@doe.com", 17 ] ] }
247
- let(:updated_values){ [ [ 100, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57 ] ] }
260
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
261
+ let(:values) { [[100, "Book", "John Doe", "john@doe.com", 17]] }
262
+ let(:updated_values) { [[100, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
248
263
 
249
264
  macro(:perform_import) do |*opts|
250
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => { :columns => update_columns }, :validate => false)
265
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: { columns: update_columns }, validate: false)
251
266
  end
252
267
 
253
268
  setup do
254
- Topic.import columns, values, :validate => false
269
+ Topic.import columns, values, validate: false
255
270
  @topic = Topic.find 100
256
271
  end
257
272
 
258
273
  context "default to the primary key" do
259
- let(:update_columns){ [ :title, :author_email_address, :parent_id ] }
274
+ let(:update_columns) { [:title, :author_email_address, :parent_id] }
260
275
  should_support_on_duplicate_key_update
261
276
  should_update_fields_mentioned
262
277
  end
263
278
  end
264
279
 
265
280
  context "with no :columns" do
266
- let(:columns){ %w( id title author_name author_email_address ) }
267
- let(:values){ [ [ 100, "Book", "John Doe", "john@doe.com" ] ] }
268
- let(:updated_values){ [ [ 100, "Title Should Not Change", "Author Should Not Change", "john@nogo.com" ] ] }
281
+ let(:columns) { %w( id title author_name author_email_address ) }
282
+ let(:values) { [[100, "Book", "John Doe", "john@doe.com"]] }
283
+ let(:updated_values) { [[100, "Title Should Not Change", "Author Should Not Change", "john@nogo.com"]] }
269
284
 
270
285
  macro(:perform_import) do |*opts|
271
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => { :conflict_target => :id }, :validate => false)
286
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: { conflict_target: :id }, validate: false)
272
287
  end
273
288
 
274
289
  setup do
275
- Topic.import columns, values, :validate => false
290
+ Topic.import columns, values, validate: false
276
291
  @topic = Topic.find 100
277
292
  end
278
293
 
279
294
  should_update_updated_at_on_timestamp_columns
280
295
  end
281
296
  end
297
+
298
+ context "with recursive: true" do
299
+ let(:new_topics) { Build(1, :topic_with_book) }
300
+
301
+ it "imports objects with associations" do
302
+ assert_difference "Topic.count", +1 do
303
+ Topic.import new_topics, recursive: true, on_duplicate_key_update: [:updated_at], validate: false
304
+ new_topics.each do |topic|
305
+ assert_not_nil topic.id
306
+ end
307
+ end
308
+ end
309
+ end
282
310
  end
283
311
  end
284
312
  end
@@ -2,8 +2,8 @@ def should_support_basic_on_duplicate_key_update
2
2
  describe "#import" do
3
3
  extend ActiveSupport::TestCase::ImportAssertions
4
4
 
5
- macro(:perform_import){ raise "supply your own #perform_import in a context below" }
6
- macro(:updated_topic){ Topic.find(@topic.id) }
5
+ macro(:perform_import) { raise "supply your own #perform_import in a context below" }
6
+ macro(:updated_topic) { Topic.find(@topic.id) }
7
7
 
8
8
  context "with :on_duplicate_key_update and validation checks turned off" do
9
9
  asssertion_group(:should_support_on_duplicate_key_update) do
@@ -13,51 +13,51 @@ def should_support_basic_on_duplicate_key_update
13
13
  should_update_updated_at_on_timestamp_columns
14
14
  end
15
15
 
16
- let(:columns){ %w( id title author_name author_email_address parent_id ) }
17
- let(:values){ [ [ 99, "Book", "John Doe", "john@doe.com", 17 ] ] }
18
- let(:updated_values){ [ [ 99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57 ] ] }
16
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
17
+ let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
18
+ let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
19
19
 
20
20
  macro(:perform_import) do |*opts|
21
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => update_columns , :validate => false)
21
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: update_columns, validate: false)
22
22
  end
23
23
 
24
24
  setup do
25
- Topic.import columns, values, :validate => false
25
+ Topic.import columns, values, validate: false
26
26
  @topic = Topic.find 99
27
27
  end
28
28
 
29
29
  context "using an empty array" do
30
- let(:update_columns){ [] }
30
+ let(:update_columns) { [] }
31
31
  should_not_update_fields_not_mentioned
32
32
  should_update_updated_at_on_timestamp_columns
33
33
  end
34
34
 
35
35
  context "using string column names" do
36
- let(:update_columns){ [ "title", "author_email_address", "parent_id" ] }
36
+ let(:update_columns) { %w(title author_email_address parent_id) }
37
37
  should_support_on_duplicate_key_update
38
38
  should_update_fields_mentioned
39
39
  end
40
40
 
41
41
  context "using symbol column names" do
42
- let(:update_columns){ [ :title, :author_email_address, :parent_id ] }
42
+ let(:update_columns) { [:title, :author_email_address, :parent_id] }
43
43
  should_support_on_duplicate_key_update
44
44
  should_update_fields_mentioned
45
45
  end
46
46
  end
47
47
 
48
48
  context "with a table that has a non-standard primary key" do
49
- let(:columns){ [ :promotion_id, :code ] }
50
- let(:values){ [ [ 1, 'DISCOUNT1' ] ] }
51
- let(:updated_values){ [ [ 1, 'DISCOUNT2'] ] }
52
- let(:update_columns){ [ :code ] }
49
+ let(:columns) { [:promotion_id, :code] }
50
+ let(:values) { [[1, 'DISCOUNT1']] }
51
+ let(:updated_values) { [[1, 'DISCOUNT2']] }
52
+ let(:update_columns) { [:code] }
53
53
 
54
54
  macro(:perform_import) do |*opts|
55
- Promotion.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => update_columns, :validate => false)
55
+ Promotion.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: update_columns, validate: false)
56
56
  end
57
- macro(:updated_promotion){ Promotion.find(@promotion.promotion_id) }
57
+ macro(:updated_promotion) { Promotion.find(@promotion.promotion_id) }
58
58
 
59
59
  setup do
60
- Promotion.import columns, values, :validate => false
60
+ Promotion.import columns, values, validate: false
61
61
  @promotion = Promotion.find 1
62
62
  end
63
63
 
@@ -68,17 +68,17 @@ def should_support_basic_on_duplicate_key_update
68
68
  end
69
69
 
70
70
  context "with :on_duplicate_key_update turned off" do
71
- let(:columns){ %w( id title author_name author_email_address parent_id ) }
72
- let(:values){ [ [ 100, "Book", "John Doe", "john@doe.com", 17 ] ] }
73
- let(:updated_values){ [ [ 100, "Book - 2nd Edition", "This should raise an exception", "john@nogo.com", 57 ] ] }
71
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
72
+ let(:values) { [[100, "Book", "John Doe", "john@doe.com", 17]] }
73
+ let(:updated_values) { [[100, "Book - 2nd Edition", "This should raise an exception", "john@nogo.com", 57]] }
74
74
 
75
75
  macro(:perform_import) do |*opts|
76
- # `:on_duplicate_key_update => false` is the tested feature
77
- Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => false, :validate => false)
76
+ # `on_duplicate_key_update: false` is the tested feature
77
+ Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: false, validate: false)
78
78
  end
79
79
 
80
80
  setup do
81
- Topic.import columns, values, :validate => false
81
+ Topic.import columns, values, validate: false
82
82
  @topic = Topic.find 100
83
83
  end
84
84