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.
- checksums.yaml +4 -4
- data/.rubocop.yml +49 -0
- data/.rubocop_todo.yml +36 -0
- data/.travis.yml +31 -7
- data/CHANGELOG.md +19 -0
- data/Gemfile +5 -2
- data/README.markdown +6 -1
- data/Rakefile +5 -2
- data/activerecord-import.gemspec +1 -1
- data/benchmarks/benchmark.rb +67 -68
- data/benchmarks/lib/base.rb +136 -137
- data/benchmarks/lib/cli_parser.rb +106 -107
- data/benchmarks/lib/mysql2_benchmark.rb +19 -21
- data/benchmarks/lib/output_to_csv.rb +2 -1
- data/benchmarks/lib/output_to_html.rb +8 -13
- data/benchmarks/schema/mysql_schema.rb +8 -8
- data/gemfiles/4.0.gemfile +1 -1
- data/gemfiles/4.1.gemfile +1 -1
- data/gemfiles/4.2.gemfile +1 -1
- data/gemfiles/5.0.gemfile +1 -1
- data/lib/activerecord-import.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +0 -1
- data/lib/activerecord-import/adapters/abstract_adapter.rb +9 -9
- data/lib/activerecord-import/adapters/mysql_adapter.rb +17 -17
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +20 -22
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +9 -9
- data/lib/activerecord-import/base.rb +3 -3
- data/lib/activerecord-import/import.rb +152 -131
- data/lib/activerecord-import/synchronize.rb +20 -20
- data/lib/activerecord-import/value_sets_parser.rb +7 -6
- data/lib/activerecord-import/version.rb +1 -1
- data/test/adapters/mysql2spatial.rb +1 -1
- data/test/adapters/postgis.rb +1 -1
- data/test/adapters/postgresql.rb +1 -1
- data/test/adapters/spatialite.rb +1 -1
- data/test/adapters/sqlite3.rb +1 -1
- data/test/import_test.rb +121 -70
- data/test/models/book.rb +5 -6
- data/test/models/chapter.rb +2 -2
- data/test/models/discount.rb +3 -0
- data/test/models/end_note.rb +2 -2
- data/test/models/promotion.rb +1 -1
- data/test/models/question.rb +1 -1
- data/test/models/rule.rb +2 -2
- data/test/models/topic.rb +3 -3
- data/test/models/widget.rb +1 -1
- data/test/postgis/import_test.rb +1 -1
- data/test/schema/generic_schema.rb +100 -96
- data/test/schema/mysql_schema.rb +5 -7
- data/test/sqlite3/import_test.rb +0 -2
- data/test/support/active_support/test_case_extensions.rb +12 -15
- data/test/support/assertions.rb +1 -1
- data/test/support/factories.rb +15 -16
- data/test/support/generate.rb +4 -4
- data/test/support/mysql/import_examples.rb +21 -21
- data/test/support/postgresql/import_examples.rb +83 -55
- data/test/support/shared_examples/on_duplicate_key_update.rb +23 -23
- data/test/synchronize_test.rb +2 -2
- data/test/test_helper.rb +6 -8
- data/test/value_sets_bytes_parser_test.rb +14 -17
- data/test/value_sets_records_parser_test.rb +6 -6
- metadata +7 -4
- data/test/travis/build.sh +0 -34
data/test/support/generate.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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){
|
23
|
-
let(:values){ [
|
24
|
-
let(:updated_values){ [
|
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(:
|
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, :
|
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){ { :
|
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){ { :
|
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){
|
62
|
-
let(:values){ [
|
63
|
-
let(:columns){ %
|
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!(:
|
67
|
-
topics << Topic.create!(:
|
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 = [
|
71
|
+
columns2update = ['author_name']
|
72
72
|
|
73
73
|
expected_count = Topic.count
|
74
74
|
Topic.import( columns, values,
|
75
|
-
:
|
76
|
-
:
|
77
|
-
:
|
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",
|
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
|
-
|
25
|
-
|
26
|
-
|
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, :
|
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, :
|
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
|
-
|
56
|
-
|
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, :
|
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, :
|
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
|
99
|
-
assert_difference "#{type
|
100
|
-
Topic.import new_topics_with_invalid_chapter, :
|
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, :
|
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){
|
149
|
-
let(:values){ [
|
150
|
-
let(:updated_values){ [
|
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(:
|
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, :
|
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){
|
188
|
-
let(:values){ [
|
189
|
-
let(:updated_values){ [
|
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(:
|
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, :
|
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){ { :
|
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){ { :
|
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){
|
227
|
-
let(:values){ [
|
228
|
-
let(:updated_values){ [
|
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(:
|
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, :
|
250
|
+
Topic.import columns, values, validate: false
|
236
251
|
@topic = Topic.find 100
|
237
252
|
end
|
238
253
|
|
239
|
-
let(:update_columns){ [
|
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){
|
246
|
-
let(:values){ [
|
247
|
-
let(:updated_values){ [
|
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(:
|
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, :
|
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){ [
|
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){
|
267
|
-
let(:values){ [
|
268
|
-
let(:updated_values){ [
|
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(:
|
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, :
|
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){
|
17
|
-
let(:values){ [
|
18
|
-
let(:updated_values){ [
|
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(:
|
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, :
|
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){
|
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){ [
|
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){ [
|
50
|
-
let(:values){ [
|
51
|
-
let(:updated_values){ [
|
52
|
-
let(:update_columns){ [
|
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(:
|
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, :
|
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){
|
72
|
-
let(:values){ [
|
73
|
-
let(:updated_values){ [
|
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
|
-
#
|
77
|
-
Topic.import columns, updated_values, opts.extract_options!.merge(:
|
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, :
|
81
|
+
Topic.import columns, values, validate: false
|
82
82
|
@topic = Topic.find 100
|
83
83
|
end
|
84
84
|
|