activerecord-import 1.0.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +78 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +91 -3
  5. data/Gemfile +6 -2
  6. data/LICENSE +21 -56
  7. data/README.markdown +61 -53
  8. data/activerecord-import.gemspec +4 -4
  9. data/benchmarks/schema/{mysql_schema.rb → mysql2_schema.rb} +0 -0
  10. data/gemfiles/6.0.gemfile +2 -1
  11. data/gemfiles/6.1.gemfile +2 -1
  12. data/gemfiles/7.0.gemfile +1 -0
  13. data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +4 -4
  14. data/lib/activerecord-import/adapters/abstract_adapter.rb +6 -0
  15. data/lib/activerecord-import/adapters/mysql_adapter.rb +6 -6
  16. data/lib/activerecord-import/adapters/postgresql_adapter.rb +3 -11
  17. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +7 -15
  18. data/lib/activerecord-import/base.rb +7 -1
  19. data/lib/activerecord-import/import.rb +95 -42
  20. data/lib/activerecord-import/synchronize.rb +1 -1
  21. data/lib/activerecord-import/value_sets_parser.rb +2 -0
  22. data/lib/activerecord-import/version.rb +1 -1
  23. data/test/{travis → github}/database.yml +3 -1
  24. data/test/import_test.rb +67 -1
  25. data/test/models/animal.rb +6 -0
  26. data/test/models/card.rb +3 -0
  27. data/test/models/customer.rb +6 -0
  28. data/test/models/deck.rb +6 -0
  29. data/test/models/order.rb +6 -0
  30. data/test/models/playing_card.rb +2 -0
  31. data/test/schema/generic_schema.rb +25 -0
  32. data/test/schema/postgresql_schema.rb +14 -0
  33. data/test/support/postgresql/import_examples.rb +55 -0
  34. data/test/support/shared_examples/on_duplicate_key_update.rb +10 -0
  35. data/test/support/shared_examples/recursive_import.rb +30 -1
  36. data/test/test_helper.rb +10 -1
  37. metadata +25 -16
  38. data/.travis.yml +0 -70
  39. data/gemfiles/3.2.gemfile +0 -2
  40. data/gemfiles/4.0.gemfile +0 -2
  41. data/gemfiles/4.1.gemfile +0 -2
@@ -52,6 +52,20 @@ ActiveRecord::Schema.define do
52
52
  t.string :name
53
53
  end
54
54
 
55
+ create_table :cards, force: :cascade do |t|
56
+ t.string :name
57
+ t.string :deck_type
58
+ t.integer :deck_id
59
+ end
60
+
61
+ create_table :decks, force: :cascade do |t|
62
+ t.string :name
63
+ end
64
+
65
+ create_table :playing_cards, force: :cascade do |t|
66
+ t.string :name
67
+ end
68
+
55
69
  create_table :books, force: :cascade do |t|
56
70
  t.string :title, null: false
57
71
  t.string :publisher, null: false, default: 'Default Publisher'
@@ -191,4 +205,15 @@ ActiveRecord::Schema.define do
191
205
  );
192
206
  ).split.join(' ').strip
193
207
  end
208
+
209
+ create_table :customers, force: :cascade do |t|
210
+ t.integer :account_id
211
+ t.string :name
212
+ end
213
+
214
+ create_table :orders, force: :cascade do |t|
215
+ t.integer :account_id
216
+ t.integer :customer_id
217
+ t.integer :amount
218
+ end
194
219
  end
@@ -3,8 +3,20 @@ ActiveRecord::Schema.define do
3
3
  execute('CREATE extension IF NOT EXISTS "pgcrypto";')
4
4
  execute('CREATE extension IF NOT EXISTS "uuid-ossp";')
5
5
 
6
+ # create ENUM if it does not exist yet
7
+ begin
8
+ execute('CREATE TYPE vendor_type AS ENUM (\'wholesaler\', \'retailer\');')
9
+ rescue ActiveRecord::StatementInvalid => e
10
+ # since PostgreSQL does not support IF NOT EXISTS when creating a TYPE,
11
+ # rescue the error and check the error class
12
+ raise unless e.cause.is_a? PG::DuplicateObject
13
+ execute('ALTER TYPE vendor_type ADD VALUE IF NOT EXISTS \'wholesaler\';')
14
+ execute('ALTER TYPE vendor_type ADD VALUE IF NOT EXISTS \'retailer\';')
15
+ end
16
+
6
17
  create_table :vendors, id: :uuid, force: :cascade do |t|
