Module: Eco::API::UseCases::GraphQL::Samples::Pages::Template::CsvBuild::FormatMap
- Defined in:
- lib/eco/api/usecases/graphql/samples/pages/template/csv_build/format_map.rb
Overview
ISOLATED column-format mapping for the CSV → template build pipeline.
============================ IMPORTANT / TODO ============================
The EXACT columnar CSV format for the ~300-template bulk build is due ~mid-July 2026 and is NOT
yet confirmed. This class is the SINGLE place the assumed format is encoded, precisely so that
when the real format lands, only THIS file (and its spec) needs to change — the Parser and
Builder are written against the neutral intermediate RowSpec, not against column names.
Assumed format (documented here, one row per FIELD, hierarchy carried on each row):
stage,stage_ordering,section,section_ordering,section_layout, field_label,field_type,field_required,field_column,field_description,field_options
field_type— a template field type accepted by addField (e.g. plain_text, select, date, number, gauge, rich_text, people, ...). Passed through verbatim.field_options— for select-type fields: pipe-separatedlabel:weightpairs, e.g. "High:10|Medium:5|Low:0". Weight optional ("High|Medium|Low").field_description— carries the SECTION/FIELD IDENTITY convention (see below).
SECTION / FIELD IDENTITY CONVENTION (per the CSV-pipeline project notes): stable identity for a
section/field across rebuilds is expressed via a HIDDEN marker field + a DESCRIPTION token, not
via the volatile Mongo id. The parser threads field_description through so the builder can
stamp a deterministic identity token; sections inherit identity from their heading + a hidden
anchor field. This keeps a rebuilt template pair-able against a prior version by the diff engine.
To adapt to the real format: change COLUMNS + the #value/#options readers here. Everything
downstream consumes RowSpec, which is format-agnostic.
Defined Under Namespace
Classes: RowSpec
Constant Summary collapse
- COLUMNS =
Logical field => CSV header name (assumed). CHANGE HERE when the real format arrives.
{ stage: 'stage', stage_ordering: 'stage_ordering', section: 'section', section_ordering: 'section_ordering', section_layout: 'section_layout', field_label: 'field_label', field_type: 'field_type', field_required: 'field_required', field_column: 'field_column', field_description: 'field_description', field_options: 'field_options' }.freeze
- OPTIONS_DELIMITER =
Delimiters (assumed). CHANGE HERE if the real format differs.
'|'.freeze
- OPTION_WEIGHT_SEPARATOR =
':'.freeze
Class Method Summary collapse
- .integer(row, logical) ⇒ Object
-
.options(cell) ⇒ Object
Parse the options cell into [ { label:, weight: }, ... ].
-
.row_spec(row) ⇒ Object
Map one CSV row (a Hash keyed by header string) to a RowSpec.
- .truthy?(row, logical) ⇒ Boolean
- .value(row, logical) ⇒ Object
Class Method Details
.integer(row, logical) ⇒ Object
95 96 97 98 |
# File 'lib/eco/api/usecases/graphql/samples/pages/template/csv_build/format_map.rb', line 95 def integer(row, logical) raw = value(row, logical) raw && Integer(raw, exception: false) end |
.options(cell) ⇒ Object
Parse the options cell into [ { label:, weight: }, ... ]. Empty → [].
76 77 78 79 80 81 82 83 |
# File 'lib/eco/api/usecases/graphql/samples/pages/template/csv_build/format_map.rb', line 76 def (cell) return [] if cell.nil? || cell.to_s.strip.empty? cell.to_s.split(OPTIONS_DELIMITER).map do |token| label, weight = token.split(OPTION_WEIGHT_SEPARATOR, 2).map(&:strip) { label: label, weight: (weight && !weight.empty? ? Integer(weight, exception: false) : nil) } end end |
.row_spec(row) ⇒ Object
Map one CSV row (a Hash keyed by header string) to a RowSpec.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/eco/api/usecases/graphql/samples/pages/template/csv_build/format_map.rb', line 59 def row_spec(row) RowSpec.new( stage: value(row, :stage), stage_ordering: integer(row, :stage_ordering), section: value(row, :section), section_ordering: integer(row, :section_ordering), section_layout: value(row, :section_layout) || 'content', field_label: value(row, :field_label), field_type: value(row, :field_type), field_required: truthy?(row, :field_required), field_column: integer(row, :field_column) || 0, field_description: value(row, :field_description), field_options: (value(row, :field_options)) ) end |
.truthy?(row, logical) ⇒ Boolean
100 101 102 103 104 105 |
# File 'lib/eco/api/usecases/graphql/samples/pages/template/csv_build/format_map.rb', line 100 def truthy?(row, logical) raw = value(row, logical) return false if raw.nil? %w[1 true yes y required].include?(raw.downcase) end |
.value(row, logical) ⇒ Object
85 86 87 88 89 90 91 92 93 |
# File 'lib/eco/api/usecases/graphql/samples/pages/template/csv_build/format_map.rb', line 85 def value(row, logical) header = COLUMNS.fetch(logical) raw = row[header] raw = row[header.to_sym] if raw.nil? && row.respond_to?(:key?) return nil if raw.nil? str = raw.to_s.strip str.empty? ? nil : str end |