@@ -24,6 +24,14 @@ type AnalyzeOpts struct {
24
24
OutStream io.Writer
25
25
}
26
26
27
+ // Defined to wrap string styling.
28
+ var (
29
+ colorTable = gchalk .Yellow
30
+ colorFileType = gchalk .Red
31
+ colorCaption = gchalk .Cyan
32
+ colorNotes = gchalk .Magenta
33
+ )
34
+
27
35
// NewAnalyzeOpts returns AnalyzeOpts.
28
36
func NewAnalyzeOpts () * AnalyzeOpts {
29
37
return & AnalyzeOpts {
@@ -37,6 +45,7 @@ func NewAnalyzeOpts() *AnalyzeOpts {
37
45
// Analyze analyzes the file and outputs the table information.
38
46
// In addition, SQL execution examples are output.
39
47
func Analyze (fileName string , opts * AnalyzeOpts , readOpts * ReadOpts ) error {
48
+ w := opts .OutStream
40
49
rOpts , fileName := GuessOpts (readOpts , fileName )
41
50
file , err := importFileOpen (fileName )
42
51
if err != nil {
@@ -61,76 +70,106 @@ func Analyze(fileName string, opts *AnalyzeOpts, readOpts *ReadOpts) error {
61
70
if err != nil {
62
71
return err
63
72
}
73
+ names := quoteNames (columnNames , opts .Quote )
74
+
64
75
columnTypes , err := reader .Types ()
65
76
if err != nil {
66
77
return err
67
78
}
68
- names := make ([]string , len (columnNames ))
69
- for i := range columnNames {
70
- names [i ] = quoted (columnNames [i ], opts .Quote )
71
- }
72
- results := make ([][]string , 0 )
73
- for _ , row := range reader .PreReadRow () {
74
- resultRow := make ([]string , len (names ))
75
- for j , col := range row {
76
- resultRow [j ] = ValString (col )
79
+
80
+ results := getResults (reader , len (names ))
81
+
82
+ if opts .Detail {
83
+ fmt .Fprintf (w , "The table name is %s.\n " , colorTable (tableName ))
84
+ fmt .Fprintf (w , "The file type is %s.\n " , colorFileType (rOpts .realFormat .String ()))
85
+ if len (names ) <= 1 && len (results ) != 0 {
86
+ additionalAdvice (w , rOpts , columnNames [0 ], results [0 ][0 ])
77
87
}
78
- results = append (results , resultRow )
88
+
89
+ fmt .Fprintln (w , colorCaption ("\n Data types:" ))
90
+ typeTableRender (w , names , columnTypes )
91
+
92
+ fmt .Fprintln (w , colorCaption ("\n Data samples:" ))
93
+ sampleTableRender (w , names , results )
94
+
95
+ fmt .Fprintln (w , colorCaption ("\n Examples:" ))
96
+ }
97
+
98
+ if len (results ) == 0 {
99
+ return nil
79
100
}
80
- typeTable := tablewriter .NewWriter (opts .OutStream )
101
+ queries := examples (tableName , names , results [0 ])
102
+ for _ , query := range queries {
103
+ fmt .Fprintf (w , "%s %s\n " , opts .Command , `"` + query + `"` )
104
+ }
105
+ return nil
106
+ }
107
+
108
+ func typeTableRender (w io.Writer , names []string , columnTypes []string ) {
109
+ typeTable := tablewriter .NewWriter (w )
81
110
typeTable .SetAutoFormatHeaders (false )
82
111
typeTable .SetHeader ([]string {"column name" , "type" })
83
- for i := range columnNames {
112
+ for i := range names {
84
113
typeTable .Append ([]string {names [i ], columnTypes [i ]})
85
114
}
86
- sampleTable := tablewriter .NewWriter (opts .OutStream )
115
+ typeTable .Render ()
116
+ }
117
+
118
+ func sampleTableRender (w io.Writer , names []string , results [][]string ) {
119
+ sampleTable := tablewriter .NewWriter (w )
87
120
sampleTable .SetAutoFormatHeaders (false )
88
121
sampleTable .SetHeader (names )
89
122
for _ , row := range results {
90
123
sampleTable .Append (row )
91
124
}
125
+ sampleTable .Render ()
126
+ }
92
127
93
- yellow := gchalk .Yellow
94
- red := gchalk .Red
95
- magenta := gchalk .Magenta
96
- cyan := gchalk .Cyan
97
- if opts .Detail {
98
- fmt .Fprintf (opts .OutStream , "The table name is %s.\n " , yellow (tableName ))
99
- fmt .Fprintf (opts .OutStream , "The file type is %s.\n " , red (rOpts .realFormat .String ()))
100
- if len (names ) <= 1 && rOpts .realFormat == CSV {
101
- fmt .Fprintln (opts .OutStream , magenta ("Is the delimiter different?" ))
102
- fmt .Fprintln (opts .OutStream , magenta (`Please try again with -id "\t" or -id " ".` ))
103
- }
104
- fmt .Fprintln (opts .OutStream , cyan ("\n Data types:" ))
105
- typeTable .Render ()
106
- fmt .Fprintln (opts .OutStream , cyan ("\n Data samples:" ))
107
- sampleTable .Render ()
108
- fmt .Fprintln (opts .OutStream , cyan ("\n Examples:" ))
128
+ func additionalAdvice (w io.Writer , rOpts * ReadOpts , name string , value string ) {
129
+ switch rOpts .realFormat {
130
+ case CSV :
131
+ checkCSV (w , value )
132
+ case JSON :
133
+ checkJSON (w , rOpts .InJQuery , name )
109
134
}
135
+ }
110
136
111
- if len (results ) == 0 {
112
- return nil
137
+ func checkCSV (w io.Writer , value string ) {
138
+ if value == "[" || value == "{" {
139
+ fmt .Fprintln (w , colorNotes ("Is it a JSON file?" ))
140
+ fmt .Fprintln (w , colorNotes ("Please try again with -ijson." ))
141
+ return
113
142
}
143
+ fmt .Fprintln (w , colorNotes ("Is the delimiter different?" ))
144
+ delimiter := " "
145
+ if strings .Count (value , ";" ) > 1 {
146
+ delimiter = ";"
147
+ }
148
+ if strings .Count (value , "\t " ) > 1 {
149
+ delimiter = "\\ t"
150
+ }
151
+ fmt .Fprintf (w , colorNotes ("Please try again with -id \" %s\" or other character.\n " ), delimiter )
152
+ if strings .Contains (value , ":" ) {
153
+ fmt .Fprintln (w , colorNotes ("Is it a LTSV file?" ))
154
+ fmt .Fprintln (w , colorNotes ("Please try again with -iltsv." ))
155
+ }
156
+ }
114
157
115
- queries := examples (tableName , names , results [0 ])
116
- for _ , query := range queries {
117
- fmt .Fprintf (opts .OutStream , "%s %s\n " , opts .Command , `"` + query + `"` )
158
+ func checkJSON (w io.Writer , jquery string , name string ) {
159
+ fmt .Fprintln (w , colorNotes ("Is it for internal objects?" ))
160
+ jq := "." + name
161
+ if jquery != "" {
162
+ jq = jquery + jq
118
163
}
119
- return nil
164
+ fmt . Fprintf ( w , colorNotes ( "Please try again with -ijq \" %s \" . \n " ), jq )
120
165
}
121
166
122
- func examples (tableName string , names []string , results []string ) []string {
123
- queries := []string {
124
- // #nosec G201
125
- fmt .Sprintf ("SELECT %s FROM %s" , strings .Join (names , ", " ), tableName ),
126
- // #nosec G201
127
- fmt .Sprintf ("SELECT %s FROM %s WHERE %s = '%s'" , strings .Join (names , ", " ), tableName , names [0 ], results [0 ]),
128
- // #nosec G201
129
- fmt .Sprintf ("SELECT %s, count(%s) FROM %s GROUP BY %s" , names [0 ], names [0 ], tableName , names [0 ]),
130
- // #nosec G201
131
- fmt .Sprintf ("SELECT %s FROM %s ORDER BY %s LIMIT 10" , strings .Join (names , ", " ), tableName , names [0 ]),
167
+ func quoteNames (names []string , quote string ) []string {
168
+ qnames := make ([]string , len (names ))
169
+ for i := range names {
170
+ qnames [i ] = quoted (names [i ], quote )
132
171
}
133
- return queries
172
+ return qnames
134
173
}
135
174
136
175
var noQuoteRegexp = regexp .MustCompile (`^[a-z0-9_]+$` )
@@ -144,3 +183,29 @@ func quoted(name string, quote string) string {
144
183
}
145
184
return quote + name + quote
146
185
}
186
+
187
+ func getResults (reader Reader , colNum int ) [][]string {
188
+ results := make ([][]string , 0 )
189
+ for _ , row := range reader .PreReadRow () {
190
+ resultRow := make ([]string , colNum )
191
+ for j , col := range row {
192
+ resultRow [j ] = ValString (col )
193
+ }
194
+ results = append (results , resultRow )
195
+ }
196
+ return results
197
+ }
198
+
199
+ func examples (tableName string , names []string , results []string ) []string {
200
+ queries := []string {
201
+ // #nosec G201
202
+ fmt .Sprintf ("SELECT %s FROM %s" , strings .Join (names , ", " ), tableName ),
203
+ // #nosec G201
204
+ fmt .Sprintf ("SELECT %s FROM %s WHERE %s = '%s'" , strings .Join (names , ", " ), tableName , names [0 ], results [0 ]),
205
+ // #nosec G201
206
+ fmt .Sprintf ("SELECT %s, count(%s) FROM %s GROUP BY %s" , names [0 ], names [0 ], tableName , names [0 ]),
207
+ // #nosec G201
208
+ fmt .Sprintf ("SELECT %s FROM %s ORDER BY %s LIMIT 10" , strings .Join (names , ", " ), tableName , names [0 ]),
209
+ }
210
+ return queries
211
+ }
0 commit comments