From 46922c15864bd89aab4b0a401333f36db98f0ede Mon Sep 17 00:00:00 2001 From: Taichi Shigematsu <65220900+shigetaichi@users.noreply.github.com> Date: Mon, 4 Sep 2023 11:02:14 +0300 Subject: [PATCH] HeaderModifier (#10) * feat: HeaderModifier * feat: use HeaderModifier * feat: add test for HeaderModifier * fix: HeaderModifier in XsvWrite * refactor: delete for loop nest --- encode_test.go | 29 +++++++++++++++++++++++++++++ xsv_write.go | 6 ++++-- xsv_writer.go | 12 ++++++++++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/encode_test.go b/encode_test.go index 481e420..d18a47a 100644 --- a/encode_test.go +++ b/encode_test.go @@ -708,3 +708,32 @@ func Test_writeToChan_emptyptr_sortOrder(t *testing.T) { assertLine(t, []string{strconv.Itoa(i - 1), "f", "baz" + strconv.Itoa(i-1), strconv.FormatFloat(float64(i-1), 'f', -1, 64), "", "*string", ""}, l) } } + +func Test_HeaderModifier(t *testing.T) { + b := bytes.Buffer{} + e := &encoder{out: &b} + blah := 2 + sptr := "*string" + s := []Sample{ + {Foo: "f", Bar: 1, Baz: "baz", Frop: 0.1, Blah: &blah, SPtr: &sptr}, + {Foo: "e", Bar: 3, Baz: "b", Frop: 6.0 / 13, Blah: nil, SPtr: nil}, + } + + xsvWrite := NewXsvWrite[Sample]() + xsvWrite.HeaderModifier = map[string]string{"BAR": "BAR-updated"} + xsvWrite.HeaderModifier["Omit"] = "" + if err := xsvWrite.SetWriter(csv.NewWriter(e.out)).Write(s); err != nil { + t.Fatal(err) + } + + lines, err := csv.NewReader(&b).ReadAll() + if err != nil { + t.Fatal(err) + } + if len(lines) != 3 { + t.Fatalf("expected 3 lines, got %d", len(lines)) + } + assertLine(t, []string{"foo", "BAR-updated", "Baz", "Quux", "Blah", "SPtr", ""}, lines[0]) + assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string", ""}, lines[1]) + assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", "", ""}, lines[2]) +} diff --git a/xsv_write.go b/xsv_write.go index a7212e3..bdc74bf 100644 --- a/xsv_write.go +++ b/xsv_write.go @@ -13,8 +13,9 @@ type XsvWrite[T any] struct { TagName string //key in the struct field's tag to scan TagSeparator string //separator string for multiple csv tags in struct fields OmitHeaders bool - SelectedColumns []string // slice of field names to output - SortOrder []int // column sort order + SelectedColumns []string // slice of field names to output + SortOrder []int // column sort order + HeaderModifier map[string]string // map to dynamically change headers nameNormalizer Normalizer } @@ -25,6 +26,7 @@ func NewXsvWrite[T any]() XsvWrite[T] { OmitHeaders: false, SelectedColumns: make([]string, 0), SortOrder: make([]int, 0), + HeaderModifier: map[string]string{}, nameNormalizer: func(s string) string { return s }, } } diff --git a/xsv_writer.go b/xsv_writer.go index bf8c817..248d414 100644 --- a/xsv_writer.go +++ b/xsv_writer.go @@ -42,7 +42,11 @@ func (xw *XsvWriter[T]) Write(data []T) error { csvHeadersLabels := make([]string, len(inInnerStructInfo.Fields)) for i, fieldInfo := range inInnerStructInfo.Fields { // Used to write the header (first line) in CSV - csvHeadersLabels[i] = fieldInfo.getFirstKey() + if newHeader, ok := xw.HeaderModifier[fieldInfo.getFirstKey()]; ok { // modify header name dynamically + csvHeadersLabels[i] = newHeader + } else { + csvHeadersLabels[i] = fieldInfo.getFirstKey() + } } if !xw.OmitHeaders { if err := xw.writer.Write(csvHeadersLabels); err != nil { @@ -87,7 +91,11 @@ func (xw *XsvWriter[T]) WriteFromChan(dataChan chan T) error { inInnerStructInfo := &structInfo{fieldInfos} csvHeadersLabels := make([]string, len(inInnerStructInfo.Fields)) for i, fieldInfo := range inInnerStructInfo.Fields { // Used to Write the header (first line) in CSV - csvHeadersLabels[i] = fieldInfo.getFirstKey() + if newHeader, ok := xw.HeaderModifier[fieldInfo.getFirstKey()]; ok { // modify header name dynamically + csvHeadersLabels[i] = newHeader + } else { + csvHeadersLabels[i] = fieldInfo.getFirstKey() + } } if !xw.OmitHeaders {