activerecord-import 0.18.1 → 0.18.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +1 -1
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +1 -1
- data/lib/activerecord-import/import.rb +47 -36
- data/lib/activerecord-import/version.rb +1 -1
- data/test/import_test.rb +15 -0
- data/test/models/topic.rb +1 -0
- data/test/support/shared_examples/on_duplicate_key_ignore.rb +6 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ebf1fdae1a4d300498ed6ba18ea8d4039697734
|
4
|
+
data.tar.gz: 41e6dfff68a59c0fd9184691cbe6731cc420df8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba3161f35e5521a4febe1a66e729f9a9c549620f54119992d87a834148dc3a42f9e28f3f4c4ca9fb722a0c73639ca678db6d9363325fe6e73a5fb61b58422c59
|
7
|
+
data.tar.gz: 4248f96c0adbd65300e1ba161ea91fcf707ac151523121ac9bc541d24cec8f32229bde28ac1783ea6ec69c1f3043f3ac5b5a06c094d2fe9f2c04f952128a0cf6
|
data/.travis.yml
CHANGED
@@ -27,9 +27,6 @@ matrix:
|
|
27
27
|
- bundle exec rake test:jdbcmysql
|
28
28
|
- bundle exec rake test:jdbcpostgresql
|
29
29
|
|
30
|
-
allow_failures:
|
31
|
-
- env: AR_VERSION=5.1
|
32
|
-
|
33
30
|
fast_finish: true
|
34
31
|
|
35
32
|
before_script:
|
@@ -47,6 +44,7 @@ addons:
|
|
47
44
|
- travis-ci/sqlite3
|
48
45
|
packages:
|
49
46
|
- sqlite3
|
47
|
+
- postgresql-9.5-postgis-2.3
|
50
48
|
|
51
49
|
script:
|
52
50
|
- bundle exec rake test:mysql2
|
@@ -60,4 +58,4 @@ script:
|
|
60
58
|
- bundle exec rake test:sqlite3
|
61
59
|
- bundle exec rubocop
|
62
60
|
|
63
|
-
|
61
|
+
dist: trusty
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## Changes in 0.18.2
|
2
|
+
|
3
|
+
### Fixes
|
4
|
+
|
5
|
+
* Enable custom validate callbacks when validating import. Thanks to @afn via \#410.
|
6
|
+
* Prevent wrong IDs being set on models when using :on_duplicate_key_ignore.
|
7
|
+
Thanks to @afn, @jkowens via \#412.
|
8
|
+
|
1
9
|
## Changes in 0.18.1
|
2
10
|
|
3
11
|
### Fixes
|
data/Gemfile
CHANGED
@@ -50,7 +50,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
50
50
|
|
51
51
|
sql += super(table_name, options)
|
52
52
|
|
53
|
-
unless options[:
|
53
|
+
unless options[:primary_key].blank? || options[:no_returning]
|
54
54
|
primary_key = Array(options[:primary_key])
|
55
55
|
sql << " RETURNING \"#{primary_key.join('", "')}\""
|
56
56
|
end
|
@@ -24,9 +24,8 @@ module ActiveRecord::Import #:nodoc:
|
|
24
24
|
end
|
25
25
|
|
26
26
|
class Validator
|
27
|
-
def initialize(
|
28
|
-
@
|
29
|
-
@options = options
|
27
|
+
def initialize(options = {})
|
28
|
+
@options = options
|
30
29
|
end
|
31
30
|
|
32
31
|
def valid_model?(model)
|
@@ -34,38 +33,47 @@ module ActiveRecord::Import #:nodoc:
|
|
34
33
|
validation_context ||= (model.new_record? ? :create : :update)
|
35
34
|
|
36
35
|
current_context = model.send(:validation_context)
|
37
|
-
|
38
|
-
|
36
|
+
begin
|
37
|
+
model.send(:validation_context=, validation_context)
|
38
|
+
model.errors.clear
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
if
|
43
|
-
v.validate(model) if validate?(v, model)
|
44
|
-
end
|
40
|
+
validate_callbacks = model._validate_callbacks.dup
|
41
|
+
validate_callbacks.each do |callback|
|
42
|
+
validate_callbacks.delete(callback) if callback.raw_filter.is_a? ActiveRecord::Validations::UniquenessValidator
|
45
43
|
end
|
46
|
-
end
|
47
|
-
|
48
|
-
if model.respond_to?(:run_validation_callbacks)
|
49
|
-
model.send(:_run_validation_callbacks, &validation_proc)
|
50
|
-
else
|
51
|
-
model.send(:run_callbacks, :validation, &validation_proc)
|
52
|
-
end
|
53
|
-
|
54
|
-
model.send(:validation_context=, current_context)
|
55
|
-
model.errors.empty?
|
56
|
-
end
|
57
44
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
45
|
+
model.run_callbacks(:validation) do
|
46
|
+
if defined?(ActiveSupport::Callbacks::Filters::Environment) # ActiveRecord >= 4.1
|
47
|
+
runner = validate_callbacks.compile
|
48
|
+
env = ActiveSupport::Callbacks::Filters::Environment.new(model, false, nil)
|
49
|
+
if runner.respond_to?(:call) # ActiveRecord < 5.1
|
50
|
+
runner.call(env)
|
51
|
+
else # ActiveRecord 5.1
|
52
|
+
# Note that this is a gross simplification of ActiveSupport::Callbacks#run_callbacks.
|
53
|
+
# It's technically possible for there to exist an "around" callback in the
|
54
|
+
# :validate chain, but this would be an aberration, since Rails doesn't define
|
55
|
+
# "around_validate". Still, rather than silently ignoring such callbacks, we
|
56
|
+
# explicitly raise a RuntimeError, since activerecord-import was asked to perform
|
57
|
+
# validations and it's unable to do so.
|
58
|
+
#
|
59
|
+
# The alternative here would be to copy-and-paste the bulk of the
|
60
|
+
# ActiveSupport::Callbacks#run_callbacks method, which is undesirable if there's
|
61
|
+
# no real-world use case for it.
|
62
|
+
raise "The :validate callback chain contains an 'around' callback, which is unsupported" unless runner.final?
|
63
|
+
runner.invoke_before(env)
|
64
|
+
runner.invoke_after(env)
|
65
|
+
end
|
66
|
+
elsif validate_callbacks.method(:compile).arity == 0 # ActiveRecord = 4.0
|
67
|
+
model.instance_eval validate_callbacks.compile
|
68
|
+
else # ActiveRecord 3.x
|
69
|
+
model.instance_eval validate_callbacks.compile(nil, model)
|
70
|
+
end
|
64
71
|
end
|
65
|
-
end
|
66
72
|
|
67
|
-
|
68
|
-
|
73
|
+
model.errors.empty?
|
74
|
+
ensure
|
75
|
+
model.send(:validation_context=, current_context)
|
76
|
+
end
|
69
77
|
end
|
70
78
|
end
|
71
79
|
end
|
@@ -212,7 +220,9 @@ class ActiveRecord::Base
|
|
212
220
|
# records that contain duplicate keys. For Postgres 9.5+ it adds
|
213
221
|
# ON CONFLICT DO NOTHING, for MySQL it uses INSERT IGNORE, and for
|
214
222
|
# SQLite it uses INSERT OR IGNORE. Cannot be enabled on a
|
215
|
-
# recursive import.
|
223
|
+
# recursive import. For database adapters that normally support
|
224
|
+
# setting primary keys on imported objects, this option prevents
|
225
|
+
# that from occurring.
|
216
226
|
# * +on_duplicate_key_update+ - an Array or Hash, tells import to
|
217
227
|
# use MySQL's ON DUPLICATE KEY UPDATE or Postgres 9.5+ ON CONFLICT
|
218
228
|
# DO UPDATE ability. See On Duplicate Key Update below.
|
@@ -511,7 +521,9 @@ class ActiveRecord::Base
|
|
511
521
|
|
512
522
|
# if we have ids, then set the id on the models and mark the models as clean.
|
513
523
|
if models && support_setting_primary_key_of_imported_objects?
|
514
|
-
|
524
|
+
if options[:recursive] || !(options[:ignore] || options[:on_duplicate_key_ignore])
|
525
|
+
set_attributes_and_mark_clean(models, return_obj, timestamps)
|
526
|
+
end
|
515
527
|
|
516
528
|
# if there are auto-save associations on the models we imported that are new, import them as well
|
517
529
|
import_associations(models, options.dup) if options[:recursive]
|
@@ -530,8 +542,7 @@ class ActiveRecord::Base
|
|
530
542
|
def import_with_validations( column_names, array_of_attributes, options = {} )
|
531
543
|
failed_instances = []
|
532
544
|
|
533
|
-
|
534
|
-
validator = ActiveRecord::Import::Validator.new(validators, options)
|
545
|
+
validator = ActiveRecord::Import::Validator.new(options)
|
535
546
|
|
536
547
|
if block_given?
|
537
548
|
yield validator, failed_instances
|
@@ -700,8 +711,8 @@ class ActiveRecord::Base
|
|
700
711
|
# Returns SQL the VALUES for an INSERT statement given the passed in +columns+
|
701
712
|
# and +array_of_attributes+.
|
702
713
|
def values_sql_for_columns_and_attributes(columns, array_of_attributes) # :nodoc:
|
703
|
-
# connection
|
704
|
-
# Reuse the same
|
714
|
+
# connection gets called a *lot* in this high intensity loop.
|
715
|
+
# Reuse the same one w/in the loop, otherwise it would keep being re-retreived (= lots of time for large imports)
|
705
716
|
connection_memo = connection
|
706
717
|
|
707
718
|
array_of_attributes.map do |arr|
|
data/test/import_test.rb
CHANGED
@@ -168,6 +168,15 @@ describe "#import" do
|
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
171
|
+
it "should not alter the callback chain of the model" do
|
172
|
+
attributes = columns.zip(valid_values.first).to_h
|
173
|
+
topic = Topic.new attributes
|
174
|
+
Topic.import [topic], validate: true
|
175
|
+
duplicate_topic = Topic.new attributes
|
176
|
+
Topic.import [duplicate_topic], validate: true
|
177
|
+
assert duplicate_topic.invalid?
|
178
|
+
end
|
179
|
+
|
171
180
|
it "should not import invalid data" do
|
172
181
|
assert_no_difference "Topic.count" do
|
173
182
|
Topic.import columns, invalid_values, validate: true
|
@@ -230,6 +239,12 @@ describe "#import" do
|
|
230
239
|
Topic.import columns, [["invalid", "Jerry Carter"]], validate: true
|
231
240
|
end
|
232
241
|
end
|
242
|
+
|
243
|
+
it "should call validation methods" do
|
244
|
+
assert_no_difference "Topic.count" do
|
245
|
+
Topic.import columns, [["validate_failed", "Jerry Carter"]], validate: true
|
246
|
+
end
|
247
|
+
end
|
233
248
|
end
|
234
249
|
end
|
235
250
|
|
data/test/models/topic.rb
CHANGED
@@ -3,6 +3,7 @@ class Topic < ActiveRecord::Base
|
|
3
3
|
validates :title, numericality: { only_integer: true }, on: :context_test
|
4
4
|
validates :title, uniqueness: true
|
5
5
|
|
6
|
+
validate -> { errors.add(:title, :validate_failed) if title == 'validate_failed' }
|
6
7
|
before_validation -> { errors.add(:title, :invalid) if title == 'invalid' }
|
7
8
|
|
8
9
|
has_many :books, inverse_of: :topic
|
@@ -8,7 +8,9 @@ def should_support_on_duplicate_key_ignore
|
|
8
8
|
it "should skip duplicates and continue import" do
|
9
9
|
topics << Topic.new(title: "Book 2", author_name: "Jane Doe")
|
10
10
|
assert_difference "Topic.count", +1 do
|
11
|
-
Topic.import topics, on_duplicate_key_ignore: true, validate: false
|
11
|
+
result = Topic.import topics, on_duplicate_key_ignore: true, validate: false
|
12
|
+
assert_not_equal topics.first.id, result.ids.first
|
13
|
+
assert_nil topics.last.id
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
@@ -31,7 +33,9 @@ def should_support_on_duplicate_key_ignore
|
|
31
33
|
it "should skip duplicates and continue import" do
|
32
34
|
topics << Topic.new(title: "Book 2", author_name: "Jane Doe")
|
33
35
|
assert_difference "Topic.count", +1 do
|
34
|
-
Topic.import topics, ignore: true, validate: false
|
36
|
+
result = Topic.import topics, ignore: true, validate: false
|
37
|
+
assert_not_equal topics.first.id, result.ids.first
|
38
|
+
assert_nil topics.last.id
|
35
39
|
end
|
36
40
|
end
|
37
41
|
end
|
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.18.
|
4
|
+
version: 0.18.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Dennis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|