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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 930cc2407877056e544604dab4c86d885349db9206e217e6518ccddda4969a06
4
- data.tar.gz: 2e2a217f8832430d9365018bfb0c9b99fa6f28787a25230748c74890d0efa5b3
3
+ metadata.gz: a36a92f9240a933980983aff9d079724cc44882cd914ed2d6c2b51c1fbb47cca
4
+ data.tar.gz: 57dbea48c65e11867605da9621029b5da65d6700ffda0f092dfbe0c00e5b2858
5
5
  SHA512:
6
- metadata.gz: 596bd1bce8110e37d1ab496cb75a2469d2e0bc438ecf2389764b28f82e940003cf10a4e296c28ef6e4a36d30dbf835023d23793b70fdea59a64b1d2d4e774a0a
7
- data.tar.gz: 1e296ae4f9c321f90f129eedaa4a26a55e8b5d472239d2d9061a639bec184a39162e5bf9277be66f8f754fb0e8a6e5e0d6853efe7ce555f43744b58436ae6135
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- csv_step_importer (0.10.0)
4
+ csv_step_importer (0.11.0)
5
5
  activemodel
6
6
  activerecord-import
7
7
  activesupport
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
- ### Simple upload of a single row
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
- ### File import using [tilo/smarter_csv](https://github.com/tilo/smarter_csv)
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( name: row.name, code: row.code )
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 `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec 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).
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
- # Daoの保存処理は基本的にstepsで行います
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 "please extend and implement"
35
+ composite_key_columns || raise("please extend and implement")
36
36
  end
37
37
 
38
38
  # NOTE: required only when importer class is set
@@ -14,7 +14,7 @@ module CSVStepImporter
14
14
  delegate :dao_values, to: :parent
15
15
 
16
16
  def create_or_update
17
- model_class.import(
17
+ model_class.import!(
18
18
  columns,
19
19
  dao_values,
20
20
  on_duplicate_key_ignore: on_duplicate_key_ignore,
@@ -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.split("/").last.to_sym
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
- def link_rows_to_daos(daos:)
71
- daos.each do |dao|
72
- # add to cache with pluralized key
73
- (dao.row.cache[self.class.cache_key.to_s.pluralize.to_sym] ||= []) << dao
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
- # add dao to cache
76
- dao.row.cache[self.class.cache_key] = 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CSVStepImporter
4
- VERSION = "0.10.0"
4
+ VERSION = "0.11.0"
5
5
  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.10.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 00:00:00.000000000 Z
11
+ date: 2018-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler