abstract_importer 1.2.1 → 1.3.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 +4 -4
- data/.ruby-version +1 -0
- data/.travis.yml +5 -3
- data/abstract_importer.gemspec +2 -1
- data/lib/abstract_importer/base.rb +63 -75
- data/lib/abstract_importer/collection_importer.rb +34 -33
- data/lib/abstract_importer/id_map.rb +22 -14
- data/lib/abstract_importer/import_options.rb +2 -0
- data/lib/abstract_importer/import_plan.rb +4 -4
- data/lib/abstract_importer/reporters/base_reporter.rb +22 -22
- data/lib/abstract_importer/reporters/debug_reporter.rb +36 -36
- data/lib/abstract_importer/reporters/null_reporter.rb +5 -5
- data/lib/abstract_importer/reporters/performance_reporter.rb +17 -17
- data/lib/abstract_importer/strategies.rb +1 -0
- data/lib/abstract_importer/strategies/base.rb +12 -0
- data/lib/abstract_importer/strategies/default_strategy.rb +1 -7
- data/lib/abstract_importer/strategies/insert_strategy.rb +58 -0
- data/lib/abstract_importer/summary.rb +3 -3
- data/lib/abstract_importer/version.rb +1 -1
- data/test/callback_test.rb +29 -29
- data/test/{importer_test.rb → default_strategy_test.rb} +49 -77
- data/test/insert_strategy_test.rb +82 -0
- data/test/replace_strategy_test.rb +29 -0
- data/test/support/mock_data_source.rb +10 -10
- data/test/support/mock_objects.rb +1 -1
- data/test/support/schema.rb +7 -6
- data/test/test_helper.rb +10 -10
- metadata +27 -7
@@ -0,0 +1,82 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
|
4
|
+
class ImporterTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
setup do
|
7
|
+
options.merge!(strategy: {students: :insert})
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
context "with a simple data source" do
|
13
|
+
setup do
|
14
|
+
plan do |import|
|
15
|
+
import.students
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
should "import the records in batches" do
|
20
|
+
mock.proxy(Student).insert_many(satisfy { |arg| arg.length == 3 })
|
21
|
+
import!
|
22
|
+
assert_equal [456, 457, 458], account.students.pluck(:legacy_id)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "with a complex data source" do
|
27
|
+
setup do
|
28
|
+
plan do |import|
|
29
|
+
import.students
|
30
|
+
import.parents
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
should "preserve mappings" do
|
35
|
+
import!
|
36
|
+
harry = account.students.find_by_name("Harry Potter")
|
37
|
+
assert_equal ["James Potter", "Lily Potter"], harry.parents.pluck(:name)
|
38
|
+
end
|
39
|
+
|
40
|
+
should "preserve mappings even when a record was previously imported" do
|
41
|
+
harry = account.students.create!(name: "Harry Potter", legacy_id: 456)
|
42
|
+
import!
|
43
|
+
assert_equal ["James Potter", "Lily Potter"], harry.parents.pluck(:name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "When records already exist" do
|
48
|
+
setup do
|
49
|
+
plan do |import|
|
50
|
+
import.students
|
51
|
+
end
|
52
|
+
account.students.create!(name: "Ron Weasley", legacy_id: 457)
|
53
|
+
end
|
54
|
+
|
55
|
+
should "not import existing records twice" do
|
56
|
+
import!
|
57
|
+
assert_equal 3, account.students.count
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "When the import would create a duplicate record" do
|
62
|
+
setup do
|
63
|
+
plan do |import|
|
64
|
+
import.students do |options|
|
65
|
+
options.rescue_batch do |batch|
|
66
|
+
names = parent.students.pluck :name
|
67
|
+
batch.reject! { |student| names.member? student[:name] }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
account.students.create!(name: "Ron Weasley")
|
72
|
+
end
|
73
|
+
|
74
|
+
should "not import existing records twice" do
|
75
|
+
import!
|
76
|
+
assert_equal 3, account.students.count
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
|
4
|
+
class ReplaceStrategyTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
setup do
|
7
|
+
options.merge!(strategy: {students: :replace})
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
context "When records already exist" do
|
13
|
+
setup do
|
14
|
+
plan do |import|
|
15
|
+
import.students
|
16
|
+
end
|
17
|
+
account.students.create!(name: "Ron Weasley", legacy_id: 457)
|
18
|
+
end
|
19
|
+
|
20
|
+
should "reimport the existing records" do
|
21
|
+
import!
|
22
|
+
assert_equal "Gryffindor", account.students.find_by_name("Ron Weasley").house,
|
23
|
+
"Expected Ron's record to have been replaced with one that has a house"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class MockDataSource
|
2
|
-
|
3
|
-
|
2
|
+
|
3
|
+
|
4
4
|
def students
|
5
5
|
Enumerator.new do |e|
|
6
6
|
e.yield id: 456, name: "Harry Potter", pet_type: "Owl", pet_id: 901, house: "Gryffindor"
|
@@ -8,21 +8,21 @@ class MockDataSource
|
|
8
8
|
e.yield id: 458, name: "Hermione Granger", pet_type: "Cat", pet_id: 901, house: "Gryffindor"
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def parents
|
13
13
|
Enumerator.new do |e|
|
14
14
|
e.yield id: 88, name: "James Potter", student_id: 456
|
15
15
|
e.yield id: 89, name: "Lily Potter", student_id: 456
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def locations
|
20
20
|
Enumerator.new do |e|
|
21
21
|
e.yield id: 5, slug: "godric's-hollow" # <-- invalid
|
22
22
|
e.yield id: 6, slug: "azkaban"
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def subjects
|
27
27
|
Enumerator.new do |e|
|
28
28
|
e.yield id: 49, name: "Care of Magical Creatures", student_ids: [456]
|
@@ -32,25 +32,25 @@ class MockDataSource
|
|
32
32
|
e.yield id: 53, name: "Study of Ancient Runes", student_ids: [458]
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def grades
|
37
37
|
Enumerator.new do |e|
|
38
38
|
e.yield id: 500, subject_id: 50, student_id: 457, value: "Acceptable"
|
39
39
|
e.yield id: 501, subject_id: 51, student_id: 457, value: "Troll"
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def cats
|
44
44
|
Enumerator.new do |e|
|
45
45
|
e.yield id: 901, name: "Crookshanks"
|
46
46
|
end
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def owls
|
50
50
|
Enumerator.new do |e|
|
51
51
|
e.yield id: 901, name: "Hedwig"
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
55
|
-
|
54
|
+
|
55
|
+
|
56
56
|
end
|
data/test/support/schema.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
ActiveRecord::Schema.define(:version => 1) do
|
2
|
-
|
2
|
+
|
3
3
|
create_table "accounts", :force => true do |t|
|
4
4
|
end
|
5
|
-
|
5
|
+
|
6
6
|
create_table "students", :force => true do |t|
|
7
7
|
t.integer "account_id"
|
8
8
|
t.integer "legacy_id"
|
@@ -10,26 +10,27 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
10
10
|
t.string "house"
|
11
11
|
t.string "pet_type"
|
12
12
|
t.integer "pet_id"
|
13
|
+
t.index "name", :unique => true
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
create_table "parents", :force => true do |t|
|
16
17
|
t.integer "account_id"
|
17
18
|
t.integer "student_id"
|
18
19
|
t.integer "legacy_id"
|
19
20
|
t.string "name"
|
20
21
|
end
|
21
|
-
|
22
|
+
|
22
23
|
create_table "locations", :force => true do |t|
|
23
24
|
t.integer "account_id"
|
24
25
|
t.integer "legacy_id"
|
25
26
|
t.string "slug"
|
26
27
|
end
|
27
|
-
|
28
|
+
|
28
29
|
create_table "students_subjects", :force => true do |t|
|
29
30
|
t.integer "student_id"
|
30
31
|
t.integer "subject_id"
|
31
32
|
end
|
32
|
-
|
33
|
+
|
33
34
|
create_table "subjects", :force => true do |t|
|
34
35
|
t.integer "account_id"
|
35
36
|
t.integer "legacy_id"
|
data/test/test_helper.rb
CHANGED
@@ -34,39 +34,39 @@ $io = ENV['VERBOSE'] ? $stderr : File.open("/dev/null", "w")
|
|
34
34
|
|
35
35
|
|
36
36
|
class ActiveSupport::TestCase
|
37
|
-
|
37
|
+
|
38
38
|
setup do
|
39
39
|
DatabaseCleaner.start
|
40
|
-
|
40
|
+
|
41
41
|
@data_source = MockDataSource.new
|
42
42
|
@klass = Class.new(AbstractImporter::Base)
|
43
43
|
@account = Account.create!
|
44
44
|
@options = {}
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
teardown do
|
48
48
|
DatabaseCleaner.clean
|
49
49
|
@importer = nil
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
protected
|
53
|
-
|
53
|
+
|
54
54
|
attr_reader :account, :results, :data_source, :options
|
55
|
-
|
55
|
+
|
56
56
|
def plan(&block)
|
57
57
|
@klass.import(&block)
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def depends_on(*args)
|
61
61
|
@klass.depends_on(*args)
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
def import!
|
65
65
|
@results = importer.perform!
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def importer
|
69
69
|
@importer ||= @klass.new(@account, @data_source, options.merge(io: $io))
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
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.3.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: 2015-
|
11
|
+
date: 2015-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '4.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: '0'
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord-insert_many
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.1
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -186,6 +200,7 @@ extensions: []
|
|
186
200
|
extra_rdoc_files: []
|
187
201
|
files:
|
188
202
|
- ".gitignore"
|
203
|
+
- ".ruby-version"
|
189
204
|
- ".travis.yml"
|
190
205
|
- Gemfile
|
191
206
|
- LICENSE.txt
|
@@ -207,11 +222,14 @@ files:
|
|
207
222
|
- lib/abstract_importer/strategies.rb
|
208
223
|
- lib/abstract_importer/strategies/base.rb
|
209
224
|
- lib/abstract_importer/strategies/default_strategy.rb
|
225
|
+
- lib/abstract_importer/strategies/insert_strategy.rb
|
210
226
|
- lib/abstract_importer/strategies/replace_strategy.rb
|
211
227
|
- lib/abstract_importer/summary.rb
|
212
228
|
- lib/abstract_importer/version.rb
|
213
229
|
- test/callback_test.rb
|
214
|
-
- test/
|
230
|
+
- test/default_strategy_test.rb
|
231
|
+
- test/insert_strategy_test.rb
|
232
|
+
- test/replace_strategy_test.rb
|
215
233
|
- test/support/mock_data_source.rb
|
216
234
|
- test/support/mock_objects.rb
|
217
235
|
- test/support/schema.rb
|
@@ -236,13 +254,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
236
254
|
version: '0'
|
237
255
|
requirements: []
|
238
256
|
rubyforge_project:
|
239
|
-
rubygems_version: 2.
|
257
|
+
rubygems_version: 2.4.8
|
240
258
|
signing_key:
|
241
259
|
specification_version: 4
|
242
260
|
summary: Provides services for the mass-import of complex relational data
|
243
261
|
test_files:
|
244
262
|
- test/callback_test.rb
|
245
|
-
- test/
|
263
|
+
- test/default_strategy_test.rb
|
264
|
+
- test/insert_strategy_test.rb
|
265
|
+
- test/replace_strategy_test.rb
|
246
266
|
- test/support/mock_data_source.rb
|
247
267
|
- test/support/mock_objects.rb
|
248
268
|
- test/support/schema.rb
|