eco-helpers 3.0.17 → 3.0.19

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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -1
  3. data/eco-helpers.gemspec +3 -3
  4. data/lib/eco/api/common/loaders/parser.rb +10 -0
  5. data/lib/eco/api/common/people/default_parsers/csv_parser.rb +21 -208
  6. data/lib/eco/api/common/people/default_parsers/helpers/expected_headers.rb +206 -0
  7. data/lib/eco/api/common/people/default_parsers/helpers/null_parsing.rb +36 -0
  8. data/lib/eco/api/common/people/default_parsers/helpers.rb +15 -0
  9. data/lib/eco/api/common/people/default_parsers/json_parser.rb +56 -0
  10. data/lib/eco/api/common/people/default_parsers/xls_parser.rb +13 -14
  11. data/lib/eco/api/common/people/default_parsers.rb +2 -0
  12. data/lib/eco/api/common/people/entry_factory.rb +15 -4
  13. data/lib/eco/api/session/batch/launcher/mode_size.rb +65 -0
  14. data/lib/eco/api/session/batch/launcher/retry.rb +3 -3
  15. data/lib/eco/api/session/batch/launcher/status_handling.rb +4 -2
  16. data/lib/eco/api/session/batch/launcher.rb +42 -37
  17. data/lib/eco/api/session.rb +2 -0
  18. data/lib/eco/api/usecases/default/utils/cli/group_csv_cli.rb +26 -0
  19. data/lib/eco/api/usecases/default/utils/cli/json_to_csv_cli.rb +10 -0
  20. data/lib/eco/api/usecases/default/utils/cli/sort_csv_cli.rb +17 -0
  21. data/lib/eco/api/usecases/default/utils/cli/split_json_cli.rb +15 -0
  22. data/lib/eco/api/usecases/default/utils/group_csv_case.rb +213 -0
  23. data/lib/eco/api/usecases/default/utils/json_to_csv_case.rb +71 -0
  24. data/lib/eco/api/usecases/default/utils/sort_csv_case.rb +127 -0
  25. data/lib/eco/api/usecases/default/utils/split_json_case.rb +224 -0
  26. data/lib/eco/api/usecases/default/utils.rb +4 -0
  27. data/lib/eco/version.rb +1 -1
  28. metadata +22 -11
  29. data/lib/eco/api/session/batch/launcher/mode.rb +0 -23
  30. data/lib/eco/api/session/batch/launcher/size.rb +0 -40
