diff --git a/cache.go b/cache.go index d596bd5..94eb304 100644 --- a/cache.go +++ b/cache.go @@ -82,6 +82,16 @@ type cField struct { cTags *cTag } +// Name return field name +func (cf *cField) Name() string { + return cf.name +} + +// AltName return field altname +func (cf *cField) AltName() string { + return cf.altName +} + type cTag struct { tag string aliasTag string @@ -94,6 +104,11 @@ type cTag struct { next *cTag } +// Param return tag param +func (ct *cTag) Param() string { + return ct.param +} + func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct { v.structCache.lock.Lock() diff --git a/field_level.go b/field_level.go index 7c74151..c743c75 100644 --- a/field_level.go +++ b/field_level.go @@ -31,6 +31,10 @@ type FieldLevel interface { // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. GetStructFieldOK() (reflect.Value, reflect.Kind, bool) + // return cache field + CField() *cField + // return cache tag + CTag() *cTag } var _ FieldLevel = new(validate) @@ -49,3 +53,13 @@ func (v *validate) Param() string { func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { return v.getStructFieldOKInternal(v.slflParent, v.flParam) } + +// Param returns cache field +func (v *validate) CField() *cField { + return v.cf +} + +// Param returns cache tag +func (v *validate) CTag() *cTag { + return v.ct +} diff --git a/validator.go b/validator.go index 7b1fd54..4ff0991 100644 --- a/validator.go +++ b/validator.go @@ -25,7 +25,8 @@ type validate struct { flField reflect.Value flParam string fldIsPointer bool - + cf *cField + ct *cTag // misc reusable values misc []byte str1 string @@ -98,6 +99,8 @@ func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, t // traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns []byte, structNs []byte, cf *cField, ct *cTag) { + v.cf = cf + v.ct = ct var typ reflect.Type var kind reflect.Kind diff --git a/validator_test.go b/validator_test.go index d1ffd97..61a67fd 100644 --- a/validator_test.go +++ b/validator_test.go @@ -7013,3 +7013,41 @@ func TestMapStructNamespace(t *testing.T) { Equal(t, len(ve), 1) AssertError(t, errs, "children[1].name", "Children[1].Name", "name", "Name", "required") } + +func TestFieldLevel_CField(t *testing.T) { + + validate := New() + validate.RegisterValidation("notEqualDesc", func(fl FieldLevel) bool { + return fl.CField().Name() != "Desc" // check field name is not Desc" + }) + + type Foo struct { + Desc string `json:"name" validate:"notEqualDesc"` // field name need not equal Desc + } + + errs := validate.Struct(&Foo{}) + + NotEqual(t, errs, nil) + + ve := errs.(ValidationErrors) + Equal(t, len(ve), 1) +} + +func TestFieldLevel_CTag(t *testing.T) { + + validate := New() + validate.RegisterValidation("fieldNameEqualParam", func(fl FieldLevel) bool { + return fl.CField().Name() == fl.CTag().Param() // check field name equal tag param" + }) + + type Foo struct { + Desc string `json:"name" validate:"fieldNameEqualParam=Asc"` // field name need equal tag param + } + + errs := validate.Struct(&Foo{}) + + NotEqual(t, errs, nil) + + ve := errs.(ValidationErrors) + Equal(t, len(ve), 1) +}