forked from gocarina/gocsv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
marshaller.go
93 lines (78 loc) · 2.26 KB
/
marshaller.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package commando
import (
"encoding/csv"
"fmt"
"reflect"
)
// Marshaller is a CSV to struct marshaller.
type Marshaller struct {
config *validConfig
writer *csv.Writer
}
// NewMarshaller is a convenience function which allocates and
// returns a new Marshaller.
func NewMarshaller(holder interface{}, writer *csv.Writer) (*Marshaller, error) {
return (&Config{Holder: holder}).NewMarshaller(writer)
}
// NewMarshaller creates a marshaller from a csv.Writer. The CSV
// header will be immediately written to writer.
func (c *Config) NewMarshaller(writer *csv.Writer) (*Marshaller, error) {
vc, err := c.validate(nil)
if err != nil {
return nil, err
}
m := &Marshaller{
writer: writer,
config: vc,
}
if err := m.writeHeaders(); err != nil {
return nil, err
}
return m, nil
}
func (m *Marshaller) writeHeaders() error {
return m.writer.Write(m.config.structInfo.headers())
}
func (m *Marshaller) Write(record interface{}) error {
if reflect.TypeOf(record) != m.config.outType {
return fmt.Errorf("Expected %q, but got %q", m.config.outType, reflect.TypeOf(record))
}
inValue, inType := getConcreteReflectValueAndType(record) // Get the concrete type
inInnerWasPointer := inType.Kind() == reflect.Ptr
csvHeadersLabels := make([]string, len(m.config.structInfo.Fields))
for i, fieldInfo := range m.config.structInfo.Fields {
inInnerFieldValue, err := getInnerField(inValue, inInnerWasPointer, fieldInfo.IndexChain) // Get the correct field header <-> position
if err != nil {
return err
}
csvHeadersLabels[i] = inInnerFieldValue
}
return m.writer.Write(csvHeadersLabels)
}
// WriteAll writes every element of values as CSV.
//
// values must be a slice of elements of the configured Holder for
// this Marshaller.
//
// Flush() must be called when writing is complete.
func (m *Marshaller) WriteAll(values interface{}) error {
v := reflect.ValueOf(values)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Type() != reflect.SliceOf(m.config.outType) {
return fmt.Errorf("Expected []%T, but got %T", m.config.outType, values)
}
n := v.Len()
for i := 0; i < n; i++ {
sv := v.Index(i).Interface()
if err := m.Write(sv); err != nil {
return err
}
}
return nil
}
func (m *Marshaller) Flush() error {
m.writer.Flush()
return m.writer.Error()
}