@@ -0,0 +1,71 @@
1
+ class Eco::API::UseCases::Default::Utils::JsonToCsv < Eco::API::Common::Loaders::UseCase
2
+ require_relative 'cli/json_to_csv_cli'
3
+
4
+ name 'json-to-csv'
5
+ type :other
6
+
7
+ def main(*_args)
8
+ return if simulate?
9
+
10
+ CSV.open(out_filename, 'w') do |csv|
11
+ csv << all_keys
12
+ data.each do |item|
13
+ csv << item.values_at(*all_keys)
14
+ end
15
+ ensure
16
+ log(:info) {
17
+ "Generated output file: '#{File.expand_path(out_filename)}'."
18
+ }
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def all_keys
25
+ @all_keys ||= data.each_with_object([]) do |item, head|
26
+ head.concat(item.keys - head)
27
+ end
28
+ end
29
+
30
+ def data
31
+ @data ||= parse_json_file.tap do |dt|
32
+ ensure_array!(dt)
33
+
34
+ log(:info) {
35
+ "Loaded #{dt.count} items (from file '#{File.basename(input_file)}')"
36
+ }
37
+
38
+ exit 0 if simulate?
39
+ end
40
+ end
41
+
42
+ def out_filename
43
+ @out_filename ||= ''.then do
44
+ input_basename = File.basename(input_file)
45
+ base_name = File.basename(input_basename, '.json')
46
+ "#{base_name}.csv"
47
+ end
48
+ end
49
+
50
+ def input_file
51
+ options.dig(:source, :file)
52
+ end
53
+
54
+ def ensure_array!(data)
55
+ return if data.is_a?(Array)
56
+
57
+ msg = "Expecting JSON file to contain an Array. Given: #{data.class}"
58
+ log(:error) { msg }
59
+ raise msg
60
+ end
61
+
62
+ def parse_json_file(filename = input_file)
63
+ fd = File.open(filename)
64
+ JSON.load fd # rubocop:disable Security/JSONLoad
65
+ rescue JSON::ParserError => err
66
+ log(:error) { "Parsing error on file '#{filename}'" }
67
+ raise err
68
+ ensure
69
+ fd&.close
70
+ end
71
+ end
@@ -0,0 +1,127 @@
1
+ class Eco::API::UseCases::Default::Utils::SortCsv < Eco::API::Custom::UseCase
2
+ name 'sort-csv'
3
+ type :other
4
+
5
+ require_relative 'cli/sort_csv_cli'
6
+
7
+ def main(*_args)
8
+ if simulate?
9
+ count = Eco::CSV.count(input_file)
10
+ log(:info) { "CSV '#{input_file}' has #{count} rows." }
11
+ else
12
+ group_input_rows
13
+ generate_file
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :headers, :headers_rest
20
+
21
+ def group_input_rows
22
+ idx = 0
23
+ first = true
24
+
25
+ Eco::CSV.foreach(input_file, headers: true, skip_blanks: true) do |row|
26
+ idx += 1
27
+
28
+ if first
29
+ first = false
30
+ @output_headers = row.headers
31
+ require_sort_field!(row, file: input_file)
32
+ end
33
+
34
+ pivot_value = row[sort_field]
35
+ (row_groups[pivot_value] ||= []) << row
36
+
37
+ if (idx % 500).zero?
38
+ print "... Tracked #{idx} rows \r"
39
+ $stdout.flush
40
+ end
41
+ end
42
+ ensure
43
+ log(:info) { "Tracked #{idx} rows"}
44
+ end
45
+
46
+ def generate_file
47
+ idx = 0
48
+
49
+ CSV.open(output_filename, 'wb') do |csv|
50
+ csv << @output_headers
51
+
52
+ row_groups.keys.sort.each do |key|
53
+ row_groups[key].each do |row|
54
+ csv << row.values_at(*@output_headers)
55
+
56
+ idx += 1
57
+ if (idx % 500).zero?
58
+ print "... Sorted #{idx} rows \r"
59
+ $stdout.flush
60
+ end
61
+ end
62
+ end
63
+ end
64
+ ensure
65
+ msg = "Generated file '#{output_filename}' with #{idx} rows."
66
+ log(:info) { msg } unless simulate?
67
+ end
68
+
69
+ def row_groups
70
+ @row_groups ||= {}
71
+ end
72
+
73
+ def output_filename
74
+ return nil unless input_name
75
+
76
+ File.join(input_dir, "#{input_name}_sorted#{input_ext}")
77
+ end
78
+
79
+ def input_name
80
+ @input_name ||= File.basename(input_basename, input_ext)
81
+ end
82
+
83
+ def input_ext
84
+ @input_ext ||= input_basename.split('.')[1..].join('.').then do |name|
85
+ ".#{name}"
86
+ end
87
+ end
88
+
89
+ def input_basename
90
+ @input_basename ||= File.basename(input_full_filename)
91
+ end
92
+
93
+ def input_dir
94
+ @input_dir = File.dirname(input_full_filename)
95
+ end
96
+
97
+ def input_full_filename
98
+ @input_full_filename ||= File.expand_path(input_file)
99
+ end
100
+
101
+ def input_file
102
+ options.dig(:input, :file)
103
+ end
104
+
105
+ def require_sort_field!(row, file:)
106
+ return true if row.key?(sort_field)
107
+
108
+ msg = "Sort field '#{sort_field}' missing in header of file '#{file}'"
109
+ log(:error) { msg }
110
+ raise msg
111
+ end
112
+
113
+ def sort_field
114
+ @sort_field ||= opts_sort_by.tap do |pivot|
115
+ next if pivot
116
+
117
+ msg = "The pivot field should be specified with -by option"
118
+
119
+ log(:error) { msg }
120
+ raise msg
121
+ end
122
+ end
123
+
124
+ def opts_sort_by
125
+ options.dig(:input, :sort_by)
126
+ end
127
+ end
@@ -0,0 +1,224 @@
1
+ class Eco::API::UseCases::Default::Utils::SplitJson < Eco::API::Common::Loaders::UseCase
2
+ require_relative 'cli/split_json_cli'
3
+
4
+ MAX_ITEMS = 15_000
5
+
6
+ name "split-json"
7
+ type :other
8
+
9
+ def main(*_args)
10
+ if simulate?
11
+ count = input_json.count
12
+ log(:info) { "JSON '#{input_file}' has #{count} elements." }
13
+ else
14
+ split_json_into_files!
15
+
16
+ msg = []
17
+ msg << "Total elements: #{total_count}"
18
+ msg << "Generated files:"
19
+ out_files.each do |file|
20
+ msg << " * #{file}'"
21
+ end
22
+
23
+ log(:info) { msg.join("\n") }
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def split_json_into_files!
30
+ first = true
31
+
32
+ while pending?
33
+ swap_file! if first
34
+ first = false
35
+
36
+ curr_json << input_json.shift
37
+ next_count!
38
+
39
+ swap_file! if split?
40
+ end
41
+
42
+ generate_file!
43
+ end
44
+
45
+ def split?
46
+ return false unless curr_count > max_items
47
+
48
+ true
49
+ end
50
+
51
+ def max_items
52
+ @max_items ||= max_items_options || self.class::MAX_ITEMS
53
+ end
54
+
55
+
56
+ # OPTIONS
57
+
58
+ def max_items_options
59
+ return unless (num = options.dig(:output, :file, :max_items))
60
+
61
+ num = num.to_i
62
+ num = nil if num.zero?
63
+ num
64
+ end
65
+
66
+ # OUTPUT JSON
67
+
68
+ # Returns the last json array and blanks the variable
69
+ def exporting_json!
70
+ curr_json.tap do
71
+ @curr_json = []
72
+ end
73
+ end
74
+
75
+ def curr_json
76
+ @curr_json ||= []
77
+ end
78
+
79
+ def pending?
80
+ !input_json.empty?
81
+ end
82
+
83
+ def input_json
84
+ @json ||= JSON.load(File.open(input_file, 'r'))
85
+ end
86
+
87
+ # COUNTS
88
+
89
+ def next_count!
90
+ @curr_count = curr_count + 1
91
+ @total_count = total_count + 1
92
+ end
93
+
94
+ def total_count
95
+ @total_count ||= 0
96
+ end
97
+
98
+ def curr_count
99
+ @curr_count ||= 0
100
+ end
101
+
102
+ def new_count!
103
+ @curr_count = 0
104
+ end
105
+
106
+ # FILE GENERATION
107
+
108
+ def swap_file!
109
+ generate_file!
110
+ next_file!
111
+ end
112
+
113
+ def generate_file!
114
+ return unless @curr_file
115
+
116
+ if curr_json.empty?
117
+ log(:info) {
118
+ msg = "No pending elements to be transferred "
119
+ msg << "(skipping creation of file '#{curr_file}')"
120
+ msg
121
+ }
122
+ out_files -= [curr_file]
123
+ return
124
+ end
125
+
126
+ log(:info) {
127
+ msg = "Generating file at elem #{total_count} "
128
+ msg << "(file elements: #{curr_count})"
129
+ msg
130
+ }
131
+
132
+ save_json(exporting_json!, curr_file)
133
+ new_count!
134
+ end
135
+
136
+ def save_json(data, file)
137
+ File.open(file, 'w') do |fd|
138
+ first = true
139
+
140
+ fd << '['
141
+ data.each do |elem|
142
+ fd << "," unless first
143
+ first = false
144
+
145
+ fd << elem.to_json
146
+ end
147
+ fd << ']'
148
+ end.tap do
149
+ log(:info) {
150
+ "Generated file '#{file}'"
151
+ }
152
+ end
153
+ end
154
+
155
+ # OUTPUT FILES
156
+ attr_reader :curr_file
157
+
158
+ def file_count
159
+ @file_count ||= 0
160
+ end
161
+
162
+ def next_file!
163
+ @file_count = file_count + 1
164
+ @curr_file = generate_name(@file_count)
165
+ @curr_file.tap do
166
+ out_files << @curr_file
167
+ end
168
+ end
169
+
170
+ def out_files
171
+ @out_files ||= []
172
+ end
173
+
174
+ def generate_name(fidx)
175
+ File.join(input_dir, "#{input_name}_#{file_number(fidx)}#{input_ext}")
176
+ end
177
+
178
+ def file_number(num)
179
+ "#{zeroed}#{num}"[-5..]
180
+ end
181
+
182
+ def zeroed
183
+ "0" * 5
184
+ end
185
+
186
+ # INPUT FILE
187
+
188
+ def input_name
189
+ @input_name ||= File.basename(input_basename, input_ext)
190
+ end
191
+
192
+ def input_ext
193
+ @input_ext ||= input_basename.split('.')[1..].join('.').then do |name|
194
+ ".#{name}"
195
+ end
196
+ end
197
+
198
+ def input_basename
199
+ @input_basename ||= File.basename(input_full_filename)
200
+ end
201
+
202
+ def input_dir
203
+ @input_dir = File.dirname(input_full_filename)
204
+ end
205
+
206
+ def input_full_filename
207
+ @input_full_filename ||= File.expand_path(input_file)
208
+ end
209
+
210
+ def input_file
211
+ options.dig(:source, :file).tap do |file|
212
+ next if file && File.exist?(file)
213
+
214
+ unless file
215
+ log(:warn) { 'No input file provided' }
216
+ exit 1
217
+ end
218
+
219
+ log(:warn) {
220
+ "File '#{file}' doesn't exist"
221
+ }
222
+ end
223
+ end
224
+ end
@@ -10,3 +10,7 @@ module Eco
10
10
  end
