abstract_importer 1.5.6 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +1 -1
- data/CHANGELOG.md +2 -0
- data/README.md +17 -0
- data/abstract_importer.gemspec +2 -3
- data/lib/abstract_importer/strategies/insert_strategy.rb +19 -4
- data/lib/abstract_importer/strategies/upsert_strategy.rb +2 -2
- data/lib/abstract_importer/version.rb +1 -1
- data/test/insert_strategy_test.rb +17 -1
- data/test/upsert_strategy_test.rb +1 -1
- metadata +8 -22
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: f1a26d52ad8e17f1b2539d5abbcf996a4c80ac157139a988fefd4a417c4fe03e
         | 
| 4 | 
            +
              data.tar.gz: 388a9123f67dd9b52c35ae50a8added3c6995d2b8d71d703269dd317e13e8918
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 19531db43b5cd36a2831384fcef16092930b23cc9fa622c1aaa1b1bdc193d73df0d824deda4bdc5ce427d80272bd1d48cd972efea15011187fffa1c5720cb4cf
         | 
| 7 | 
            +
              data.tar.gz: 14d9f5e0d630fc2e15be68bd83ef61ca610bf4cec4442af820cfa429915020320d88416af4c8f2fc5d7779daa8b83900c7b0be7e4a87bc21aa73985dd0a58c17
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            2.3 | 
| 1 | 
            +
            2.6.3
         | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/CHANGELOG.md
    ADDED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -187,6 +187,23 @@ The following alternate strategies are built in: | |
| 187 187 |  | 
| 188 188 | 
             
            Replaces records that have already been imported rather than skipping them.
         | 
| 189 189 |  | 
| 190 | 
            +
            ##### insert
         | 
| 191 | 
            +
             | 
| 192 | 
            +
            Bulk inserts records rather than creating them one-by-one as ActiveRecord objects, skipping those that have already been imported.
         | 
| 193 | 
            +
             | 
| 194 | 
            +
            ##### upsert
         | 
| 195 | 
            +
             | 
| 196 | 
            +
            Bulk inserts records, but updates records that have already been imported rather than skipping them.
         | 
| 197 | 
            +
             | 
| 198 | 
            +
             | 
| 199 | 
            +
             | 
| 200 | 
            +
            ### Important Note on Upgrading from 1.5.x to 1.6.0
         | 
| 201 | 
            +
             | 
| 202 | 
            +
            With the jump to 1.6.0, `abstract_importer` has dropped reliance upon the `activerecord-insert_many` gem in favor of taking advantage of Rails 6's built-in `insert_all` and `upsert_all` for the insert and upsert strategies. With the move from the gem to relying on Rails, the syntax to specify what constitutes a conflict/duplicate record has been updated to align more closely with that of Rails. In particular:
         | 
| 203 | 
            +
             | 
| 204 | 
            +
            * Instead of specifying an `on_conflict: { do: :update }` clause, you should specify `on_duplicate: :update` to opt-in to upsert behavior.
         | 
| 205 | 
            +
            * Rather than listing columns in `on_conflict: { columns: %i{legacy_id id} }`, you should use `unique_by: %i{legacy_id id}` to specify the index or columns by which a duplicate or conflict is defined. The option follows the behavior of Rails' `upsert_all`, so refer to the Rails 6 documentation for more information.
         | 
| 206 | 
            +
             | 
| 190 207 |  | 
| 191 208 |  | 
| 192 209 | 
             
            ## Contributing
         | 
    
        data/abstract_importer.gemspec
    CHANGED
    
    | @@ -17,9 +17,8 @@ Gem::Specification.new do |spec| | |
| 17 17 | 
             
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         | 
| 18 18 | 
             
              spec.require_paths = ["lib"]
         | 
| 19 19 |  | 
| 20 | 
            -
              spec.add_dependency "activerecord", ">=  | 
| 21 | 
            -
              spec.add_dependency "activesupport", ">=  | 
| 22 | 
            -
              spec.add_dependency "activerecord-insert_many", ">= 0.4.4"
         | 
| 20 | 
            +
              spec.add_dependency "activerecord", ">= 6.0"
         | 
| 21 | 
            +
              spec.add_dependency "activesupport", ">= 6.0"
         | 
| 23 22 | 
             
              spec.add_dependency "progressbar"
         | 
