优化结构
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
// Package protoutil contains protobuf helpers that are independent of any
|
||||
// application module.
|
||||
package protoutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// MergeProtoJSON applies a JSON object as a partial protobuf update while
|
||||
// retaining fields omitted by the caller.
|
||||
func MergeProtoJSON(target proto.Message, patch json.RawMessage, options protojson.UnmarshalOptions) error {
|
||||
currentRaw, err := protojson.MarshalOptions{UseProtoNames: false}.Marshal(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var current map[string]any
|
||||
if err = json.Unmarshal(currentRaw, ¤t); err != nil {
|
||||
return err
|
||||
}
|
||||
var incoming map[string]any
|
||||
if err = json.Unmarshal(patch, &incoming); err != nil {
|
||||
return err
|
||||
}
|
||||
incoming = normalizeJSONKeys(incoming).(map[string]any)
|
||||
mergeJSONObjects(current, incoming)
|
||||
merged, err := json.Marshal(current)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return options.Unmarshal(merged, target)
|
||||
}
|
||||
|
||||
func normalizeJSONKeys(value any) any {
|
||||
switch item := value.(type) {
|
||||
case map[string]any:
|
||||
result := make(map[string]any, len(item))
|
||||
for key, nested := range item {
|
||||
result[snakeToLowerCamel(key)] = normalizeJSONKeys(nested)
|
||||
}
|
||||
return result
|
||||
case []any:
|
||||
result := make([]any, len(item))
|
||||
for index, nested := range item {
|
||||
result[index] = normalizeJSONKeys(nested)
|
||||
}
|
||||
return result
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
func snakeToLowerCamel(value string) string {
|
||||
if !strings.Contains(value, "_") {
|
||||
return value
|
||||
}
|
||||
parts := strings.Split(value, "_")
|
||||
result := parts[0]
|
||||
for _, part := range parts[1:] {
|
||||
if part != "" {
|
||||
result += strings.ToUpper(part[:1]) + part[1:]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeJSONObjects(target, patch map[string]any) {
|
||||
for key, value := range patch {
|
||||
if incoming, ok := value.(map[string]any); ok {
|
||||
if existing, exists := target[key].(map[string]any); exists {
|
||||
mergeJSONObjects(existing, incoming)
|
||||
continue
|
||||
}
|
||||
}
|
||||
target[key] = value
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user