11
11
 
12
12
  require_relative 'utils/split_csv_case'
13
+ require_relative 'utils/split_json_case'
14
+ require_relative 'utils/json_to_csv_case'
15
+ require_relative 'utils/sort_csv_case'
16
+ require_relative 'utils/group_csv_case'
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = '3.0.17'.freeze
2
+ VERSION = '3.0.19'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eco-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.17
4
+ version: 3.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-17 00:00:00.000000000 Z
11
+ date: 2024-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -229,7 +229,7 @@ dependencies:
229
229
  version: '0.10'
230
230
  - - ">="
231
231
  - !ruby/object:Gem::Version
232
- version: 0.10.5
232
+ version: 0.10.7
233
233
  type: :runtime
234
234
  prerelease: false
235
235
  version_requirements: !ruby/object:Gem::Requirement
@@ -239,7 +239,7 @@ dependencies:
239
239
  version: '0.10'
240
240
  - - ">="
241
241
  - !ruby/object:Gem::Version
242
- version: 0.10.5
242
+ version: 0.10.7
243
243
  - !ruby/object:Gem::Dependency
244
244
  name: ecoportal-api-graphql
245
245
  requirement: !ruby/object:Gem::Requirement
@@ -249,7 +249,7 @@ dependencies:
249
249
  version: '0.4'