| 24 23 |  | 
| 25 24 | 
             
              spec.add_development_dependency "bundler"
         | 
| @@ -1,5 +1,4 @@ | |
| 1 1 | 
             
            require "abstract_importer/strategies/base"
         | 
| 2 | 
            -
            require "activerecord/insert_many"
         | 
| 3 2 |  | 
| 4 3 | 
             
            module AbstractImporter
         | 
| 5 4 | 
             
              module Strategies
         | 
| @@ -9,7 +8,8 @@ module AbstractImporter | |
| 9 8 | 
             
                    super
         | 
| 10 9 | 
             
                    @batch = []
         | 
| 11 10 | 
             
                    @batch_size = options.fetch(:batch_size, 250)
         | 
| 12 | 
            -
                    @ | 
| 11 | 
            +
                    @bulk_operation = options[:on_duplicate] == :update ? :upsert_all : :insert_all
         | 
| 12 | 
            +
                    @insert_options = options.slice(:unique_by)
         | 
| 13 13 | 
             
                    @insert_options.merge!(returning: [:legacy_id, :id]) if remap_ids?
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 |  | 
| @@ -52,7 +52,9 @@ module AbstractImporter | |
| 52 52 |  | 
| 53 53 |  | 
| 54 54 | 
             
                  def insert_batch(batch)
         | 
| 55 | 
            -
                     | 
| 55 | 
            +
                    return if batch.empty?
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    result = collection.scope.public_send(@bulk_operation, batch, @insert_options)
         | 
| 56 58 | 
             
                    add_batch_to_id_map(result) if remap_ids?
         | 
| 57 59 | 
             
                  end
         | 
| 58 60 |  | 
| @@ -66,13 +68,26 @@ module AbstractImporter | |
| 66 68 |  | 
| 67 69 |  | 
| 68 70 | 
             
                  def add_batch_to_id_map(result)
         | 
| 69 | 
            -
                    map = result.each_with_object({}) do |attrs, map|
         | 
| 71 | 
            +
                    map = cast_result(result, collection.table_name).each_with_object({}) do |attrs, map|
         | 
| 70 72 | 
             
                      map[attrs.fetch("legacy_id")] = attrs.fetch("id")
         | 
| 71 73 | 
             
                    end
         | 
| 72 74 | 
             
                    id_map.merge! collection.table_name, map
         | 
| 73 75 | 
             
                  end
         | 
| 74 76 |  | 
| 75 77 |  | 
| 78 | 
            +
                  def cast_result(result, table_name)
         | 
| 79 | 
            +
                    types_by_column = result.columns.each_with_object({}) do |column_name, types|
         | 
| 80 | 
            +
                      types[column_name] = collection.scope.connection.lookup_cast_type_from_column(collection.scope.columns.find { |column| column.name == column_name })
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    result.to_a.map { |row|
         | 
| 84 | 
            +
                      Hash[row.map { |column_name, value|
         | 
| 85 | 
            +
                        [ column_name, types_by_column[column_name].deserialize(value) ]
         | 
| 86 | 
            +
                      }]
         | 
| 87 | 
            +
                    }
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
             | 
| 76 91 | 
             
                end
         | 
| 77 92 | 
             
              end
         | 
| 78 93 | 
             
            end
         | 
| @@ -1,5 +1,4 @@ | |
| 1 1 | 
             
            require "abstract_importer/strategies/insert_strategy"
         | 
| 2 | 
            -
            require "activerecord/insert_many"
         | 
| 3 2 |  | 
| 4 3 | 
             
            module AbstractImporter
         | 
| 5 4 | 
             
              module Strategies
         | 
| @@ -7,7 +6,8 @@ module AbstractImporter | |
| 7 6 |  | 
| 8 7 | 
             
                  def initialize(collection, options={})
         | 
| 9 8 | 
             
                    super
         | 
| 10 | 
            -
                    @ | 
| 9 | 
            +
                    @bulk_operation = :upsert_all
         | 
| 10 | 
            +
                    @insert_options.reverse_merge!(unique_by: remap_ids? ? (association_attrs.keys + %i{legacy_id}) : :id)
         | 
| 11 11 | 
             
                  end
         | 
| 12 12 |  | 
| 13 13 | 
             
                  # We won't skip any records for already being imported
         | 
| @@ -17,7 +17,7 @@ class InsertStrategyTest < ActiveSupport::TestCase | |
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 19 | 
             
                should "import the records in batches" do
         | 
