activerecord-import 1.0.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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'