Skip to content

Commit

Permalink
feat: allow struct slice and struct array for valueType (#70)
Browse files Browse the repository at this point in the history
* feat: allow struct slice and struct array for to determine Header
  • Loading branch information
cia-rana authored Feb 3, 2024
1 parent 4c3b8e6 commit 53deda7
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 9 deletions.
17 changes: 11 additions & 6 deletions csvutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func countRecords(s []byte) (n int) {
}
}

// Header scans the provided struct type and generates a CSV header for it.
// Header scans the provided struct type, struct slice or struct array and generates a CSV header for it.
//
// Field names are written in the same order as struct fields are defined.
// Embedded struct's fields are treated as if they were part of the outer struct.
Expand All @@ -175,8 +175,8 @@ func countRecords(s []byte) (n int) {
//
// If tag is left empty the default "csv" will be used.
//
// Header will return UnsupportedTypeError if the provided value is nil or is
// not a struct.
// Header will return UnsupportedTypeError if the provided value is nil, is
// not a struct, a struct slice or a struct array.
func Header(v any, tag string) ([]string, error) {
typ, err := valueType(v)
if err != nil {
Expand Down Expand Up @@ -216,10 +216,15 @@ loop:
}

typ := walkType(val.Type())
if typ.Kind() != reflect.Struct {
return nil, &UnsupportedTypeError{Type: typ}
switch typ.Kind() {
case reflect.Struct:
return typ, nil
case reflect.Slice, reflect.Array:
if eTyp := walkType(typ.Elem()); eTyp.Kind() == reflect.Struct {
return eTyp, nil
}
}
return typ, nil
return nil, &UnsupportedTypeError{Type: typ}
}

func newCSVReader(r io.Reader) *csv.Reader {
Expand Down
60 changes: 57 additions & 3 deletions csvutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,10 +627,64 @@ func TestHeader(t *testing.T) {
err: &UnsupportedTypeError{Type: reflect.TypeOf(int(0))},
},
{
desc: "slice",
v: []TypeJ{{}},
desc: "slice",
v: []TypeJ{{}},
tag: "csv",
header: []string{"STR", "int", "Bool", "Uint8", "float"},
},
{
desc: "ptr slice",
v: &[]TypeJ{{}},
tag: "csv",
header: []string{"STR", "int", "Bool", "Uint8", "float"},
},
{
desc: "slice with ptr value",
v: []*TypeJ{{}},
tag: "csv",
header: []string{"STR", "int", "Bool", "Uint8", "float"},
},
{
desc: "slice with non-struct",
v: []int{0},
tag: "csv",
err: &UnsupportedTypeError{Type: reflect.TypeOf([]int{0})},
},
{
desc: "two-dimensional slice",
v: [][]TypeJ{{{}}},
tag: "csv",
err: &UnsupportedTypeError{Type: reflect.TypeOf([][]TypeJ{{}})},
},
{
desc: "array",
v: [1]TypeJ{{}},
tag: "csv",
header: []string{"STR", "int", "Bool", "Uint8", "float"},
},
{
desc: "ptr array",
v: &[1]TypeJ{{}},
tag: "csv",
header: []string{"STR", "int", "Bool", "Uint8", "float"},
},
{
desc: "array with ptr value",
v: [1]*TypeJ{{}},
tag: "csv",
header: []string{"STR", "int", "Bool", "Uint8", "float"},
},
{
desc: "array with non-struct",
v: [1]int{0},
tag: "csv",
err: &UnsupportedTypeError{Type: reflect.TypeOf([1]int{0})},
},
{
desc: "two-dimensional array",
v: [1][1]TypeJ{{{}}},
tag: "csv",
err: &UnsupportedTypeError{Type: reflect.TypeOf([]TypeJ{})},
err: &UnsupportedTypeError{Type: reflect.TypeOf([1][1]TypeJ{{}})},
},
{
desc: "nil interface",
Expand Down
40 changes: 40 additions & 0 deletions encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,46 @@ func TestEncoder(t *testing.T) {
},
},
},
{
desc: "struct slice",
in: []TypeF{},
out: [][]string{
{
"int",
"pint",
"int8",
"pint8",
"int16",
"pint16",
"int32",
"pint32",
"int64",
"pint64",
"uint",
"puint",
"uint8",
"puint8",
"uint16",
"puint16",
"uint32",
"puint32",
"uint64",
"puint64",
"float32",
"pfloat32",
"float64",
"pfloat64",
"string",
"pstring",
"bool",
"pbool",
"interface",
"pinterface",
"binary",
"pbinary",
},
},
},
{
desc: "ptr to nil interface",
in: &nilIface,
Expand Down

0 comments on commit 53deda7

Please sign in to comment.