250
250
  - - ">="
251
251
  - !ruby/object:Gem::Version
252
- version: 0.4.2
252
+ version: 0.4.3
253
253
  type: :runtime
254
254
  prerelease: false
255
255
  version_requirements: !ruby/object:Gem::Requirement
@@ -259,7 +259,7 @@ dependencies:
259
259
  version: '0.4'
260
260
  - - ">="
261
261
  - !ruby/object:Gem::Version
262
- version: 0.4.2
262
+ version: 0.4.3
263
263
  - !ruby/object:Gem::Dependency
264
264
  name: ecoportal-api-v2
265
265
  requirement: !ruby/object:Gem::Requirement
@@ -269,7 +269,7 @@ dependencies:
269
269
  version: '2.0'
270
270
  - - ">="
271
271
  - !ruby/object:Gem::Version
272
- version: 2.0.10
272
+ version: 2.0.12
273
273
  type: :runtime
274
274
  prerelease: false
275
275
  version_requirements: !ruby/object:Gem::Requirement
@@ -279,7 +279,7 @@ dependencies:
279
279
  version: '2.0'
280
280
  - - ">="
281
281
  - !ruby/object:Gem::Version
282
- version: 2.0.10
282
+ version: 2.0.12
283
283
  - !ruby/object:Gem::Dependency
284
284
  name: ed25519
285
285
  requirement: !ruby/object:Gem::Requirement
@@ -551,6 +551,10 @@ files:
551
551
  - lib/eco/api/common/people/default_parsers/csv_parser.rb
552
552
  - lib/eco/api/common/people/default_parsers/date_parser.rb
553
553
  - lib/eco/api/common/people/default_parsers/freemium_parser.rb
554
+ - lib/eco/api/common/people/default_parsers/helpers.rb
555
+ - lib/eco/api/common/people/default_parsers/helpers/expected_headers.rb
556
+ - lib/eco/api/common/people/default_parsers/helpers/null_parsing.rb
557
+ - lib/eco/api/common/people/default_parsers/json_parser.rb
554
558
  - lib/eco/api/common/people/default_parsers/login_providers_parser.rb
