diff --git a/README.md b/README.md index 3d52c7347..ef073fa7e 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ Baked-in Validations | btc_addr | Bitcoin Address | | btc_addr_bech32 | Bitcoin Bech32 Address (segwit) | | credit_card | Credit Card Number | +| mongodb | MongoDB ObjectID | | cron | Cron | | datetime | Datetime | | e164 | e164 formatted phone number | diff --git a/baked_in.go b/baked_in.go index 9ce2282f6..122f30fd3 100644 --- a/baked_in.go +++ b/baked_in.go @@ -219,6 +219,7 @@ var ( "semver": isSemverFormat, "dns_rfc1035_label": isDnsRFC1035LabelFormat, "credit_card": isCreditCard, + "mongodb": isMongoDB, "cron": isCron, } ) @@ -2567,6 +2568,12 @@ func isDnsRFC1035LabelFormat(fl FieldLevel) bool { return dnsRegexRFC1035Label.MatchString(val) } +// isMongoDB is the validation function for validating if the current field's value is valid mongoDB objectID +func isMongoDB(fl FieldLevel) bool { + val := fl.Field().String() + return mongodbRegex.MatchString(val) +} + // isCreditCard is the validation function for validating if the current field's value is a valid credit card number func isCreditCard(fl FieldLevel) bool { val := fl.Field().String() diff --git a/doc.go b/doc.go index 2b44b5369..e0b79b78e 100644 --- a/doc.go +++ b/doc.go @@ -1332,6 +1332,13 @@ This validates that a string value contains a valid credit card number using Luh Usage: credit_card +#MongoDb ObjectID + +This validates that a string is a valid 24 character hexadecimal string. + + Usage: mongodb + + # Cron This validates that a string value contains a valid cron expression. diff --git a/regexes.go b/regexes.go index 029dd9120..a65ac6f02 100644 --- a/regexes.go +++ b/regexes.go @@ -65,6 +65,7 @@ const ( bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$` semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/ dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$" + mongodbRegexString = "^[a-f\\d]{24}$" cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})` ) @@ -129,5 +130,6 @@ var ( bicRegex = regexp.MustCompile(bicRegexString) semverRegex = regexp.MustCompile(semverRegexString) dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label) + mongodbRegex = regexp.MustCompile(mongodbRegexString) cronRegex = regexp.MustCompile(cronRegexString) ) diff --git a/validator_test.go b/validator_test.go index ec7e3aaa3..8e1ea3e8c 100644 --- a/validator_test.go +++ b/validator_test.go @@ -12546,6 +12546,42 @@ func TestValidate_ValidateMapCtx(t *testing.T) { } } +func TestMongoDBObjectIDFormatValidation(t *testing.T) { + tests := []struct { + value string `validate:"mongodb"` + tag string + expected bool + }{ + {"507f191e810c19729de860ea", "mongodb", true}, + {"507f191e810c19729de860eG", "mongodb", false}, + {"M07f191e810c19729de860eG", "mongodb", false}, + {"07f191e810c19729de860ea", "mongodb", false}, + {"507f191e810c19729de860e", "mongodb", false}, + {"507f191e810c19729de860ea4", "mongodb", false}, + } + + validate := New() + + for i, test := range tests { + errs := validate.Var(test.value, test.tag) + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d mongodb failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d mongodb failed Error: %s", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "mongodb" { + t.Fatalf("Index: %d mongodb failed Error: %s", i, errs) + } + } + } + } +} + func TestCreditCardFormatValidation(t *testing.T) { tests := []struct { value string `validate:"credit_card"`