Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,10 @@ func WithRequiredStructEnabled() Option {
v.requiredStructEnabled = true
}
}

// WithRequiredStructEnabled enables omitting the name of embedded anonymous structs from the namespace.
func WithOmitAnonymousName() Option {
return func(v *Validate) {
v.omitAnonymousName = true
}
}
4 changes: 1 addition & 3 deletions validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ type validate struct {

// parent and current will be the same the first run of validateStruct
func (v *validate) validateStruct(ctx context.Context, parent reflect.Value, current reflect.Value, typ reflect.Type, ns []byte, structNs []byte, ct *cTag) {

cs, ok := v.v.structCache.Get(typ)
if !ok {
cs = v.v.extractStructCache(current, typ.Name())
Expand Down Expand Up @@ -193,7 +192,7 @@ OUTER:
// Var - doesn't make much sense to do it that way, should call 'Struct', but no harm...
// VarWithField - this allows for validating against each field within the struct against a specific value
// pretty handy in certain situations
if len(cf.name) > 0 {
if len(cf.name) > 0 && !(v.v.omitAnonymousName && parent.Type().Field(cf.idx).Anonymous) {
ns = append(append(ns, cf.altName...), '.')
structNs = append(append(structNs, cf.name...), '.')
}
Expand Down Expand Up @@ -482,5 +481,4 @@ OUTER:
ct = ct.next
}
}

}
8 changes: 1 addition & 7 deletions validator_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ type Validate struct {
hasCustomFuncs bool
hasTagNameFunc bool
requiredStructEnabled bool
omitAnonymousName bool
}

// New returns a new instance of 'validate' with sane defaults.
Expand All @@ -102,7 +103,6 @@ type Validate struct {
// in essence only parsing your validation tags once per struct type.
// Using multiple instances neglects the benefit of caching.
func New(options ...Option) *Validate {

tc := new(tagCache)
tc.m.Store(make(map[string]*cTag))

Expand All @@ -124,7 +124,6 @@ func New(options ...Option) *Validate {

// must copy validators for separate validations to be used in each instance
for k, val := range bakedInValidators {

switch k {
// these require that even if the value is nil that the validation should run, omitempty still overrides this behaviour
case requiredIfTag, requiredUnlessTag, requiredWithTag, requiredWithAllTag, requiredWithoutTag, requiredWithoutAllTag,
Expand Down Expand Up @@ -254,7 +253,6 @@ func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn bool, nilC
//
// NOTE: this function is not thread-safe it is intended that these all be registered prior to any validation
func (v *Validate) RegisterAlias(alias, tags string) {

_, ok := restrictedTags[alias]

if ok || strings.ContainsAny(alias, restrictedTagChars) {
Expand All @@ -278,7 +276,6 @@ func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interfa
// NOTE:
// - this method is not thread-safe it is intended that these all be registered prior to any validation
func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, types ...interface{}) {

if v.structLevelFuncs == nil {
v.structLevelFuncs = make(map[reflect.Type]StructLevelFuncCtx)
}
Expand Down Expand Up @@ -325,7 +322,6 @@ func (v *Validate) RegisterStructValidationMapRules(rules map[string]string, typ
//
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {

if v.customFuncs == nil {
v.customFuncs = make(map[reflect.Type]CustomTypeFunc)
}
Expand All @@ -339,7 +335,6 @@ func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{

// RegisterTranslation registers translations against the provided tag.
func (v *Validate) RegisterTranslation(tag string, trans ut.Translator, registerFn RegisterTranslationsFunc, translationFn TranslationFunc) (err error) {

if v.transTagFunc == nil {
v.transTagFunc = make(map[ut.Translator]map[string]TranslationFunc)
}
Expand Down Expand Up @@ -373,7 +368,6 @@ func (v *Validate) Struct(s interface{}) error {
// It returns InvalidValidationError for bad values passed in and nil or ValidationErrors as error otherwise.
// You will need to assert the error if it's not nil eg. err.(validator.ValidationErrors) to access the array of errors.
func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err error) {

val := reflect.ValueOf(s)
top := val

Expand Down
39 changes: 30 additions & 9 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,11 +746,9 @@ func TestStructPartial(t *testing.T) {

SubSlice: []*SubTest{
{

Test: "Required",
},
{

Test: "Required",
},
},
Expand Down Expand Up @@ -4002,7 +4000,6 @@ func TestUUID5Validation(t *testing.T) {
param string
expected bool
}{

{"", false},
{"xxxa987fbc9-4bed-3078-cf07-9141ba07c9f3", false},
{"9c858901-8a57-4791-81fe-4c455b099bc9", false},
Expand Down Expand Up @@ -4190,7 +4187,6 @@ func TestUUID5RFC4122Validation(t *testing.T) {
param string
expected bool
}{

{"", false},
{"xxxa987Fbc9-4bed-3078-cf07-9141ba07c9f3", false},
{"9c858901-8a57-4791-81Fe-4c455b099bc9", false},
Expand Down Expand Up @@ -8793,6 +8789,7 @@ func TestNumeric(t *testing.T) {
errs = validate.Var(i, "numeric")
Equal(t, errs, nil)
}

func TestBoolean(t *testing.T) {
validate := New()

Expand Down Expand Up @@ -9518,11 +9515,9 @@ func TestStructFiltered(t *testing.T) {

SubSlice: []*SubTest{
{

Test: "Required",
},
{

Test: "Required",
},
},
Expand Down Expand Up @@ -12909,7 +12904,6 @@ func TestSemverFormatValidation(t *testing.T) {
}

func TestCveFormatValidation(t *testing.T) {

tests := []struct {
value string `validate:"cve"`
tag string
Expand Down Expand Up @@ -13106,7 +13100,6 @@ func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) {
}

func TestValidate_ValidateMapCtx(t *testing.T) {

type args struct {
data map[string]interface{}
rules map[string]interface{}
Expand Down Expand Up @@ -13588,7 +13581,7 @@ func TestNestedStructValidation(t *testing.T) {
},
}

var evaluateTest = func(tt test, errs error) {
evaluateTest := func(tt test, errs error) {
if tt.err != (testErr{}) && errs != nil {
Equal(t, len(errs.(ValidationErrors)), 1)

Expand Down Expand Up @@ -13626,6 +13619,34 @@ func TestNestedStructValidation(t *testing.T) {
}
}

func TestHideEmbeddedStructName(t *testing.T) {
validate := New(WithOmitAnonymousName())

type Inner struct {
Test string `validate:"required"`
}

t.Run("anonymous", func(t *testing.T) {
type Anonymous struct {
Inner
}

err := validate.Struct(Anonymous{})
NotEqual(t, err, nil)
AssertError(t, err.(ValidationErrors), "Anonymous.Test", "Anonymous.Test", "Test", "Test", "required")
})

t.Run("named", func(t *testing.T) {
type Named struct {
Inner Inner
}

err := validate.Struct(Named{})
NotEqual(t, err, nil)
AssertError(t, err.(ValidationErrors), "Named.Inner.Test", "Named.Inner.Test", "Test", "Test", "required")
})
}

func TestTimeRequired(t *testing.T) {
validate := New()
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
Expand Down