activerecord-import 0.28.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 39f2e5b83b07075c09bba10e3c9a53953b484641
4
- data.tar.gz: 28869f9586c6200e932a34dadbed9f4790ee820d
2
+ SHA256:
3
+ metadata.gz: cbf4c01d6a3f043ed541f7331d6a19e651cbc035fcc3030b17f1e741a6d4e8b7
4
+ data.tar.gz: a740491de16c78d4d94ccb428c69342fd8a809f235ce9d42fc41237a4d15c7e6
5
5
  SHA512:
6
- metadata.gz: dad31c1f3f11c1b6ba63cf2c5e65d71713603cb7604cac06e35d2786f34394e88a2ad69bc76fcaf14d7cd90e84fa277e84427425aa27cd0bcb65c61024990e1a
7
- data.tar.gz: e842906754fd995d1be896e7929213919426ccf9c107f06c996c0216b9331c3232ff85ceb622c9de4678de6ff639e22ee783c5482bb9fbdb8c5740df46d55304
6
+ metadata.gz: 48e62637f6493cd5446cd78aee3db3b4a58e646fb0bc07d3583a662f89f52b03c2a079c83fc2cae807c5577f922e1e3219354cf36dff8ae8cc81ae68266e711f
7
+ data.tar.gz: 2f40f5fd61975589f8af932a3dbf5b6d14d2cfc6884ebe7019c85956c8c380d3faebffb1b600a7fa04536fe262ed40688946c8d35b8cf5b1bfedd1ddff20af5a
@@ -1,30 +1,29 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.3.7
4
+ - 2.5.5
5
5
 
6
6
  env:
7
7
  global:
8
8
  # https://github.com/discourse/discourse/blob/master/.travis.yml
9
9
  - RUBY_GC_MALLOC_LIMIT=50000000
10
10
  matrix:
11
- - AR_VERSION=3.2
12
- - AR_VERSION=4.0
13
- - AR_VERSION=4.1
14
- - AR_VERSION=4.2
15
- - AR_VERSION=5.0
16
11
  - AR_VERSION=5.1
17
12
  - AR_VERSION=5.2
13
+ - AR_VERSION=6.0
18
14
 
19
15
  matrix:
20
16
  include:
21
- - rvm: jruby-9.1.14.0
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
22
24
  env: AR_VERSION=4.2
23
-
24
- script:
25
- - bundle exec rake test:jdbcsqlite3
26
- - bundle exec rake test:jdbcmysql
27
- - bundle exec rake test:jdbcpostgresql
25
+ - rvm: 2.3.8
26
+ env: AR_VERSION=5.0
28
27
 
29
28
  fast_finish: true
30
29
 
@@ -38,7 +37,7 @@ addons:
38
37
  - sqlite3
39
38
  - mysql-server
40
39
  - mysql-client
41
- - postgresql-9.5-postgis-2.3
40
+ - postgresql-9.5-postgis-2.4
42
41
 
43
42
  before_install:
44
43
  - gem update --system
@@ -66,6 +65,10 @@ script:
66
65
  - bundle exec rake test:sqlite3
67
66
  - bundle exec rubocop
68
67
 
69
- dist: trusty
68
+ dist: xenial
69
+
70
+ services:
71
+ - mysql
72
+ - postgresql
70
73
 
71
74
  sudo: required
@@ -1,3 +1,71 @@
1
+ ## Changes in 1.0.4
2
+
3
+ ### Fixes
4
+
5
+ * Use prepend pattern for ActiveRecord::Base#establish_connection patching. Thanks to @dombesz via \#648.
6
+ * Fix NoMethodError when using PostgreSQL ENUM types. Thanks to @sebcoetzee via \#651.
7
+ * Fix issue updating optimistic lock in Postgres. Thanks to @timanovsky
8
+ via \#656.
9
+
10
+ ## Changes in 1.0.3
11
+
12
+ ### New Features
13
+
14
+ * Add support for ActiveRecord 6.1.0.alpha. Thanks to @imtayadeway via
15
+ \#642.
16
+
17
+ ### Fixes
18
+
19
+ * Return an empty array for results instead of nil when importing empty
20
+ array. Thanks to @gyfis via \#636.
21
+
22
+ ## Changes in 1.0.2
23
+
24
+ ### New Features
25
+
26
+ * Add support for CockroachDB adapter. Thanks to @willie via \#605.
27
+ * Add support for ActiveRecord 6.0.0.rc1. Thanks to @madeindjs, @bill-filler,
28
+ @jkowens via \#619, \#623.
29
+
30
+ ### Fixes
31
+
32
+ * Fixes NoMethodError when attempting to use nil logger. Thanks to @MattMecel,
33
+ @khiav22357.
34
+ * Fix issue validating STI models. Thanks to @thejbsmith, @jkowens via
35
+ \#626.
36
+
37
+ ## Changes in 1.0.1
38
+
39
+ ### Fixes
40
+
41
+ * Raise an error with a helpful message if array of values exceeds the number of
42
+ columns for a table. Thanks to @golddranks via \#589.
43
+ * Properly check if model responds to import before creating alias.
44
+ Thanks to @jcw- via \#591.
45
+ * No longer pass :returning option to child associations on recursive
46
+ import. Thanks to @dmitriy-kiriyenko via \#595.
47
+ * Fix import issue for models with Postgresql json/jsonb fields. Thanks
48
+ to @stokarenko via \#594.
49
+ * Fix issue importing models with timestamps that contain timezone
50
+ information. Thaks to @dekaikiwi, @jkowens via \#598.
51
+ * Ignore :no_returning when using :recursive option. Thanks to @dgollahon, @jkowens
52
+ via \#599.
53
+
54
+ ## Changes in 1.0.0
55
+
56
+ ### New Features
57
+
58
+ * Move ActiveRecord::Dirty changes to previous_changes after import.
59
+ Thanks to @stokarenko via \#584.
60
+
61
+ ### Breaking Changes
62
+
63
+ * Previously :on_duplicate_key_update was enabled by default for MySQL.
64
+ The update timestamp columns (updated_at, updated_on) would be updated
65
+ on duplicate key. This was behavior is inconsistent with the other database
66
+ adapters and could also be considered surprising. Going forward it must
67
+ be explicitly enabled. See \#548.
68
+
1
69
  ## Changes in 0.28.2
2
70
 
