summaryrefslogtreecommitdiff
path: root/vendor/github.com/gocarina/gocsv/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gocarina/gocsv/decode.go')
-rw-r--r--vendor/github.com/gocarina/gocsv/decode.go69
1 files changed, 51 insertions, 18 deletions
diff --git a/vendor/github.com/gocarina/gocsv/decode.go b/vendor/github.com/gocarina/gocsv/decode.go
index a832e84..537251d 100644
--- a/vendor/github.com/gocarina/gocsv/decode.go
+++ b/vendor/github.com/gocarina/gocsv/decode.go
@@ -10,13 +10,13 @@ import (
// Decoder .
type Decoder interface {
- getCSVRows() ([][]string, error)
+ GetCSVRows() ([][]string, error)
}
// SimpleDecoder .
type SimpleDecoder interface {
- getCSVRow() ([]string, error)
- getCSVRows() ([][]string, error)
+ GetCSVRow() ([]string, error)
+ GetCSVRows() ([][]string, error)
}
type CSVReader interface {
@@ -32,6 +32,11 @@ func newSimpleDecoderFromReader(r io.Reader) SimpleDecoder {
return csvDecoder{getCSVReader(r)}
}
+var (
+ ErrEmptyCSVFile = errors.New("empty csv file given")
+ ErrNoStructTags = errors.New("no csv struct tags found")
+)
+
// NewSimpleDecoderFromCSVReader creates a SimpleDecoder, which may be passed
// to the UnmarshalDecoder* family of functions, from a CSV reader. Note that
// encoding/csv.Reader implements CSVReader, so you can pass one of those
@@ -40,11 +45,11 @@ func NewSimpleDecoderFromCSVReader(r CSVReader) SimpleDecoder {
return csvDecoder{r}
}
-func (c csvDecoder) getCSVRows() ([][]string, error) {
+func (c csvDecoder) GetCSVRows() ([][]string, error) {
return c.ReadAll()
}
-func (c csvDecoder) getCSVRow() ([]string, error) {
+func (c csvDecoder) GetCSVRow() ([]string, error) {
return c.Read()
}
@@ -137,19 +142,19 @@ func readToWithErrorHandler(decoder Decoder, errHandler ErrorHandler, out interf
if err := ensureOutInnerType(outInnerType); err != nil {
return err
}
- csvRows, err := decoder.getCSVRows() // Get the CSV csvRows
+ csvRows, err := decoder.GetCSVRows() // Get the CSV csvRows
if err != nil {
return err
}
if len(csvRows) == 0 {
- return errors.New("empty csv file given")
+ return ErrEmptyCSVFile
}
if err := ensureOutCapacity(&outValue, len(csvRows)); err != nil { // Ensure the container is big enough to hold the CSV content
return err
}
outInnerStructInfo := getStructInfo(outInnerType) // Get the inner struct info to get CSV annotations
if len(outInnerStructInfo.Fields) == 0 {
- return errors.New("no csv struct tags found")
+ return ErrNoStructTags
}
headers := normalizeHeaders(csvRows[0])
@@ -203,8 +208,11 @@ func readToWithErrorHandler(decoder Decoder, errHandler ErrorHandler, out interf
continue
}
}
-
- if err := setInnerField(&outInner, outInnerWasPointer, fieldInfo.IndexChain, csvColumnContent, fieldInfo.omitEmpty); err != nil { // Set field of struct
+ value := csvColumnContent
+ if value == "" {
+ value = fieldInfo.defaultValue
+ }
+ if err := setInnerField(&outInner, outInnerWasPointer, fieldInfo.IndexChain, value, fieldInfo.omitEmpty); err != nil { // Set field of struct
parseError := csv.ParseError{
Line: i + 2, //add 2 to account for the header & 0-indexing of arrays
Column: j + 1,
@@ -234,7 +242,7 @@ func readEach(decoder SimpleDecoder, c interface{}) error {
}
defer outValue.Close()
- headers, err := decoder.getCSVRow()
+ headers, err := decoder.GetCSVRow()
if err != nil {
return err
}
@@ -246,7 +254,7 @@ func readEach(decoder SimpleDecoder, c interface{}) error {
}
outInnerStructInfo := getStructInfo(outInnerType) // Get the inner struct info to get CSV annotations
if len(outInnerStructInfo.Fields) == 0 {
- return errors.New("no csv struct tags found")
+ return ErrNoStructTags
}
csvHeadersLabels := make(map[int]*fieldInfo, len(outInnerStructInfo.Fields)) // Used to store the correspondance header <-> position in CSV
headerCount := map[string]int{}
@@ -272,7 +280,7 @@ func readEach(decoder SimpleDecoder, c interface{}) error {
}
i := 0
for {
- line, err := decoder.getCSVRow()
+ line, err := decoder.GetCSVRow()
if err == io.EOF {
break
} else if err != nil {
@@ -309,12 +317,12 @@ func readEachWithoutHeaders(decoder SimpleDecoder, c interface{}) error {
}
outInnerStructInfo := getStructInfo(outInnerType) // Get the inner struct info to get CSV annotations
if len(outInnerStructInfo.Fields) == 0 {
- return errors.New("no csv struct tags found")
+ return ErrNoStructTags
}
i := 0
for {
- line, err := decoder.getCSVRow()
+ line, err := decoder.GetCSVRow()
if err == io.EOF {
break
} else if err != nil {
@@ -346,19 +354,19 @@ func readToWithoutHeaders(decoder Decoder, out interface{}) error {
if err := ensureOutInnerType(outInnerType); err != nil {
return err
}
- csvRows, err := decoder.getCSVRows() // Get the CSV csvRows
+ csvRows, err := decoder.GetCSVRows() // Get the CSV csvRows
if err != nil {
return err
}
if len(csvRows) == 0 {
- return errors.New("empty csv file given")
+ return ErrEmptyCSVFile
}
if err := ensureOutCapacity(&outValue, len(csvRows)+1); err != nil { // Ensure the container is big enough to hold the CSV content
return err
}
outInnerStructInfo := getStructInfo(outInnerType) // Get the inner struct info to get CSV annotations
if len(outInnerStructInfo.Fields) == 0 {
- return errors.New("no csv struct tags found")
+ return ErrNoStructTags
}
for i, csvRow := range csvRows {
@@ -446,6 +454,31 @@ func setInnerField(outInner *reflect.Value, outInnerWasPointer bool, index []int
}
oi = outInner.Elem()
}
+
+ if oi.Kind() == reflect.Slice || oi.Kind() == reflect.Array {
+ i := index[0]
+
+ // grow slice when needed
+ if i >= oi.Cap() {
+ newcap := oi.Cap() + oi.Cap()/2
+ if newcap < 4 {
+ newcap = 4
+ }
+ newoi := reflect.MakeSlice(oi.Type(), oi.Len(), newcap)
+ reflect.Copy(newoi, oi)
+ oi.Set(newoi)
+ }
+ if i >= oi.Len() {
+ oi.SetLen(i + 1)
+ }
+
+ item := oi.Index(i)
+ if len(index) > 1 {
+ return setInnerField(&item, false, index[1:], value, omitEmpty)
+ }
+ return setField(item, value, omitEmpty)
+ }
+
// because pointers can be nil need to recurse one index at a time and perform nil check
if len(index) > 1 {
nextField := oi.Field(index[0])