7
18
  t.string :name, null: true
19
+ t.text :hours
8
20
  t.text :preferences
9
21
 
10
22
  if t.respond_to?(:json)
@@ -29,6 +41,8 @@ ActiveRecord::Schema.define do
29
41
  t.text :json_data
30
42
  end
31
43
 
44
+ t.column :vendor_type, :vendor_type
45
+
32
46
  t.datetime :created_at
33
47
  t.datetime :updated_at
34
48
  end
@@ -116,6 +116,26 @@ def should_support_postgresql_import_functionality
116
116
  assert_equal [%w(King It)], result.results
117
117
  end
118
118
 
119
+ context "when given an empty array" do
120
+ let(:result) { Book.import([], returning: %w(title)) }
121
+
122
+ setup { result }
123
+
124
+ it "returns empty arrays for ids and results" do
125
+ assert_equal [], result.ids
126
+ assert_equal [], result.results
127
+ end
128
+ end
129
+
130
+ context "when a returning column is a serialized attribute" do
131
+ let(:vendor) { Vendor.new(hours: { monday: '8-5' }) }
132
+ let(:result) { Vendor.import([vendor], returning: %w(hours)) }
133
+
134
+ it "creates records" do
135
+ assert_difference("Vendor.count", +1) { result }
136
+ end
137
+ end
138
+
119
139
  context "when primary key and returning overlap" do
120
140
  let(:result) { Book.import(books, returning: %w(id title)) }
121
141
 
@@ -249,6 +269,17 @@ def should_support_postgresql_import_functionality
249
269
  end
250
270
  end
251
271
 
272
+ describe "with enum field" do
273
+ let(:vendor_type) { "retailer" }
274
+ it "imports the correct values for enum fields" do
275
+ vendor = Vendor.new(name: 'Vendor 1', vendor_type: vendor_type)
276
+ assert_difference "Vendor.count", +1 do
277
+ Vendor.import [vendor]
278
+ end
279
+ assert_equal(vendor_type, Vendor.first.vendor_type)
280
+ end
281
+ end
282
+
252
283
  describe "with binary field" do
253
284
  let(:binary_value) { "\xE0'c\xB2\xB0\xB3Bh\\\xC2M\xB1m\\I\xC4r".force_encoding('ASCII-8BIT') }
254
285
  it "imports the correct values for binary fields" do
@@ -259,6 +290,30 @@ def should_support_postgresql_import_functionality
259
290
  assert_equal(binary_value, Alarm.first.secret_key)
260
291
  end
261
292
  end
293
+
294
+ unless ENV["SKIP_COMPOSITE_PK"]
295
+ describe "with composite foreign keys" do
296
+ let(:account_id) { 555 }
297
+ let(:customer) { Customer.new(account_id: account_id, name: "foo") }
298
+ let(:order) { Order.new(account_id: account_id, amount: 100, customer: customer) }
299
+
300
+ it "imports and correctly maps foreign keys" do
301
+ assert_difference "Customer.count", +1 do
302
+ Customer.import [customer]
303
+ end
304
+
305
+ assert_difference "Order.count", +1 do
306
+ Order.import [order]
307
+ end
308
+
309
+ db_customer = Customer.last
310
+ db_order = Order.last
311
+
312
+ assert_equal db_customer.orders.last, db_order
313
+ assert_not_equal db_order.customer_id, nil
314
+ end
315
+ end
316
+ end
262
317
  end
263
318
 
264
319
  def should_support_postgresql_upsert_functionality
@@ -73,6 +73,16 @@ def should_support_basic_on_duplicate_key_update
73
73
  assert_equal user.name, users[i].name + ' Rothschild'
74
74
  assert_equal 1, user.lock_version
75
75
  end
