Class: ForestAdminAgent::Utils::CsvGenerator
- Inherits:
-
Object
- Object
- ForestAdminAgent::Utils::CsvGenerator
- Defined in:
- lib/forest_admin_agent/utils/csv_generator.rb
Class Method Summary collapse
-
.filter_header(header, requested, kept) ⇒ Object
Labels are positionally aligned with the requested projection, so dropping a field without dropping its label shifts every later value under the wrong heading.
- .generate(records, projection) ⇒ Object
-
.generate_csv_string(data) ⇒ Object
data = { "id" => [1, 2], "email" => ["[email protected]", "[email protected]"], "name" => ["Matthieu", "Nicolas"], }.
-
.parse_header_labels(header) ⇒ Object
The front joins the labels with commas; a JSON array comes from older callers.
Class Method Details
.filter_header(header, requested, kept) ⇒ Object
Labels are positionally aligned with the requested projection, so dropping a field without dropping its label shifts every later value under the wrong heading. The header carries one label per exported column, so a label survives exactly when the projection path at its index did.
A count that does not match the requested projection cannot be mapped onto columns — a to-one
relation expanded into several paths, or a polymorphic type field appended — and there is then
no header to hand back. Returning the original would leave CsvGeneratorStream.parse_header
to check it against the kept count instead, so labels that happen to match the redacted
column count would be accepted, printing each surviving column under the label of whatever
preceded it. nil is what makes the stream fall back to the field paths.
Handing it back untouched is only safe on the branch above, where nothing was redacted: there the two counts are the same number, so the stream's own check cannot reach a different answer.
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/forest_admin_agent/utils/csv_generator.rb', line 20 def self.filter_header(header, requested, kept) return header if header.nil? || kept.size == requested.size labels = parse_header_labels(header) return nil unless labels&.size == requested.size labels.each_with_index .select { |_label, index| kept.include?(requested[index]) } .map(&:first) end |
.generate(records, projection) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/forest_admin_agent/utils/csv_generator.rb', line 46 def self.generate(records, projection) data = {} projection.each do |schema_field| is_relation = schema_field.include?(':') && projection.relations.key?(schema_field.split(':').first) col_name = (is_relation ? schema_field.split(':').first : schema_field) data[col_name] = [] records.each do |row| data[col_name] << if is_relation row[col_name]&.[](schema_field.split(':').last) else row[col_name] end end end generate_csv_string(data) end |
.generate_csv_string(data) ⇒ Object
data = { "id" => [1, 2], "email" => ["[email protected]", "[email protected]"], "name" => ["Matthieu", "Nicolas"], }
70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/forest_admin_agent/utils/csv_generator.rb', line 70 def self.generate_csv_string(data) CSV.generate do |csv| # headers csv << data.keys num_rows = data.values.first.size num_rows.times do |i| row = data.keys.map { |key| data[key][i] } csv << row end end end |
.parse_header_labels(header) ⇒ Object
The front joins the labels with commas; a JSON array comes from older callers.
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/forest_admin_agent/utils/csv_generator.rb', line 33 def self.parse_header_labels(header) return header if header.is_a?(Array) return nil unless header.is_a?(String) parsed = begin JSON.parse(header) rescue JSON::ParserError nil end parsed.is_a?(Array) ? parsed : header.split(',', -1) end |