Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross Field OR validation #195

Closed
scisci opened this issue Oct 15, 2015 · 5 comments
Closed

Cross Field OR validation #195

scisci opened this issue Oct 15, 2015 · 5 comments
Assignees
Labels
Milestone

Comments

@scisci
Copy link

scisci commented Oct 15, 2015

Is it possible to validate that on a given struct at least one of two options is required? I often have a struct where as long as one out of 2 of the fields are filled in, it will pass validation. One basic example would be having a username field and an email field (just a basic example though).

@deankarn deankarn self-assigned this Oct 15, 2015
@deankarn deankarn added this to the Questions milestone Oct 15, 2015
@deankarn
Copy link
Contributor

Currently there are no built in tags to do Cross Field OR validation. once getting into situations like you defined above, I consider them to be complex validation rules that even if built in tags could be used, it would become very hard to read.

But the library has a an easy reusable way to achieve what you want by creating a custom validation function, and then you may use and reuse it as a tag in your structs.

Example

// define funciton
func oneFieldSet(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
    // use topStruct instead of currentStructOrField below if want function to be able to do cross struct cross field validation
    currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
    if !ok || currentKind != fieldKind {
        return false
    }

   // if field has a value, just like the hasValue function then return true

   // if currentField has a value return true

   // return false by default
}

validate := //new validator
validate.RegisterValidation("eitherrequired", oneFieldSet)

type User struct {
  Username string `validate:"eitherrequired=Email"`
  Email    string `validate:"eitherrequired=Username"`
}

then you could reuse this tag/validation function in a bunch of your structs

Does that make sense?

P.S. you gave me a great idea, that I should expose the existing validators so that you can use them inside custom ones; then you could use hasValue ( which is the function that "required" tag runs ) in your custom function.

@deankarn
Copy link
Contributor

Hey @scisci

I've updated validator to expose the baked in functions for use within custom functions, so below is a more complete example using the exposed functions.

Example

// define funciton
func oneFieldSet(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
    // use topStruct instead of currentStructOrField below if want function to be able to do cross struct cross field validation
    currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
    if !ok || currentKind != fieldKind {
        return false
    }

    if validator.HasValue(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
      return true
    }

    if validator.HasValue(v, topStruct, currentStructOrField, currentField, fieldType, currentKind, param) {
      return true
    }

    return false
}

validate := //new validator
validate.RegisterValidation("eitherrequired", oneFieldSet)

type User struct {
  Username string `validate:"eitherrequired=Email"`
  Email    string `validate:"eitherrequired=Username"`
}

will this work for your needs? it should be generic enough to use within many of your structs

@scisci
Copy link
Author

scisci commented Oct 16, 2015

awesome! yeah that totally works for me. I will look into implementing it as soon as possible. thanks @joeybloggs I had some more complex validation as well so using a validation function makes total sense.

@deankarn
Copy link
Contributor

perfect! glad I could help @scisci

if you need any help or have any question, just let me know.

@deankarn
Copy link
Contributor

Hey @scisci thought I'd let you know about Struct Level Validations see here: https://github.com/go-playground/validator/releases/tag/v8.7

this may be an even better way to do your username or email check 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants