Files
opencatd-open/internal/utils/map_tools.go
2025-04-16 18:01:27 +08:00

140 lines
3.5 KiB
Go

package utils
import (
"fmt"
"reflect"
"strings"
)
func MergeJSONObjects(dst, src map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for k, v := range dst {
result[k] = v
}
for key, value2 := range src {
value1, exists := result[key]
if exists {
map1Val, map1IsMap := value1.(map[string]interface{})
map2Val, map2IsMap := value2.(map[string]interface{})
if map1IsMap && map2IsMap {
result[key] = MergeJSONObjects(map1Val, map2Val)
} else {
// 覆盖第一个map中的值
result[key] = value2
}
} else {
// 添加新的键值对
result[key] = value2
}
}
return result
}
func StructToMap(in interface{}) (map[string]interface{}, error) {
out := make(map[string]interface{})
v := reflect.ValueOf(in)
// If it's a pointer, dereference it
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// Check if it's a struct
if v.Kind() != reflect.Struct {
return nil, fmt.Errorf("StructToMap only accepts structs or pointers to structs; got %T", v.Interface())
}
t := v.Type() // Get the type of the struct
for i := 0; i < v.NumField(); i++ {
// Get the field Value and Type
fieldV := v.Field(i)
fieldT := t.Field(i)
// Skip unexported fields
if !fieldT.IsExported() {
continue
}
// --- Handle JSON Tag ---
tag := fieldT.Tag.Get("json")
key := fieldT.Name // Default key is the field name
omitempty := false
if tag != "" {
parts := strings.Split(tag, ",")
tagName := parts[0]
if tagName == "-" {
// Skip fields tagged with "-"
continue
}
if tagName != "" {
key = tagName // Use tag name as key
}
// Check for omitempty option
for _, part := range parts[1:] {
if part == "omitempty" {
omitempty = true
break
}
}
}
// --- Handle omitempty ---
val := fieldV.Interface()
if omitempty && fieldV.IsZero() {
continue // Skip zero-value fields if omitempty is set
}
// --- Handle Nested Structs/Pointers to Structs (Recursion) ---
// Check for pointer first
if fieldV.Kind() == reflect.Ptr {
// If pointer is nil and omitempty is set, it was already skipped
// If pointer is nil and omitempty is not set, add nil to map
if fieldV.IsNil() {
// Only add nil if omitempty is not set (already handled above)
if !omitempty {
out[key] = nil
}
continue // Move to next field
}
// If it points to a struct, dereference and recurse
if fieldV.Elem().Kind() == reflect.Struct {
nestedMap, err := StructToMap(fieldV.Interface()) // Pass the pointer
if err != nil {
// Decide how to handle nested errors, e.g., log or return
fmt.Printf("Warning: could not convert nested struct pointer %s: %v\n", fieldT.Name, err)
out[key] = val // Store original value on error? Or skip?
} else {
out[key] = nestedMap
}
continue // Move to next field after handling pointer
}
// If pointer to non-struct, just get the interface value (handled below)
val = fieldV.Interface() // Use the actual pointer value
} else if fieldV.Kind() == reflect.Struct {
// If it's a struct (not a pointer), recurse
nestedMap, err := StructToMap(fieldV.Interface()) // Pass the struct value
if err != nil {
fmt.Printf("Warning: could not convert nested struct %s: %v\n", fieldT.Name, err)
out[key] = val // Store original value on error? Or skip?
} else {
out[key] = nestedMap
}
continue // Move to next field after handling struct
}
// Assign the value (primitive, slice, map, non-struct pointer, etc.)
out[key] = val
}
return out, nil
}