diff --git a/cache.go b/cache.go index 2063e1b79..408c42faf 100644 --- a/cache.go +++ b/cache.go @@ -76,11 +76,12 @@ type cStruct struct { } type cField struct { - idx int - name string - altName string - namesEqual bool - cTags *cTag + idx int + name string + altName string + namesEqual bool + cTags *cTag + structField reflect.StructField } type cTag struct { @@ -161,11 +162,12 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr } cs.fields = append(cs.fields, &cField{ - idx: i, - name: fld.Name, - altName: customName, - cTags: ctag, - namesEqual: fld.Name == customName, + idx: i, + name: fld.Name, + altName: customName, + cTags: ctag, + namesEqual: fld.Name == customName, + structField: fld, }) } v.structCache.Set(typ, cs) diff --git a/errors.go b/errors.go index be2676e9e..67034e013 100644 --- a/errors.go +++ b/errors.go @@ -146,6 +146,8 @@ type FieldError interface { // eg. time.Time's type is time.Time Type() reflect.Type + ReflectStructField() reflect.StructField + // Translate returns the FieldError's translated error // from the provided 'ut.Translator' and registered 'TranslationFunc' // @@ -176,6 +178,7 @@ type fieldError struct { param string kind reflect.Kind typ reflect.Type + structField reflect.StructField } // Tag returns the validation tag that failed. @@ -224,6 +227,12 @@ func (fe *fieldError) StructField() string { return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] } +// ReflectStructField get reflect struct field +func (fe *fieldError) ReflectStructField() reflect.StructField { + // return fe.structField + return fe.structField +} + // Value returns the actual field's value in case needed for creating the error // message func (fe *fieldError) Value() interface{} { diff --git a/validator.go b/validator.go index 901e7b50a..8476c0b08 100644 --- a/validator.go +++ b/validator.go @@ -136,6 +136,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr structfieldLen: uint8(len(cf.name)), param: ct.param, kind: kind, + structField: cf.structField, }, ) return @@ -161,6 +162,7 @@ func (v *validate) traverseField(ctx context.Context, parent reflect.Value, curr param: ct.param, kind: kind, typ: current.Type(), + structField: cf.structField, }, ) return @@ -415,6 +417,7 @@ OUTER: param: ct.param, kind: kind, typ: typ, + structField: cf.structField, }, ) @@ -435,6 +438,7 @@ OUTER: param: ct.param, kind: kind, typ: typ, + structField: cf.structField, }, ) } @@ -475,6 +479,7 @@ OUTER: param: ct.param, kind: kind, typ: typ, + structField: cf.structField, }, ) diff --git a/validator_test.go b/validator_test.go index 0f96b7775..9477808dc 100644 --- a/validator_test.go +++ b/validator_test.go @@ -13622,6 +13622,28 @@ func TestMultiOrOperatorGroup(t *testing.T) { } } +type testTag struct { + CreatedAt *time.Time `validate:"required" langKey:"test.created_at"` + String string `validate:"required" langKey:"test.string"` + Int int `validate:"required" langKey:"test.int"` + Uint uint `validate:"required" langKey:"test.uint"` + Float float64 `validate:"required" langKey:"test.float"` + Array []string `validate:"required" langKey:"test.array"` +} + +func TestReflectStructField(t *testing.T) { + validate := New() + var test testTag + err := validate.Struct(test) + NotEqual(t, err, nil) + + errs, ok := err.(ValidationErrors) + Equal(t, ok, true) + + fe := errs[0] + Equal(t, fe.ReflectStructField().Tag.Get("langKey"), "test.created_at") +} + func TestCronExpressionValidation(t *testing.T) { tests := []struct { value string `validate:"cron"`