76
+ updated_values2 = User.all.map do |user|
77
+ user.name += ' jr.'
78
+ { id: user.id, name: user.name }
79
+ end
80
+ User.import(updated_values2, on_duplicate_key_update: [:name])
81
+ assert User.count == updated_values2.length
82
+ User.all.each_with_index do |user, i|
83
+ assert_equal user.name, users[i].name + ' Rothschild jr.'
84
+ assert_equal 2, user.lock_version
85
+ end
76
86
  end
77
87
 
78
88
  it 'upsert optimistic lock columns other than lock_version by model' do
@@ -138,6 +138,15 @@ def should_support_recursive_import
138
138
  books.each do |book|
139
139
  assert_equal book.topic_id, second_new_topic.id
140
140
  end
141
+
142
+ books.each { |book| book.topic_id = nil }
143
+ assert_no_difference "Book.count", books.size do
144
+ Book.import books, validate: false, on_duplicate_key_update: [:topic_id]
145
+ end
146
+
147
+ books.each do |book|
148
+ assert_equal book.topic_id, nil
149
+ end
141
150
  end
142
151
 
143
152
  unless ENV["SKIP_COMPOSITE_PK"]
@@ -167,7 +176,7 @@ def should_support_recursive_import
167
176
  end
168
177
  end
169
178
 
170
- # If adapter supports on_duplicate_key_update, it is only applied to top level models so that SQL with invalid
179
+ # If adapter supports on_duplicate_key_update and specific columns are specified, it is only applied to top level models so that SQL with invalid
171
180
  # columns, keys, etc isn't generated for child associations when doing recursive import
172
181
  if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
173
182
  describe "on_duplicate_key_update" do
@@ -181,6 +190,26 @@ def should_support_recursive_import
181
190
  end
182
191
  end
183
192
  end
193
+
194
+ context "when :all fields are updated" do
195
+ setup do
196
+ Topic.import new_topics, recursive: true
197
+ end
198
+
199
+ it "updates associated objects" do
200
+ new_author_name = 'Richard Bachman'
201
+ topic = new_topics.first
202
+ topic.books.each do |book|
203
+ book.author_name = new_author_name
204
+ end
205
+ assert_nothing_raised do
206
+ Topic.import new_topics, recursive: true, on_duplicate_key_update: :all
207
+ end
208
+ Topic.find(topic.id).books.each do |book|
209
+ assert_equal new_author_name, book.author_name
210
+ end
211
+ end
212
+ end
184
213
  end
185
214
  end
186
215
 
data/test/test_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'pathname'
2
+ require 'rake'
2
3
  test_dir = Pathname.new File.dirname(__FILE__)
3
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -48,7 +49,15 @@ adapter = ENV["ARE_DB"] || "sqlite3"
48
49
  FileUtils.mkdir_p 'log'
49
50
  ActiveRecord::Base.logger = Logger.new("log/test.log")
50
51
  ActiveRecord::Base.logger.level = Logger::DEBUG
51
- ActiveRecord::Base.configurations["test"] = YAML.load_file(test_dir.join("database.yml"))[adapter]
52
+
53
+ if ENV['AR_VERSION'].to_f >= 6.0
54
+ yaml_config = YAML.load_file(test_dir.join("database.yml"))[adapter]
55
+ config = ActiveRecord::DatabaseConfigurations::HashConfig.new("test", adapter, yaml_config)
56
+ ActiveRecord::Base.configurations.configurations << config
57
+ else
58
+ ActiveRecord::Base.configurations["test"] = YAML.load_file(test_dir.join("database.yml"))[adapter]
59
+ end
60
+
52
61
  ActiveRecord::Base.default_timezone = :utc
53
62
 
54
63
  require "activerecord-import"
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: 1.0.2
4
+ version: 1.3.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: 2019-06-01 00:00:00.000000000 Z
11
+ date: 2021-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '4.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.2'
26
+ version: '4.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -45,10 +45,10 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".github/workflows/test.yaml"
48
49
  - ".gitignore"
49
50
  - ".rubocop.yml"
50
51
  - ".rubocop_todo.yml"
51
- - ".travis.yml"
52
52
  - Brewfile
53
53
  - CHANGELOG.md