| 20 | 
            -
                  mock.proxy(Student). | 
| 20 | 
            +
                  mock.proxy(Student).insert_all(satisfy { |arg| arg.length == 3 }, anything)
         | 
| 21 21 | 
             
                  import!
         | 
| 22 22 | 
             
                  assert_equal [456, 457, 458], account.students.pluck(:legacy_id)
         | 
| 23 23 | 
             
                end
         | 
| @@ -54,6 +54,22 @@ class InsertStrategyTest < ActiveSupport::TestCase | |
| 54 54 | 
             
                end
         | 
| 55 55 | 
             
              end
         | 
| 56 56 |  | 
| 57 | 
            +
              context "With an empty data source" do
         | 
| 58 | 
            +
                setup do
         | 
| 59 | 
            +
                  plan do |import|
         | 
| 60 | 
            +
                    import.students
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                  @data_source = OpenStruct.new
         | 
| 63 | 
            +
                  @data_source.students = []
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                should "still be able to import" do
         | 
| 67 | 
            +
                  assert_nothing_raised do
         | 
| 68 | 
            +
                    import!
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 57 73 | 
             
              context "When records already exist" do
         | 
| 58 74 | 
             
                setup do
         | 
| 59 75 | 
             
                  plan do |import|
         | 
| @@ -17,7 +17,7 @@ class UpsertStrategyTest < ActiveSupport::TestCase | |
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 19 | 
             
                should "import the records in batches" do
         | 
| 20 | 
            -
                  mock.proxy(Student). | 
| 20 | 
            +
                  mock.proxy(Student).upsert_all(satisfy { |arg| arg.length == 3 }, anything)
         | 
| 21 21 | 
             
                  import!
         | 
| 22 22 | 
             
                  assert_equal [456, 457, 458], account.students.pluck(:legacy_id)
         | 
| 23 23 | 
             
                end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: abstract_importer
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.6.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Bob Lail
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2019-09- | 
| 11 | 
            +
            date: 2019-09-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activerecord
         | 
| @@ -16,42 +16,28 @@ dependencies: | |
| 16 16 | 
             
                requirements:
         | 
| 17 17 | 
             
                - - ">="
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: ' | 
| 19 | 
            +
                    version: '6.0'
         | 
| 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: ' | 
| 26 | 
            +
                    version: '6.0'
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: activesupport
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 30 | 
             
                requirements:
         | 
| 31 31 | 
             
                - - ">="
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: ' | 
| 33 | 
            +
                    version: '6.0'
         | 
| 34 34 | 
             
              type: :runtime
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 38 | 
             
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: ' | 
| 41 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            -
              name: activerecord-insert_many
         | 
| 43 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            -
                requirements:
         | 
| 45 | 
            -
                - - ">="
         | 
| 46 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: 0.4.4
         | 
| 48 | 
            -
              type: :runtime
         | 
| 49 | 
            -
              prerelease: false
         | 
| 50 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            -
                requirements:
         | 
| 52 | 
            -
                - - ">="
         | 
| 53 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version: 0.4.4
         | 
| 40 | 
            +
                    version: '6.0'
         | 
| 55 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 42 | 
             
              name: progressbar
         | 
| 57 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -230,6 +216,7 @@ files: | |
| 230 216 | 
             
            - ".gitignore"
         | 
| 231 217 | 
             
            - ".ruby-version"
         | 
| 232 218 | 
             
            - ".travis.yml"
         | 
| 219 | 
            +
            - CHANGELOG.md
         | 
| 233 220 | 
             
            - Gemfile
         | 
| 234 221 | 
             
            - LICENSE.txt
         | 
| 235 222 | 
             
            - README.md
         | 
| @@ -288,8 +275,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 288 275 | 
             
                - !ruby/object:Gem::Version
         | 
| 289 276 | 
             
                  version: '0'
         | 
| 290 277 | 
             
            requirements: []
         | 
| 291 | 
            -
             | 
| 292 | 
            -
            rubygems_version: 2.5.1
         | 
| 278 | 
            +
            rubygems_version: 3.0.3
         | 
| 293 279 | 
             
            signing_key: 
         | 
| 294 280 | 
             
            specification_version: 4
         | 
| 295 281 | 
             
            summary: Provides services for the mass-import of complex relational data
         |