activerecord-import 0.11.0 → 0.12.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/CHANGELOG.md +24 -0
- data/Gemfile +4 -2
- data/README.markdown +8 -7
- data/Rakefile +1 -1
- data/benchmarks/benchmark.rb +2 -1
- data/benchmarks/lib/cli_parser.rb +1 -1
- data/benchmarks/lib/{mysql_benchmark.rb → mysql2_benchmark.rb} +6 -7
- data/gemfiles/3.1.gemfile +0 -2
- data/gemfiles/3.2.gemfile +0 -2
- data/gemfiles/4.0.gemfile +0 -2
- data/gemfiles/4.1.gemfile +0 -2
- data/gemfiles/4.2.gemfile +0 -2
- data/gemfiles/5.0.gemfile +0 -2
- data/lib/activerecord-import/adapters/abstract_adapter.rb +11 -2
- data/lib/activerecord-import/adapters/mysql_adapter.rb +14 -2
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +105 -1
- data/lib/activerecord-import/base.rb +0 -1
- data/lib/activerecord-import/import.rb +92 -21
- data/lib/activerecord-import/version.rb +1 -1
- data/test/database.yml.sample +0 -12
- data/test/import_test.rb +1 -1
- data/test/jdbcmysql/import_test.rb +2 -2
- data/test/jdbcpostgresql/import_test.rb +0 -1
- data/test/models/book.rb +4 -4
- data/test/models/promotion.rb +3 -0
- data/test/models/question.rb +3 -0
- data/test/models/rule.rb +3 -0
- data/test/models/topic.rb +1 -1
- data/test/mysql2/import_test.rb +2 -3
- data/test/mysqlspatial2/import_test.rb +2 -2
- data/test/postgresql/import_test.rb +4 -0
- data/test/schema/generic_schema.rb +19 -2
- data/test/support/{mysql/assertions.rb → assertions.rb} +12 -3
- data/test/support/factories.rb +14 -0
- data/test/support/mysql/import_examples.rb +28 -119
- data/test/support/postgresql/import_examples.rb +156 -1
- data/test/support/shared_examples/on_duplicate_key_update.rb +92 -0
- data/test/test_helper.rb +5 -1
- data/test/travis/build.sh +12 -8
- data/test/travis/database.yml +0 -12
- metadata +14 -23
- data/lib/activerecord-import/active_record/adapters/em_mysql2_adapter.rb +0 -8
- data/lib/activerecord-import/active_record/adapters/mysql_adapter.rb +0 -6
- data/lib/activerecord-import/em_mysql2.rb +0 -7
- data/lib/activerecord-import/mysql.rb +0 -7
- data/test/adapters/em_mysql2.rb +0 -1
- data/test/adapters/mysql.rb +0 -1
- data/test/adapters/mysqlspatial.rb +0 -1
- data/test/em_mysql2/import_test.rb +0 -6
- data/test/mysql/import_test.rb +0 -6
- data/test/mysqlspatial/import_test.rb +0 -6
- data/test/support/em-synchrony_extensions.rb +0 -13
data/test/database.yml.sample
CHANGED
@@ -5,25 +5,13 @@ common: &common
|
|
5
5
|
host: localhost
|
6
6
|
database: activerecord_import_test
|
7
7
|
|
8
|
-
mysql: &mysql
|
9
|
-
<<: *common
|
10
|
-
adapter: mysql
|
11
|
-
|
12
8
|
mysql2: &mysql2
|
13
9
|
<<: *common
|
14
10
|
adapter: mysql2
|
15
11
|
|
16
|
-
mysqlspatial:
|
17
|
-
<<: *mysql
|
18
|
-
|
19
12
|
mysql2spatial:
|
20
13
|
<<: *mysql2
|
21
14
|
|
22
|
-
em_mysql2:
|
23
|
-
<<: *common
|
24
|
-
adapter: em_mysql2
|
25
|
-
pool: 5
|
26
|
-
|
27
15
|
seamless_database_pool:
|
28
16
|
<<: *common
|
29
17
|
adapter: seamless_database_pool
|
data/test/import_test.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
2
|
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + '/../support/
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
|
4
4
|
require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
|
5
5
|
|
6
|
-
should_support_mysql_import_functionality
|
6
|
+
should_support_mysql_import_functionality
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
2
|
|
3
|
-
#require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/assertions')
|
4
3
|
require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
|
5
4
|
|
6
5
|
should_support_postgresql_import_functionality
|
data/test/models/book.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
class Book < ActiveRecord::Base
|
2
|
-
belongs_to :topic, :inverse_of
|
3
|
-
has_many :chapters, :
|
4
|
-
has_many :end_notes, :
|
5
|
-
if ENV['AR_VERSION'].
|
2
|
+
belongs_to :topic, :inverse_of => :books
|
3
|
+
has_many :chapters, :inverse_of => :book
|
4
|
+
has_many :end_notes, :inverse_of => :book
|
5
|
+
if ENV['AR_VERSION'].to_f >= 4.1
|
6
6
|
enum status: [:draft, :published]
|
7
7
|
end
|
8
8
|
end
|
data/test/models/rule.rb
ADDED
data/test/models/topic.rb
CHANGED
@@ -2,7 +2,7 @@ class Topic < ActiveRecord::Base
|
|
2
2
|
validates_presence_of :author_name
|
3
3
|
validates :title, numericality: { only_integer: true }, on: :context_test
|
4
4
|
|
5
|
-
has_many :books, :
|
5
|
+
has_many :books, :inverse_of => :topic
|
6
6
|
belongs_to :parent, :class_name => "Topic"
|
7
7
|
|
8
8
|
composed_of :description, :mapping => [ %w(title title), %w(author_name author_name)], :allow_nil => true, :class_name => "TopicDescription"
|
data/test/mysql2/import_test.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
-
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/assertions')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
|
4
3
|
require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
|
5
4
|
|
6
|
-
should_support_mysql_import_functionality
|
5
|
+
should_support_mysql_import_functionality
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
2
|
|
3
|
-
require File.expand_path(File.dirname(__FILE__) + '/../support/
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
|
4
4
|
require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
|
5
5
|
|
6
|
-
should_support_mysql_import_functionality
|
6
|
+
should_support_mysql_import_functionality
|
@@ -2,3 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
|
3
3
|
|
4
4
|
should_support_postgresql_import_functionality
|
5
|
+
|
6
|
+
if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
|
7
|
+
should_support_postgresql_upsert_functionality
|
8
|
+
end
|
@@ -7,7 +7,7 @@ ActiveRecord::Schema.define do
|
|
7
7
|
|
8
8
|
create_table :group, :force => true do |t|
|
9
9
|
t.column :order, :string
|
10
|
-
t.timestamps
|
10
|
+
t.timestamps null: true
|
11
11
|
end
|
12
12
|
|
13
13
|
create_table :topics, :force=>true do |t|
|
@@ -64,7 +64,7 @@ ActiveRecord::Schema.define do
|
|
64
64
|
t.column :publish_date, :date
|
65
65
|
t.column :topic_id, :integer
|
66
66
|
t.column :for_sale, :boolean, :default => true
|
67
|
-
t.column :status, :integer
|
67
|
+
t.column :status, :integer, :default => 0
|
68
68
|
end
|
69
69
|
|
70
70
|
create_table :chapters, :force => true do |t|
|
@@ -118,4 +118,21 @@ ActiveRecord::Schema.define do
|
|
118
118
|
t.text :data
|
119
119
|
t.text :json_data
|
120
120
|
end
|
121
|
+
|
122
|
+
create_table "promotions", primary_key: "promotion_id", force: :cascade do |t|
|
123
|
+
t.string :code
|
124
|
+
t.string :description
|
125
|
+
t.decimal :discount
|
126
|
+
end
|
127
|
+
|
128
|
+
add_index :promotions, [:code], :unique => true, :name => 'uk_code'
|
129
|
+
|
130
|
+
create_table :rules, force: true do |t|
|
131
|
+
t.column :condition_text, :string
|
132
|
+
t.column :question_id, :integer
|
133
|
+
end
|
134
|
+
|
135
|
+
create_table :questions, force: true do |t|
|
136
|
+
t.column :body, :string
|
137
|
+
end
|
121
138
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class ActiveSupport::TestCase
|
2
|
-
module
|
2
|
+
module ImportAssertions
|
3
3
|
def self.extended(klass)
|
4
4
|
klass.instance_eval do
|
5
5
|
assertion(:should_not_update_created_at_on_timestamp_columns) do
|
@@ -19,6 +19,15 @@ class ActiveSupport::TestCase
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
assertion(:should_not_update_updated_at_on_timestamp_columns) do
|
23
|
+
time = Chronic.parse("5 minutes from now")
|
24
|
+
Timecop.freeze time do
|
25
|
+
perform_import
|
26
|
+
assert_in_delta @topic.updated_at.to_i, updated_topic.updated_at.to_i, 1
|
27
|
+
assert_in_delta @topic.updated_on.to_i, updated_topic.updated_on.to_i, 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
22
31
|
assertion(:should_not_update_timestamps) do
|
23
32
|
Timecop.freeze Chronic.parse("5 minutes from now") do
|
24
33
|
perform_import :timestamps => false
|
@@ -40,10 +49,10 @@ class ActiveSupport::TestCase
|
|
40
49
|
end
|
41
50
|
|
42
51
|
assertion(:should_raise_update_fields_mentioned) do
|
43
|
-
assert_raise ActiveRecord::RecordNotUnique do
|
52
|
+
assert_raise ActiveRecord::RecordNotUnique do
|
44
53
|
perform_import
|
45
54
|
end
|
46
|
-
|
55
|
+
|
47
56
|
assert_equal "Book", updated_topic.title
|
48
57
|
assert_equal "john@doe.com", updated_topic.author_email_address
|
49
58
|
end
|
data/test/support/factories.rb
CHANGED
@@ -21,6 +21,20 @@ FactoryGirl.define do
|
|
21
21
|
sequence(:w_id){ |n| n}
|
22
22
|
end
|
23
23
|
|
24
|
+
factory :question do
|
25
|
+
sequence(:body) { |n| "Text #{n}"}
|
26
|
+
|
27
|
+
trait :with_rule do
|
28
|
+
after(:build) do |question|
|
29
|
+
question.build_rule(FactoryGirl.attributes_for(:rule))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
factory :rule do
|
35
|
+
sequence(:condition_text){ |n| "q_#{n}_#{n}"}
|
36
|
+
end
|
37
|
+
|
24
38
|
factory :topic_with_book, :parent=>:topic do |m|
|
25
39
|
after(:build) do |topic|
|
26
40
|
2.times do
|
@@ -3,29 +3,22 @@ def should_support_mysql_import_functionality
|
|
3
3
|
# Forcefully disable strict mode for this session.
|
4
4
|
ActiveRecord::Base.connection.execute "set sql_mode='STRICT_ALL_TABLES'"
|
5
5
|
|
6
|
-
|
7
|
-
extend ActiveSupport::TestCase::MySQLAssertions
|
8
|
-
|
9
|
-
asssertion_group(:should_support_on_duplicate_key_update) do
|
10
|
-
should_not_update_fields_not_mentioned
|
11
|
-
should_update_foreign_keys
|
12
|
-
should_not_update_created_at_on_timestamp_columns
|
13
|
-
should_update_updated_at_on_timestamp_columns
|
14
|
-
end
|
6
|
+
should_support_basic_on_duplicate_key_update
|
15
7
|
|
16
|
-
|
17
|
-
|
8
|
+
describe "#import" do
|
9
|
+
context "with :on_duplicate_key_update and validation checks turned off" do
|
10
|
+
extend ActiveSupport::TestCase::ImportAssertions
|
18
11
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
12
|
+
asssertion_group(:should_support_on_duplicate_key_update) do
|
13
|
+
should_not_update_fields_not_mentioned
|
14
|
+
should_update_foreign_keys
|
15
|
+
should_not_update_created_at_on_timestamp_columns
|
16
|
+
should_update_updated_at_on_timestamp_columns
|
25
17
|
end
|
26
|
-
end
|
27
18
|
|
28
|
-
|
19
|
+
macro(:perform_import){ raise "supply your own #perform_import in a context below" }
|
20
|
+
macro(:updated_topic){ Topic.find(@topic.id) }
|
21
|
+
|
29
22
|
let(:columns){ %w( id title author_name author_email_address parent_id ) }
|
30
23
|
let(:values){ [ [ 99, "Book", "John Doe", "john@doe.com", 17 ] ] }
|
31
24
|
let(:updated_values){ [ [ 99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57 ] ] }
|
@@ -39,18 +32,6 @@ def should_support_mysql_import_functionality
|
|
39
32
|
@topic = Topic.find 99
|
40
33
|
end
|
41
34
|
|
42
|
-
context "using string column names" do
|
43
|
-
let(:update_columns){ [ "title", "author_email_address", "parent_id" ] }
|
44
|
-
should_support_on_duplicate_key_update
|
45
|
-
should_update_fields_mentioned
|
46
|
-
end
|
47
|
-
|
48
|
-
context "using symbol column names" do
|
49
|
-
let(:update_columns){ [ :title, :author_email_address, :parent_id ] }
|
50
|
-
should_support_on_duplicate_key_update
|
51
|
-
should_update_fields_mentioned
|
52
|
-
end
|
53
|
-
|
54
35
|
context "using string hash map" do
|
55
36
|
let(:update_columns){ { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
|
56
37
|
should_support_on_duplicate_key_update
|
@@ -76,101 +57,29 @@ def should_support_mysql_import_functionality
|
|
76
57
|
end
|
77
58
|
end
|
78
59
|
|
79
|
-
context "
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
@topic.author_email_address = "johndoe@example.com"
|
84
|
-
@topic.parent_id = 57
|
85
|
-
Topic.import [@topic], opts.extract_options!.merge(:on_duplicate_key_update => update_columns, :validate => false)
|
86
|
-
end
|
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) }
|
87
64
|
|
88
65
|
setup do
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
context "using string column names" do
|
93
|
-
let(:update_columns){ [ "title", "author_email_address", "parent_id" ] }
|
94
|
-
should_support_on_duplicate_key_update
|
95
|
-
should_update_fields_mentioned
|
96
|
-
end
|
97
|
-
|
98
|
-
context "using symbol column names" do
|
99
|
-
let(:update_columns){ [ :title, :author_email_address, :parent_id ] }
|
100
|
-
should_support_on_duplicate_key_update
|
101
|
-
should_update_fields_mentioned
|
102
|
-
end
|
103
|
-
|
104
|
-
context "using string hash map" do
|
105
|
-
let(:update_columns){ { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
|
106
|
-
should_support_on_duplicate_key_update
|
107
|
-
should_update_fields_mentioned
|
108
|
-
end
|
109
|
-
|
110
|
-
context "using string hash map, but specifying column mismatches" do
|
111
|
-
let(:update_columns){ { "title" => "author_email_address", "author_email_address" => "title", "parent_id" => "parent_id" } }
|
112
|
-
should_support_on_duplicate_key_update
|
113
|
-
should_update_fields_mentioned_with_hash_mappings
|
66
|
+
topics << Topic.create!(:title=>"LDAP", :author_name=>"Big Bird")
|
67
|
+
topics << Topic.create!(:title=>"Rails Recipes", :author_name=>"Elmo")
|
114
68
|
end
|
115
69
|
|
116
|
-
|
117
|
-
|
118
|
-
should_support_on_duplicate_key_update
|
119
|
-
should_update_fields_mentioned
|
120
|
-
end
|
121
|
-
|
122
|
-
context "using symbol hash map, but specifying column mismatches" do
|
123
|
-
let(:update_columns){ { :title => :author_email_address, :author_email_address => :title, :parent_id => :parent_id } }
|
124
|
-
should_support_on_duplicate_key_update
|
125
|
-
should_update_fields_mentioned_with_hash_mappings
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
context "given array of model instances with :on_duplicate_key_update turned off" do
|
130
|
-
let(:columns){ %w( id title author_name author_email_address parent_id ) }
|
131
|
-
let(:values){ [ [ 100, "Book", "John Doe", "john@doe.com", 17 ] ] }
|
132
|
-
let(:updated_values){ [ [ 100, "Book - 2nd Edition", "This should raise an exception", "john@nogo.com", 57 ] ] }
|
70
|
+
it "synchronizes passed in ActiveRecord model instances with the data just imported" do
|
71
|
+
columns2update = [ 'author_name' ]
|
133
72
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
73
|
+
expected_count = Topic.count
|
74
|
+
Topic.import( columns, values,
|
75
|
+
:validate=>false,
|
76
|
+
:on_duplicate_key_update=>columns2update,
|
77
|
+
:synchronize=>topics )
|
138
78
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
143
|
-
|
144
|
-
context "using string column names" do
|
145
|
-
let(:update_columns){ [ "title", "author_email_address", "parent_id" ] }
|
146
|
-
should_raise_update_fields_mentioned
|
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!"
|
81
|
+
assert_equal "Chad Fowler", topics.last.author_name, "wrong author!"
|
147
82
|
end
|
148
83
|
end
|
149
84
|
end
|
150
|
-
|
151
|
-
describe "#import with :synchronization option" do
|
152
|
-
let(:topics){ Array.new }
|
153
|
-
let(:values){ [ [topics.first.id, "Jerry Carter", "title1"], [topics.last.id, "Chad Fowler", "title2"] ]}
|
154
|
-
let(:columns){ %W(id author_name title) }
|
155
|
-
|
156
|
-
setup do
|
157
|
-
topics << Topic.create!(:title=>"LDAP", :author_name=>"Big Bird")
|
158
|
-
topics << Topic.create!(:title=>"Rails Recipes", :author_name=>"Elmo")
|
159
|
-
end
|
160
|
-
|
161
|
-
it "synchronizes passed in ActiveRecord model instances with the data just imported" do
|
162
|
-
columns2update = [ 'author_name' ]
|
163
|
-
|
164
|
-
expected_count = Topic.count
|
165
|
-
Topic.import( columns, values,
|
166
|
-
:validate=>false,
|
167
|
-
:on_duplicate_key_update=>columns2update,
|
168
|
-
:synchronize=>topics )
|
169
|
-
|
170
|
-
assert_equal expected_count, Topic.count, "no new records should have been created!"
|
171
|
-
assert_equal "Jerry Carter", topics.first.author_name, "wrong author!"
|
172
|
-
assert_equal "Chad Fowler", topics.last.author_name, "wrong author!"
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
85
|
end
|
@@ -19,7 +19,6 @@ def should_support_postgresql_import_functionality
|
|
19
19
|
end
|
20
20
|
|
21
21
|
describe "importing objects with associations" do
|
22
|
-
|
23
22
|
let(:new_topics) { Build(num_topics, :topic_with_book) }
|
24
23
|
let(:new_topics_with_invalid_chapter) {
|
25
24
|
chapter = new_topics.first.books.first.chapters.first
|
@@ -31,6 +30,8 @@ def should_support_postgresql_import_functionality
|
|
31
30
|
let(:num_chapters) {18}
|
32
31
|
let(:num_endnotes) {24}
|
33
32
|
|
33
|
+
let(:new_question_with_rule) { FactoryGirl.build :question, :with_rule }
|
34
|
+
|
34
35
|
it 'imports top level' do
|
35
36
|
assert_difference "Topic.count", +num_topics do
|
36
37
|
Topic.import new_topics, :recursive => true
|
@@ -83,6 +84,12 @@ def should_support_postgresql_import_functionality
|
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
87
|
+
it 'imports has_one associations' do
|
88
|
+
assert_difference 'Rule.count' do
|
89
|
+
Question.import [new_question_with_rule], recursive: true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
86
93
|
# These models dont validate associated. So we expect that books and topics get inserted, but not chapters
|
87
94
|
# Putting a transaction around everything wouldn't work, so if you want your chapters to prevent topics from
|
88
95
|
# being created, you would need to have validates_associated in your models and insert with validation
|
@@ -127,3 +134,151 @@ def should_support_postgresql_import_functionality
|
|
127
134
|
end
|
128
135
|
end
|
129
136
|
end
|
137
|
+
|
138
|
+
def should_support_postgresql_upsert_functionality
|
139
|
+
should_support_basic_on_duplicate_key_update
|
140
|
+
|
141
|
+
describe "#import" do
|
142
|
+
extend ActiveSupport::TestCase::ImportAssertions
|
143
|
+
|
144
|
+
macro(:perform_import){ raise "supply your own #perform_import in a context below" }
|
145
|
+
macro(:updated_topic){ Topic.find(@topic.id) }
|
146
|
+
|
147
|
+
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 ] ] }
|
151
|
+
|
152
|
+
macro(:perform_import) do |*opts|
|
153
|
+
Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_ignore => value, :validate => false)
|
154
|
+
end
|
155
|
+
|
156
|
+
setup do
|
157
|
+
Topic.import columns, values, :validate => false
|
158
|
+
@topic = Topic.find 99
|
159
|
+
end
|
160
|
+
|
161
|
+
context "using true" do
|
162
|
+
let(:value){ true }
|
163
|
+
should_not_update_updated_at_on_timestamp_columns
|
164
|
+
end
|
165
|
+
|
166
|
+
context "using hash with :conflict_target" do
|
167
|
+
let(:value){ { conflict_target: :id } }
|
168
|
+
should_not_update_updated_at_on_timestamp_columns
|
169
|
+
end
|
170
|
+
|
171
|
+
context "using hash with :constraint_target" do
|
172
|
+
let(:value){ { constraint_name: :topics_pkey } }
|
173
|
+
should_not_update_updated_at_on_timestamp_columns
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context "with :on_duplicate_key_update and validation checks turned off" do
|
178
|
+
asssertion_group(:should_support_on_duplicate_key_update) do
|
179
|
+
should_not_update_fields_not_mentioned
|
180
|
+
should_update_foreign_keys
|
181
|
+
should_not_update_created_at_on_timestamp_columns
|
182
|
+
should_update_updated_at_on_timestamp_columns
|
183
|
+
end
|
184
|
+
|
185
|
+
context "using a hash" do
|
186
|
+
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 ] ] }
|
190
|
+
|
191
|
+
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)
|
193
|
+
end
|
194
|
+
|
195
|
+
setup do
|
196
|
+
Topic.import columns, values, :validate => false
|
197
|
+
@topic = Topic.find 99
|
198
|
+
end
|
199
|
+
|
200
|
+
context "using string hash map" do
|
201
|
+
let(:update_columns){ { "title" => "title", "author_email_address" => "author_email_address", "parent_id" => "parent_id" } }
|
202
|
+
should_support_on_duplicate_key_update
|
203
|
+
should_update_fields_mentioned
|
204
|
+
end
|
205
|
+
|
206
|
+
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" } }
|
208
|
+
should_support_on_duplicate_key_update
|
209
|
+
should_update_fields_mentioned_with_hash_mappings
|
210
|
+
end
|
211
|
+
|
212
|
+
context "using symbol hash map" do
|
213
|
+
let(:update_columns){ { :title => :title, :author_email_address => :author_email_address, :parent_id => :parent_id } }
|
214
|
+
should_support_on_duplicate_key_update
|
215
|
+
should_update_fields_mentioned
|
216
|
+
end
|
217
|
+
|
218
|
+
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 } }
|
220
|
+
should_support_on_duplicate_key_update
|
221
|
+
should_update_fields_mentioned_with_hash_mappings
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
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 ] ] }
|
229
|
+
|
230
|
+
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)
|
232
|
+
end
|
233
|
+
|
234
|
+
setup do
|
235
|
+
Topic.import columns, values, :validate => false
|
236
|
+
@topic = Topic.find 100
|
237
|
+
end
|
238
|
+
|
239
|
+
let(:update_columns){ [ :title, :author_email_address, :parent_id ] }
|
240
|
+
should_support_on_duplicate_key_update
|
241
|
+
should_update_fields_mentioned
|
242
|
+
end
|
243
|
+
|
244
|
+
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 ] ] }
|
248
|
+
|
249
|
+
macro(:perform_import) do |*opts|
|
250
|
+
Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => { :columns => update_columns }, :validate => false)
|
251
|
+
end
|
252
|
+
|
253
|
+
setup do
|
254
|
+
Topic.import columns, values, :validate => false
|
255
|
+
@topic = Topic.find 100
|
256
|
+
end
|
257
|
+
|
258
|
+
context "default to the primary key" do
|
259
|
+
let(:update_columns){ [ :title, :author_email_address, :parent_id ] }
|
260
|
+
should_support_on_duplicate_key_update
|
261
|
+
should_update_fields_mentioned
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
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" ] ] }
|
269
|
+
|
270
|
+
macro(:perform_import) do |*opts|
|
271
|
+
Topic.import columns, updated_values, opts.extract_options!.merge(:on_duplicate_key_update => { :conflict_target => :id }, :validate => false)
|
272
|
+
end
|
273
|
+
|
274
|
+
setup do
|
275
|
+
Topic.import columns, values, :validate => false
|
276
|
+
@topic = Topic.find 100
|
277
|
+
end
|
278
|
+
|
279
|
+
should_update_updated_at_on_timestamp_columns
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|