github.com/blend/go-sdk@v1.20220411.3/reflectutil/decompose_strings.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package reflectutil
     9  
    10  import (
    11  	"encoding/base64"
    12  	"fmt"
    13  	"reflect"
    14  	"strings"
    15  )
    16  
    17  // DecomposeStrings decomposes an object into a string map.
    18  func DecomposeStrings(obj interface{}, tagName ...string) map[string]string {
    19  	output := map[string]string{}
    20  
    21  	objMeta := reflectType(obj)
    22  	objValue := reflectValue(obj)
    23  
    24  	var field reflect.StructField
    25  	var fieldValue reflect.Value
    26  	var tag, tagValue string
    27  	var dataField string
    28  	var pieces []string
    29  	var isCSV bool
    30  	var isBytes bool
    31  	var isBase64 bool
    32  
    33  	if len(tagName) > 0 {
    34  		tag = tagName[0]
    35  	}
    36  
    37  	for x := 0; x < objMeta.NumField(); x++ {
    38  		isCSV = false
    39  		isBytes = false
    40  		isBase64 = false
    41  
    42  		field = objMeta.Field(x)
    43  		if !IsExported(field.Name) {
    44  			continue
    45  		}
    46  
    47  		fieldValue = objValue.FieldByName(field.Name)
    48  		dataField = field.Name
    49  
    50  		if field.Type.Kind() == reflect.Struct {
    51  			childFields := DecomposeStrings(fieldValue.Interface(), tagName...)
    52  			for key, value := range childFields {
    53  				output[key] = value
    54  			}
    55  		}
    56  
    57  		if len(tag) > 0 {
    58  			tagValue = field.Tag.Get(tag)
    59  			if len(tagValue) > 0 {
    60  				if field.Type.Kind() == reflect.Map {
    61  					continue
    62  				} else {
    63  					pieces = strings.Split(tagValue, ",")
    64  					dataField = pieces[0]
    65  
    66  					if len(pieces) > 1 {
    67  						for y := 1; y < len(pieces); y++ {
    68  							if pieces[y] == FieldFlagCSV {
    69  								isCSV = true
    70  							} else if pieces[y] == FieldFlagBase64 {
    71  								isBase64 = true
    72  							} else if pieces[y] == FieldFlagBytes {
    73  								isBytes = true
    74  							}
    75  						}
    76  					}
    77  				}
    78  			}
    79  		}
    80  
    81  		if isCSV {
    82  			if typed, isTyped := fieldValue.Interface().([]string); isTyped {
    83  				output[dataField] = strings.Join(typed, ",")
    84  			}
    85  		} else if isBytes {
    86  			if typed, isTyped := fieldValue.Interface().([]byte); isTyped {
    87  				output[dataField] = string(typed)
    88  			}
    89  		} else if isBase64 {
    90  			if typed, isTyped := fieldValue.Interface().([]byte); isTyped {
    91  				output[dataField] = base64.StdEncoding.EncodeToString(typed)
    92  			}
    93  			if typed, isTyped := fieldValue.Interface().(string); isTyped {
    94  				output[dataField] = typed
    95  			}
    96  		} else {
    97  			output[dataField] = fmt.Sprintf("%v", FollowValue(fieldValue))
    98  		}
    99  	}
   100  
   101  	return output
   102  }