package convert import ( "bytes" "encoding/json" "errors" "fmt" "strconv" "strings" "time" "unicode" ) func Singular(value interface{}) interface{} { if slice, ok := value.([]string); ok { if len(slice) == 0 { return nil } return slice[0] } if slice, ok := value.([]interface{}); ok { if len(slice) == 0 { return nil } return slice[0] } return value } func ToStringNoTrim(value interface{}) string { if t, ok := value.(time.Time); ok { return t.Format(time.RFC3339) } single := Singular(value) if single == nil { return "" } return fmt.Sprint(single) } func ToString(value interface{}) string { return strings.TrimSpace(ToStringNoTrim(value)) } func ToTimestamp(value interface{}) (int64, error) { str := ToString(value) if str == "" { return 0, errors.New("invalid date") } t, err := time.Parse(time.RFC3339, str) if err != nil { return 0, err } return t.UnixNano() / 1000000, nil } func ToBool(value interface{}) bool { value = Singular(value) b, ok := value.(bool) if ok { return b } str := strings.ToLower(ToString(value)) return str == "true" || str == "t" || str == "yes" || str == "y" } func ToNumber(value interface{}) (int64, error) { value = Singular(value) i, ok := value.(int64) if ok { return i, nil } f, ok := value.(float64) if ok { return int64(f), nil } if n, ok := value.(json.Number); ok { i, err := n.Int64() if err == nil { return i, nil } f, err := n.Float64() return int64(f), err } return strconv.ParseInt(ToString(value), 10, 64) } func ToFloat(value interface{}) (float64, error) { value = Singular(value) f64, ok := value.(float64) if ok { return f64, nil } f32, ok := value.(float32) if ok { return float64(f32), nil } if n, ok := value.(json.Number); ok { i, err := n.Int64() if err == nil { return float64(i), nil } f, err := n.Float64() return float64(f), err } return strconv.ParseFloat(ToString(value), 64) } func Capitalize(s string) string { if len(s) <= 1 { return strings.ToUpper(s) } return strings.ToUpper(s[:1]) + s[1:] } func Uncapitalize(s string) string { if len(s) <= 1 { return strings.ToLower(s) } return strings.ToLower(s[:1]) + s[1:] } func LowerTitle(input string) string { runes := []rune(input) for i := 0; i < len(runes); i++ { if unicode.IsUpper(runes[i]) && (i == 0 || i == len(runes)-1 || unicode.IsUpper(runes[i+1])) { runes[i] = unicode.ToLower(runes[i]) } else { break } } return string(runes) } func IsEmptyValue(v interface{}) bool { if v == nil || v == "" || v == 0 || v == false { return true } if m, ok := v.(map[string]interface{}); ok { return len(m) == 0 } if s, ok := v.([]interface{}); ok { return len(s) == 0 } return false } func ToMapInterface(obj interface{}) map[string]interface{} { v, _ := obj.(map[string]interface{}) return v } func ToInterfaceSlice(obj interface{}) []interface{} { if v, ok := obj.([]interface{}); ok { return v } return nil } func ToMapSlice(obj interface{}) []map[string]interface{} { if v, ok := obj.([]map[string]interface{}); ok { return v } vs, _ := obj.([]interface{}) var result []map[string]interface{} for _, item := range vs { if v, ok := item.(map[string]interface{}); ok { result = append(result, v) } else { return nil } } return result } func ToStringSlice(data interface{}) []string { if v, ok := data.([]string); ok { return v } if v, ok := data.([]interface{}); ok { var result []string for _, item := range v { result = append(result, ToString(item)) } return result } return nil } func ToObj(data interface{}, into interface{}) error { bytes, err := json.Marshal(data) if err != nil { return err } return json.Unmarshal(bytes, into) } func EncodeToMap(obj interface{}) (map[string]interface{}, error) { if m, ok := obj.(map[string]interface{}); ok { return m, nil } b, err := json.Marshal(obj) if err != nil { return nil, err } result := map[string]interface{}{} dec := json.NewDecoder(bytes.NewBuffer(b)) dec.UseNumber() return result, dec.Decode(&result) } func ToJSONKey(str string) string { parts := strings.Split(str, "_") for i := 1; i < len(parts); i++ { parts[i] = strings.Title(parts[i]) } return strings.Join(parts, "") } func ToYAMLKey(str string) string { var result []rune cap := false for i, r := range []rune(str) { if i == 0 { if unicode.IsUpper(r) { cap = true } result = append(result, unicode.ToLower(r)) continue } if unicode.IsUpper(r) { if cap { result = append(result, unicode.ToLower(r)) } else { result = append(result, '_', unicode.ToLower(r)) } } else { cap = false result = append(result, r) } } return string(result) }