mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-23 16:58:31 +02:00
updated deserialize method to support validation
This commit is contained in:
@@ -36,7 +36,7 @@ func NearestField(input string, s any) string {
|
||||
fields[i] = key.String()
|
||||
}
|
||||
default:
|
||||
panic("unsupported type: " + t.String())
|
||||
panic("NearestField unsupported type: " + t.String())
|
||||
}
|
||||
}
|
||||
for _, field := range fields {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/santhosh-tekuri/jsonschema"
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
@@ -33,6 +34,8 @@ var (
|
||||
ErrUnknownField = E.New("unknown field")
|
||||
)
|
||||
|
||||
var validate = validator.New()
|
||||
|
||||
func ValidateYaml(schema *jsonschema.Schema, data []byte) E.Error {
|
||||
var i any
|
||||
|
||||
@@ -143,7 +146,7 @@ func Serialize(data any) (SerializedObject, error) {
|
||||
// Deserialize ignores case differences between the field names in the SerializedObject and the target.
|
||||
//
|
||||
// The target value must be a struct or a map[string]any.
|
||||
// If the target value is a struct, the SerializedObject will be deserialized into the struct fields.
|
||||
// If the target value is a struct, the SerializedObject will be deserialized into the struct fields and validate if needed.
|
||||
// If the target value is a map[string]any, the SerializedObject will be deserialized into the map.
|
||||
//
|
||||
// The function returns an error if the target value is not a struct or a map[string]any, or if there is an error during deserialization.
|
||||
@@ -158,9 +161,13 @@ func Deserialize(src SerializedObject, dst any) E.Error {
|
||||
dstV := reflect.ValueOf(dst)
|
||||
dstT := dstV.Type()
|
||||
|
||||
if dstV.Kind() == reflect.Ptr {
|
||||
for dstT.Kind() == reflect.Ptr {
|
||||
if dstV.IsNil() {
|
||||
return E.Errorf("deserialize: dst is %w", ErrNilValue)
|
||||
if dstV.CanSet() {
|
||||
dstV.Set(reflect.New(dstT.Elem()))
|
||||
} else {
|
||||
return E.Errorf("deserialize: dst is %w", ErrNilValue)
|
||||
}
|
||||
}
|
||||
dstV = dstV.Elem()
|
||||
dstT = dstV.Type()
|
||||
@@ -174,9 +181,20 @@ func Deserialize(src SerializedObject, dst any) E.Error {
|
||||
|
||||
switch dstV.Kind() {
|
||||
case reflect.Struct:
|
||||
needValidate := false
|
||||
mapping := make(map[string]reflect.Value)
|
||||
for _, field := range reflect.VisibleFields(dstT) {
|
||||
mapping[strutils.ToLowerNoSnake(field.Name)] = dstV.FieldByName(field.Name)
|
||||
var key string
|
||||
if jsonTag, ok := field.Tag.Lookup("json"); ok {
|
||||
key = strings.Split(jsonTag, ",")[0]
|
||||
} else {
|
||||
key = field.Name
|
||||
}
|
||||
mapping[strutils.ToLowerNoSnake(key)] = dstV.FieldByName(field.Name)
|
||||
_, ok := field.Tag.Lookup("validate")
|
||||
if ok {
|
||||
needValidate = true
|
||||
}
|
||||
}
|
||||
for k, v := range src {
|
||||
if field, ok := mapping[strutils.ToLowerNoSnake(k)]; ok {
|
||||
@@ -185,9 +203,12 @@ func Deserialize(src SerializedObject, dst any) E.Error {
|
||||
errs.Add(err.Subject(k))
|
||||
}
|
||||
} else {
|
||||
errs.Add(ErrUnknownField.Subject(k).Withf(strutils.DoYouMean(NearestField(k, dst))))
|
||||
errs.Add(ErrUnknownField.Subject(k).Withf(strutils.DoYouMean(NearestField(k, dstV.Interface()))))
|
||||
}
|
||||
}
|
||||
if needValidate {
|
||||
errs.Add(validate.Struct(dstV.Interface()))
|
||||
}
|
||||
return errs.Error()
|
||||
case reflect.Map:
|
||||
if dstV.IsNil() {
|
||||
|
||||
@@ -44,6 +44,15 @@ func ExpectError2(t *testing.T, input any, expected error, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func ExpectErrorT[T error](t *testing.T, err error) {
|
||||
t.Helper()
|
||||
var errAs T
|
||||
if !errors.As(err, &errAs) {
|
||||
t.Errorf("expected err %T, got %v", errAs, err)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func ExpectEqual[T comparable](t *testing.T, got T, want T) {
|
||||
t.Helper()
|
||||
if got != want {
|
||||
@@ -98,10 +107,9 @@ func ExpectFalse(t *testing.T, got bool) {
|
||||
|
||||
func ExpectType[T any](t *testing.T, got any) (_ T) {
|
||||
t.Helper()
|
||||
tExpect := reflect.TypeFor[T]()
|
||||
_, ok := got.(T)
|
||||
if !ok {
|
||||
t.Fatalf("expected type %s, got %s", tExpect, reflect.TypeOf(got).Elem())
|
||||
t.Fatalf("expected type %s, got %s", reflect.TypeFor[T](), reflect.TypeOf(got).Elem())
|
||||
return
|
||||
}
|
||||
return got.(T)
|
||||
|
||||
Reference in New Issue
Block a user