3
71
  ### Fixes
data/Gemfile CHANGED
@@ -6,6 +6,8 @@ version = ENV['AR_VERSION'].to_f
6
6
 
7
7
  mysql2_version = '0.3.0'
8
8
  mysql2_version = '0.4.0' if version >= 4.2
9
+ sqlite3_version = '1.3.0'
10
+ sqlite3_version = '1.4.0' if version >= 6.0
9
11
 
10
12
  group :development, :test do
11
13
  gem 'rubocop', '~> 0.40.0'
@@ -16,7 +18,7 @@ end
16
18
  platforms :ruby do
17
19
  gem "mysql2", "~> #{mysql2_version}"
18
20
  gem "pg", "~> 0.9"
19
- gem "sqlite3", "~> 1.3.10"
21
+ gem "sqlite3", "~> #{sqlite3_version}"
20
22
  gem "seamless_database_pool", "~> 1.0.20"
21
23
  end
22
24
 
@@ -1,6 +1,6 @@
1
- # activerecord-import [![Build Status](https://travis-ci.org/zdennis/activerecord-import.svg?branch=master)](https://travis-ci.org/zdennis/activerecord-import)
1
+ # Activerecord-Import [![Build Status](https://travis-ci.org/zdennis/activerecord-import.svg?branch=master)](https://travis-ci.org/zdennis/activerecord-import)
2
2
 
3
- activerecord-import is a library for bulk inserting data using ActiveRecord.
3
+ Activerecord-Import is a library for bulk inserting data using ActiveRecord.
4
4
 
5
5
  One of its major features is following activerecord associations and generating the minimal
6
6
  number of SQL insert statements required, avoiding the N+1 insert problem. An example probably
@@ -23,10 +23,10 @@ an 18 hour batch process to <2 hrs.
23
23
 
24
24
  The gem provides the following high-level features:
25
25
 
26
- * activerecord-import can work with raw columns and arrays of values (fastest)
27
- * activerecord-import works with model objects (faster)
28
- * activerecord-import can perform validations (fast)
29
- * activerecord-import can perform on duplicate key updates (requires MySQL or Postgres 9.5+)
26
+ * Works with raw columns and arrays of values (fastest)
27
+ * Works with model objects (faster)
28
+ * Performs validations (fast)
29
+ * Performs on duplicate key updates (requires MySQL, SQLite 3.24.0+, or Postgres 9.5+)
30
30
 
31
31
  ## Table of Contents
32
32
 
@@ -54,6 +54,7 @@ The gem provides the following high-level features:
54
54
  * [More Information](#more-information)
55
55
  * [Contributing](#contributing)
56
56
  * [Running Tests](#running-tests)
57
+ * [Issue Triage](#issue-triage)
57
58
 
58
59
  ### Examples
59
60
 
@@ -63,7 +64,7 @@ Without `activerecord-import`, you'd write something like this:
63
64
 
64
65
  ```ruby
65
66
  10.times do |i|
66
- Book.create! :name => "book #{i}"
67
+ Book.create! name: "book #{i}"
67
68
  end
68
69
  ```
69
70
 
@@ -72,7 +73,7 @@ This would end up making 10 SQL calls. YUCK! With `activerecord-import`, you ca
72
73
  ```ruby
73
74
  books = []
74
75
  10.times do |i|
75
- books << Book.new(:name => "book #{i}")
76
+ books << Book.new(name: "book #{i}")
76
77
  end
77
78
  Book.import books # or use import!
78
79
  ```
@@ -85,13 +86,13 @@ The `import` method can take an array of column names (string or symbols) and an
85
86
 
86
87
  ```ruby
87
88
  columns = [ :title, :author ]
88
- values = [ ['Book1', 'FooManChu'], ['Book2', 'Bob Jones'] ]
89
+ values = [ ['Book1', 'George Orwell'], ['Book2', 'Bob Jones'] ]
89
90
 
90
91
  # Importing without model validations
91
- Book.import columns, values, :validate => false
92
+ Book.import columns, values, validate: false
92
93
 
93
94
  # Import with model validations
94
- Book.import columns, values, :validate => true
95
+ Book.import columns, values, validate: true
95
96
 
96
97
  # when not specified :validate defaults to true
97
98
  Book.import columns, values
@@ -102,7 +103,7 @@ Book.import columns, values
102
103
  The `import` method can take an array of hashes. The keys map to the column names in the database.
103
104
 
104
105
  ```ruby
105
- values = [{ title: 'Book1', author: 'FooManChu' }, { title: 'Book2', author: 'Bob Jones'}]
106
+ values = [{ title: 'Book1', author: 'George Orwell' }, { title: 'Book2', author: 'Bob Jones'}]
106
107
 
107
108
  # Importing without model validations
108
109
  Book.import values, validate: false
@@ -113,13 +114,13 @@ Book.import values, validate: true
113
114
  # when not specified :validate defaults to true
114
115
  Book.import values
115
116
  ```
116
- h2. Import Using Hashes and Explicit Column Names
117
+ #### Import Using Hashes and Explicit Column Names
117
118
 
118
119
  The `import` method can take an array of column names and an array of hash objects. The column names are used to determine what fields of data should be imported. The following example will only import books with the `title` field:
119
120
 
120
121
  ```ruby
121
122
  books = [
122
- { title: "Book 1", author: "FooManChu" },
123
+ { title: "Book 1", author: "George Orwell" },
123
124
  { title: "Book 2", author: "Bob Jones" }
124
125
  ]
125
126
  columns = [ :title ]
@@ -171,15 +172,15 @@ The `import` method can take an array of models. The attributes will be pulled o
171
172
 
172
173
  ```ruby
173
174
  books = [
174
- Book.new(:title => "Book 1", :author => "FooManChu"),
175
- Book.new(:title => "Book 2", :author => "Bob Jones")
175
+ Book.new(title: "Book 1", author: "George Orwell"),
176
+ Book.new(title: "Book 2", author: "Bob Jones")
176
177
  ]
177
178
 
178
179
  # without validations
179
- Book.import books, :validate => false
180
+ Book.import books, validate: false
180
181
 
181
182
  # with validations
182
- Book.import books, :validate => true
183
+ Book.import books, validate: true
183
184
 
184
185
  # when not specified :validate defaults to true
185
186
  Book.import books
@@ -189,16 +190,16 @@ The `import` method can take an array of column names and an array of models. Th
189
190
 
190
191
  ```ruby
191
192
  books = [
192
- Book.new(:title => "Book 1", :author => "FooManChu"),
193
- Book.new(:title => "Book 2", :author => "Bob Jones")
193
+ Book.new(title: "Book 1", author: "George Orwell"),
194
+ Book.new(title: "Book 2", author: "Bob Jones")
194
195
  ]
195
196
  columns = [ :title ]
196
197
 
197
198
  # without validations
198
- Book.import columns, books, :validate => false
199
+ Book.import columns, books, validate: false
199
200
 
200
201
  # with validations
201
- Book.import columns, books, :validate => true
202
+ Book.import columns, books, validate: true
202
203
 
203
204
  # when not specified :validate defaults to true
204
205
  Book.import columns, books
@@ -217,15 +218,15 @@ The `import` method can take a `batch_size` option to control the number of rows
217
218
 
218
219
  ```ruby
219
220
  books = [
220
- Book.new(:title => "Book 1", :author => "FooManChu"),
221
- Book.new(:title => "Book 2", :author => "Bob Jones"),
222
- Book.new(:title => "Book 1", :author => "John Doe"),
223
- Book.new(:title => "Book 2", :author => "Richard Wright")
221
+ Book.new(title: "Book 1", author: "George Orwell"),
222
+ Book.new(title: "Book 2", author: "Bob Jones"),
223
+ Book.new(title: "Book 1", author: "John Doe"),
224
+ Book.new(title: "Book 2", author: "Richard Wright")
224
225
  ]
225
226
  columns = [ :title ]
226
227
 
227
228
  # 2 INSERT statements for 4 records
228
- Book.import columns, books, :batch_size => 2
229
+ Book.import columns, books, batch_size: 2
229
230
  ```
230
231
 
231
232
  #### Recursive
@@ -237,8 +238,8 @@ Assume that Books <code>has_many</code> Reviews.
237
238
  ```ruby
238
239
  books = []
239
240
  10.times do |i|
240
- book = Book.new(:name => "book #{i}")
241
- book.reviews.build(:title => "Excellent")
241
+ book = Book.new(name: "book #{i}")
242
+ book.reviews.build(title: "Excellent")
242
243
  books << book
243
244
  end
244
245
  Book.import books, recursive: true
@@ -248,8 +249,9 @@ Book.import books, recursive: true
248
249
 
249
250
  Key | Options | Default | Description
250
251
  ----------------------- | --------------------- | ------------------ | -----------
251
- :validate | `true`/`false` | `true` | Whether or not to run `ActiveRecord` validations (uniqueness skipped).
252
+ :validate | `true`/`false` | `true` | Whether or not to run `ActiveRecord` validations (uniqueness skipped). This option will always be true when using `import!`.
252
253
  :validate_uniqueness | `true`/`false` | `false` | Whether or not to run uniqueness validations, has potential pitfalls, use with caution (requires `>= v0.27.0`).
254
+ :validate_with_context | `Symbol` |`:create`/`:update` | Allows passing an ActiveModel validation context for each model. Default is `:create` for new records and `:update` for existing ones.
253
255
  :on_duplicate_key_ignore| `true`/`false` | `false` | Allows skipping records with duplicate keys. See [here](https://github.com/zdennis/activerecord-import/#duplicate-key-ignore) for more details.
254
256
  :ignore | `true`/`false` | `false` | Alias for :on_duplicate_key_ignore.
255
257
  :on_duplicate_key_update| :all, `Array`, `Hash` | N/A | Allows upsert logic to be used. See [here](https://github.com/zdennis/activerecord-import/#duplicate-key-update) for more details.
@@ -257,8 +259,8 @@ Key | Options | Default | Descripti
257
259
  :timestamps | `true`/`false` | `true` | Enables/disables timestamps on imported records.
258
260
  :recursive | `true`/`false` | `false` | Imports has_many/has_one associations (PostgreSQL only).
259
261
  :batch_size | `Integer` | total # of records | Max number of records to insert per import
260
- :raise_error | `true`/`false` | `false` | Throws an exception if there are invalid records. `import!` is a shortcut for this.
261
-
262
+ :raise_error | `true`/`false` | `false` | Raises an exception at the first invalid record. This means there will not be a result object returned. The `import!` method is a shortcut for this.
263
+ :all_or_none | `true`/`false` | `false` | Will not import any records if there is a record with validation errors.
262
264
 
263
265
  #### Duplicate Key Ignore
264
266
 
@@ -267,14 +269,14 @@ Key | Options | Default | Descripti
267
269
  For Postgres 9.5+ it adds `ON CONFLICT DO NOTHING`, for MySQL it uses `INSERT IGNORE`, and for SQLite it uses `INSERT OR IGNORE`. Cannot be enabled on a recursive import. For database adapters that normally support setting primary keys on imported objects, this option prevents that from occurring.
268
270
 
269
271
  ```ruby
270
- book = Book.create! title: "Book1", author: "FooManChu"
272
+ book = Book.create! title: "Book1", author: "George Orwell"
271
273
  book.title = "Updated Book Title"
272
274
  book.author = "Bob Barker"
273
275
 
274
276
  Book.import [book], on_duplicate_key_ignore: true
275
277
 
276
278
  book.reload.title # => "Book1" (stayed the same)
277
- book.reload.author # => "FooManChu" (stayed the same)
279
+ book.reload.author # => "George Orwell" (stayed the same)
278
280
  ```
279
281
 
280
282
  The option `:on_duplicate_key_ignore` is bypassed when `:recursive` is enabled for [PostgreSQL imports](https://github.com/zdennis/activerecord-import/wiki#recursive-example-postgresql-only).
@@ -290,7 +292,7 @@ This will use MySQL's `ON DUPLICATE KEY UPDATE` or Postgres/SQLite `ON CONFLICT
290
292
  Basic Update
291
293
 
292
294
  ```ruby
293
- book = Book.create! title: "Book1", author: "FooManChu"
295
+ book = Book.create! title: "Book1", author: "George Orwell"
294
296
  book.title = "Updated Book Title"
295
297
  book.author = "Bob Barker"
296
298
 
@@ -304,13 +306,13 @@ Book.import [book], on_duplicate_key_update: {conflict_target: [:id], columns: [
304
306
  Book.import [book], on_duplicate_key_update: [:title]
305
307
 
306
308
  book.reload.title # => "Updated Book Title" (changed)
307
- book.reload.author # => "FooManChu" (stayed the same)
309
+ book.reload.author # => "George Orwell" (stayed the same)
308
310
  ```
309
311
 
310
312
  Using the value from another column
311
313
 
312
314
  ```ruby
313
- book = Book.create! title: "Book1", author: "FooManChu"
315
+ book = Book.create! title: "Book1", author: "George Orwell"
314
316
  book.title = "Updated Book Title"
315
317
 
316
318
  # MySQL version
@@ -328,7 +330,7 @@ book.reload.author # => "Updated Book Title" (changed)
328
330
  Using Custom SQL
329
331
 
330
332
  ```ruby
331
- book = Book.create! title: "Book1", author: "FooManChu"
333
+ book = Book.create! title: "Book1", author: "George Orwell"
332
334
  book.author = "Bob Barker"
333
335
 
334
336
  # MySQL version
@@ -349,7 +351,7 @@ book.reload.author # => "Bob Barker" (changed)
349
351
  PostgreSQL Using constraints
350
352
 
351
353
  ```ruby
352
- book = Book.create! title: "Book1", author: "FooManChu", edition: 3, published_at: nil
354
+ book = Book.create! title: "Book1", author: "George Orwell", edition: 3, published_at: nil
353
355
  book.published_at = Time.now
354
356
 
355
357
  # in migration
@@ -363,7 +365,7 @@ Book.import [book], on_duplicate_key_update: {constraint_name: :for_upsert, colu
363
365
 
364
366
 
365
367
  book.reload.title # => "Book1" (stayed the same)
366
- book.reload.author # => "FooManChu" (stayed the same)
368
+ book.reload.author # => "George Orwell" (stayed the same)
367
369
  book.reload.edition # => 3 (stayed the same)
368
370
  book.reload.published_at # => 2017-10-09 (changed)
369
371
  ```
@@ -383,7 +385,7 @@ articles = [
383
385
  Article.new(author_id: 3, content: '')
384
386
  ]
385
387
 
386
- demo = Article.import(articles), returning: :title # => #<struct ActiveRecord::Import::Result
388
+ demo = Article.import(articles, returning: :title) # => #<struct ActiveRecord::Import::Result
387
389
 
388
390
  demo.failed_instances
389
391
  => [#<Article id: 3, author_id: 3, title: nil, content: "", created_at: nil, updated_at: nil>]
@@ -397,7 +399,7 @@ demo.ids
397
399
 
398
400
  demo.results
399
401
  => ["First Article", "Second Article"] # for Postgres
400
- => [] for other DBs
402
+ => [] # for other DBs
401
403
  ```
402
404
 
403
405
  ### Counter Cache
@@ -552,7 +554,7 @@ When rubygems pushes the `lib` folder onto the load path a `require` will now fi
552
554
 
553
555
  ### Conflicts With Other Gems
554
556
 
555
- `activerecord-import` adds the `.import` method onto `ActiveRecord::Base`. There are other gems, such as `elasticsearch-rails`, that do the same thing. In conflicts such as this, there is an aliased method named `.bulk_import` that can be used interchangeably.
557
+ Activerecord-Import adds the `.import` method onto `ActiveRecord::Base`. There are other gems, such as `elasticsearch-rails`, that do the same thing. In conflicts such as this, there is an aliased method named `.bulk_import` that can be used interchangeably.
556
558
 
557
559
  If you are using the `apartment` gem, there is a weird triple interaction between that gem, `activerecord-import`, and `activerecord` involving caching of the `sequence_name` of a model. This can be worked around by explcitly setting this value within the model. For example:
558
560
 
@@ -579,7 +581,7 @@ See https://github.com/zdennis/activerecord-import/issues/233 for further discus
579
581
 
580
582
  ### More Information
581
583
 
582
- For more information on activerecord-import please see its wiki: https://github.com/zdennis/activerecord-import/wiki
584
+ For more information on Activerecord-Import please see its wiki: https://github.com/zdennis/activerecord-import/wiki
583
585
 
584
586
  To document new information, please add to the README instead of the wiki. See https://github.com/zdennis/activerecord-import/issues/397 for discussion.
585
587
 
@@ -605,6 +607,10 @@ AR_VERSION=4.2 bundle exec rake test:postgresql test:sqlite3 test:mysql2
605
607
 
606
608
  Once you have pushed up your changes, you can find your CI results [here](https://travis-ci.org/zdennis/activerecord-import/).
607
609
 
610
+ ## Issue Triage [![Open Source Helpers](https://www.codetriage.com/zdennis/activerecord-import/badges/users.svg)](https://www.codetriage.com/zdennis/activerecord-import)
611
+
612
+ You can triage issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to activerecord-import on CodeTriage](https://www.codetriage.com/zdennis/activerecord-import).
613
+
608
614
  # License
609
615
 
610
616
  This is licensed under the ruby license.
@@ -612,17 +618,3 @@ This is licensed under the ruby license.
612
618
  # Author
613
619
 
614
620
  Zach Dennis (zach.dennis@gmail.com)
615
-
616
- # Contributors
617
-
618
- * Jordan Owens (@jkowens)
619
- * Erik Michaels-Ober (@sferik)
620
- * Blythe Dunham
621
- * Gabe da Silveira
622
- * Henry Work
623
- * James Herdman
624
- * Marcus Crafter
625
- * Thibaud Guillaume-Gentil
626
- * Mark Van Holstyn
627
- * Victor Costan
628
- * Dillon Welch
@@ -0,0 +1 @@
1
+ gem 'activerecord', '~> 6.0.0'
@@ -0,0 +1 @@
1
+ gem 'activerecord', '~> 6.1.0.alpha', github: "rails/rails"
@@ -46,7 +46,7 @@ module ActiveRecord::Import::AbstractAdapter
46
46
 
47
47
  if supports_on_duplicate_key_update? && options[:on_duplicate_key_update]
48
48
  post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:primary_key], options[:locking_column] )
49
- elsif options[:on_duplicate_key_update]
49
+ elsif logger && 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
52
52
 
@@ -59,8 +59,14 @@ module ActiveRecord::Import::AbstractAdapter
59
59
  post_sql_statements
60
60
  end
61
61
 
62
+ def increment_locking_column!(table_name, results, locking_column)
63
+ if locking_column.present?
64
+ results << "\"#{locking_column}\"=#{table_name}.\"#{locking_column}\"+1"
65
+ end
66
+ end
67
+
62
68
  def supports_on_duplicate_key_update?
63
- false
69
+ true
64
70
  end
65
71
  end
66
72
  end
@@ -1,6 +1,5 @@
1
1
  module ActiveRecord::Import::MysqlAdapter
2
2
  include ActiveRecord::Import::ImportSupport
3
- include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
4
3
 
5
4
  NO_MAX_PACKET = 0
6
5
  QUERY_OVERHEAD = 8 # This was shown to be true for MySQL, but it's not clear where the overhead is from.
@@ -71,14 +70,11 @@ module ActiveRecord::Import::MysqlAdapter
71
70
 
72
71
  # Add a column to be updated on duplicate key update
73
72
  def add_column_for_on_duplicate_key_update( column, options = {} ) # :nodoc:
74
- if options.include?(:on_duplicate_key_update)
75
- columns = options[:on_duplicate_key_update]
73
+ if (columns = options[:on_duplicate_key_update])
76
74
  case columns
77
75
  when Array then columns << column.to_sym unless columns.include?(column.to_sym)
78
76
  when Hash then columns[column.to_sym] = column.to_sym
79
77
  end
80
- elsif !options[:ignore] && !options[:on_duplicate_key_ignore]
81
- options[:on_duplicate_key_update] = [column.to_sym]
82
78
  end
83
79
  end
84
80
 
@@ -105,7 +101,7 @@ module ActiveRecord::Import::MysqlAdapter
105
101
  qc = quote_column_name( column )
106
102
  "#{table_name}.#{qc}=VALUES(#{qc})"
107
103
  end
108
- increment_locking_column!(results, table_name, locking_column)
104
+ increment_locking_column!(table_name, results, locking_column)
109
105
  results.join( ',' )
110
106
  end
111
107
 
@@ -115,7 +111,7 @@ module ActiveRecord::Import::MysqlAdapter
115
111
  qc2 = quote_column_name( column2 )
116
112
  "#{table_name}.#{qc1}=VALUES( #{qc2} )"
117
113
  end
118
- increment_locking_column!(results, table_name, locking_column)
114
+ increment_locking_column!(table_name, results, locking_column)
119
115
  results.join( ',')
120
116
  end
121
117
 
@@ -124,9 +120,9 @@ module ActiveRecord::Import::MysqlAdapter
124
120
  exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
125
121
  end
126
122
 
127
- def increment_locking_column!(results, table_name, locking_column)
123
+ def increment_locking_column!(table_name, results, locking_column)
128
124
  if locking_column.present?
129
- results << "#{table_name}.`#{locking_column}`=`#{locking_column}`+1"
125
+ results << "`#{locking_column}`=#{table_name}.`#{locking_column}`+1"
130
126
  end
131
127
  end
132
128
  end
@@ -1,6 +1,5 @@
1
1
  module ActiveRecord::Import::PostgreSQLAdapter
2
2
  include ActiveRecord::Import::ImportSupport
3
- include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
4
3
 
5
4
  MIN_VERSION_FOR_UPSERT = 90_500
6
5
 
@@ -19,7 +18,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
19
18
  sql2insert = base_sql + values.join( ',' ) + post_sql
20
19
 
21
20
  columns = returning_columns(options)
22
- if columns.blank? || options[:no_returning]
21
+ if columns.blank? || (options[:no_returning] && !options[:recursive])
23
22
  insert( sql2insert, *args )
24
23
  else
25
24
  returned_values = if columns.size > 1
@@ -73,14 +72,14 @@ module ActiveRecord::Import::PostgreSQLAdapter
73
72
  if (options[:ignore] || options[:on_duplicate_key_ignore]) && !options[:on_duplicate_key_update] && !options[:recursive]
74
73
  sql << sql_for_on_duplicate_key_ignore( table_name, options[:on_duplicate_key_ignore] )
75
74
  end
76
- elsif options[:on_duplicate_key_ignore] && !options[:on_duplicate_key_update]
75
+ elsif logger && options[:on_duplicate_key_ignore] && !options[:on_duplicate_key_update]
77
76
  logger.warn "Ignoring on_duplicate_key_ignore because it is not supported by the database."
78
77
  end
79
78
 
80
79
  sql += super(table_name, options)
81
80
 
82
81
  columns = returning_columns(options)
83
- unless columns.blank? || options[:no_returning]
82
+ unless columns.blank? || (options[:no_returning] && !options[:recursive])
84
83
  sql << " RETURNING \"#{columns.join('", "')}\""
85
84
  end
86
85
 
@@ -158,7 +157,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
158
157
  qc = quote_column_name( column )
159
158
  "#{qc}=EXCLUDED.#{qc}"
160
159
  end
161
- increment_locking_column!(results, locking_column)
160
+ increment_locking_column!(table_name, results, locking_column)
162
161
  results.join( ',' )
163
162
  end
164
163
 
@@ -168,7 +167,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
168
167
  qc2 = quote_column_name( column2 )
169
168
  "#{qc1}=EXCLUDED.#{qc2}"
170
169
  end
171
- increment_locking_column!(results, locking_column)
170
+ increment_locking_column!(table_name, results, locking_column)
172
171
  results.join( ',' )
173
172
  end
174
173
 
@@ -195,17 +194,17 @@ module ActiveRecord::Import::PostgreSQLAdapter
195
194
  exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('duplicate key')
196
195
  end
197
196
 
198
- def supports_on_duplicate_key_update?(current_version = postgresql_version)
199
- current_version >= MIN_VERSION_FOR_UPSERT
197
+ def supports_on_duplicate_key_update?
198
+ database_version >= MIN_VERSION_FOR_UPSERT
200
199
  end
201
200
 
202
201
  def supports_setting_primary_key_of_imported_objects?
203
202
  true
204
203
  end
205
204
 
206
- def increment_locking_column!(results, locking_column)
207
- if locking_column.present?
208
- results << "\"#{locking_column}\"=EXCLUDED.\"#{locking_column}\"+1"
209
- end
205
+ private
206
+
207
+ def database_version
208
+ defined?(postgresql_version) ? postgresql_version : super
210
209
  end
211
210
  end
@@ -1,6 +1,5 @@
1
1
  module ActiveRecord::Import::SQLite3Adapter
2
2
  include ActiveRecord::Import::ImportSupport
3
- include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
4
3
 
5
4
  MIN_VERSION_FOR_IMPORT = "3.7.11".freeze
6
5
  MIN_VERSION_FOR_UPSERT = "3.24.0".freeze
@@ -9,16 +8,12 @@ module ActiveRecord::Import::SQLite3Adapter
9
8
  # Override our conformance to ActiveRecord::Import::ImportSupport interface
10
9
  # to ensure that we only support import in supported version of SQLite.
11
10
  # Which INSERT statements with multiple value sets was introduced in 3.7.11.
12
- def supports_import?(current_version = sqlite_version)
13
- if current_version >= MIN_VERSION_FOR_IMPORT
14
- true
15
- else
16
- false
17
- end
11
+ def supports_import?
12
+ database_version >= MIN_VERSION_FOR_IMPORT
18
13
  end
19
14
 
20
- def supports_on_duplicate_key_update?(current_version = sqlite_version)
21
- current_version >= MIN_VERSION_FOR_UPSERT
15
+ def supports_on_duplicate_key_update?
16
+ database_version >= MIN_VERSION_FOR_UPSERT
22
17
  end
23
18
 
24
19
  # +sql+ can be a single string or an array. If it is an array all
@@ -96,7 +91,7 @@ module ActiveRecord::Import::SQLite3Adapter
96
91
 
97
92
  # Returns a generated ON CONFLICT DO UPDATE statement given the passed
98
93
  # in +args+.
99
- def sql_for_on_duplicate_key_update( _table_name, *args ) # :nodoc:
94
+ def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
100
95
  arg, primary_key, locking_column = args
101
96
  arg = { columns: arg } if arg.is_a?( Array ) || arg.is_a?( String )
102
97
  return unless arg.is_a?( Hash )
@@ -117,9 +112,9 @@ module ActiveRecord::Import::SQLite3Adapter
117
112
 
118
113
  sql << "#{conflict_target}DO UPDATE SET "
119
114
  if columns.is_a?( Array )
120
- sql << sql_for_on_duplicate_key_update_as_array( locking_column, columns )
115
+ sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, columns )
121
116
  elsif columns.is_a?( Hash )
122
- sql << sql_for_on_duplicate_key_update_as_hash( locking_column, columns )
117
+ sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, columns )
123
118
  elsif columns.is_a?( String )
124
119
  sql << columns
125
120
  else
@@ -131,22 +126,22 @@ module ActiveRecord::Import::SQLite3Adapter
131
126
  sql
132
127
  end
133
128
 
134
- def sql_for_on_duplicate_key_update_as_array( locking_column, arr ) # :nodoc:
129
+ def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
135
130
  results = arr.map do |column|
136
131
  qc = quote_column_name( column )
137
132
  "#{qc}=EXCLUDED.#{qc}"
138
133
  end
139
- increment_locking_column!(results, locking_column)
134
+ increment_locking_column!(table_name, results, locking_column)
140
135
  results.join( ',' )
141
136
  end
142
137
 
143
- def sql_for_on_duplicate_key_update_as_hash( locking_column, hsh ) # :nodoc:
138
+ def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
144
139
  results = hsh.map do |column1, column2|
145
140
  qc1 = quote_column_name( column1 )
146
141
  qc2 = quote_column_name( column2 )
147
142
  "#{qc1}=EXCLUDED.#{qc2}"
148
143
  end
149
- increment_locking_column!(results, locking_column)
144
+ increment_locking_column!(table_name, results, locking_column)
150
145
  results.join( ',' )
151
146
  end
152
147
 
@@ -170,9 +165,9 @@ module ActiveRecord::Import::SQLite3Adapter
170
165
  exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('duplicate key')
171
166
  end
172
167
 
173
- def increment_locking_column!(results, locking_column)
174
- if locking_column.present?
175
- results << "\"#{locking_column}\"=EXCLUDED.\"#{locking_column}\"+1"
176
- end
168
+ private
169
+
170
+ def database_version
171
+ defined?(sqlite_version) ? sqlite_version : super
177
172
  end
178
173
  end
@@ -13,6 +13,7 @@ module ActiveRecord::Import
13
13
  when 'postgresql_makara' then 'postgresql'
14
14
  when 'makara_postgis' then 'postgresql'
15
15
  when 'postgis' then 'postgresql'
16
+ when 'cockroachdb' then 'postgresql'
16
17
  else adapter
17
18
  end
18
19
  end
@@ -26,7 +27,13 @@ module ActiveRecord::Import
26
27
 
27
28
  # Loads the import functionality for the passed in ActiveRecord connection
28
29
  def self.load_from_connection_pool(connection_pool)
29
- require_adapter connection_pool.spec.config[:adapter]
30
+ adapter =
31
+ if connection_pool.respond_to?(:db_config) # ActiveRecord >= 6.1
32
+ connection_pool.db_config.adapter
33
+ else
34
+ connection_pool.spec.config[:adapter]
35
+ end
36
+ require_adapter adapter
30
37
  end
31
38
  end
32
39
 
@@ -11,12 +11,6 @@ module ActiveRecord::Import #:nodoc:
11
11
  end
12
12
  end
13
13
 
14
- module OnDuplicateKeyUpdateSupport #:nodoc:
15
- def supports_on_duplicate_key_update? #:nodoc:
16
- true
17
- end
18
- end
19
-
20
14
  class MissingColumnError < StandardError
21
15
  def initialize(name, index)
22
16
  super "Missing column for value <#{name}> at index #{index}"
@@ -26,6 +20,7 @@ module ActiveRecord::Import #:nodoc:
26
20
  class Validator
27
21
  def initialize(klass, options = {})
28
22
  @options = options
23
+ @validator_class = klass
29
24
  init_validations(klass)
30
25
  end
31
26
 
@@ -70,6 +65,8 @@ module ActiveRecord::Import #:nodoc:
70
65
  end
71
66
 
72
67
  def valid_model?(model)
68
+ init_validations(model.class) unless model.class == @validator_class
69
+
73
70
  validation_context = @options[:validate_with_context]
74
71
  validation_context ||= (model.new_record? ? :create : :update)
75
72
  current_context = model.send(:validation_context)
@@ -242,16 +239,16 @@ class ActiveRecord::Associations::CollectionAssociation
242
239
  alias import bulk_import unless respond_to? :import
243
240
  end
244
241
 
242
+ module ActiveRecord::Import::Connection
243
+ def establish_connection(args = nil)
244
+ super(args)
245
+ ActiveRecord::Import.load_from_connection_pool connection_pool
246
+ end
247
+ end
248
+
245
249
  class ActiveRecord::Base
246
250
  class << self
247
- def establish_connection_with_activerecord_import(*args)
248
- conn = establish_connection_without_activerecord_import(*args)
249
- ActiveRecord::Import.load_from_connection_pool connection_pool
250
- conn
251
- end
252
-
253
- alias establish_connection_without_activerecord_import establish_connection
254
- alias establish_connection establish_connection_with_activerecord_import
251
+ prepend ActiveRecord::Import::Connection
255
252
 
256
253
  # Returns true if the current database connection adapter
257
254
  # supports import functionality, otherwise returns false.
@@ -528,7 +525,7 @@ class ActiveRecord::Base
528
525
  import_helper(*args)
529
526
  end
530
527
  end
531
- alias import bulk_import unless respond_to? :import
528
+ alias import bulk_import unless ActiveRecord::Base.respond_to? :import
532
529
 
533
530
  # Imports a collection of values if all values are valid. Import fails at the
534
531
  # first encountered validation error and raises ActiveRecord::RecordInvalid
@@ -540,7 +537,7 @@ class ActiveRecord::Base
540
537
 
541
538
  bulk_import(*args, options)
542
539
  end
543
- alias import! bulk_import! unless respond_to? :import!
540
+ alias import! bulk_import! unless ActiveRecord::Base.respond_to? :import!
544
541
 
545
542
  def import_helper( *args )
546
543
  options = { validate: true, timestamps: true }
@@ -574,15 +571,6 @@ class ActiveRecord::Base
574
571
  end
575
572
  end
576
573
 
577
- default_values = column_defaults
578
- stored_attrs = respond_to?(:stored_attributes) ? stored_attributes : {}
579
- serialized_attrs = if defined?(ActiveRecord::Type::Serialized)
580
- attrs = column_names.select { |c| type_for_attribute(c.to_s).class == ActiveRecord::Type::Serialized }
581
- Hash[attrs.map { |a| [a, nil] }]
582
- else
583
- serialized_attributes
584
- end
585
-
586
574
  update_attrs = if record_timestamps && options[:timestamps]
587
575
  if respond_to?(:timestamp_attributes_for_update, true)
588
576
  send(:timestamp_attributes_for_update).map(&:to_sym)
@@ -608,12 +596,8 @@ class ActiveRecord::Base
608
596
  update_attrs && update_attrs.include?(name.to_sym) &&
609
597
  !model.send("#{name}_changed?")
610
598
  nil
611
- elsif stored_attrs.key?(name.to_sym) ||
612
- serialized_attrs.key?(name.to_s) ||
613
- default_values[name.to_s]
614
- model.read_attribute(name.to_s)
615
599
  else
616
- model.read_attribute_before_type_cast(name.to_s)
600
+ model.read_attribute(name.to_s)
617
601
  end
618
602
  end
619
603
  end
@@ -640,7 +624,7 @@ class ActiveRecord::Base
640
624
  end
641
625
  # supports empty array
642
626
  elsif args.last.is_a?( Array ) && args.last.empty?
643
- return ActiveRecord::Import::Result.new([], 0, [])
627
+ return ActiveRecord::Import::Result.new([], 0, [], [])
644
628
  # supports 2-element array and array
645
629
  elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
646
630
 
@@ -868,7 +852,10 @@ class ActiveRecord::Base
868
852
  end
869
853
 
870
854
  models.each do |model|
871
- if model.respond_to?(:clear_changes_information) # Rails 4.0 and higher
855
+ if model.respond_to?(:changes_applied) # Rails 4.1.8 and higher
856
+ model.changes_internally_applied if model.respond_to?(:changes_internally_applied) # legacy behavior for Rails 5.1
857
+ model.changes_applied
858
+ elsif model.respond_to?(:clear_changes_information) # Rails 4.0 and higher
872
859
  model.clear_changes_information
873
860
  else # Rails 3.2
874
861
  model.instance_variable_get(:@changed_attributes).clear
@@ -901,8 +888,9 @@ class ActiveRecord::Base
901
888
  associated_objects_by_class = {}
902
889
  models.each { |model| find_associated_objects_for_import(associated_objects_by_class, model) }
903
890
 
904
- # :on_duplicate_key_update not supported for associations
891
+ # :on_duplicate_key_update and :returning not supported for associations
905
892
  options.delete(:on_duplicate_key_update)
893
+ options.delete(:returning)
906
894
 
907
895
  associated_objects_by_class.each_value do |associations|
908
896
  associations.each_value do |associated_records|
@@ -970,9 +958,11 @@ class ActiveRecord::Base
970
958
  val = serialized_attributes[column.name].dump(val)
971
959
  end
972
960
  # Fixes #443 to support binary (i.e. bytea) columns on PG
973
- val = column.type_cast(val) unless column.type.to_sym == :binary
961
+ val = column.type_cast(val) unless column.type && column.type.to_sym == :binary
974
962
  connection_memo.quote(val, column)
975
963
  end
964
+ else
965
+ raise ArgumentError, "Number of values (#{arr.length}) exceeds number of columns (#{columns.length})"
976
966
  end
977
967
  end
978
968
  "(#{my_values.join(',')})"
@@ -39,8 +39,8 @@ module ActiveRecord # :nodoc:
39
39
 
40
40
  next unless matched_instance
41
41
 
42
- instance.send :clear_aggregation_cache
43
42
  instance.send :clear_association_cache
43
+ instance.send :clear_aggregation_cache if instance.respond_to?(:clear_aggregation_cache, true)
44
44
  instance.instance_variable_set :@attributes, matched_instance.instance_variable_get(:@attributes)
45
45
 
46
46
  if instance.respond_to?(:clear_changes_information)
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Import
3
- VERSION = "0.28.2".freeze
3
+ VERSION = "1.0.4".freeze
4
4
  end
5
5
  end
@@ -17,6 +17,11 @@ describe "#import" do
17
17
  assert_equal error.message, "Last argument should be a two dimensional array '[[]]'. First element in array was a String"
18
18
  end
19
19
 
20
+ it "warns you that you're passing more data than you ought to" do
21
+ error = assert_raise(ArgumentError) { Topic.import %w(title author_name), [['Author #1', 'Book #1', 0]] }
22
+ assert_equal error.message, "Number of values (8) exceeds number of columns (7)"
23
+ end
24
+
20
25
  it "should not produce an error when importing empty arrays" do
21
26
  assert_nothing_raised do
22
27
  Topic.import []
@@ -3,11 +3,23 @@ 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
8
19
  t.text :preferences
9
20
 
10
21
  if t.respond_to?(:json)
22
+ t.json :pure_json_data
11
23
  t.json :data
12
24
  else
13
25
  t.text :data
@@ -20,6 +32,7 @@ ActiveRecord::Schema.define do
20
32
  end
21
33
 
22
34
  if t.respond_to?(:jsonb)
35
+ t.jsonb :pure_jsonb_data
23
36
  t.jsonb :settings
24
37
  t.jsonb :json_data, null: false, default: {}
25
38
  else
@@ -27,6 +40,8 @@ ActiveRecord::Schema.define do
27
40
  t.text :json_data
28
41
  end
29
42
 
43
+ t.column :vendor_type, :vendor_type
44
+
30
45
  t.datetime :created_at
31
46
  t.datetime :updated_at
32
47
  end
@@ -37,6 +37,12 @@ def should_support_postgresql_import_functionality
37
37
  assert !topic.changed?
38
38
  end
39
39
 
40
+ if ENV['AR_VERSION'].to_f > 4.1
41
+ it "moves the dirty changes to previous_changes" do
42
+ assert topic.previous_changes.present?
43
+ end
44
+ end
45
+
40
46
  it "marks models as persisted" do
41
47
  assert !topic.new_record?
42
48
  assert topic.persisted?
@@ -110,6 +116,17 @@ def should_support_postgresql_import_functionality
110
116
  assert_equal [%w(King It)], result.results
111
117
  end
112
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
+
113
130
  context "when primary key and returning overlap" do
114
131
  let(:result) { Book.import(books, returning: %w(id title)) }
115
132
 
@@ -228,6 +245,30 @@ def should_support_postgresql_import_functionality
228
245
  assert_equal({}, Vendor.first.json_data)
229
246
  end
230
247
  end
248
+
249
+ %w(json jsonb).each do |json_type|
250
+ describe "with pure #{json_type} fields" do
251
+ let(:data) { { a: :b } }
252
+ let(:json_field_name) { "pure_#{json_type}_data" }
253
+ it "imports the values from saved records" do
254
+ vendor = Vendor.create!(name: 'Vendor 1', json_field_name => data)
255
+
256
+ Vendor.import [vendor], on_duplicate_key_update: [json_field_name]
257
+ assert_equal(data.as_json, vendor.reload[json_field_name])
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ describe "with enum field" do
264
+ let(:vendor_type) { "retailer" }
265
+ it "imports the correct values for enum fields" do
266
+ vendor = Vendor.new(name: 'Vendor 1', vendor_type: vendor_type)
267
+ assert_difference "Vendor.count", +1 do
268
+ Vendor.import [vendor]
269
+ end
270
+ assert_equal(vendor_type, Vendor.first.vendor_type)
271
+ end
231
272
  end
232
273
 
233
274
  describe "with binary field" do
@@ -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
@@ -183,5 +183,34 @@ def should_support_recursive_import
183
183
  end
184
184
  end
185
185
  end
186
+
187
+ # If returning option is provided, it is only applied to top level models so that SQL with invalid
188
+ # columns, keys, etc isn't generated for child associations when doing recursive import
189
+ describe "returning" do
190
+ let(:new_topics) { Build(1, :topic_with_book) }
191
+
192
+ it "imports objects with associations" do
193
+ assert_difference "Topic.count", +1 do
194
+ Topic.import new_topics, recursive: true, returning: [:content], validate: false
195
+ new_topics.each do |topic|
196
+ assert_not_nil topic.id
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ # If no returning option is provided, it is ignored
203
+ describe "no returning" do
204
+ let(:new_topics) { Build(1, :topic_with_book) }
205
+
206
+ it "is ignored and imports objects with associations" do
207
+ assert_difference "Topic.count", +1 do
208
+ Topic.import new_topics, recursive: true, no_returning: true, validate: false
209
+ new_topics.each do |topic|
210
+ assert_not_nil topic.id
211
+ end
212
+ end
213
+ end
214
+ end
186
215
  end
187
216
  end
@@ -5,21 +5,8 @@ def should_support_sqlite3_import_functionality
5
5
  end
6
6
 
7
7
  describe "#supports_imports?" do
8
- context "and SQLite is 3.7.11 or higher" do
9
- it "supports import" do
10
- version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.11")
11
- assert ActiveRecord::Base.supports_import?(version)
12
-
13
- version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.12")
14
- assert ActiveRecord::Base.supports_import?(version)
15
- end
16
- end
17
-
18
- context "and SQLite less than 3.7.11" do
19
- it "doesn't support import" do
20
- version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.10")
21
- assert !ActiveRecord::Base.supports_import?(version)
22
- end
8
+ it "should support import" do
9
+ assert ActiveRecord::Base.supports_import?
23
10
  end
24
11
  end
25
12
 
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.28.2
4
+ version: 1.0.4
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-01-29 00:00:00.000000000 Z
11
+ date: 2019-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -75,6 +75,8 @@ files:
75
75
  - gemfiles/5.0.gemfile
76
76
  - gemfiles/5.1.gemfile
77
77
  - gemfiles/5.2.gemfile
78
+ - gemfiles/6.0.gemfile
79
+ - gemfiles/6.1.gemfile
78
80
  - lib/activerecord-import.rb
79
81
  - lib/activerecord-import/active_record/adapters/abstract_adapter.rb
80
82
  - lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb
@@ -183,8 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
185
  - !ruby/object:Gem::Version
184
186
  version: '0'
185
187
  requirements: []
186
- rubyforge_project:
187
- rubygems_version: 2.6.11
188
+ rubygems_version: 3.0.6
188
189
  signing_key:
189
190
  specification_version: 4
190
191
  summary: Bulk insert extension for ActiveRecord