54
54
  - Gemfile
@@ -67,16 +67,14 @@ files:
67
67
  - benchmarks/models/test_innodb.rb
68
68
  - benchmarks/models/test_memory.rb
69
69
  - benchmarks/models/test_myisam.rb
70
- - benchmarks/schema/mysql_schema.rb
71
- - gemfiles/3.2.gemfile
72
- - gemfiles/4.0.gemfile
73
- - gemfiles/4.1.gemfile
70
+ - benchmarks/schema/mysql2_schema.rb
74
71
  - gemfiles/4.2.gemfile
75
72
  - gemfiles/5.0.gemfile
76
73
  - gemfiles/5.1.gemfile
77
74
  - gemfiles/5.2.gemfile
78
75
  - gemfiles/6.0.gemfile
79
76
  - gemfiles/6.1.gemfile
77
+ - gemfiles/7.0.gemfile
80
78
  - lib/activerecord-import.rb
81
79
  - lib/activerecord-import/active_record/adapters/abstract_adapter.rb
82
80
  - lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb
@@ -114,6 +112,7 @@ files:
114
112
  - test/adapters/spatialite.rb
115
113
  - test/adapters/sqlite3.rb
116
114
  - test/database.yml.sample
115
+ - test/github/database.yml
117
116
  - test/import_test.rb
118
117
  - test/jdbcmysql/import_test.rb
119
118
  - test/jdbcpostgresql/import_test.rb
@@ -121,14 +120,20 @@ files:
121
120
  - test/makara_postgis/import_test.rb
122
121
  - test/models/account.rb
123
122
  - test/models/alarm.rb
123
+ - test/models/animal.rb
124
124
  - test/models/bike_maker.rb
125
125
  - test/models/book.rb
126
126
  - test/models/car.rb
127
+ - test/models/card.rb
127
128
  - test/models/chapter.rb
129
+ - test/models/customer.rb
130
+ - test/models/deck.rb
128
131
  - test/models/dictionary.rb
129
132
  - test/models/discount.rb
130
133
  - test/models/end_note.rb
131
134
  - test/models/group.rb
135
+ - test/models/order.rb
136
+ - test/models/playing_card.rb
132
137
  - test/models/promotion.rb
133
138
  - test/models/question.rb
134
139
  - test/models/rule.rb
@@ -163,12 +168,11 @@ files:
163
168
  - test/support/sqlite3/import_examples.rb
164
169
  - test/synchronize_test.rb
165
170
  - test/test_helper.rb
166
- - test/travis/database.yml
167
171
  - test/value_sets_bytes_parser_test.rb
168
172
  - test/value_sets_records_parser_test.rb
169
- homepage: http://github.com/zdennis/activerecord-import
173
+ homepage: https://github.com/zdennis/activerecord-import
170
174
  licenses:
171
- - Ruby
175
+ - MIT
172
176
  metadata: {}
173
177
  post_install_message:
174
178
  rdoc_options: []
@@ -178,15 +182,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
178
182
  requirements:
179
183
  - - ">="
180
184
  - !ruby/object:Gem::Version
181
- version: 1.9.2
185
+ version: 2.4.0
182
186
  required_rubygems_version: !ruby/object:Gem::Requirement
183
187
  requirements:
184
188
  - - ">="
185
189
  - !ruby/object:Gem::Version
186
190
  version: '0'
187
191
  requirements: []
188
- rubyforge_project:
189
- rubygems_version: 2.7.8
192
+ rubygems_version: 3.0.3
190
193
  signing_key:
191
194
  specification_version: 4
192
195
  summary: Bulk insert extension for ActiveRecord
@@ -205,6 +208,7 @@ test_files:
205
208
  - test/adapters/spatialite.rb
206
209
  - test/adapters/sqlite3.rb
207
210
  - test/database.yml.sample
211
+ - test/github/database.yml
208
212
  - test/import_test.rb
209
213
  - test/jdbcmysql/import_test.rb
210
214
  - test/jdbcpostgresql/import_test.rb
@@ -212,14 +216,20 @@ test_files:
212
216
  - test/makara_postgis/import_test.rb
213
217
  - test/models/account.rb
