From 1c1f70d35b58e3ecf9416b30f7b3804e8e68dee3 Mon Sep 17 00:00:00 2001 From: zemzale <14844365+zemzale@users.noreply.github.com> Date: Sun, 19 Mar 2023 21:28:12 +0200 Subject: [PATCH] feat(unique): Add support for struct memember validation (#1048) This allows validating that two struct memebers are unique. This has been documented as a feature, but has never been actually implemented. --- baked_in.go | 13 +++++++++++++ validator_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/baked_in.go b/baked_in.go index dd4b331..1e6e00d 100644 --- a/baked_in.go +++ b/baked_in.go @@ -335,6 +335,19 @@ func isUnique(fl FieldLevel) bool { return field.Len() == m.Len() default: + if parent := fl.Parent(); parent.Kind() == reflect.Struct { + uniqueField := parent.FieldByName(param) + if uniqueField == reflect.ValueOf(nil) { + panic(fmt.Sprintf("Bad field name provided %s", param)) + } + + if uniqueField.Kind() != field.Kind() { + panic(fmt.Sprintf("Bad field type %T:%T", field.Interface(), uniqueField.Interface())) + } + + return field.Interface() != uniqueField.Interface() + } + panic(fmt.Sprintf("Bad field type %T", field.Interface())) } } diff --git a/validator_test.go b/validator_test.go index 07bc889..fdf8a54 100644 --- a/validator_test.go +++ b/validator_test.go @@ -9991,6 +9991,41 @@ func TestUniqueValidation(t *testing.T) { } } PanicMatches(t, func() { _ = validate.Var(1.0, "unique") }, "Bad field type float64") + + t.Run("struct", func(t *testing.T) { + tests := []struct { + param interface{} + expected bool + }{ + {struct { + A string `validate:"unique=B"` + B string + }{A: "abc", B: "bcd"}, true}, + {struct { + A string `validate:"unique=B"` + B string + }{A: "abc", B: "abc"}, false}, + } + validate := New() + + for i, test := range tests { + errs := validate.Struct(test.param) + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d unique failed Error: %v", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d unique failed Error: %v", i, errs) + } else { + val := getError(errs, "A", "A") + if val.Tag() != "unique" { + t.Fatalf("Index: %d unique failed Error: %v", i, errs) + } + } + } + } + }) } func TestUniqueValidationStructSlice(t *testing.T) {