555
559
  - lib/eco/api/common/people/default_parsers/multi_parser.rb
556
560
  - lib/eco/api/common/people/default_parsers/numeric_parser.rb
@@ -658,10 +662,9 @@ files:
658
662
  - lib/eco/api/session/batch/jobs_groups.rb
659
663
  - lib/eco/api/session/batch/launcher.rb
660
664
  - lib/eco/api/session/batch/launcher/benchmarking.rb
661
- - lib/eco/api/session/batch/launcher/mode.rb
665
+ - lib/eco/api/session/batch/launcher/mode_size.rb
662
666
  - lib/eco/api/session/batch/launcher/options.rb
663
667
  - lib/eco/api/session/batch/launcher/retry.rb
664
- - lib/eco/api/session/batch/launcher/size.rb
665
668
  - lib/eco/api/session/batch/launcher/status_handling.rb
666
669
  - lib/eco/api/session/batch/launcher/valid_methods.rb
667
670
  - lib/eco/api/session/batch/policies.rb
@@ -736,8 +739,16 @@ files:
736
739
  - lib/eco/api/usecases/default/people/utils/switch_supervisor_case.rb
737
740
  - lib/eco/api/usecases/default/people/utils/transfer_account_case.rb
738
741
  - lib/eco/api/usecases/default/utils.rb
742
+ - lib/eco/api/usecases/default/utils/cli/group_csv_cli.rb
743
+ - lib/eco/api/usecases/default/utils/cli/json_to_csv_cli.rb
744
+ - lib/eco/api/usecases/default/utils/cli/sort_csv_cli.rb
739
745
  - lib/eco/api/usecases/default/utils/cli/split_csv_cli.rb
746
+ - lib/eco/api/usecases/default/utils/cli/split_json_cli.rb
747
+ - lib/eco/api/usecases/default/utils/group_csv_case.rb
748
+ - lib/eco/api/usecases/default/utils/json_to_csv_case.rb
749
+ - lib/eco/api/usecases/default/utils/sort_csv_case.rb
740
750
  - lib/eco/api/usecases/default/utils/split_csv_case.rb
751
+ - lib/eco/api/usecases/default/utils/split_json_case.rb
741
752
  - lib/eco/api/usecases/default_cases.rb
742
753
  - lib/eco/api/usecases/default_cases/create_case.rb
743
754
  - lib/eco/api/usecases/default_cases/delete_sync_case.rb
@@ -952,7 +963,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
952
963
  - !ruby/object:Gem::Version
953
964
  version: '0'
954
965
  requirements: []
955
- rubygems_version: 3.5.18
966
+ rubygems_version: 3.5.23
956
967
  signing_key:
957
968
  specification_version: 4
958
969
  summary: eco-helpers to manage people api cases
@@ -1,23 +0,0 @@
1
- module Eco
2
- module API
3
- class Session
4
- class Batch
5
- module Launcher
6
- module Mode
7
- include Eco::API::Session::Batch::Launcher::Options
8
-
9
- # @return [Symbol] the batch mode to run
10
- def batch_mode(opts = options)
11
- opts.dig(:workflow, :batch, :mode) || :batch
12
- end
13
-
14
- # @return [Boolean] are we running in `:job` mode?
15
- def job_mode?(opts = options)
16
- batch_mode(opts) == :job
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,40 +0,0 @@
1
- module Eco
2
- module API
3
- class Session
4
- class Batch
5
- module Launcher
6
- module Size
7
- include Eco::API::Session::Batch::Launcher::Mode
8
-
9
- DEFAULT_BATCH_SIZE = 50
10
- DEFAULT_JOB_SIZE = 100
11
-
12
- def batch_size(opts = options)
13
- return job_mode_size if job_mode?(opts)
14
-
15
- batch_mode_size
16
- end
17
-
18
- private
19
-
20
- def job_mode_size
21
- options.dig(:workflow, :batch, :job, :size).then do |size|
22
- next self.class::DEFAULT_JOB_SIZE unless size
23
-
24
- size
25
- end
26
- end
27
-
28
- def batch_mode_size
29
- options.dig(:workflow, :batch, :size).then do |size|
30
- next self.class::DEFAULT_BATCH_SIZE unless size
31
-
32
- [size, 100].min
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end