activerecord-import 0.18.1 → 0.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +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
         |