initial commit
This commit is contained in:
79
pkg/helper/struct.go
Normal file
79
pkg/helper/struct.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func MapToStruct(source map[string]interface{}, target interface{}) error {
|
||||
jsonBytes, err := json.Marshal(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(jsonBytes, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StructToMap converts a struct to a map[string]interface{}
|
||||
// Uses json tag name as key when available, so keys match validation schema (e.g. "provider" not "Provider")
|
||||
// does not support nested structs
|
||||
func StructToMap(v any) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
val := reflect.ValueOf(v)
|
||||
typ := reflect.TypeOf(v)
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
typ = typ.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
value := val.Field(i)
|
||||
|
||||
// Skip unexported fields
|
||||
if !value.CanInterface() {
|
||||
continue
|
||||
}
|
||||
|
||||
key := field.Name
|
||||
if tag := field.Tag.Get("json"); tag != "" {
|
||||
// Use first part before comma (e.g. "provider,omitempty" -> "provider")
|
||||
if name := strings.TrimSpace(strings.Split(tag, ",")[0]); name != "" && name != "-" {
|
||||
key = name
|
||||
}
|
||||
}
|
||||
fieldVal := value.Interface()
|
||||
// If type implements String(), use it so validation gets string (e.g. oauth.Provider -> "mock")
|
||||
// Use reflect to detect nil pointer - s != nil passes for interface holding (*T)(nil)
|
||||
if s, ok := fieldVal.(fmt.Stringer); ok {
|
||||
if isNilValue(value) {
|
||||
result[key] = fieldVal // keep nil/zero for optional fields
|
||||
} else {
|
||||
result[key] = s.String()
|
||||
}
|
||||
} else {
|
||||
result[key] = fieldVal
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// isNilValue returns true if v is nil (ptr, slice, map, chan, func, interface).
|
||||
// Used to avoid calling String() on nil receivers (e.g. *uuid.UUID).
|
||||
func isNilValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Interface:
|
||||
return v.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user