activerecord-import 0.22.0 → 0.23.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/.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
|