@@ -119,14 +119,13 @@ func toCSV(data interface{}) (string, error) {
119119// How much values does it add? Using CSV for a single object feels a bit odd
120120// -> honestly none imo - tested current implementation on get_commit and this does more harm than good
121121// as we lose insight on certain, deeply nested, fields
122- if v .Kind ()== reflect .Struct || v . Kind () == reflect . Map {
122+ if v .Kind ()== reflect .Struct {
123123slice := reflect .MakeSlice (reflect .SliceOf (v .Type ()),1 ,1 )
124124slice .Index (0 ).Set (v )
125125return sliceToCSV (slice )
126126}
127127
128- // Return any primitive as is
129- return fmt .Sprintf ("%v" ,data ),nil
128+ return "" ,fmt .Errorf ("unsupported data type: %v" ,v .Kind ())
130129}
131130
132131// unwrap dereferences pointers and interfaces until reaching a concrete value
@@ -154,7 +153,11 @@ func sliceToCSV(slice reflect.Value) (string, error) {
154153
155154// Get all possible headers from first element
156155firstElem := slice .Index (0 )
157- allHeaders := extractHeaders (firstElem )
156+ firstElem ,isNil := unwrap (firstElem )
157+ if isNil {
158+ return "" ,nil
159+ }
160+ allHeaders := extractStructHeaders (firstElem ,"" )
158161if len (allHeaders )== 0 {
159162return "" ,fmt .Errorf ("no fields found in data" )
160163}
@@ -220,22 +223,6 @@ func sliceToCSV(slice reflect.Value) (string, error) {
220223return buf .String (),nil
221224}
222225
223- // extractHeaders gets all field names from an object, flattening nested structures
224- func extractHeaders (v reflect.Value ) []string {
225- v ,isNil := unwrap (v )
226- if isNil {
227- return nil
228- }
229-
230- if v .Kind ()== reflect .Struct {
231- return extractStructHeaders (v ,"" )
232- }
233- if v .Kind ()== reflect .Map {
234- return extractMapKeys (v )
235- }
236- return nil
237- }
238-
239226// getFieldName extracts field name from struct field, preferring json tag
240227func getFieldName (field reflect.StructField )string {
241228if jsonTag := field .Tag .Get ("json" );jsonTag != "" && jsonTag != "-" {
@@ -272,13 +259,13 @@ func extractStructHeaders(v reflect.Value, prefix string) []string {
272259
273260kind := fieldValue .Kind ()
274261
275- // Skip complex types (arrays,maps , interfaces), only allow primitives and timestamps
262+ // Skip complex types (arrays,slices , interfaces), only allow primitives and timestamps
276263if kind == reflect .Struct {
277264typeName := fieldValue .Type ().Name ()
278265if typeName != "Timestamp" && typeName != "Time" {
279266continue
280267}
281- }else if kind == reflect .Slice || kind == reflect .Array || kind == reflect .Map || kind == reflect . Interface {
268+ }else if kind == reflect .Slice || kind == reflect .Array || kind == reflect .Interface {
282269continue
283270}
284271}
@@ -329,8 +316,7 @@ func hasPrimitiveFields(v reflect.Value) bool {
329316kind := field .Kind ()
330317
331318// Check for any primitive types
332- if kind == reflect .String || kind == reflect .Int || kind == reflect .Int64 ||
333- kind == reflect .Bool || kind == reflect .Float32 || kind == reflect .Float64 {
319+ if kind == reflect .String || kind == reflect .Int || kind == reflect .Int64 || kind == reflect .Bool {
334320return true
335321}
336322
@@ -346,20 +332,7 @@ func hasPrimitiveFields(v reflect.Value) bool {
346332return false
347333}
348334
349- // extractMapKeys gets keys from a map
350- func extractMapKeys (v reflect.Value ) []string {
351- var keys []string
352- iter := v .MapRange ()
353- for iter .Next () {
354- if key := iter .Key ();key .Kind ()== reflect .String {
355- keys = append (keys ,key .String ())
356- }
357- }
358-
359- return keys
360- }
361-
362- // extractValues gets field values from an object in the same order as headers
335+ // extractValues gets field values from a struct in the same order as headers
363336func extractValues (v reflect.Value ,headers []string ) []string {
364337v ,isNil := unwrap (v )
365338values := make ([]string ,len (headers ))
@@ -386,12 +359,9 @@ func extractFieldValue(v reflect.Value, path string) string {
386359return ""
387360}
388361
389- switch v .Kind () {
390- case reflect .Struct :
362+ if v .Kind ()== reflect .Struct {
391363v = getStructField (v ,part )
392- case reflect .Map :
393- v = v .MapIndex (reflect .ValueOf (part ))
394- default :
364+ }else {
395365return ""
396366}
397367}
@@ -438,21 +408,11 @@ func formatValue(v reflect.Value) string {
438408return strings .Join (strings .Fields (v .String ())," " )
439409
440410// Handle numeric and boolean types
441- case reflect .Int ,reflect .Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
411+ case reflect .Int ,reflect .Int64 :
442412if n := v .Int ();n != 0 {
443413return fmt .Sprintf ("%d" ,n )
444414}
445415
446- case reflect .Uint ,reflect .Uint8 ,reflect .Uint16 ,reflect .Uint32 ,reflect .Uint64 :
447- if n := v .Uint ();n != 0 {
448- return fmt .Sprintf ("%d" ,n )
449- }
450-
451- case reflect .Float32 ,reflect .Float64 :
452- if n := v .Float ();n != 0 {
453- return fmt .Sprintf ("%g" ,n )
454- }
455-
456416case reflect .Bool :
457417if v .Bool () {
458418return "true"