github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/types/map2table.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sort"
     7  )
     8  
     9  func MapToTable(v []interface{}, callback func([]string) error) error {
    10  	if len(v) == 0 {
    11  		return nil
    12  	}
    13  
    14  	if reflect.TypeOf(v[0]).Kind() != reflect.Map {
    15  		return fmt.Errorf("expecting map on row %d, instead got a %s", 0, reflect.TypeOf(v[0]).Kind().String())
    16  	}
    17  
    18  	headings, err := getMapKeys(v[0].(map[string]any))
    19  	if err != nil {
    20  		return err
    21  	}
    22  
    23  	//table := make([][]string, len(v)+1)
    24  	//table[0] = headings
    25  	err = callback(headings)
    26  	if err != nil {
    27  		return err
    28  	}
    29  
    30  	lenHeadings := len(headings)
    31  	slice := make([]string, lenHeadings)
    32  	var j int
    33  
    34  	for i := range v {
    35  		//if reflect.TypeOf(v[i]).Kind() != reflect.Map {
    36  		//	return nil, fmt.Errorf("expecting map on row %d, instead got a %s", i, reflect.TypeOf(v[i]).Kind().String())
    37  		//}
    38  
    39  		m, ok := v[i].(map[string]any)
    40  		if !ok {
    41  			return fmt.Errorf("expecting map on row %d, instead got a %s", i, reflect.TypeOf(v[i]).Kind().String())
    42  		}
    43  
    44  		if len(m) != len(headings) {
    45  			return fmt.Errorf("row %d has a different number of records to the first row:\nrow 0 == %d records,\nrow %d == %d records",
    46  				i, lenHeadings, i, len(v))
    47  		}
    48  
    49  		for j = 0; j < lenHeadings; j++ {
    50  			val, ok := v[i].(map[string]any)[headings[j]]
    51  			if !ok {
    52  				return fmt.Errorf("row %d is missing a record name found in the first row: '%s'", i, headings[j])
    53  			}
    54  			s, err := ConvertGoType(val, String)
    55  			if err != nil {
    56  				return fmt.Errorf("cannot convert a %T (%v) to a %s in record %d: %s", val, val, String, i, err.Error())
    57  			}
    58  			slice[j] = s.(string)
    59  		}
    60  
    61  		err = callback(slice)
    62  		if err != nil {
    63  			return err
    64  		}
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  func getMapKeys(v map[string]any) ([]string, error) {
    71  	slice := make([]string, len(v))
    72  	var i int
    73  
    74  	for k := range v {
    75  		s, err := ConvertGoType(k, String)
    76  		if err != nil {
    77  			return nil, fmt.Errorf("cannot convert a %T (%v) to a %s: %s", k, k, String, err.Error())
    78  		}
    79  		slice[i] = s.(string)
    80  		i++
    81  	}
    82  	sort.Strings(slice)
    83  	return slice, nil
    84  }