332 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Go
		
	
	
package util
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"log"
 | 
						|
	"net/url"
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// change instance=["a", "b"]
 | 
						|
// to instance.1="a" instance.2="b"
 | 
						|
func FlattenFn(fieldName string, field reflect.Value, values *url.Values) {
 | 
						|
	l := field.Len()
 | 
						|
	if l > 0 {
 | 
						|
		for i := 0; i < l; i++ {
 | 
						|
			str := field.Index(i).String()
 | 
						|
			values.Set(fieldName+"."+strconv.Itoa(i+1), str)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func Underline2Dot(name string) string {
 | 
						|
	return strings.Replace(name, "_", ".", -1)
 | 
						|
}
 | 
						|
 | 
						|
//ConvertToQueryValues converts the struct to url.Values
 | 
						|
func ConvertToQueryValues(ifc interface{}) url.Values {
 | 
						|
	values := url.Values{}
 | 
						|
	SetQueryValues(ifc, &values)
 | 
						|
	return values
 | 
						|
}
 | 
						|
 | 
						|
//SetQueryValues sets the struct to existing url.Values following ECS encoding rules
 | 
						|
func SetQueryValues(ifc interface{}, values *url.Values) {
 | 
						|
	setQueryValues(ifc, values, "")
 | 
						|
}
 | 
						|
 | 
						|
func SetQueryValueByFlattenMethod(ifc interface{}, values *url.Values) {
 | 
						|
	setQueryValuesByFlattenMethod(ifc, values, "")
 | 
						|
}
 | 
						|
 | 
						|
func setQueryValues(i interface{}, values *url.Values, prefix string) {
 | 
						|
	// add to support url.Values
 | 
						|
	mapValues, ok := i.(url.Values)
 | 
						|
	if ok {
 | 
						|
		for k, _ := range mapValues {
 | 
						|
			values.Set(k, mapValues.Get(k))
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	elem := reflect.ValueOf(i)
 | 
						|
	if elem.Kind() == reflect.Ptr {
 | 
						|
		elem = elem.Elem()
 | 
						|
	}
 | 
						|
	elemType := elem.Type()
 | 
						|
	for i := 0; i < elem.NumField(); i++ {
 | 
						|
 | 
						|
		fieldName := elemType.Field(i).Name
 | 
						|
		anonymous := elemType.Field(i).Anonymous
 | 
						|
		tag := elemType.Field(i).Tag.Get("query")
 | 
						|
		argName := elemType.Field(i).Tag.Get("ArgName")
 | 
						|
		field := elem.Field(i)
 | 
						|
		// TODO Use Tag for validation
 | 
						|
		// tag := typ.Field(i).Tag.Get("tagname")
 | 
						|
		kind := field.Kind()
 | 
						|
		isPtr := false
 | 
						|
		if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if kind == reflect.Ptr {
 | 
						|
			field = field.Elem()
 | 
						|
			kind = field.Kind()
 | 
						|
			isPtr = true
 | 
						|
		}
 | 
						|
		var value string
 | 
						|
		//switch field.Interface().(type) {
 | 
						|
		switch kind {
 | 
						|
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
			i := field.Int()
 | 
						|
			if i != 0 || isPtr {
 | 
						|
				value = strconv.FormatInt(i, 10)
 | 
						|
			}
 | 
						|
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
						|
			i := field.Uint()
 | 
						|
			if i != 0 || isPtr {
 | 
						|
				value = strconv.FormatUint(i, 10)
 | 
						|
			}
 | 
						|
		case reflect.Float32:
 | 
						|
			value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
 | 
						|
		case reflect.Float64:
 | 
						|
			value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
 | 
						|
		case reflect.Bool:
 | 
						|
			value = strconv.FormatBool(field.Bool())
 | 
						|
		case reflect.String:
 | 
						|
			value = field.String()
 | 
						|
		case reflect.Map:
 | 
						|
			ifc := field.Interface()
 | 
						|
			m := ifc.(map[string]string)
 | 
						|
			if m != nil {
 | 
						|
				j := 0
 | 
						|
				for k, v := range m {
 | 
						|
					j++
 | 
						|
					keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
 | 
						|
					values.Set(keyName, k)
 | 
						|
					valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
 | 
						|
					values.Set(valueName, v)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		case reflect.Slice:
 | 
						|
			switch field.Type().Elem().Kind() {
 | 
						|
			case reflect.Uint8:
 | 
						|
				value = string(field.Bytes())
 | 
						|
			case reflect.String:
 | 
						|
				l := field.Len()
 | 
						|
				if l > 0 {
 | 
						|
					if tag == "list" {
 | 
						|
						name := argName
 | 
						|
						if argName == "" {
 | 
						|
							name = fieldName
 | 
						|
						}
 | 
						|
						for i := 0; i < l; i++ {
 | 
						|
							valueName := fmt.Sprintf("%s.%d", name, (i + 1))
 | 
						|
							values.Set(valueName, field.Index(i).String())
 | 
						|
						}
 | 
						|
					} else {
 | 
						|
						strArray := make([]string, l)
 | 
						|
						for i := 0; i < l; i++ {
 | 
						|
							strArray[i] = field.Index(i).String()
 | 
						|
						}
 | 
						|
						bytes, err := json.Marshal(strArray)
 | 
						|
						if err == nil {
 | 
						|
							value = string(bytes)
 | 
						|
						} else {
 | 
						|
							log.Printf("Failed to convert JSON: %v", err)
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			default:
 | 
						|
				l := field.Len()
 | 
						|
				for j := 0; j < l; j++ {
 | 
						|
					prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
 | 
						|
					ifc := field.Index(j).Interface()
 | 
						|
					//log.Printf("%s : %v", prefixName, ifc)
 | 
						|
					if ifc != nil {
 | 
						|
						setQueryValues(ifc, values, prefixName)
 | 
						|
					}
 | 
						|
				}
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
		default:
 | 
						|
			switch field.Interface().(type) {
 | 
						|
			case ISO6801Time:
 | 
						|
				t := field.Interface().(ISO6801Time)
 | 
						|
				value = t.String()
 | 
						|
			case time.Time:
 | 
						|
				t := field.Interface().(time.Time)
 | 
						|
				value = GetISO8601TimeStamp(t)
 | 
						|
			default:
 | 
						|
				ifc := field.Interface()
 | 
						|
				if ifc != nil {
 | 
						|
					if anonymous {
 | 
						|
						SetQueryValues(ifc, values)
 | 
						|
					} else {
 | 
						|
						prefixName := fieldName + "."
 | 
						|
						setQueryValues(ifc, values, prefixName)
 | 
						|
					}
 | 
						|
					continue
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if value != "" {
 | 
						|
			name := argName
 | 
						|
			if argName == "" {
 | 
						|
				name = fieldName
 | 
						|
			}
 | 
						|
			if prefix != "" {
 | 
						|
				name = prefix + name
 | 
						|
			}
 | 
						|
			values.Set(name, value)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func setQueryValuesByFlattenMethod(i interface{}, values *url.Values, prefix string) {
 | 
						|
	// add to support url.Values
 | 
						|
	mapValues, ok := i.(url.Values)
 | 
						|
	if ok {
 | 
						|
		for k, _ := range mapValues {
 | 
						|
			values.Set(k, mapValues.Get(k))
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	elem := reflect.ValueOf(i)
 | 
						|
	if elem.Kind() == reflect.Ptr {
 | 
						|
		elem = elem.Elem()
 | 
						|
	}
 | 
						|
	elemType := elem.Type()
 | 
						|
	for i := 0; i < elem.NumField(); i++ {
 | 
						|
 | 
						|
		fieldName := elemType.Field(i).Name
 | 
						|
		anonymous := elemType.Field(i).Anonymous
 | 
						|
		field := elem.Field(i)
 | 
						|
 | 
						|
		// TODO Use Tag for validation
 | 
						|
		// tag := typ.Field(i).Tag.Get("tagname")
 | 
						|
		kind := field.Kind()
 | 
						|
 | 
						|
		isPtr := false
 | 
						|
		if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if kind == reflect.Ptr {
 | 
						|
			field = field.Elem()
 | 
						|
			kind = field.Kind()
 | 
						|
			isPtr = true
 | 
						|
		}
 | 
						|
 | 
						|
		var value string
 | 
						|
		//switch field.Interface().(type) {
 | 
						|
		switch kind {
 | 
						|
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						|
			i := field.Int()
 | 
						|
			if i != 0 || isPtr {
 | 
						|
				value = strconv.FormatInt(i, 10)
 | 
						|
			}
 | 
						|
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
						|
			i := field.Uint()
 | 
						|
			if i != 0 || isPtr {
 | 
						|
				value = strconv.FormatUint(i, 10)
 | 
						|
			}
 | 
						|
		case reflect.Float32:
 | 
						|
			value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
 | 
						|
		case reflect.Float64:
 | 
						|
			value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
 | 
						|
		case reflect.Bool:
 | 
						|
			value = strconv.FormatBool(field.Bool())
 | 
						|
		case reflect.String:
 | 
						|
			value = field.String()
 | 
						|
		case reflect.Map:
 | 
						|
			ifc := field.Interface()
 | 
						|
			m := ifc.(map[string]string)
 | 
						|
			if m != nil {
 | 
						|
				j := 0
 | 
						|
				for k, v := range m {
 | 
						|
					j++
 | 
						|
					keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
 | 
						|
					values.Set(keyName, k)
 | 
						|
					valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
 | 
						|
					values.Set(valueName, v)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		case reflect.Slice:
 | 
						|
			if field.Type().Name() == "FlattenArray" {
 | 
						|
				FlattenFn(fieldName, field, values)
 | 
						|
			} else {
 | 
						|
				switch field.Type().Elem().Kind() {
 | 
						|
				case reflect.Uint8:
 | 
						|
					value = string(field.Bytes())
 | 
						|
				case reflect.String:
 | 
						|
					l := field.Len()
 | 
						|
					if l > 0 {
 | 
						|
						strArray := make([]string, l)
 | 
						|
						for i := 0; i < l; i++ {
 | 
						|
							strArray[i] = field.Index(i).String()
 | 
						|
						}
 | 
						|
						bytes, err := json.Marshal(strArray)
 | 
						|
						if err == nil {
 | 
						|
							value = string(bytes)
 | 
						|
						} else {
 | 
						|
							log.Printf("Failed to convert JSON: %v", err)
 | 
						|
						}
 | 
						|
					}
 | 
						|
				default:
 | 
						|
					l := field.Len()
 | 
						|
					for j := 0; j < l; j++ {
 | 
						|
						prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
 | 
						|
						ifc := field.Index(j).Interface()
 | 
						|
						//log.Printf("%s : %v", prefixName, ifc)
 | 
						|
						if ifc != nil {
 | 
						|
							setQueryValuesByFlattenMethod(ifc, values, prefixName)
 | 
						|
						}
 | 
						|
					}
 | 
						|
					continue
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
		default:
 | 
						|
			switch field.Interface().(type) {
 | 
						|
			case ISO6801Time:
 | 
						|
				t := field.Interface().(ISO6801Time)
 | 
						|
				value = t.String()
 | 
						|
			case time.Time:
 | 
						|
				t := field.Interface().(time.Time)
 | 
						|
				value = GetISO8601TimeStamp(t)
 | 
						|
			default:
 | 
						|
 | 
						|
				ifc := field.Interface()
 | 
						|
				if ifc != nil {
 | 
						|
					if anonymous {
 | 
						|
						SetQueryValues(ifc, values)
 | 
						|
					} else {
 | 
						|
						prefixName := fieldName + "."
 | 
						|
						setQueryValuesByFlattenMethod(ifc, values, prefixName)
 | 
						|
					}
 | 
						|
					continue
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if value != "" {
 | 
						|
			name := elemType.Field(i).Tag.Get("ArgName")
 | 
						|
			if name == "" {
 | 
						|
				name = fieldName
 | 
						|
			}
 | 
						|
			if prefix != "" {
 | 
						|
				name = prefix + name
 | 
						|
			}
 | 
						|
			// NOTE: here we will change name to underline style when the type is UnderlineString
 | 
						|
			if field.Type().Name() == "UnderlineString" {
 | 
						|
				name = Underline2Dot(name)
 | 
						|
			}
 | 
						|
			values.Set(name, value)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |