@@ -5,11 +5,12 @@ import (
5
5
"html/template"
6
6
"io"
7
7
"reflect"
8
+ "sort"
8
9
"strings"
9
10
)
10
11
11
12
type Table struct {
12
- Dataset [] interface {}
13
+ Dataset interface {}
13
14
Columns []Column
14
15
Attr Attributes
15
16
HeaderAttr Attributes
@@ -24,7 +25,7 @@ func NewTable() Table {
24
25
}
25
26
}
26
27
27
- func (t Table ) WithDataset (dataset [] interface {}) Table {
28
+ func (t Table ) WithDataset (dataset interface {}) Table {
28
29
t .Dataset = dataset
29
30
return t
30
31
}
@@ -35,31 +36,58 @@ func (t Table) WithColumns(columns []Column) Table {
35
36
}
36
37
37
38
func (t Table ) Render (writer io.Writer ) error {
38
- if len (t .Dataset ) == 0 {
39
+ dataset := reflect .ValueOf (t .Dataset )
40
+ if dataset .Kind () != reflect .Slice {
41
+ return fmt .Errorf ("%v is not a slice" , dataset .Type ())
42
+ }
43
+
44
+ if dataset .Len () == 0 {
39
45
return fmt .Errorf ("empty data" )
40
46
}
41
47
42
- typ := reflect .TypeOf (t .Dataset [0 ])
43
- if typ .Kind () != reflect .Struct {
48
+ mapItem := false
49
+ typ := dataset .Index (0 ).Type ()
50
+ switch typ .Kind () {
51
+ case reflect .Map :
52
+ mapItem = true
53
+ case reflect .Struct :
54
+ // do nothing
55
+ default :
56
+ return fmt .Errorf ("unsupported slice item type: %v" , typ )
57
+ }
58
+ if typ .Kind () != reflect .Struct && typ .Kind () != reflect .Map {
44
59
return fmt .Errorf ("%v is not a struct" , typ )
45
60
}
46
61
47
- for i , v := range t .Dataset {
48
- t := reflect .TypeOf (v )
49
- if t != typ {
62
+ for i := 0 ; i < dataset .Len (); i ++ {
63
+ if t := dataset .Index (i ).Type (); t != typ {
50
64
return fmt .Errorf ("item %v is %v, not %v" , i , t , typ )
51
65
}
52
66
}
53
67
54
68
columns := t .Columns
55
69
if len (columns ) == 0 {
56
- numField := typ .NumField ()
57
- for i := 0 ; i < numField ; i ++ {
58
- field := typ .Field (i )
59
- columns = append (columns , Column {
60
- Name : field .Name ,
61
- Template : fmt .Sprintf ("{{.%s}}" , field .Name ),
62
- })
70
+ if mapItem {
71
+ var keys []string
72
+ for _ , v := range dataset .Index (0 ).MapKeys () {
73
+ keys = append (keys , fmt .Sprint (v .Interface ()))
74
+ }
75
+ sort .Strings (keys )
76
+ for _ , key := range keys {
77
+ columns = append (columns , Column {
78
+ Name : key ,
79
+ Template : fmt .Sprintf ("{{.%s}}" , key ),
80
+ })
81
+ }
82
+ } else {
83
+ numField := typ .NumField ()
84
+ for i := 0 ; i < numField ; i ++ {
85
+ field := typ .Field (i )
86
+ columns = append (columns , Column {
87
+ Name : field .Name ,
88
+ Template : fmt .Sprintf ("{{.%s}}" , field .Name ),
89
+ })
90
+ }
63
91
}
64
92
}
65
93
var rowTemplate * template.Template
@@ -88,8 +116,8 @@ func (t Table) Render(writer io.Writer) error {
88
116
}
89
117
render .Println ("</tr>" )
90
118
91
- for _ , row := range t . Dataset {
92
- if err := rowTemplate .Execute (render , row ); err != nil {
119
+ for i := 0 ; i < dataset . Len (); i ++ {
120
+ if err := rowTemplate .Execute (render , dataset . Index ( i ) ); err != nil {
93
121
return fmt .Errorf ("Execute: %w" , err )
94
122
}
95
123
render .Println ()
@@ -107,12 +135,12 @@ type Column struct {
107
135
108
136
var (
109
137
DefaultTableAttr = Attributes {
110
- {Name : "style" , Value : "font-family: verdana,arial,sans-serif;font-size:14px;color:#333333; border-width: 1px;border-color: #666666; border-collapse: collapse;" },
138
+ {Name : "style" , Value : "border: 1px black solid; padding:3px 3px 3px 3px; border-collapse:collapse;" },
111
139
}
112
140
DefaultTableHeaderAttr = Attributes {
113
- {Name : "style" , Value : "border-width: 1px; padding: 8px;border-style: solid; border-color: #666666; background-color: #dedede;" },
141
+ {Name : "style" , Value : "border: 1px black solid; padding:3px 3px 3px 3px; border-collapse:collapse; background-color:#dedede;" },
114
142
}
115
143
DefaultTableDataAttr = Attributes {
116
- {Name : "style" , Value : "border-width: 1px; padding: 8px;border-style: solid; border-color: #666666;background-color: #ffffff " },
144
+ {Name : "style" , Value : "border: 1px black solid; padding:3px 3px 3px 3px; border-collapse:collapse; " },
117
145
}
118
146
)
0 commit comments