214
218
  - test/models/alarm.rb
219
+ - test/models/animal.rb
215
220
  - test/models/bike_maker.rb
216
221
  - test/models/book.rb
217
222
  - test/models/car.rb
223
+ - test/models/card.rb
218
224
  - test/models/chapter.rb
225
+ - test/models/customer.rb
226
+ - test/models/deck.rb
219
227
  - test/models/dictionary.rb
220
228
  - test/models/discount.rb
221
229
  - test/models/end_note.rb
222
230
  - test/models/group.rb
231
+ - test/models/order.rb
232
+ - test/models/playing_card.rb
223
233
  - test/models/promotion.rb
224
234
  - test/models/question.rb
225
235
  - test/models/rule.rb
@@ -254,6 +264,5 @@ test_files:
254
264
  - test/support/sqlite3/import_examples.rb
255
265
  - test/synchronize_test.rb
256
266
  - test/test_helper.rb
257
- - test/travis/database.yml
258
267
  - test/value_sets_bytes_parser_test.rb
259
268
  - test/value_sets_records_parser_test.rb
data/.travis.yml DELETED
@@ -1,70 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
- rvm:
4
- - 2.5.5
5
-
6
- env:
7
- global:
8
- # https://github.com/discourse/discourse/blob/master/.travis.yml
9
- - RUBY_GC_MALLOC_LIMIT=50000000
10
- matrix:
11
- - AR_VERSION=5.1
12
- - AR_VERSION=5.2
13
- - AR_VERSION=6.0
14
-
15
- matrix:
16
- include:
17
- - rvm: 2.3.8
18
- env: AR_VERSION=3.2
19
- - rvm: 2.3.8
20
- env: AR_VERSION=4.0
21
- - rvm: 2.3.8
22
- env: AR_VERSION=4.1
23
- - rvm: 2.3.8
24
- env: AR_VERSION=4.2
25
- - rvm: 2.3.8
26
- env: AR_VERSION=5.0
27
-
28
- fast_finish: true
29
-
30
- addons:
31
- postgresql: "9.5"
32
- apt:
33
- sources:
34
- - travis-ci/sqlite3
35
- - mysql-5.7-trusty
36
- packages:
37
- - sqlite3
38
- - mysql-server
39
- - mysql-client
40
- - postgresql-9.5-postgis-2.3
41
-
42
- before_install:
43
- - gem update --system
44
- - sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
45
- - sudo mysql_upgrade
46
- - sudo service mysql restart
47
-
48
- before_script:
49
- - mysql -e 'create database activerecord_import_test;'
50
- - psql -c 'create database activerecord_import_test;' -U postgres
51
- - psql activerecord_import_test -c 'create extension if not exists hstore;' -U postgres
52
- - psql -c 'create extension if not exists postgis;' -U postgres
53
- - psql -c 'create extension if not exists "uuid-ossp";' -U postgres
54
- - cp test/travis/database.yml test/database.yml
55
-
56
- script:
57
- - bundle exec rake test:mysql2
58
- - bundle exec rake test:mysql2_makara
59
- - bundle exec rake test:mysql2spatial
60
- - bundle exec rake test:postgis
61
- - bundle exec rake test:postgresql
62
- - bundle exec rake test:postgresql_makara
63
- - bundle exec rake test:seamless_database_pool
64
- - bundle exec rake test:spatialite
65
- - bundle exec rake test:sqlite3
66
- - bundle exec rubocop
67
-
68
- dist: trusty
69
-
70
- sudo: required
data/gemfiles/3.2.gemfile DELETED
@@ -1,2 +0,0 @@
1
- gem 'activerecord', '~> 3.2.0'
2
- gem 'composite_primary_keys', '~> 5.0'
data/gemfiles/4.0.gemfile DELETED
@@ -1,2 +0,0 @@
1
- gem 'activerecord', '~> 4.0.0'
2
- gem 'composite_primary_keys', '~> 6.0'
data/gemfiles/4.1.gemfile DELETED
@@ -1,2 +0,0 @@
1
- gem 'activerecord', '~> 4.1.0'
2
- gem 'composite_primary_keys', '~> 7.0'