activerecord-import 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +17 -1
- data/Gemfile +8 -5
- data/gemfiles/5.0.gemfile +0 -1
- data/gemfiles/5.1.gemfile +0 -1
- data/gemfiles/5.2.gemfile +2 -0
- data/lib/activerecord-import/adapters/abstract_adapter.rb +1 -1
- data/lib/activerecord-import/adapters/mysql_adapter.rb +13 -4
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +13 -5
- data/lib/activerecord-import/import.rb +18 -11
- data/lib/activerecord-import/version.rb +1 -1
- data/test/models/account.rb +3 -0
- data/test/models/bike_maker.rb +7 -0
- data/test/models/user.rb +1 -0
- data/test/schema/generic_schema.rb +15 -0
- data/test/support/shared_examples/on_duplicate_key_update.rb +207 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25b9f077b6e370081a1c29b59ba3ce50be68659c
|
4
|
+
data.tar.gz: adc5eff35697da10f5a6e3922980dfdd3ea849a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8211cc8ed17997e92e944c1d36533ce501d18401da25df549e700fdd37e4223f5bcef2a342b3c8aa74af31d23d16c932a6e39b2445dba83dc8866575da16196
|
7
|
+
data.tar.gz: 293a3eb933956824ec0fd0b9dfe760ba43d262b3154a5286f3cb33d677ae0c2949effd9c92006dbaa97f5748d97b289bd2483c5b68933ca8e2d8698c18d26111
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## Changes in 0.23.0
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
|
5
|
+
* Rename `import` method to `bulk_import and alias to `import`. Thanks
|
6
|
+
to @itay-grudev, @jkowens via \#498.
|
7
|
+
* Increment lock_version on duplicate key update. Thanks to @aimerald
|
8
|
+
via \#400.
|
9
|
+
|
10
|
+
### Fixes
|
11
|
+
|
12
|
+
* Fix import_without_validations_or_callbacks exception if array is empty.
|
13
|
+
Thanks to @doloopwhile via \#508.
|
14
|
+
|
1
15
|
## Changes in 0.22.0
|
2
16
|
|
3
17
|
### New Features
|
@@ -7,7 +21,9 @@
|
|
7
21
|
|
8
22
|
### Fixes
|
9
23
|
|
10
|
-
* Fix validation logic for recursive import.
|
24
|
+
* Fix validation logic for recursive import. For those on Rails 5.0 and 5.1,
|
25
|
+
this change requires models with polymorphic associations to specify the `inverse_of`
|
26
|
+
argument (See issue #495). Thanks to @eric-simonton-sama, @jkowens via
|
11
27
|
\#489.
|
12
28
|
|
13
29
|
## Changes in 0.21.0
|
data/Gemfile
CHANGED
@@ -2,6 +2,11 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
version = ENV['AR_VERSION'].to_f
|
6
|
+
|
7
|
+
mysql2_version = '0.3.0'
|
8
|
+
mysql2_version = '0.4.0' if version >= 4.2
|
9
|
+
|
5
10
|
group :development, :test do
|
6
11
|
gem 'rubocop', '~> 0.40.0'
|
7
12
|
gem 'rake'
|
@@ -9,7 +14,7 @@ end
|
|
9
14
|
|
10
15
|
# Database Adapters
|
11
16
|
platforms :ruby do
|
12
|
-
gem "mysql2", "~>
|
17
|
+
gem "mysql2", "~> #{mysql2_version}"
|
13
18
|
gem "pg", "~> 0.9"
|
14
19
|
gem "sqlite3", "~> 1.3.10"
|
15
20
|
gem "seamless_database_pool", "~> 1.0.20"
|
@@ -27,7 +32,7 @@ end
|
|
27
32
|
gem "factory_girl", "~> 4.2.0"
|
28
33
|
gem "timecop"
|
29
34
|
gem "chronic"
|
30
|
-
gem "mocha"
|
35
|
+
gem "mocha", "~> 1.3.0"
|
31
36
|
|
32
37
|
# Debugging
|
33
38
|
platforms :jruby do
|
@@ -43,9 +48,7 @@ platforms :ruby do
|
|
43
48
|
gem "rb-readline"
|
44
49
|
end
|
45
50
|
|
46
|
-
version
|
47
|
-
|
48
|
-
if version >= "4.0"
|
51
|
+
if version >= 4.0
|
49
52
|
gem "minitest"
|
50
53
|
else
|
51
54
|
gem "test-unit"
|
data/gemfiles/5.0.gemfile
CHANGED
data/gemfiles/5.1.gemfile
CHANGED
@@ -45,7 +45,7 @@ module ActiveRecord::Import::AbstractAdapter
|
|
45
45
|
post_sql_statements = []
|
46
46
|
|
47
47
|
if supports_on_duplicate_key_update? && options[:on_duplicate_key_update]
|
48
|
-
post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:primary_key] )
|
48
|
+
post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:primary_key], options[:locking_column] )
|
49
49
|
elsif options[:on_duplicate_key_update]
|
50
50
|
logger.warn "Ignoring on_duplicate_key_update because it is not supported by the database."
|
51
51
|
end
|
@@ -87,10 +87,11 @@ module ActiveRecord::Import::MysqlAdapter
|
|
87
87
|
def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
|
88
88
|
sql = ' ON DUPLICATE KEY UPDATE '
|
89
89
|
arg = args.first
|
90
|
+
locking_column = args.last
|
90
91
|
if arg.is_a?( Array )
|
91
|
-
sql << sql_for_on_duplicate_key_update_as_array( table_name, arg )
|
92
|
+
sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arg )
|
92
93
|
elsif arg.is_a?( Hash )
|
93
|
-
sql << sql_for_on_duplicate_key_update_as_hash( table_name, arg )
|
94
|
+
sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, arg )
|
94
95
|
elsif arg.is_a?( String )
|
95
96
|
sql << arg
|
96
97
|
else
|
@@ -99,20 +100,22 @@ module ActiveRecord::Import::MysqlAdapter
|
|
99
100
|
sql
|
100
101
|
end
|
101
102
|
|
102
|
-
def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
|
103
|
+
def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
|
103
104
|
results = arr.map do |column|
|
104
105
|
qc = quote_column_name( column )
|
105
106
|
"#{table_name}.#{qc}=VALUES(#{qc})"
|
106
107
|
end
|
108
|
+
increment_locking_column!(results, table_name, locking_column)
|
107
109
|
results.join( ',' )
|
108
110
|
end
|
109
111
|
|
110
|
-
def sql_for_on_duplicate_key_update_as_hash( table_name, hsh ) # :nodoc:
|
112
|
+
def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
|
111
113
|
results = hsh.map do |column1, column2|
|
112
114
|
qc1 = quote_column_name( column1 )
|
113
115
|
qc2 = quote_column_name( column2 )
|
114
116
|
"#{table_name}.#{qc1}=VALUES( #{qc2} )"
|
115
117
|
end
|
118
|
+
increment_locking_column!(results, table_name, locking_column)
|
116
119
|
results.join( ',')
|
117
120
|
end
|
118
121
|
|
@@ -120,4 +123,10 @@ module ActiveRecord::Import::MysqlAdapter
|
|
120
123
|
def duplicate_key_update_error?(exception) # :nodoc:
|
121
124
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
|
122
125
|
end
|
126
|
+
|
127
|
+
def increment_locking_column!(results, table_name, locking_column)
|
128
|
+
if locking_column.present?
|
129
|
+
results << "#{table_name}.`#{locking_column}`=`#{locking_column}`+1"
|
130
|
+
end
|
131
|
+
end
|
123
132
|
end
|
@@ -119,7 +119,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
119
119
|
# Returns a generated ON CONFLICT DO UPDATE statement given the passed
|
120
120
|
# in +args+.
|
121
121
|
def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
|
122
|
-
arg, primary_key = args
|
122
|
+
arg, primary_key, locking_column = args
|
123
123
|
arg = { columns: arg } if arg.is_a?( Array ) || arg.is_a?( String )
|
124
124
|
return unless arg.is_a?( Hash )
|
125
125
|
|
@@ -139,9 +139,9 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
139
139
|
|
140
140
|
sql << "#{conflict_target}DO UPDATE SET "
|
141
141
|
if columns.is_a?( Array )
|
142
|
-
sql << sql_for_on_duplicate_key_update_as_array( table_name, columns )
|
142
|
+
sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, columns )
|
143
143
|
elsif columns.is_a?( Hash )
|
144
|
-
sql << sql_for_on_duplicate_key_update_as_hash( table_name, columns )
|
144
|
+
sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, columns )
|
145
145
|
elsif columns.is_a?( String )
|
146
146
|
sql << columns
|
147
147
|
else
|
@@ -153,20 +153,22 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
153
153
|
sql
|
154
154
|
end
|
155
155
|
|
156
|
-
def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
|
156
|
+
def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
|
157
157
|
results = arr.map do |column|
|
158
158
|
qc = quote_column_name( column )
|
159
159
|
"#{qc}=EXCLUDED.#{qc}"
|
160
160
|
end
|
161
|
+
increment_locking_column!(results, locking_column)
|
161
162
|
results.join( ',' )
|
162
163
|
end
|
163
164
|
|
164
|
-
def sql_for_on_duplicate_key_update_as_hash( table_name, hsh ) # :nodoc:
|
165
|
+
def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
|
165
166
|
results = hsh.map do |column1, column2|
|
166
167
|
qc1 = quote_column_name( column1 )
|
167
168
|
qc2 = quote_column_name( column2 )
|
168
169
|
"#{qc1}=EXCLUDED.#{qc2}"
|
169
170
|
end
|
171
|
+
increment_locking_column!(results, locking_column)
|
170
172
|
results.join( ',' )
|
171
173
|
end
|
172
174
|
|
@@ -200,4 +202,10 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
200
202
|
def supports_setting_primary_key_of_imported_objects?
|
201
203
|
true
|
202
204
|
end
|
205
|
+
|
206
|
+
def increment_locking_column!(results, locking_column)
|
207
|
+
if locking_column.present?
|
208
|
+
results << "\"#{locking_column}\"=EXCLUDED.\"#{locking_column}\"+1"
|
209
|
+
end
|
210
|
+
end
|
203
211
|
end
|
@@ -79,13 +79,14 @@ module ActiveRecord::Import #:nodoc:
|
|
79
79
|
end
|
80
80
|
|
81
81
|
class ActiveRecord::Associations::CollectionProxy
|
82
|
-
def
|
83
|
-
@association.
|
82
|
+
def bulk_import(*args, &block)
|
83
|
+
@association.bulk_import(*args, &block)
|
84
84
|
end
|
85
|
+
alias import bulk_import unless respond_to? :import
|
85
86
|
end
|
86
87
|
|
87
88
|
class ActiveRecord::Associations::CollectionAssociation
|
88
|
-
def
|
89
|
+
def bulk_import(*args, &block)
|
89
90
|
unless owner.persisted?
|
90
91
|
raise ActiveRecord::RecordNotSaved, "You cannot call import unless the parent is saved"
|
91
92
|
end
|
@@ -118,7 +119,7 @@ class ActiveRecord::Associations::CollectionAssociation
|
|
118
119
|
m.public_send "#{reflection.type}=", owner.class.name if reflection.type
|
119
120
|
end
|
120
121
|
|
121
|
-
return model_klass.
|
122
|
+
return model_klass.bulk_import column_names, models, options
|
122
123
|
|
123
124
|
# supports array of hash objects
|
124
125
|
elsif args.last.is_a?( Array ) && args.last.first.is_a?(Hash)
|
@@ -157,7 +158,7 @@ class ActiveRecord::Associations::CollectionAssociation
|
|
157
158
|
end
|
158
159
|
end
|
159
160
|
|
160
|
-
return model_klass.
|
161
|
+
return model_klass.bulk_import column_names, array_of_attributes, options
|
161
162
|
|
162
163
|
# supports empty array
|
163
164
|
elsif args.last.is_a?( Array ) && args.last.empty?
|
@@ -192,11 +193,12 @@ class ActiveRecord::Associations::CollectionAssociation
|
|
192
193
|
end
|
193
194
|
end
|
194
195
|
|
195
|
-
return model_klass.
|
196
|
+
return model_klass.bulk_import column_names, array_of_attributes, options
|
196
197
|
else
|
197
198
|
raise ArgumentError, "Invalid arguments!"
|
198
199
|
end
|
199
200
|
end
|
201
|
+
alias import bulk_import unless respond_to? :import
|
200
202
|
end
|
201
203
|
|
202
204
|
class ActiveRecord::Base
|
@@ -447,7 +449,7 @@ class ActiveRecord::Base
|
|
447
449
|
# * num_inserts - the number of insert statements it took to import the data
|
448
450
|
# * ids - the primary keys of the imported ids if the adapter supports it, otherwise an empty array.
|
449
451
|
# * results - import results if the adapter supports it, otherwise an empty array.
|
450
|
-
def
|
452
|
+
def bulk_import(*args)
|
451
453
|
if args.first.is_a?( Array ) && args.first.first.is_a?(ActiveRecord::Base)
|
452
454
|
options = {}
|
453
455
|
options.merge!( args.pop ) if args.last.is_a?(Hash)
|
@@ -458,23 +460,26 @@ class ActiveRecord::Base
|
|
458
460
|
import_helper(*args)
|
459
461
|
end
|
460
462
|
end
|
463
|
+
alias import bulk_import unless respond_to? :import
|
461
464
|
|
462
465
|
# Imports a collection of values if all values are valid. Import fails at the
|
463
466
|
# first encountered validation error and raises ActiveRecord::RecordInvalid
|
464
467
|
# with the failed instance.
|
465
|
-
def
|
468
|
+
def bulk_import!(*args)
|
466
469
|
options = args.last.is_a?( Hash ) ? args.pop : {}
|
467
470
|
options[:validate] = true
|
468
471
|
options[:raise_error] = true
|
469
472
|
|
470
|
-
|
473
|
+
bulk_import(*args, options)
|
471
474
|
end
|
475
|
+
alias import! bulk_import! unless respond_to? :import!
|
472
476
|
|
473
477
|
def import_helper( *args )
|
474
478
|
options = { validate: true, timestamps: true }
|
475
479
|
options.merge!( args.pop ) if args.last.is_a? Hash
|
476
480
|
# making sure that current model's primary key is used
|
477
481
|
options[:primary_key] = primary_key
|
482
|
+
options[:locking_column] = locking_column if attribute_names.include?(locking_column)
|
478
483
|
|
479
484
|
# Don't modify incoming arguments
|
480
485
|
on_duplicate_key_update = options[:on_duplicate_key_update]
|
@@ -656,7 +661,7 @@ class ActiveRecord::Base
|
|
656
661
|
|
657
662
|
array_of_attributes.compact!
|
658
663
|
|
659
|
-
result = if
|
664
|
+
result = if options[:all_or_none] && failed_instances.any?
|
660
665
|
ActiveRecord::Import::Result.new([], 0, [], [])
|
661
666
|
else
|
662
667
|
import_without_validations_or_callbacks( column_names, array_of_attributes, options )
|
@@ -671,6 +676,8 @@ class ActiveRecord::Base
|
|
671
676
|
# information on +column_names+, +array_of_attributes_ and
|
672
677
|
# +options+.
|
673
678
|
def import_without_validations_or_callbacks( column_names, array_of_attributes, options = {} )
|
679
|
+
return ActiveRecord::Import::Result.new([], 0, [], []) if array_of_attributes.empty?
|
680
|
+
|
674
681
|
column_names = column_names.map(&:to_sym)
|
675
682
|
scope_columns, scope_values = scope_attributes.to_a.transpose
|
676
683
|
|
@@ -802,7 +809,7 @@ class ActiveRecord::Base
|
|
802
809
|
|
803
810
|
associated_objects_by_class.each_value do |associations|
|
804
811
|
associations.each_value do |associated_records|
|
805
|
-
associated_records.first.class.
|
812
|
+
associated_records.first.class.bulk_import(associated_records, options) unless associated_records.empty?
|
806
813
|
end
|
807
814
|
end
|
808
815
|
end
|
data/test/models/user.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
class User < ActiveRecord::Base; end
|
@@ -159,6 +159,21 @@ ActiveRecord::Schema.define do
|
|
159
159
|
t.string :Features
|
160
160
|
end
|
161
161
|
|
162
|
+
create_table :users, force: :cascade do |t|
|
163
|
+
t.string :name, null: false
|
164
|
+
t.integer :lock_version, null: false, default: 0
|
165
|
+
end
|
166
|
+
|
167
|
+
create_table :accounts, force: :cascade do |t|
|
168
|
+
t.string :name, null: false
|
169
|
+
t.integer :lock, null: false, default: 0
|
170
|
+
end
|
171
|
+
|
172
|
+
create_table :bike_makers, force: :cascade do |t|
|
173
|
+
t.string :name, null: false
|
174
|
+
t.integer :lock_version, null: false, default: 0
|
175
|
+
end
|
176
|
+
|
162
177
|
add_index :cars, :Name, unique: true
|
163
178
|
|
164
179
|
unless ENV["SKIP_COMPOSITE_PK"]
|
@@ -5,6 +5,213 @@ def should_support_basic_on_duplicate_key_update
|
|
5
5
|
macro(:perform_import) { raise "supply your own #perform_import in a context below" }
|
6
6
|
macro(:updated_topic) { Topic.find(@topic.id) }
|
7
7
|
|
8
|
+
context "with lock_version upsert" do
|
9
|
+
describe 'optimistic lock' do
|
10
|
+
it 'lock_version upsert after on_duplcate_key_update by model' do
|
11
|
+
users = [
|
12
|
+
User.new(name: 'Salomon'),
|
13
|
+
User.new(name: 'Nathan')
|
14
|
+
]
|
15
|
+
User.import(users)
|
16
|
+
assert User.count == users.length
|
17
|
+
User.all.each do |user|
|
18
|
+
assert_equal 0, user.lock_version
|
19
|
+
end
|
20
|
+
updated_users = User.all.map do |user|
|
21
|
+
user.name += ' Rothschild'
|
22
|
+
user
|
23
|
+
end
|
24
|
+
User.import(updated_users, on_duplicate_key_update: [:name])
|
25
|
+
assert User.count == updated_users.length
|
26
|
+
User.all.each_with_index do |user, i|
|
27
|
+
assert_equal user.name, users[i].name + ' Rothschild'
|
28
|
+
assert_equal 1, user.lock_version
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'lock_version upsert after on_duplcate_key_update by array' do
|
33
|
+
users = [
|
34
|
+
User.new(name: 'Salomon'),
|
35
|
+
User.new(name: 'Nathan')
|
36
|
+
]
|
37
|
+
User.import(users)
|
38
|
+
assert User.count == users.length
|
39
|
+
User.all.each do |user|
|
40
|
+
assert_equal 0, user.lock_version
|
41
|
+
end
|
42
|
+
|
43
|
+
columns = [:id, :name]
|
44
|
+
updated_values = User.all.map do |user|
|
45
|
+
user.name += ' Rothschild'
|
46
|
+
[user.id, user.name]
|
47
|
+
end
|
48
|
+
User.import(columns, updated_values, on_duplicate_key_update: [:name])
|
49
|
+
assert User.count == updated_values.length
|
50
|
+
User.all.each_with_index do |user, i|
|
51
|
+
assert_equal user.name, users[i].name + ' Rothschild'
|
52
|
+
assert_equal 1, user.lock_version
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'lock_version upsert after on_duplcate_key_update by hash' do
|
57
|
+
users = [
|
58
|
+
User.new(name: 'Salomon'),
|
59
|
+
User.new(name: 'Nathan')
|
60
|
+
]
|
61
|
+
User.import(users)
|
62
|
+
assert User.count == users.length
|
63
|
+
User.all.each do |user|
|
64
|
+
assert_equal 0, user.lock_version
|
65
|
+
end
|
66
|
+
updated_values = User.all.map do |user|
|
67
|
+
user.name += ' Rothschild'
|
68
|
+
{ id: user.id, name: user.name }
|
69
|
+
end
|
70
|
+
User.import(updated_values, on_duplicate_key_update: [:name])
|
71
|
+
assert User.count == updated_values.length
|
72
|
+
User.all.each_with_index do |user, i|
|
73
|
+
assert_equal user.name, users[i].name + ' Rothschild'
|
74
|
+
assert_equal 1, user.lock_version
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'upsert optimistic lock columns other than lock_version by model' do
|
79
|
+
accounts = [
|
80
|
+
Account.new(name: 'Salomon'),
|
81
|
+
Account.new(name: 'Nathan')
|
82
|
+
]
|
83
|
+
Account.import(accounts)
|
84
|
+
assert Account.count == accounts.length
|
85
|
+
Account.all.each do |user|
|
86
|
+
assert_equal 0, user.lock
|
87
|
+
end
|
88
|
+
updated_accounts = Account.all.map do |user|
|
89
|
+
user.name += ' Rothschild'
|
90
|
+
user
|
91
|
+
end
|
92
|
+
Account.import(updated_accounts, on_duplicate_key_update: [:id, :name])
|
93
|
+
assert Account.count == updated_accounts.length
|
94
|
+
Account.all.each_with_index do |user, i|
|
95
|
+
assert_equal user.name, accounts[i].name + ' Rothschild'
|
96
|
+
assert_equal 1, user.lock
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'upsert optimistic lock columns other than lock_version by array' do
|
101
|
+
accounts = [
|
102
|
+
Account.new(name: 'Salomon'),
|
103
|
+
Account.new(name: 'Nathan')
|
104
|
+
]
|
105
|
+
Account.import(accounts)
|
106
|
+
assert Account.count == accounts.length
|
107
|
+
Account.all.each do |user|
|
108
|
+
assert_equal 0, user.lock
|
109
|
+
end
|
110
|
+
|
111
|
+
columns = [:id, :name]
|
112
|
+
updated_values = Account.all.map do |user|
|
113
|
+
user.name += ' Rothschild'
|
114
|
+
[user.id, user.name]
|
115
|
+
end
|
116
|
+
Account.import(columns, updated_values, on_duplicate_key_update: [:name])
|
117
|
+
assert Account.count == updated_values.length
|
118
|
+
Account.all.each_with_index do |user, i|
|
119
|
+
assert_equal user.name, accounts[i].name + ' Rothschild'
|
120
|
+
assert_equal 1, user.lock
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'upsert optimistic lock columns other than lock_version by hash' do
|
125
|
+
accounts = [
|
126
|
+
Account.new(name: 'Salomon'),
|
127
|
+
Account.new(name: 'Nathan')
|
128
|
+
]
|
129
|
+
Account.import(accounts)
|
130
|
+
assert Account.count == accounts.length
|
131
|
+
Account.all.each do |user|
|
132
|
+
assert_equal 0, user.lock
|
133
|
+
end
|
134
|
+
updated_values = Account.all.map do |user|
|
135
|
+
user.name += ' Rothschild'
|
136
|
+
{ id: user.id, name: user.name }
|
137
|
+
end
|
138
|
+
Account.import(updated_values, on_duplicate_key_update: [:name])
|
139
|
+
assert Account.count == updated_values.length
|
140
|
+
Account.all.each_with_index do |user, i|
|
141
|
+
assert_equal user.name, accounts[i].name + ' Rothschild'
|
142
|
+
assert_equal 1, user.lock
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'update the lock_version of models separated by namespaces by model' do
|
147
|
+
makers = [
|
148
|
+
Bike::Maker.new(name: 'Yamaha'),
|
149
|
+
Bike::Maker.new(name: 'Honda')
|
150
|
+
]
|
151
|
+
Bike::Maker.import(makers)
|
152
|
+
assert Bike::Maker.count == makers.length
|
153
|
+
Bike::Maker.all.each do |maker|
|
154
|
+
assert_equal 0, maker.lock_version
|
155
|
+
end
|
156
|
+
updated_makers = Bike::Maker.all.map do |maker|
|
157
|
+
maker.name += ' bikes'
|
158
|
+
maker
|
159
|
+
end
|
160
|
+
Bike::Maker.import(updated_makers, on_duplicate_key_update: [:name])
|
161
|
+
assert Bike::Maker.count == updated_makers.length
|
162
|
+
Bike::Maker.all.each_with_index do |maker, i|
|
163
|
+
assert_equal maker.name, makers[i].name + ' bikes'
|
164
|
+
assert_equal 1, maker.lock_version
|
165
|
+
end
|
166
|
+
end
|
167
|
+
it 'update the lock_version of models separated by namespaces by array' do
|
168
|
+
makers = [
|
169
|
+
Bike::Maker.new(name: 'Yamaha'),
|
170
|
+
Bike::Maker.new(name: 'Honda')
|
171
|
+
]
|
172
|
+
Bike::Maker.import(makers)
|
173
|
+
assert Bike::Maker.count == makers.length
|
174
|
+
Bike::Maker.all.each do |maker|
|
175
|
+
assert_equal 0, maker.lock_version
|
176
|
+
end
|
177
|
+
|
178
|
+
columns = [:id, :name]
|
179
|
+
updated_values = Bike::Maker.all.map do |maker|
|
180
|
+
maker.name += ' bikes'
|
181
|
+
[maker.id, maker.name]
|
182
|
+
end
|
183
|
+
Bike::Maker.import(columns, updated_values, on_duplicate_key_update: [:name])
|
184
|
+
assert Bike::Maker.count == updated_values.length
|
185
|
+
Bike::Maker.all.each_with_index do |maker, i|
|
186
|
+
assert_equal maker.name, makers[i].name + ' bikes'
|
187
|
+
assert_equal 1, maker.lock_version
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'update the lock_version of models separated by namespaces by hash' do
|
192
|
+
makers = [
|
193
|
+
Bike::Maker.new(name: 'Yamaha'),
|
194
|
+
Bike::Maker.new(name: 'Honda')
|
195
|
+
]
|
196
|
+
Bike::Maker.import(makers)
|
197
|
+
assert Bike::Maker.count == makers.length
|
198
|
+
Bike::Maker.all.each do |maker|
|
199
|
+
assert_equal 0, maker.lock_version
|
200
|
+
end
|
201
|
+
updated_values = Bike::Maker.all.map do |maker|
|
202
|
+
maker.name += ' bikes'
|
203
|
+
{ id: maker.id, name: maker.name }
|
204
|
+
end
|
205
|
+
Bike::Maker.import(updated_values, on_duplicate_key_update: [:name])
|
206
|
+
assert Bike::Maker.count == updated_values.length
|
207
|
+
Bike::Maker.all.each_with_index do |maker, i|
|
208
|
+
assert_equal maker.name, makers[i].name + ' bikes'
|
209
|
+
assert_equal 1, maker.lock_version
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
8
215
|
context "with :on_duplicate_key_update" do
|
9
216
|
describe "argument safety" do
|
10
217
|
it "should not modify the passed in :on_duplicate_key_update array" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-import
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.23.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Dennis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- gemfiles/4.2.gemfile
|
75
75
|
- gemfiles/5.0.gemfile
|
76
76
|
- gemfiles/5.1.gemfile
|
77
|
+
- gemfiles/5.2.gemfile
|
77
78
|
- lib/activerecord-import.rb
|
78
79
|
- lib/activerecord-import/active_record/adapters/abstract_adapter.rb
|
79
80
|
- lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb
|
@@ -114,7 +115,9 @@ files:
|
|
114
115
|
- test/jdbcmysql/import_test.rb
|
115
116
|
- test/jdbcpostgresql/import_test.rb
|
116
117
|
- test/jdbcsqlite3/import_test.rb
|
118
|
+
- test/models/account.rb
|
117
119
|
- test/models/alarm.rb
|
120
|
+
- test/models/bike_maker.rb
|
118
121
|
- test/models/book.rb
|
119
122
|
- test/models/car.rb
|
120
123
|
- test/models/chapter.rb
|
@@ -127,6 +130,7 @@ files:
|
|
127
130
|
- test/models/rule.rb
|
128
131
|
- test/models/tag.rb
|
129
132
|
- test/models/topic.rb
|
133
|
+
- test/models/user.rb
|
130
134
|
- test/models/vendor.rb
|
131
135
|
- test/models/widget.rb
|
132
136
|
- test/mysql2/import_test.rb
|
@@ -198,7 +202,9 @@ test_files:
|
|
198
202
|
- test/jdbcmysql/import_test.rb
|
199
203
|
- test/jdbcpostgresql/import_test.rb
|
200
204
|
- test/jdbcsqlite3/import_test.rb
|
205
|
+
- test/models/account.rb
|
201
206
|
- test/models/alarm.rb
|
207
|
+
- test/models/bike_maker.rb
|
202
208
|
- test/models/book.rb
|
203
209
|
- test/models/car.rb
|
204
210
|
- test/models/chapter.rb
|
@@ -211,6 +217,7 @@ test_files:
|
|
211
217
|
- test/models/rule.rb
|
212
218
|
- test/models/tag.rb
|
213
219
|
- test/models/topic.rb
|
220
|
+
- test/models/user.rb
|
214
221
|
- test/models/vendor.rb
|
215
222
|
- test/models/widget.rb
|
216
223
|
- test/mysql2/import_test.rb
|