Skip to content

Commit

Permalink
OnRecord (#14)
Browse files Browse the repository at this point in the history
* add OnRecord

* add OnRecord to xsvRead

* add OnRecord Test
  • Loading branch information
shigetaichi authored Oct 3, 2023
1 parent 7e9b48a commit d14273a
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 5 deletions.
96 changes: 96 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,32 @@ e,BAD_INPUT,b`)

}

func Test_readTo_OnRecord(t *testing.T) {
blah := 0
sptr := "*string"
b := bytes.NewBufferString(`foo,BAR,Baz,Blah,SPtr,Omit
f,1,baz,,*string,*string`)
var samples []Sample
xsvRead := NewXsvRead[Sample]()
xsvRead.OnRecord = func(sample Sample) Sample {
if sample.Foo == "f" {
sample.Foo = "f-onrecord"
}
return sample
}
if err := xsvRead.SetReader(csv.NewReader(b)).ReadTo(&samples); err != nil {
t.Fatal(err)
}

if len(samples) != 1 {
t.Fatalf("expected 1 sample instances, got %d", len(samples))
}
expected := Sample{Foo: "f-onrecord", Bar: 1, Baz: "baz", Blah: &blah, SPtr: &sptr, Omit: &sptr}
if !reflect.DeepEqual(expected, samples[0]) {
t.Fatalf("expected first sample %v, got %v", expected, samples[0])
}
}

func Test_readToNormalized(t *testing.T) {

blah := 0
Expand Down Expand Up @@ -327,6 +353,46 @@ ff,gg,22,hh,ii,jj`)
}
}

func Test_readEach_OnRecord(t *testing.T) {
b := bytes.NewBufferString(`first,foo,BAR,Baz,last,abc
aa,bb,11,cc,dd,ee`)
c := make(chan SkipFieldSample)
var samples []SkipFieldSample
xsvRead := NewXsvRead[SkipFieldSample]()
go func() {
xsvRead.OnRecord = func(sample SkipFieldSample) SkipFieldSample {
if sample.Foo == "bb" {
sample.Foo = "bb-onrecord"
}
return sample
}
if err := xsvRead.SetReader(csv.NewReader(b)).ReadEach(c); err != nil {
t.Fatal(err)
}
}()
for v := range c {
samples = append(samples, v)
}
if len(samples) != 1 {
t.Fatalf("expected 1 sample instances, got %d", len(samples))
}
expected := SkipFieldSample{
EmbedSample: EmbedSample{
Qux: "aa",
Sample: Sample{
Foo: "bb-onrecord",
Bar: 11,
Baz: "cc",
},
Quux: "dd",
},
Corge: "ee",
}
if expected != samples[0] {
t.Fatalf("expected first sample %v, got %v", expected, samples[0])
}
}

func Test_readEachWithoutHeaders(t *testing.T) {
blah := 0
sptr := ""
Expand Down Expand Up @@ -797,6 +863,36 @@ func TestCSVToMaps(t *testing.T) {
}
}

func TestCSVToMaps_OnRecord(t *testing.T) {
b := bytes.NewBufferString(`foo,BAR,Baz
4,Jose,42`)
xsvRead := NewXsvRead[map[string]string]()
xsvRead.OnRecord = func(record map[string]string) map[string]string {
r2 := make(map[string]string, len(record))
for k, v := range record {
r2[k] = v
}
if r2["foo"] == "4" {
r2["foo"] = "4-onrecord-to-maps"
}
return r2
}
m, err := xsvRead.SetReader(csv.NewReader(b)).ToMap()
if err != nil {
t.Fatal(err)
}
firstRecord := m[0]
if firstRecord["foo"] != "4-onrecord-to-maps" {
t.Fatal("Expected 4-onrecord-to-maps got", firstRecord["foo"])
}
if firstRecord["BAR"] != "Jose" {
t.Fatal("Expected Jose got", firstRecord["BAR"])
}
if firstRecord["Baz"] != "42" {
t.Fatal("Expected 42 got", firstRecord["Baz"])
}
}

