From fb68f39656d7ebf8aa339ad4917aa0c260ecc237 Mon Sep 17 00:00:00 2001 From: Dean Karn Date: Sun, 11 Jun 2017 22:26:53 -0700 Subject: [PATCH] Add Access to Field Name from FieldLevel (#284) --- README.md | 14 ++-- {examples => _examples}/custom/main.go | 0 .../gin-upgrading-overriding/main.go | 0 .../gin-upgrading-overriding/v8_to_v9.go | 0 {examples => _examples}/simple/main.go | 0 {examples => _examples}/struct-level/main.go | 0 {examples => _examples}/translations/main.go | 0 doc.go | 2 +- field_level.go | 22 ++++++- validator.go | 12 ++-- validator_test.go | 66 +++++++++++++++++++ 11 files changed, 102 insertions(+), 14 deletions(-) rename {examples => _examples}/custom/main.go (100%) rename {examples => _examples}/gin-upgrading-overriding/main.go (100%) rename {examples => _examples}/gin-upgrading-overriding/v8_to_v9.go (100%) rename {examples => _examples}/simple/main.go (100%) rename {examples => _examples}/struct-level/main.go (100%) rename {examples => _examples}/translations/main.go (100%) diff --git a/README.md b/README.md index 5ad1e77..f586966 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Package validator ================ [![Join the chat at https://gitter.im/go-playground/validator](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -![Project status](https://img.shields.io/badge/version-9.3.6-green.svg) +![Project status](https://img.shields.io/badge/version-9.4.0-green.svg) [![Build Status](https://semaphoreci.com/api/v1/joeybloggs/validator/branches/v9/badge.svg)](https://semaphoreci.com/joeybloggs/validator) [![Coverage Status](https://coveralls.io/repos/go-playground/validator/badge.svg?branch=v9&service=github)](https://coveralls.io/github/go-playground/validator?branch=v9) [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/validator)](https://goreportcard.com/report/github.com/go-playground/validator) @@ -19,7 +19,7 @@ It has the following **unique** features: - Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs - Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError - Customizable i18n aware error messages. -- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/v9/examples/gin-upgrading-overriding) +- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) Installation ------------ @@ -56,11 +56,11 @@ Please see http://godoc.org/gopkg.in/go-playground/validator.v9 for detailed usa ##### Examples: -- [Simple](https://github.com/go-playground/validator/blob/v9/examples/simple/main.go) -- [Custom Field Types](https://github.com/go-playground/validator/blob/v9/examples/custom/main.go) -- [Struct Level](https://github.com/go-playground/validator/blob/v9/examples/struct-level/main.go) -- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/v9/examples/translations/main.go) -- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/examples/gin-upgrading-overriding) +- [Simple](https://github.com/go-playground/validator/blob/v9/_examples/simple/main.go) +- [Custom Field Types](https://github.com/go-playground/validator/blob/v9/_examples/custom/main.go) +- [Struct Level](https://github.com/go-playground/validator/blob/v9/_examples/struct-level/main.go) +- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go) +- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding) - [wash - an example application putting it all together](https://github.com/bluesuncorp/wash) Benchmarks diff --git a/examples/custom/main.go b/_examples/custom/main.go similarity index 100% rename from examples/custom/main.go rename to _examples/custom/main.go diff --git a/examples/gin-upgrading-overriding/main.go b/_examples/gin-upgrading-overriding/main.go similarity index 100% rename from examples/gin-upgrading-overriding/main.go rename to _examples/gin-upgrading-overriding/main.go diff --git a/examples/gin-upgrading-overriding/v8_to_v9.go b/_examples/gin-upgrading-overriding/v8_to_v9.go similarity index 100% rename from examples/gin-upgrading-overriding/v8_to_v9.go rename to _examples/gin-upgrading-overriding/v8_to_v9.go diff --git a/examples/simple/main.go b/_examples/simple/main.go similarity index 100% rename from examples/simple/main.go rename to _examples/simple/main.go diff --git a/examples/struct-level/main.go b/_examples/struct-level/main.go similarity index 100% rename from examples/struct-level/main.go rename to _examples/struct-level/main.go diff --git a/examples/translations/main.go b/_examples/translations/main.go similarity index 100% rename from examples/translations/main.go rename to _examples/translations/main.go diff --git a/doc.go b/doc.go index bea8772..7da5e59 100644 --- a/doc.go +++ b/doc.go @@ -5,7 +5,7 @@ based on tags. It can also handle Cross-Field and Cross-Struct validation for nested structs and has the ability to dive into arrays and maps of any type. -see more examples https://github.com/go-playground/validator/tree/v9/examples +see more examples https://github.com/go-playground/validator/tree/v9/_examples Validation Functions Return Type error diff --git a/field_level.go b/field_level.go index 7c74151..6d73192 100644 --- a/field_level.go +++ b/field_level.go @@ -16,6 +16,13 @@ type FieldLevel interface { // returns current field for validation Field() reflect.Value + // returns the field's name with the tag + // name takeing precedence over the fields actual name. + FieldName() string + + // returns the struct field's name + StructFieldName() string + // returns param for validation against current field Param() string @@ -40,12 +47,23 @@ func (v *validate) Field() reflect.Value { return v.flField } +// FieldName returns the field's name with the tag +// name takeing precedence over the fields actual name. +func (v *validate) FieldName() string { + return v.cf.altName +} + +// StructFieldName returns the struct field's name +func (v *validate) StructFieldName() string { + return v.cf.name +} + // Param returns param for validation against current field func (v *validate) Param() string { - return v.flParam + return v.ct.param } // GetStructFieldOK returns Param returns param for validation against current field func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) { - return v.getStructFieldOKInternal(v.slflParent, v.flParam) + return v.getStructFieldOKInternal(v.slflParent, v.ct.param) } diff --git a/validator.go b/validator.go index 7b1fd54..98bf265 100644 --- a/validator.go +++ b/validator.go @@ -23,8 +23,9 @@ type validate struct { slflParent reflect.Value slCurrent reflect.Value flField reflect.Value - flParam string fldIsPointer bool + cf *cField + ct *cTag // misc reusable values misc []byte @@ -215,7 +216,8 @@ OUTER: // set Field Level fields v.slflParent = parent v.flField = current - v.flParam = "" + v.cf = cf + v.ct = ct if !v.fldIsPointer && !hasValue(v) { return @@ -309,7 +311,8 @@ OUTER: // set Field Level fields v.slflParent = parent v.flField = current - v.flParam = ct.param + v.cf = cf + v.ct = ct if ct.fn(v) { @@ -397,7 +400,8 @@ OUTER: // set Field Level fields v.slflParent = parent v.flField = current - v.flParam = ct.param + v.cf = cf + v.ct = ct // // report error interface functions need these // v.ns = ns diff --git a/validator_test.go b/validator_test.go index d1ffd97..c1dcb63 100644 --- a/validator_test.go +++ b/validator_test.go @@ -7013,3 +7013,69 @@ func TestMapStructNamespace(t *testing.T) { Equal(t, len(ve), 1) AssertError(t, errs, "children[1].name", "Children[1].Name", "name", "Name", "required") } + +func TestFieldLevelName(t *testing.T) { + type Test struct { + String string `validate:"custom1" json:"json1"` + Array []string `validate:"dive,custom2" json:"json2"` + Map map[string]string `validate:"dive,custom3" json:"json3"` + Array2 []string `validate:"custom4" json:"json4"` + Map2 map[string]string `validate:"custom5" json:"json5"` + } + + var res1, res2, res3, res4, res5, alt1, alt2, alt3, alt4, alt5 string + validate := New() + validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] + + if name == "-" { + return "" + } + + return name + }) + validate.RegisterValidation("custom1", func(fl FieldLevel) bool { + res1 = fl.FieldName() + alt1 = fl.StructFieldName() + return true + }) + validate.RegisterValidation("custom2", func(fl FieldLevel) bool { + res2 = fl.FieldName() + alt2 = fl.StructFieldName() + return true + }) + validate.RegisterValidation("custom3", func(fl FieldLevel) bool { + res3 = fl.FieldName() + alt3 = fl.StructFieldName() + return true + }) + validate.RegisterValidation("custom4", func(fl FieldLevel) bool { + res4 = fl.FieldName() + alt4 = fl.StructFieldName() + return true + }) + validate.RegisterValidation("custom5", func(fl FieldLevel) bool { + res5 = fl.FieldName() + alt5 = fl.StructFieldName() + return true + }) + + test := Test{ + String: "test", + Array: []string{"1"}, + Map: map[string]string{"test": "test"}, + } + + errs := validate.Struct(test) + Equal(t, errs, nil) + Equal(t, res1, "json1") + Equal(t, alt1, "String") + Equal(t, res2, "json2[0]") + Equal(t, alt2, "Array[0]") + Equal(t, res3, "json3[test]") + Equal(t, alt3, "Map[test]") + Equal(t, res4, "json4") + Equal(t, alt4, "Array2") + Equal(t, res5, "json5") + Equal(t, alt5, "Map2") +}