csv_step_importer 0.10.0 → 0.11.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/CHANGELOG.md +43 -0
- data/Gemfile.lock +1 -1
- data/README.md +15 -6
- data/lib/csv_step_importer/model/dao.rb +29 -1
- data/lib/csv_step_importer/model/importable_model.rb +1 -1
- data/lib/csv_step_importer/model/importer.rb +1 -1
- data/lib/csv_step_importer/model/model.rb +25 -8
- data/lib/csv_step_importer/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a36a92f9240a933980983aff9d079724cc44882cd914ed2d6c2b51c1fbb47cca
|
4
|
+
data.tar.gz: 57dbea48c65e11867605da9621029b5da65d6700ffda0f092dfbe0c00e5b2858
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15157867c54bdd4d7868901c353667775f24a9b9ae5a34cc98659184bb52d0119f923cfa4577a4e6385b440da810c2fca4ba03ae2c1bce35cdf07d70045c6b98
|
7
|
+
data.tar.gz: 94f5eebbdc2fac03edcf0a18d3727bc0681f062a8f2cc631f201a8c2e94a2b97460fdb8370615f8dc262ae7e152de58dec77772a13a36ebe4685fd1cd02a0793
|
data/CHANGELOG.md
CHANGED
@@ -86,3 +86,46 @@ See lib/csv_step_importer/file.rb for more options
|
|
86
86
|
|
87
87
|
- Changed README, especially a note to include smarter_csv 2.0.0.pre1 into your project
|
88
88
|
- Chunks default for the first row index is now 0
|
89
|
+
|
90
|
+
## 2018-09-11 Version 0.11.0
|
91
|
+
### Added
|
92
|
+
- Added methods to DAO
|
93
|
+
- dao_for(model:, pluralize: false)
|
94
|
+
retrieve a dao for a different model using the same CSV row. This is useful e.g. if you use the reflector to get ids of related data
|
95
|
+
- link!
|
96
|
+
link this dao to a row
|
97
|
+
- unlink!
|
98
|
+
unlink this dao from the row and replace it with a different dao
|
99
|
+
- Model allows now to specify a unique composite key `composite_key_columns` to avoid duplicated daos.
|
100
|
+
|
101
|
+
Usage:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class Author < ApplicationRecord
|
105
|
+
class ImportableModel < CSVStepImporter::Model::ImportableModel
|
106
|
+
def composite_key_columns
|
107
|
+
[:name]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
And a CSV which contains the same name twice or more, like this:
|
114
|
+
|
115
|
+
```csv
|
116
|
+
Author,Book
|
117
|
+
A1,B1
|
118
|
+
A1,B2
|
119
|
+
A2,B3
|
120
|
+
```
|
121
|
+
|
122
|
+
If you do NOT specify `composite_key_columns` you will get three DAOs for A1, A1 and A2.
|
123
|
+
If you specify `composite_key_columns` non unique daos will be removed and you only will get A1 and A2.
|
124
|
+
|
125
|
+
- The `Model`'s `cache_key` method allows now a `pluralize` option.
|
126
|
+
- The `Model`'s `cache_key` method is now available in the instance as well.
|
127
|
+
|
128
|
+
### Changed
|
129
|
+
|
130
|
+
- ImportableModel's finder_keys method now defaults to composite_key_columns
|
131
|
+
- ImportableModel's Importer (uses ActiveRecord::Import) now raises an exception if the import fails
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -53,14 +53,23 @@ class Author < ApplicationRecord
|
|
53
53
|
class ImportableModel < CSVStepImporter::Model::ImportableModel
|
54
54
|
# The model to be updated
|
55
55
|
def model_class
|
56
|
-
puts Module.nesting.inspect
|
57
56
|
Module.nesting[1]
|
58
57
|
end
|
59
58
|
|
59
|
+
# return CSVStepImporter::Model::Reflector in order to enable reflections (e.g. get ids of all rows)
|
60
|
+
# disabled by default
|
61
|
+
def reflector_class
|
62
|
+
CSVStepImporter::Model::Reflector
|
63
|
+
end
|
64
|
+
|
60
65
|
def columns
|
61
66
|
[:name, :email, :created_at, :updated_at]
|
62
67
|
end
|
63
68
|
|
69
|
+
def composite_key_columns
|
70
|
+
[:name]
|
71
|
+
end
|
72
|
+
|
64
73
|
def on_duplicate_key_update
|
65
74
|
[:email, :updated_at]
|
66
75
|
end
|
@@ -68,7 +77,7 @@ class Author < ApplicationRecord
|
|
68
77
|
end
|
69
78
|
```
|
70
79
|
|
71
|
-
###
|
80
|
+
### Import a single data row
|
72
81
|
|
73
82
|
```shell
|
74
83
|
rails c
|
@@ -116,7 +125,7 @@ irb(main)> puts JSON.parse(Author.all.to_json).to_yaml # Isn't there an easy way
|
|
116
125
|
updated_at: '2018-09-11T12:19:17.000Z'
|
117
126
|
```
|
118
127
|
|
119
|
-
###
|
128
|
+
### Import a CSV data file
|
120
129
|
|
121
130
|
```shell
|
122
131
|
rails c
|
@@ -153,7 +162,7 @@ irb(main)> puts JSON.parse(Author.all.to_json).to_yaml
|
|
153
162
|
### Simple model
|
154
163
|
|
155
164
|
By default, for each row read from the CSV file, a DAO belonging to a model will be created.
|
156
|
-
These models will be validated and saved in the order specified by the processor_classes option.
|
165
|
+
These models will be validated and saved in the order specified by the `processor_classes` option.
|
157
166
|
|
158
167
|
The simplest model is one, which simply calls `save` on all DAOs, which calls internally `create_or_update`.
|
159
168
|
`create_or_update` is customizable.
|
@@ -165,7 +174,7 @@ This example will call `find_or_create_by` for each row after all validations ha
|
|
165
174
|
```ruby
|
166
175
|
class SimpleDAO < CSVStepImporter::Model::DAO
|
167
176
|
def create_or_update
|
168
|
-
Currency.find_or_create_by(
|
177
|
+
Currency.find_or_create_by(name: row.name, code: row.code)
|
169
178
|
end
|
170
179
|
end
|
171
180
|
|
@@ -182,7 +191,7 @@ CSVStepImporter::Loader.new(path: 'currencies.csv', processor_classes: [SimpleMo
|
|
182
191
|
|
183
192
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
184
193
|
|
185
|
-
To install this gem onto your local machine, run `
|
194
|
+
To install this gem onto your local machine, run `rake install`. To release a new version, update the version number in `version.rb`, and then run `rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
186
195
|
|
187
196
|
## Contributing
|
188
197
|
|
@@ -20,12 +20,14 @@ module CSVStepImporter
|
|
20
20
|
parent.parent
|
21
21
|
end
|
22
22
|
|
23
|
+
# returns an array of all column values, used for batch importing
|
23
24
|
def value
|
24
25
|
@value ||= columns.each_with_object({}) do |key, values|
|
25
26
|
values[key] = value_for_key key
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
30
|
+
# retrieve a value for a key from the dao or row
|
29
31
|
def value_for_key(key)
|
30
32
|
if respond_to?(key)
|
31
33
|
send key
|
@@ -41,7 +43,7 @@ module CSVStepImporter
|
|
41
43
|
end
|
42
44
|
|
43
45
|
def create_or_update
|
44
|
-
#
|
46
|
+
# DAOs are usually processed in batches by the model and not saved one by one
|
45
47
|
true
|
46
48
|
end
|
47
49
|
|
@@ -56,6 +58,32 @@ module CSVStepImporter
|
|
56
58
|
def updated_at
|
57
59
|
current_timestamp
|
58
60
|
end
|
61
|
+
|
62
|
+
# retrieve a dao for a different model using the same CSV row. This is useful e.g. if you use the reflector to get ids of related data
|
63
|
+
def dao_for model:, pluralize: false
|
64
|
+
row.cache[model.cache_key(pluralize: pluralize)]
|
65
|
+
end
|
66
|
+
|
67
|
+
# link this dao to a row
|
68
|
+
def link!
|
69
|
+
# add to cache with pluralized key
|
70
|
+
(row.cache[model.cache_key(pluralize: true)] ||= []) << self
|
71
|
+
|
72
|
+
# add to cache with singular key (for convenience)
|
73
|
+
row.cache[model.cache_key(pluralize: false)] = self
|
74
|
+
end
|
75
|
+
|
76
|
+
# unlink this dao from the row and replace it with a different dao
|
77
|
+
def unlink! replace_with: nil
|
78
|
+
cached_daos = row.cache[model.cache_key(pluralize: true)]
|
79
|
+
|
80
|
+
# remove from cache with pluralized key
|
81
|
+
cached_daos.delete self
|
82
|
+
cached_daos << replace_with
|
83
|
+
|
84
|
+
# set any dao to cache with singular key (for convenience)
|
85
|
+
row.cache[model.cache_key(pluralize: false)] = cached_daos.first
|
86
|
+
end
|
59
87
|
end
|
60
88
|
end
|
61
89
|
end
|
@@ -32,7 +32,7 @@ module CSVStepImporter
|
|
32
32
|
# NOTE: required only when reflector class is set
|
33
33
|
# example: [:email]
|
34
34
|
def finder_keys
|
35
|
-
raise
|
35
|
+
composite_key_columns || raise("please extend and implement")
|
36
36
|
end
|
37
37
|
|
38
38
|
# NOTE: required only when importer class is set
|
@@ -7,11 +7,13 @@ module CSVStepImporter
|
|
7
7
|
class Model < CSVStepImporter::Node
|
8
8
|
attr_accessor :dao_values
|
9
9
|
delegate :rows, :cache, to: :parent
|
10
|
+
delegate :cache_key, to: :class
|
10
11
|
|
11
12
|
def initialize(**attributes)
|
12
13
|
super **attributes
|
13
14
|
|
14
15
|
add_daos
|
16
|
+
filter_daos! if composite_key_columns
|
15
17
|
add_model_children
|
16
18
|
end
|
17
19
|
|
@@ -19,8 +21,9 @@ module CSVStepImporter
|
|
19
21
|
# Configuration
|
20
22
|
#########################################################
|
21
23
|
|
22
|
-
def self.cache_key
|
23
|
-
name.underscore.
|
24
|
+
def self.cache_key pluralize: false
|
25
|
+
key = name.underscore.gsub('/', '_')
|
26
|
+
(pluralize ? key.pluralize : key.singularize).to_sym
|
24
27
|
end
|
25
28
|
|
26
29
|
# example: [:email, :updated_at, :created_at]
|
@@ -32,6 +35,11 @@ module CSVStepImporter
|
|
32
35
|
CSVStepImporter::Model::DAO
|
33
36
|
end
|
34
37
|
|
38
|
+
# specify to an array of columns in order filter duplicates from daos
|
39
|
+
def composite_key_columns
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
35
43
|
#########################################################
|
36
44
|
# Logic
|
37
45
|
#########################################################
|
@@ -67,15 +75,24 @@ module CSVStepImporter
|
|
67
75
|
dao_class.new parent: dao_node, row: row
|
68
76
|
end
|
69
77
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
78
|
+
# TODO a possible feature would be to add validation errors if the duplicates do not match in all columns (columns other than the composite key)
|
79
|
+
def filter_daos!
|
80
|
+
unique_daos = {}
|
81
|
+
|
82
|
+
daos.delete_if do |dao|
|
83
|
+
hash = dao.value.slice(composite_key_columns).hash
|
84
|
+
should_delete = (unique_daos[hash] ||= dao) == dao
|
74
85
|
|
75
|
-
#
|
76
|
-
dao.
|
86
|
+
# unlink to be deleted dao and add a link to
|
87
|
+
dao.unlink! replace_with: unique_daos[hash] unless should_delete
|
88
|
+
|
89
|
+
should_delete
|
77
90
|
end
|
78
91
|
end
|
92
|
+
|
93
|
+
def link_rows_to_daos(daos:)
|
94
|
+
daos.each(&:link!)
|
95
|
+
end
|
79
96
|
end
|
80
97
|
end
|
81
98
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv_step_importer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian-Manuel Butzke
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|