summaryrefslogtreecommitdiff
path: root/vendor/github.com/gocarina/gocsv/reflect.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gocarina/gocsv/reflect.go')
-rw-r--r--vendor/github.com/gocarina/gocsv/reflect.go95
1 files changed, 81 insertions, 14 deletions
diff --git a/vendor/github.com/gocarina/gocsv/reflect.go b/vendor/github.com/gocarina/gocsv/reflect.go
index dfc63b3..309f80b 100644
--- a/vendor/github.com/gocarina/gocsv/reflect.go
+++ b/vendor/github.com/gocarina/gocsv/reflect.go
@@ -1,7 +1,9 @@
package gocsv
import (
+ "fmt"
"reflect"
+ "strconv"
"strings"
"sync"
)
@@ -17,9 +19,10 @@ type structInfo struct {
// Each IndexChain element before the last is the index of an the embedded struct field
// that defines Key as a tag
type fieldInfo struct {
- keys []string
- omitEmpty bool
- IndexChain []int
+ keys []string
+ omitEmpty bool
+ IndexChain []int
+ defaultValue string
}
func (f fieldInfo) getFirstKey() string {
@@ -64,18 +67,17 @@ func getFieldInfos(rType reflect.Type, parentIndexChain []int) []fieldInfo {
var cpy = make([]int, len(parentIndexChain))
copy(cpy, parentIndexChain)
indexChain := append(cpy, i)
-
// if the field is a pointer to a struct, follow the pointer then create fieldinfo for each field
if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
- // unless it implements marshalText or marshalCSV. Structs that implement this
+ // Structs that implement any of the text or CSV marshaling methods
// should result in one value and not have their fields exposed
- if !(canMarshal(field.Type.Elem())) {
+ if !(canMarshal(field.Type.Elem()) || canMarshal(field.Type)) {
fieldsList = append(fieldsList, getFieldInfos(field.Type.Elem(), indexChain)...)
}
}
// if the field is a struct, create a fieldInfo for each of its fields
if field.Type.Kind() == reflect.Struct {
- // unless it implements marshalText or marshalCSV. Structs that implement this
+ // Structs that implement any of the text or CSV marshaling methods
// should result in one value and not have their fields exposed
if !(canMarshal(field.Type)) {
fieldsList = append(fieldsList, getFieldInfos(field.Type, indexChain)...)
@@ -87,26 +89,91 @@ func getFieldInfos(rType reflect.Type, parentIndexChain []int) []fieldInfo {
continue
}
- fieldInfo := fieldInfo{IndexChain: indexChain}
+ currFieldInfo := fieldInfo{IndexChain: indexChain}
fieldTag := field.Tag.Get(TagName)
fieldTags := strings.Split(fieldTag, TagSeparator)
filteredTags := []string{}
for _, fieldTagEntry := range fieldTags {
- if fieldTagEntry != "omitempty" {
- filteredTags = append(filteredTags, normalizeName(fieldTagEntry))
+ trimmedFieldTagEntry := strings.TrimSpace(fieldTagEntry) // handles cases like `csv:"foo, omitempty, default=test"`
+ if trimmedFieldTagEntry == "omitempty" {
+ currFieldInfo.omitEmpty = true
+ } else if strings.HasPrefix(trimmedFieldTagEntry, "default=") {
+ currFieldInfo.defaultValue = strings.TrimPrefix(trimmedFieldTagEntry, "default=")
} else {
- fieldInfo.omitEmpty = true
+ filteredTags = append(filteredTags, normalizeName(trimmedFieldTagEntry))
}
}
if len(filteredTags) == 1 && filteredTags[0] == "-" {
continue
} else if len(filteredTags) > 0 && filteredTags[0] != "" {
- fieldInfo.keys = filteredTags
+ currFieldInfo.keys = filteredTags
+ } else {
+ currFieldInfo.keys = []string{normalizeName(field.Name)}
+ }
+
+ if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Array {
+ var arrayLength = -1
+ if arrayTag, ok := field.Tag.Lookup(TagName + "[]"); ok {
+ arrayLength, _ = strconv.Atoi(arrayTag)
+ }
+
+ // When the field is a slice/array of structs, create a fieldInfo for each index and each field
+ if field.Type.Elem().Kind() == reflect.Struct {
+ fieldInfos := getFieldInfos(field.Type.Elem(), []int{})
+
+ for idx := 0; idx < arrayLength; idx++ {
+ // copy index chain and append array index
+ var cpy2 = make([]int, len(indexChain))
+ copy(cpy2, indexChain)
+ arrayIndexChain := append(cpy2, idx)
+ for _, childFieldInfo := range fieldInfos {
+ // copy array index chain and append array index
+ var cpy3 = make([]int, len(arrayIndexChain))
+ copy(cpy3, arrayIndexChain)
+
+ arrayFieldInfo := fieldInfo{
+ IndexChain: append(cpy3, childFieldInfo.IndexChain...),
+ omitEmpty: childFieldInfo.omitEmpty,
+ defaultValue: childFieldInfo.defaultValue,
+ }
+
+ // create cartesian product of keys
+ // eg: array field keys x struct field keys
+ for _, akey := range currFieldInfo.keys {
+ for _, fkey := range childFieldInfo.keys {
+ arrayFieldInfo.keys = append(arrayFieldInfo.keys, normalizeName(fmt.Sprintf("%s[%d].%s", akey, idx, fkey)))
+ }
+ }
+
+ fieldsList = append(fieldsList, arrayFieldInfo)
+ }
+ }
+ } else if arrayLength > 0 {
+ // When the field is a slice/array of primitives, create a fieldInfo for each index
+ for idx := 0; idx < arrayLength; idx++ {
+ // copy index chain and append array index
+ var cpy2 = make([]int, len(indexChain))
+ copy(cpy2, indexChain)
+
+ arrayFieldInfo := fieldInfo{
+ IndexChain: append(cpy2, idx),
+ omitEmpty: currFieldInfo.omitEmpty,
+ defaultValue: currFieldInfo.defaultValue,
+ }
+
+ for _, akey := range currFieldInfo.keys {
+ arrayFieldInfo.keys = append(arrayFieldInfo.keys, normalizeName(fmt.Sprintf("%s[%d]", akey, idx)))
+ }
+
+ fieldsList = append(fieldsList, arrayFieldInfo)
+ }
+ } else {
+ fieldsList = append(fieldsList, currFieldInfo)
+ }
} else {
- fieldInfo.keys = []string{normalizeName(field.Name)}
+ fieldsList = append(fieldsList, currFieldInfo)
}
- fieldsList = append(fieldsList, fieldInfo)
}
return fieldsList
}