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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2273e7488017981f0caa7c51ae1bfc7fa2bf8dd3
4
- data.tar.gz: 0b2cf66310053405eace82238f10bc42b8af8dbf
2
+ SHA256:
3
+ metadata.gz: f1a26d52ad8e17f1b2539d5abbcf996a4c80ac157139a988fefd4a417c4fe03e
4
+ data.tar.gz: 388a9123f67dd9b52c35ae50a8added3c6995d2b8d71d703269dd317e13e8918
5
5
  SHA512:
6
- metadata.gz: 1d72f4017de21ff358da2f080289cb470b695ac0ee404bf2cd0a3fc6d04b71e1eb8ae38b3d3f98a93b574cd77737ffab17d3f63d1d4e30117c9e2edf18ff7d15
7
- data.tar.gz: fc0233f350e80133e8e699a17a95217a546b1de174baf7680ad925fde166a7637733ab509d6bf0bf174547038f54d496bfece1e9a55b6f9260514ca23791e81c
6
+ metadata.gz: 19531db43b5cd36a2831384fcef16092930b23cc9fa622c1aaa1b1bdc193d73df0d824deda4bdc5ce427d80272bd1d48cd972efea15011187fffa1c5720cb4cf
7
+ data.tar.gz: 14d9f5e0d630fc2e15be68bd83ef61ca610bf4cec4442af820cfa429915020320d88416af4c8f2fc5d7779daa8b83900c7b0be7e4a87bc21aa73985dd0a58c17
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.6.3
@@ -1,6 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.1
3
+ - 2.6.3
4
4
 
5
5
  # Use Postgres 9.5
6
6
  # https://www.brandur.org/fragments/postgres-95-travis
@@ -0,0 +1,2 @@
1
+ ## v1.6.0 (2019 Sept 23)
2
+ * BREAKING: Updated to use Rails 6 and its `insert_all` and `upsert_all` methods and arguments
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
@@ -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", ">= 5.0"
21
- spec.add_dependency "activesupport", ">= 5.0"
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
- @insert_options = options.slice(:on_conflict)
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
- result = collection.scope.insert_many(batch, @insert_options)
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
- @insert_options.reverse_merge!(on_conflict: { column: remap_ids? ? (association_attrs.keys + [:legacy_id]) : :id, do: :update })
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
@@ -1,3 +1,3 @@
1
1
  module AbstractImporter
2
- VERSION = "1.5.6"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -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).insert_many(satisfy { |arg| arg.length == 3 }, anything)
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).insert_many(satisfy { |arg| arg.length == 3 }, anything)
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.5.6
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-16 00:00:00.000000000 Z
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: '5.0'
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: '5.0'
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: '5.0'
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: '5.0'
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
- rubyforge_project:
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