func TestUnmarshalToDecoder(t *testing.T) {
blah := 0
sptr := "*string"
Expand Down
12 changes: 7 additions & 5 deletions xsv_read.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import (

// XsvRead manages configuration values related to the csv read process.
type XsvRead[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
FailIfUnmatchedStructTags bool // indicates whether it is considered an error when there is an unmatched struct tag.
FailIfDoubleHeaderNames bool // indicates whether it is considered an error when a header name is repeated in the csv header.
ShouldAlignDuplicateHeadersWithStructFieldOrder bool // indicates whether we should align duplicate CSV headers per their alignment in the struct definition.
TagName string //key in the struct field's tag to scan
TagSeparator string //separator string for multiple csv tags in struct fields
FailIfUnmatchedStructTags bool // indicates whether it is considered an error when there is an unmatched struct tag.
FailIfDoubleHeaderNames bool // indicates whether it is considered an error when a header name is repeated in the csv header.
ShouldAlignDuplicateHeadersWithStructFieldOrder bool // indicates whether we should align duplicate CSV headers per their alignment in the struct definition.
OnRecord func(T) T // callback function to be called on each record
NameNormalizer Normalizer
ErrorHandler ErrorHandler
}
Expand All @@ -26,6 +27,7 @@ func NewXsvRead[T any]() *XsvRead[T] {
FailIfUnmatchedStructTags: false,
FailIfDoubleHeaderNames: false,
ShouldAlignDuplicateHeadersWithStructFieldOrder: false,
OnRecord: nil,
NameNormalizer: func(s string) string { return s },
ErrorHandler: nil,
}
Expand Down
21 changes: 21 additions & 0 deletions xsv_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ func (r *XsvReader[T]) ReadTo(out *[]T) error {
outInner = reflectedObject.Elem()
}

if r.OnRecord != nil {
outInner = reflect.ValueOf(r.OnRecord(outInner.Interface().(T)))
}

outValue.Index(i).Set(outInner)
}
return nil
Expand Down Expand Up @@ -189,6 +193,9 @@ func (r *XsvReader[T]) ReadEach(c chan T) error {
}
}
}
if r.OnRecord != nil {
outInner = reflect.ValueOf(r.OnRecord(outInner.Interface().(T)))
}
outValue.Send(outInner)
i++
}
Expand Down Expand Up @@ -230,6 +237,9 @@ func (r *XsvReader[T]) ReadToWithoutHeaders(out *[]T) error {
}
}
}
if r.OnRecord != nil {
outInner = reflect.ValueOf(r.OnRecord(outInner.Interface().(T)))
}
outValue.Index(i).Set(outInner)
}

Expand Down Expand Up @@ -269,6 +279,9 @@ func (r *XsvReader[T]) ReadEachWithoutHeaders(c chan T) error {
}
}
}
if r.OnRecord != nil {
outInner = reflect.ValueOf(r.OnRecord(outInner.Interface().(T)))
}
outValue.Send(outInner)
i++
}
Expand Down Expand Up @@ -315,6 +328,10 @@ func (r *XsvReader[T]) ToMap() ([]map[string]string, error) {
for i := range header {
dict[header[i]] = record[i]
}
if r.OnRecord != nil {
v := r.OnRecord(reflect.ValueOf(dict).Interface().(T))
dict = reflect.ValueOf(v).Interface().(map[string]string)
}
rows = append(rows, dict)
}
}
Expand All @@ -337,6 +354,10 @@ func (r *XsvReader[T]) ToChanMaps(c chan<- map[string]string) error {
dict := map[string]string{}
for i := range header {
dict[header[i]] = record[i]
if r.OnRecord != nil {
v := r.OnRecord(reflect.ValueOf(dict).Interface().(T))
dict = reflect.ValueOf(v).Interface().(map[string]string)
}
}
c <- dict
}
Expand Down

0 comments on commit d14273a

Please sign in to comment.