mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-19 20:32:35 +02:00
updated deserialize method to support validation
This commit is contained in:
parent
4188bbc5bd
commit
edc1ad952d
5 changed files with 52 additions and 8 deletions
5
go.mod
5
go.mod
|
@ -31,13 +31,18 @@ require (
|
|||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.23.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/miekg/dns v1.1.62 // indirect
|
||||
|
|
10
go.sum
10
go.sum
|
@ -33,6 +33,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
|||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/go-acme/lego/v4 v4.20.4 h1:yCQGBX9jOfMbriEQUocdYm7EBapdTp8nLXYG8k6SqSU=
|
||||
github.com/go-acme/lego/v4 v4.20.4/go.mod h1:foauPlhnhoq8WUphaWx5U04uDc+JGhk4ZZtPz/Vqsjg=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
||||
|
@ -42,6 +44,12 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
|||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
|
||||
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
@ -72,6 +80,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue